From 1ac8d991454ef97796ddf1090448096f8e09b0f9 Mon Sep 17 00:00:00 2001 From: zzz <zzz@mail.i2p> Date: Fri, 3 Apr 2015 12:19:41 +0000 Subject: [PATCH] i2ptunnel: Send HTTP server port 443 traffic to the server transparently, to support HTTPS over the same tunnel, when so configured. Jetty: Add extensive help to jetty-ssl.xml for setting up SSL on the same server. --- .../i2p/i2ptunnel/I2PTunnelHTTPServer.java | 63 +++-- installer/resources/eepsite/jetty-ssl.xml | 235 +++++++++++++++++- installer/resources/eepsite/jetty.xml | 13 - 3 files changed, 272 insertions(+), 39 deletions(-) diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPServer.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPServer.java index 3c8066c568..79b17c3504 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPServer.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPServer.java @@ -69,8 +69,8 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer { private long _startedOn = 0L; private ConnThrottler _postThrottler; - private final static byte[] ERR_UNAVAILABLE = - ("HTTP/1.1 503 Service Unavailable\r\n"+ + private final static String ERR_UNAVAILABLE = + "HTTP/1.1 503 Service Unavailable\r\n"+ "Content-Type: text/html; charset=iso-8859-1\r\n"+ "Cache-control: no-cache\r\n"+ "Connection: close\r\n"+ @@ -79,11 +79,10 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer { "<html><head><title>503 Service Unavailable</title></head>\n"+ "<body><h2>503 Service Unavailable</h2>\n" + "<p>This I2P website is unavailable. It may be down or undergoing maintenance.</p>\n" + - "</body></html>") - .getBytes(); + "</body></html>"; - private final static byte[] ERR_DENIED = - ("HTTP/1.1 403 Denied\r\n"+ + private final static String ERR_DENIED = + "HTTP/1.1 403 Denied\r\n"+ "Content-Type: text/html; charset=iso-8859-1\r\n"+ "Cache-control: no-cache\r\n"+ "Connection: close\r\n"+ @@ -92,11 +91,10 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer { "<html><head><title>403 Denied</title></head>\n"+ "<body><h2>403 Denied</h2>\n" + "<p>Denied due to excessive requests. Please try again later.</p>\n" + - "</body></html>") - .getBytes(); + "</body></html>"; - private final static byte[] ERR_INPROXY = - ("HTTP/1.1 403 Denied\r\n"+ + private final static String ERR_INPROXY = + "HTTP/1.1 403 Denied\r\n"+ "Content-Type: text/html; charset=iso-8859-1\r\n"+ "Cache-control: no-cache\r\n"+ "Connection: close\r\n"+ @@ -105,8 +103,19 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer { "<html><head><title>403 Denied</title></head>\n"+ "<body><h2>403 Denied</h2>\n" + "<p>Inproxy access denied. You must run <a href=\"https://geti2p.net/\">I2P</a> to access this site.</p>\n" + - "</body></html>") - .getBytes(); + "</body></html>"; + + private final static String ERR_SSL = + "HTTP/1.1 503 Service Unavailable\r\n"+ + "Content-Type: text/html; charset=iso-8859-1\r\n"+ + "Cache-control: no-cache\r\n"+ + "Connection: close\r\n"+ + "Proxy-Connection: close\r\n"+ + "\r\n"+ + "<html><head><title>503 Service Unavailable</title></head>\n"+ + "<body><h2>503 Service Unavailable</h2>\n" + + "<p>This I2P website is not configured for SSL.</p>\n" + + "</body></html>"; public I2PTunnelHTTPServer(InetAddress host, int port, String privData, String spoofHost, Logging l, EventDispatcher notifyThis, I2PTunnel tunnel) { super(host, port, privData, l, notifyThis, tunnel); @@ -203,7 +212,27 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer { //local is fast, so synchronously. Does not need that many //threads. try { + if (socket.getLocalPort() == 443) { + if (getTunnel().getClientOptions().getProperty("targetForPort.443") == null) { + try { + socket.getOutputStream().write(ERR_SSL.getBytes("UTF-8")); + } catch (IOException ioe) { + } finally { + try { + socket.close(); + } catch (IOException ioe) {} + } + return; + } + Socket s = getSocket(socket.getPeerDestination().calculateHash(), 443); + Runnable t = new I2PTunnelRunner(s, socket, slock, null, null, + null, (I2PTunnelRunner.FailCallback) null); + _clientExecutor.execute(t); + return; + } + long afterAccept = getTunnel().getContext().clock().now(); + // The headers _should_ be in the first packet, but // may not be, depending on the client-side options socket.setReadTimeout(HEADER_TIMEOUT); @@ -237,7 +266,7 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer { try { // Send a 403, so the user doesn't get an HTTP Proxy error message // and blame his router or the network. - socket.getOutputStream().write(ERR_INPROXY); + socket.getOutputStream().write(ERR_INPROXY.getBytes("UTF-8")); } catch (IOException ioe) {} try { socket.close(); @@ -254,7 +283,7 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer { try { // Send a 403, so the user doesn't get an HTTP Proxy error message // and blame his router or the network. - socket.getOutputStream().write(ERR_DENIED); + socket.getOutputStream().write(ERR_DENIED.getBytes("UTF-8")); } catch (IOException ioe) {} try { socket.close(); @@ -339,7 +368,7 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer { try { // Send a 503, so the user doesn't get an HTTP Proxy error message // and blame his router or the network. - socket.getOutputStream().write(ERR_UNAVAILABLE); + socket.getOutputStream().write(ERR_UNAVAILABLE.getBytes("UTF-8")); } catch (IOException ioe) {} try { socket.close(); @@ -360,7 +389,7 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer { try { // Send a 503, so the user doesn't get an HTTP Proxy error message // and blame his router or the network. - socket.getOutputStream().write(ERR_UNAVAILABLE); + socket.getOutputStream().write(ERR_UNAVAILABLE.getBytes("UTF-8")); } catch (IOException ioe) {} try { socket.close(); @@ -451,7 +480,7 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer { try { if (browserout == null) browserout = _browser.getOutputStream(); - browserout.write(ERR_UNAVAILABLE); + browserout.write(ERR_UNAVAILABLE.getBytes("UTF-8")); } catch (IOException ioe) {} } catch (IOException ioe) { if (_log.shouldLog(Log.WARN)) diff --git a/installer/resources/eepsite/jetty-ssl.xml b/installer/resources/eepsite/jetty-ssl.xml index c6d91cc83d..56253c6b90 100644 --- a/installer/resources/eepsite/jetty-ssl.xml +++ b/installer/resources/eepsite/jetty-ssl.xml @@ -1,35 +1,252 @@ <?xml version="1.0"?> <!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd"> +<!-- ========================================================================= --> +<!-- If you have a 'split' directory installation, with configuration --> +<!-- files in ~/.i2p (Linux) or %APPDATA%\I2P (Windows), be sure to --> +<!-- edit the file in the configuration directory, NOT the install directory. --> +<!-- When running as a Linux daemon, the configuration directory is --> +<!-- /var/lib/i2p and the install directory is /usr/share/i2p . --> +<!-- --> +<!-- ========================================================================= --> + <!-- =============================================================== --> <!-- Configure SSL for the Jetty Server --> <!-- this configuration file should be used in combination with --> -<!-- other configuration files. e.g. --> -<!-- java -jar start.jar etc/jetty-ssl.xml --> +<!-- other configuration files. --> +<!-- --> +<!-- =============================================================== --> +<!-- Add a HTTPS SSL listener on port 7668 --> +<!-- --> +<!-- NOTE: --> +<!-- --> +<!-- While I2P already encrypts end-to-end, HTTPS support --> +<!-- is valuable for authentication. --> +<!-- --> +<!-- These instructions are to add SSL support to an existing --> +<!-- HTTP Jetty website. --> +<!-- --> +<!-- For HTTPS ONLY, create a standard server tunnel --> +<!-- (NOT HTTP server), and skip step 8. --> +<!-- --> +<!-- For non-Jetty servers (e.g. Apache), follow your server --> +<!-- instructions to generate and configure the certificates, --> +<!-- and skip steps 1-7. --> <!-- --> -<!-- alternately, add to the start.ini for easier usage --> <!-- =============================================================== --> +<!-- --> +<!-- To add SSL support for your existing website: --> +<!-- --> +<!-- Step 1: --> +<!-- Get the b32 for your wehsite, it's the link at the --> +<!-- "preview" button in the Hidden Services Manager in --> +<!-- the console. If you aren't running i2p, you can --> +<!-- get it from your private key file --> +<!-- (probably ~/.i2p/eepsite/eepPriv.dat) --> +<!-- with the command: --> +<!-- java -cp ~/i2p/lib/i2p.jar net.i2p.data.PrivateKeyFile ~/.i2p/eepsite/eepPriv.dat --> +<!-- Save the b32 to put in the certificate's CN in Step 2. --> +<!-- --> +<!-- --> +<!-- Step 2: --> +<!-- Generate selfsigned certificates. --> +<!-- We recommend two: one for the hostname, and one for the b32. --> +<!-- Note that server-side SNI to serve the correct certificate --> +<!-- requires Java 8. Otherwise it will pick one. --> +<!-- (at random? first one?) --> +<!-- Change the CN and key password in the example, of course. --> +<!-- It's OK to keep the keystore password as "changeit" if you like. --> +<!-- Use the same passwords for both certificates. --> +<!-- See https://wiki.eclipse.org/Jetty/Howto/Configure_SSL --> +<!-- for alternate methods. --> +<!-- + keytool -genkey -keystore ~/.i2p/eepsite/etc/keystore.ks -storepass changeit -alias b32 -dname CN=biglongkey.b32.i2p,OU=Eepsite,O=XX,L=XX,ST=XX,C=XX -validity 3652 -keyalg RSA -keysize 2048 -keypass myKeyPassword + keytool -genkey -keystore ~/.i2p/eepsite/etc/keystore.ks -storepass changeit -alias hostname -dname CN=example.i2p,OU=Eepsite,O=XX,L=XX,ST=XX,C=XX -validity 3652 -keyalg RSA -keysize 2048 -keypass myKeyPassword + chmod 600 ~/.i2p/eepsite/etc/keystore.ks + --> +<!-- --> +<!-- But does SNI work? see: --> +<!-- http://blog.ivanristic.com/2014/03/ssl-tls-improvements-in-java-8.html --> +<!-- http://stackoverflow.com/questions/20887504/tls-extension-server-name-indication-sni-value-not-available-on-server-side --> +<!-- --> +<!-- And no, you can't get a real certificate for an i2p --> +<!-- address from a Certificate Authority, but someday --> +<!-- it may be possible. Here's how Tor did it: --> +<!-- https://cabforum.org/2015/02/18/ballot-144-validation-rules-dot-onion-names/ --> +<!-- --> +<!-- --> +<!-- Step 3: --> +<!-- Update this configuration file. --> +<!-- Edit the KeyStorePassword, TrustStorePassword, and --> +<!-- KeyManagerPassword below to match the passwords from Step 2. --> +<!-- --> +<!-- --> +<!-- Step 4: --> +<!-- If running I2P, stop the website Jetty on /configclients --> +<!-- in the console. --> +<!-- --> +<!-- --> +<!-- Step 5: --> +<!-- Configure Jetty to read in this file at startup. --> +<!-- If running I2P, edit the website Jetty on /configclients --> +<!-- to add the argument "/path/to/.i2p/eepsite/jetty-ssl.xml". --> +<!-- --> +<!-- If I2P is not running, edit the file ~/.i2p/clients.config --> +<!-- to add the argument "/path/to/.i2p/eepsite/jetty-ssl.xml" --> +<!-- at the end of the line: --> +<-- clientApp.3.args="eepsite/jetty.xml" --> +<!-- so it now looks like: --> +<-- clientApp.3.args="/path to/.i2p/eepsite/jetty.xml" "/path/to/.i2p/eepsite/jetty-ssl.xml" --> +<!-- --> +<!-- --> +<!-- Step 6: --> +<!-- Start Jetty. --> +<!-- If running I2P, start the website Jetty on /configclients --> +<!-- in the console. --> +<!-- If I2P is not running, start it. --> +<!-- --> +<!-- Now go to the /logs page in the console and check for errors --> +<!-- in both the router and wrapper logs. --> +<!-- --> +<!-- --> +<!-- Step 7: --> +<!-- Test Jetty. --> +<!-- If there were no errors, test your Jetty SSL by --> +<!-- going to https://127.0.0.1:7668/ in your browser. --> +<!-- You will have to confirm the security exception for --> +<!-- the selfsigned certificate. --> +<!-- --> +<!-- --> +<!-- Step 8: --> +<!-- Configure i2ptunnel. --> +<!-- Tell i2ptunnel to route SSL to port 7668 by adding the --> +<!-- following custom option on the i2ptunnel edit page --> +<!-- for your website: --> +<!-- targetForPort.443=127.0.0.1:7668 --> +<!-- Also, verify that "Use SSL" near the top is NOT set. --> +<!-- That would be SSL-over-SSL, which won't work. --> +<!-- --> +<!-- --> +<!-- Step 9: --> +<!-- Start the tunnel if it isn't started. --> +<!-- --> +<!-- --> +<!-- Step 10: --> +<!-- In the i2ptunnel HTTP Client configuration, --> +<!-- enable "Allow SSL to I2P addresses" if it isn't already. --> +<!-- --> +<!-- --> +<!-- Step 11: --> +<!-- Test SSL via i2ptunnel. --> +<!-- Test SSL to your website through I2P by entering --> +<!-- https://yoursite.i2p/ in your browser. --> +<!-- If it doesn't work, check the /logs page in the console. --> +<!-- You may need to adjust your browser proxy settings to --> +<!-- ensure that https i2p URLs are fetched through the I2P proxy. --> +<!-- For example, in privoxy, add --> +<!-- https://*.i2p/* and https://*.i2p:*/* --> +<!-- --> +<!-- --> +<!-- Step 12: --> +<!-- Tell your users. --> +<!-- Put a link to the https version on your --> +<!-- home page. Remind them that in --> +<!-- the i2ptunnel HTTP Client configuration, --> +<!-- enable "Allow SSL to I2P addresses" if it isn't already. --> +<!-- Remind them to confirm the security exception for --> +<!-- the selfsigned certificate (but not one for a hostname --> +<!-- mismatch) (but see SNI issues above). --> +<!-- Users may need to adjust their browser proxy settings to --> +<!-- ensure that https i2p URLs are fetched through the I2P proxy. --> +<!-- For example, in privoxy, add --> +<!-- https://*.i2p/* and https://*.i2p:*/* --> +<!-- --> +<!-- Decide what link to use. The hostname is not secure, --> +<!-- as users may have a different hostname in their browser. --> +<!-- Also, new address helpers won't work with SSL. --> +<!-- The b32 is the recommended hostname. --> +<!-- --> +<!-- --> +<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> + <Configure id="Server" class="org.eclipse.jetty.server.Server"> <!-- if NIO is not available, use org.eclipse.jetty.server.ssl.SslSocketConnector --> <New id="sslContextFactory" class="org.eclipse.jetty.http.ssl.SslContextFactory"> - <Set name="KeyStore">./eepsite/etc/keystore</Set> - <Set name="KeyStorePassword">OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4</Set> - <Set name="KeyManagerPassword">OBF:1u2u1wml1z7s1z7a1wnl1u2g</Set> - <Set name="TrustStore">./eepsite/etc/keystore</Set> - <Set name="TrustStorePassword">OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4</Set> + <Set name="KeyStore">./eepsite/etc/keystore.ks</Set> + <Set name="KeyStorePassword">changeit</Set> + <Set name="KeyManagerPassword">myKeyPassword</Set> + <Set name="TrustStore">./eepsite/etc/keystore.ks</Set> + <Set name="TrustStorePassword">changeit</Set> </New> <Call name="addConnector"> <Arg> <New class="org.eclipse.jetty.server.ssl.SslSelectChannelConnector"> <Arg><Ref id="sslContextFactory" /></Arg> - <Set name="Port">8443</Set> + <Set name="Port">7668</Set> <Set name="maxIdleTime">600000</Set> <Set name="useDirectBuffers">false</Set> <Set name="Acceptors">2</Set> <Set name="AcceptQueueSize">100</Set> + <Set name="ExcludeCipherSuites"> + <Array type="java.lang.String"> + <Item>SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA</Item> + <Item>SSL_DH_anon_EXPORT_WITH_RC4_40_MD5</Item> + <Item>SSL_DH_anon_WITH_3DES_EDE_CBC_SHA</Item> + <Item>SSL_DH_anon_WITH_DES_CBC_SHA</Item> + <Item>SSL_DH_anon_WITH_RC4_128_MD5</Item> + <Item>SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA</Item> + <Item>SSL_DHE_DSS_WITH_DES_CBC_SHA</Item> + <Item>SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA</Item> + <Item>SSL_DHE_RSA_WITH_DES_CBC_SHA</Item> + <Item>SSL_RSA_EXPORT_WITH_DES40_CBC_SHA</Item> + <Item>SSL_RSA_EXPORT_WITH_RC4_40_MD5</Item> + <Item>SSL_RSA_WITH_DES_CBC_SHA</Item> + <Item>SSL_RSA_WITH_NULL_MD5</Item> + <Item>SSL_RSA_WITH_NULL_SHA</Item> + <Item>TLS_DH_anon_WITH_AES_128_CBC_SHA</Item> + <Item>TLS_DH_anon_WITH_AES_128_CBC_SHA256</Item> + <Item>TLS_DH_anon_WITH_AES_128_GCM_SHA256</Item> + <Item>TLS_DH_anon_WITH_AES_256_CBC_SHA</Item> + <Item>TLS_DH_anon_WITH_AES_256_CBC_SHA256</Item> + <Item>TLS_DH_anon_WITH_AES_256_GCM_SHA384</Item> + <Item>TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA</Item> + <Item>TLS_ECDH_anon_WITH_AES_128_CBC_SHA</Item> + <Item>TLS_ECDH_anon_WITH_AES_256_CBC_SHA</Item> + <Item>TLS_ECDH_anon_WITH_NULL_SHA</Item> + <Item>TLS_ECDH_anon_WITH_RC4_128_SHA</Item> + <Item>TLS_ECDH_ECDSA_WITH_NULL_SHA</Item> + <Item>TLS_ECDHE_ECDSA_WITH_NULL_SHA</Item> + <Item>TLS_ECDHE_RSA_WITH_NULL_SHA</Item> + <Item>TLS_ECDH_RSA_WITH_NULL_SHA</Item> + <Item>TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5</Item> + <Item>TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA</Item> + <Item>TLS_KRB5_EXPORT_WITH_RC4_40_MD5</Item> + <Item>TLS_KRB5_EXPORT_WITH_RC4_40_SHA</Item> + <Item>TLS_KRB5_WITH_3DES_EDE_CBC_MD5</Item> + <Item>TLS_KRB5_WITH_3DES_EDE_CBC_SHA</Item> + <Item>TLS_KRB5_WITH_DES_CBC_MD5</Item> + <Item>TLS_KRB5_WITH_DES_CBC_SHA</Item> + <Item>TLS_KRB5_WITH_RC4_128_MD5</Item> + <Item>TLS_KRB5_WITH_RC4_128_SHA</Item> + <Item>TLS_RSA_WITH_NULL_SHA256</Item> + <Item>SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA</Item> + <Item>SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA</Item> + <Item>SSL_RSA_WITH_3DES_EDE_CBC_SHA</Item> + <Item>SSL_RSA_WITH_RC4_128_MD5</Item> + <Item>SSL_RSA_WITH_RC4_128_SHA</Item> + <Item>TLS_ECDH_ECDSA_WITH_RC4_128_SHA</Item> + <Item>TLS_ECDH_RSA_WITH_RC4_128_SHA</Item> + <Item>TLS_ECDHE_ECDSA_WITH_RC4_128_SHA</Item> + <Item>TLS_ECDHE_RSA_WITH_RC4_128_SHA</Item> + <Item>TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA</Item> + <Item>TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA</Item> + <Item>TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA</Item> + <Item>TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA</Item> + </Array> + </Set> </New> </Arg> </Call> diff --git a/installer/resources/eepsite/jetty.xml b/installer/resources/eepsite/jetty.xml index b524459531..f828a1d9f9 100644 --- a/installer/resources/eepsite/jetty.xml +++ b/installer/resources/eepsite/jetty.xml @@ -168,19 +168,6 @@ <!-- --> <!-- clientApp3.args=etc/jetty.xml etc/jetty-ssl.xml --> <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - <!-- Add a HTTPS SSL listener on port 8443 --> - <!-- --> - <!-- In the unlikely event you would want SSL support for your eepsite. --> - <!-- You would need to generate a selfsigned certificate in a keystore --> - <!-- in ~/.i2p/eepsite/keystore.ks, for example with the command line: --> - <!-- - keytool -genkey -storetype JKS -keystore ~/.i2p/eepsite/etc/keystore.ks -storepass changeit -alias console -dname CN=xyz123.eepsite.i2p.net,OU=Eepsite,O=I2P Anonymous Network,L=XX,ST=XX,C=XX -validity 3650 -keyalg DSA -keysize 1024 -keypass myKeyPassword - --> - <!-- Change the CN and key password in the example, of course. --> - <!-- You wouldn't want to open this up to the regular internet, --> - <!-- would you?? Untested and not recommended. --> - <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> <!-- =========================================================== --> <!-- Set up global session ID manager --> -- GitLab