Console, I2CP, i2ptunnel, SSLEepGet: Set allowed SSL protocols and ciphers

This commit is contained in:
zzz
2014-10-15 20:44:23 +00:00
parent 3bea7f5ad5
commit 83b3f242a9
7 changed files with 300 additions and 3 deletions

View File

@ -24,6 +24,7 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicLong;
import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLServerSocketFactory;
import net.i2p.I2PAppContext;
@ -36,6 +37,7 @@ import net.i2p.client.streaming.I2PSocketOptions;
import net.i2p.data.Destination;
import net.i2p.util.EventDispatcher;
import net.i2p.util.I2PAppThread;
import net.i2p.util.I2PSSLSocketFactory;
import net.i2p.util.Log;
public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runnable {
@ -622,6 +624,7 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
}
SSLServerSocketFactory fact = SSLClientUtil.initializeFactory(opts);
ss = fact.createServerSocket(localPort, 0, addr);
I2PSSLSocketFactory.setProtocolsAndCiphers((SSLServerSocket) ss);
} else {
ss = new ServerSocket(localPort, 0, addr);
}

View File

@ -37,6 +37,7 @@ import net.i2p.util.FileUtil;
import net.i2p.util.I2PAppThread;
import net.i2p.util.PortMapper;
import net.i2p.util.SecureDirectory;
import net.i2p.util.I2PSSLSocketFactory;
import net.i2p.util.SystemVersion;
import org.eclipse.jetty.security.HashLoginService;
import org.eclipse.jetty.security.ConstraintMapping;
@ -464,6 +465,10 @@ public class RouterConsoleRunner implements RouterApp {
sslFactory.setKeyStorePassword(_context.getProperty(PROP_KEYSTORE_PASSWORD, DEFAULT_KEYSTORE_PASSWORD));
// the X.509 cert password (if not present, verifyKeyStore() returned false)
sslFactory.setKeyManagerPassword(_context.getProperty(PROP_KEY_PASSWORD, "thisWontWork"));
sslFactory.addExcludeProtocols(I2PSSLSocketFactory.EXCLUDE_PROTOCOLS.toArray(
new String[I2PSSLSocketFactory.EXCLUDE_PROTOCOLS.size()]));
sslFactory.addExcludeCipherSuites(I2PSSLSocketFactory.INCLUDE_CIPHERS.toArray(
new String[I2PSSLSocketFactory.EXCLUDE_CIPHERS.size()]));
StringTokenizer tok = new StringTokenizer(_sslListenHost, " ,");
while (tok.hasMoreTokens()) {
String host = tok.nextToken().trim();

View File

@ -1,13 +1,42 @@
package net.i2p.util;
/*
* Contains code adapted from:
* Jetty SslContextFactory.java
*
* =======================================================================
* Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
* ------------------------------------------------------------------------
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Apache License v2.0 which accompanies this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* The Apache License v2.0 is available at
* http://www.opensource.org/licenses/apache2.0.php
*
* You may elect to redistribute this code under either of these licenses.
* ========================================================================
*/
import java.io.File;
import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.security.KeyStore;
import java.security.GeneralSecurityException;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManagerFactory;
@ -22,6 +51,103 @@ import net.i2p.crypto.KeyStoreUtil;
*/
public class I2PSSLSocketFactory {
/**
* Unmodifiable.
* Public for RouterConsoleRunner.
* @since 0.9.16
*/
public static final List<String> EXCLUDE_PROTOCOLS = Collections.unmodifiableList(Arrays.asList(new String[] {
"SSLv2Hello", "SSLv3"
}));
/**
* Java 7 does not enable 1.1 or 1.2 by default on the client side.
* Java 8 does enable 1.1 and 1.2 by default on the client side.
* ref: http://docs.oracle.com/javase/7/docs/technotes/guides/security/SunProviders.html
* Unmodifiable.
* Public for RouterConsoleRunner.
* @since 0.9.16
*/
public static final List<String> INCLUDE_PROTOCOLS = Collections.unmodifiableList(Arrays.asList(new String[] {
"TLSv1", "TLSv1.1", "TLSv1.2"
}));
/**
* We exclude everything that Java 8 disables by default, plus some others.
* ref: http://docs.oracle.com/javase/8/docs/technotes/guides/security/SunProviders.html
* Unmodifiable.
* Public for RouterConsoleRunner.
* @since 0.9.16
*/
public static final List<String> EXCLUDE_CIPHERS = Collections.unmodifiableList(Arrays.asList(new String[] {
// following are disabled by default in Java 8
"SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA",
"SSL_DH_anon_EXPORT_WITH_RC4_40_MD5",
"SSL_DH_anon_WITH_3DES_EDE_CBC_SHA",
"SSL_DH_anon_WITH_DES_CBC_SHA",
"SSL_DH_anon_WITH_RC4_128_MD5",
"SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA",
"SSL_DHE_DSS_WITH_DES_CBC_SHA",
"SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA",
"SSL_DHE_RSA_WITH_DES_CBC_SHA",
"SSL_RSA_EXPORT_WITH_DES40_CBC_SHA",
"SSL_RSA_EXPORT_WITH_RC4_40_MD5",
"SSL_RSA_WITH_DES_CBC_SHA",
"SSL_RSA_WITH_NULL_MD5",
"SSL_RSA_WITH_NULL_SHA",
"TLS_DH_anon_WITH_AES_128_CBC_SHA",
"TLS_DH_anon_WITH_AES_128_CBC_SHA256",
"TLS_DH_anon_WITH_AES_128_GCM_SHA256",
"TLS_DH_anon_WITH_AES_256_CBC_SHA",
"TLS_DH_anon_WITH_AES_256_CBC_SHA256",
"TLS_DH_anon_WITH_AES_256_GCM_SHA384",
"TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA",
"TLS_ECDH_anon_WITH_AES_128_CBC_SHA",
"TLS_ECDH_anon_WITH_AES_256_CBC_SHA",
"TLS_ECDH_anon_WITH_NULL_SHA",
"TLS_ECDH_anon_WITH_RC4_128_SHA",
"TLS_ECDH_ECDSA_WITH_NULL_SHA",
"TLS_ECDHE_ECDSA_WITH_NULL_SHA",
"TLS_ECDHE_RSA_WITH_NULL_SHA",
"TLS_ECDH_RSA_WITH_NULL_SHA",
"TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5",
"TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA",
"TLS_KRB5_EXPORT_WITH_RC4_40_MD5",
"TLS_KRB5_EXPORT_WITH_RC4_40_SHA",
"TLS_KRB5_WITH_3DES_EDE_CBC_MD5",
"TLS_KRB5_WITH_3DES_EDE_CBC_SHA",
"TLS_KRB5_WITH_DES_CBC_MD5",
"TLS_KRB5_WITH_DES_CBC_SHA",
"TLS_KRB5_WITH_RC4_128_MD5",
"TLS_KRB5_WITH_RC4_128_SHA",
"TLS_RSA_WITH_NULL_SHA256",
// following are disabled because they are SSLv3
"SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA",
"SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA",
"SSL_RSA_WITH_3DES_EDE_CBC_SHA",
"SSL_RSA_WITH_RC4_128_MD5",
"SSL_RSA_WITH_RC4_128_SHA",
// following are disabled because they are RC4
"TLS_ECDH_ECDSA_WITH_RC4_128_SHA",
"TLS_ECDH_RSA_WITH_RC4_128_SHA",
"TLS_ECDHE_ECDSA_WITH_RC4_128_SHA",
"TLS_ECDHE_RSA_WITH_RC4_128_SHA",
// following are disabled because they are 3DES
"TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA",
"TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA",
"TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA",
"TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA"
}));
/**
* Nothing for now.
* There's nothing disabled by default we would want to enable.
* Unmodifiable.
* Public for RouterConsoleRunner.
* @since 0.9.16
*/
public static final List<String> INCLUDE_CIPHERS = Collections.emptyList();
private final SSLSocketFactory _factory;
/**
@ -37,7 +163,9 @@ public class I2PSSLSocketFactory {
* Returns a socket to the host.
*/
public Socket createSocket(String host, int port) throws IOException {
return _factory.createSocket(host, port);
SSLSocket rv = (SSLSocket) _factory.createSocket(host, port);
setProtocolsAndCiphers(rv);
return rv;
}
/**
@ -45,7 +173,9 @@ public class I2PSSLSocketFactory {
* @since 0.9.9
*/
public Socket createSocket(InetAddress host, int port) throws IOException {
return _factory.createSocket(host, port);
SSLSocket rv = (SSLSocket) _factory.createSocket(host, port);
setProtocolsAndCiphers(rv);
return rv;
}
/**
@ -104,4 +234,106 @@ public class I2PSSLSocketFactory {
sslc.init(null, tmf.getTrustManagers(), context.random());
return sslc.getSocketFactory();
}
/**
* Select protocols and cipher suites to be used
* based on configured inclusion and exclusion lists
* as well as enabled and supported protocols and cipher suites.
*
* Adapted from Jetty SslContextFactory.java
*
* @since 0.9.16
*/
public static void setProtocolsAndCiphers(SSLSocket socket) {
socket.setEnabledProtocols(selectProtocols(socket.getEnabledProtocols(),
socket.getSupportedProtocols()));
socket.setEnabledCipherSuites(selectCipherSuites(socket.getEnabledCipherSuites(),
socket.getSupportedCipherSuites()));
}
/**
* Select protocols and cipher suites to be used
* based on configured inclusion and exclusion lists
* as well as enabled and supported protocols and cipher suites.
*
* Adapted from Jetty SslContextFactory.java
*
* @since 0.9.16
*/
public static void setProtocolsAndCiphers(SSLServerSocket socket) {
socket.setEnabledProtocols(selectProtocols(socket.getEnabledProtocols(),
socket.getSupportedProtocols()));
socket.setEnabledCipherSuites(selectCipherSuites(socket.getEnabledCipherSuites(),
socket.getSupportedCipherSuites()));
}
/**
* Select protocols to be used
* based on configured inclusion and exclusion lists
* as well as enabled and supported protocols.
*
* Adapted from Jetty SslContextFactory.java
*
* @param enabledProtocols Array of enabled protocols
* @param supportedProtocols Array of supported protocols
* @return Array of protocols to enable
* @since 0.9.16
*/
private static String[] selectProtocols(String[] enabledProtocols, String[] supportedProtocols) {
return select(enabledProtocols, supportedProtocols, INCLUDE_PROTOCOLS, EXCLUDE_PROTOCOLS);
}
/**
* Select cipher suites to be used
* based on configured inclusion and exclusion lists
* as well as enabled and supported cipher suite lists.
*
* Adapted from Jetty SslContextFactory.java
*
* @param enabledCipherSuites Array of enabled cipher suites
* @param supportedCipherSuites Array of supported cipher suites
* @return Array of cipher suites to enable
* @since 0.9.16
*/
private static String[] selectCipherSuites(String[] enabledCipherSuites, String[] supportedCipherSuites) {
return select(enabledCipherSuites, supportedCipherSuites, INCLUDE_CIPHERS, EXCLUDE_CIPHERS);
}
/**
* Adapted from Jetty SslContextFactory.java
*
* @param toEnable Add all these to what is enabled, if supported
* @param toExclude Remove all these from what is enabled
* @since 0.9.16
*/
private static String[] select(String[] enabledArr, String[] supportedArr,
List<String> toEnable, List<String> toExclude) {
Log log = I2PAppContext.getGlobalContext().logManager().getLog(I2PSSLSocketFactory.class);
Set<String> selected = new HashSet<String>(enabledArr.length);
selected.addAll(Arrays.asList(enabledArr));
selected.removeAll(toExclude);
Set<String> supported = new HashSet<String>(supportedArr.length);
supported.addAll(Arrays.asList(supportedArr));
for (String s : toEnable) {
if (supported.contains(s)) {
if (selected.add(s)) {
if (log.shouldLog(Log.INFO))
log.info("Added, previously disabled: " + s);
}
} else if (log.shouldLog(Log.INFO)) {
log.info("Not supported in this JVM: " + s);
}
}
if (selected.isEmpty()) {
// shouldn't happen, Java 6 supports TLSv1
log.logAlways(Log.WARN, "No TLS support for SSLEepGet, falling back");
return enabledArr;
}
if (log.shouldLog(Log.DEBUG)) {
List<String> foo = new ArrayList(selected);
Collections.sort(foo);
log.debug("Selected: " + foo);
}
return selected.toArray(new String[selected.size()]);
}
}

View File

@ -50,9 +50,13 @@ import java.security.KeyStore;
import java.security.GeneralSecurityException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.Locale;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLHandshakeException;
import javax.net.ssl.SSLParameters;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
@ -254,6 +258,50 @@ public class SSLEepGet extends EepGet {
X509TrustManager defaultTrustManager = (X509TrustManager)tmf.getTrustManagers()[0];
_stm = new SavingTrustManager(defaultTrustManager);
sslc.init(null, new TrustManager[] {_stm}, null);
if (_log.shouldLog(Log.DEBUG)) {
SSLEngine eng = sslc.createSSLEngine();
SSLParameters params = sslc.getDefaultSSLParameters();
String[] s = eng.getSupportedProtocols();
Arrays.sort(s);
_log.debug("Supported protocols: " + s.length);
for (int i = 0; i < s.length; i++) {
_log.debug(s[i]);
}
s = eng.getEnabledProtocols();
Arrays.sort(s);
_log.debug("Enabled protocols: " + s.length);
for (int i = 0; i < s.length; i++) {
_log.debug(s[i]);
}
s = params.getProtocols();
if (s == null)
s = new String[0];
_log.debug("Default protocols: " + s.length);
Arrays.sort(s);
for (int i = 0; i < s.length; i++) {
_log.debug(s[i]);
}
s = eng.getSupportedCipherSuites();
Arrays.sort(s);
_log.debug("Supported ciphers: " + s.length);
for (int i = 0; i < s.length; i++) {
_log.debug(s[i]);
}
s = eng.getEnabledCipherSuites();
Arrays.sort(s);
_log.debug("Enabled ciphers: " + s.length);
for (int i = 0; i < s.length; i++) {
_log.debug(s[i]);
}
s = params.getCipherSuites();
if (s == null)
s = new String[0];
_log.debug("Default ciphers: " + s.length);
Arrays.sort(s);
for (int i = 0; i < s.length; i++) {
_log.debug(s[i]);
}
}
return sslc;
} catch (GeneralSecurityException gse) {
_log.error("Key Store update error", gse);
@ -505,6 +553,8 @@ public class SSLEepGet extends EepGet {
_proxy = _sslContext.getSocketFactory().createSocket(host, port);
else
_proxy = SSLSocketFactory.getDefault().createSocket(host, port);
SSLSocket socket = (SSLSocket) _proxy;
I2PSSLSocketFactory.setProtocolsAndCiphers(socket);
} else {
throw new MalformedURLException("Only https supported: " + _actualURL);
}

View File

@ -1,3 +1,7 @@
2014-10-15 zzz
* Console, I2CP, i2ptunnel, SSLEepGet: Set allowed SSL
protocols and ciphers
2014-10-14 zzz
* I2NP: Implement DatabaseLookupMessage search type field

View File

@ -18,7 +18,7 @@ public class RouterVersion {
/** deprecated */
public final static String ID = "Monotone";
public final static String VERSION = CoreVersion.VERSION;
public final static long BUILD = 10;
public final static long BUILD = 11;
/** for example "-test" */
public final static String EXTRA = "";

View File

@ -13,12 +13,14 @@ import java.util.HashMap;
import java.util.Map;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLServerSocketFactory;
import javax.net.ssl.SSLContext;
import net.i2p.client.I2PClient;
import net.i2p.crypto.KeyStoreUtil;
import net.i2p.router.RouterContext;
import net.i2p.util.I2PSSLSocketFactory;
import net.i2p.util.Log;
import net.i2p.util.SecureDirectory;
@ -174,6 +176,7 @@ class SSLClientListenerRunner extends ClientListenerRunner {
_log.info("Listening on port " + _port + " of the specific interface: " + listenInterface);
rv = _factory.createServerSocket(_port, 0, InetAddress.getByName(listenInterface));
}
I2PSSLSocketFactory.setProtocolsAndCiphers((SSLServerSocket) rv);
return rv;
}