Author: markt Date: Thu Oct 23 10:17:26 2014 New Revision: 1633788 URL: http://svn.apache.org/r1633788 Log: Better handling for https://issues.apache.org/bugzilla/show_bug.cgi?id=56780 Now it is only necessary for the connector to be configured with sslProtocol="TLSv1.2" when using an IBM JRE in strict SP800-131a mode.
Modified: tomcat/tc7.0.x/trunk/ (props changed) tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/net/jsse/JSSESocketFactory.java tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/net/jsse/res/LocalStrings.properties Propchange: tomcat/tc7.0.x/trunk/ ------------------------------------------------------------------------------ Merged /tomcat/trunk:r1633785 Modified: tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/net/jsse/JSSESocketFactory.java URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/net/jsse/JSSESocketFactory.java?rev=1633788&r1=1633787&r2=1633788&view=diff ============================================================================== --- tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/net/jsse/JSSESocketFactory.java (original) +++ tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/net/jsse/JSSESocketFactory.java Thu Oct 23 10:17:26 2014 @@ -87,11 +87,6 @@ public class JSSESocketFactory implement private static final StringManager sm = StringManager.getManager("org.apache.tomcat.util.net.jsse.res"); - private static final boolean RFC_5746_SUPPORTED; - - private static final String[] DEFAULT_SERVER_PROTOCOLS; - private static final String[] DEFAULT_SERVER_CIPHER_SUITES; - // Defaults - made public where re-used private static final String defaultProtocol = "TLS"; private static final String defaultKeystoreType = "JKS"; @@ -102,64 +97,12 @@ public class JSSESocketFactory implement private static final String ALLOW_ALL_SUPPORTED_CIPHERS = "ALL"; public static final String DEFAULT_KEY_PASS = "changeit"; - static { - boolean result = false; - SSLContext context; - String[] ciphers = null; - String[] protocols = null; - try { - // BZ 56780 IBM JRE can throw IllegalArgumentException here - context = SSLContext.getInstance("TLS"); - context.init(null, null, null); - SSLServerSocketFactory ssf = context.getServerSocketFactory(); - String supportedCiphers[] = ssf.getSupportedCipherSuites(); - for (String cipher : supportedCiphers) { - if ("TLS_EMPTY_RENEGOTIATION_INFO_SCSV".equals(cipher)) { - result = true; - break; - } - } - - // There is no API to obtain the default server protocols and cipher - // suites. Having inspected the OpenJDK code there the same results - // can be achieved via the standard API but there is no guarantee - // that every JVM implementation determines the defaults the same - // way. Therefore the defaults are determined by creating a server - // socket and requested the configured values. - - SSLServerSocket socket = (SSLServerSocket) ssf.createServerSocket(); - ciphers = socket.getEnabledCipherSuites(); - // Filter out all the SSL protocols (SSLv2 and SSLv3) from the - // default protocols since they are no longer considered secure - List<String> filteredProtocols = new ArrayList<String>(); - for (String protocol : socket.getEnabledProtocols()) { - if (protocol.contains("SSL")) { - log.debug(sm.getString("jsse.excludeDefaultProtocol", protocol)); - continue; - } - filteredProtocols.add(protocol); - } - protocols = filteredProtocols.toArray(new String[filteredProtocols.size()]); - } catch (NoSuchAlgorithmException e ) { - // Assume no RFC 5746 support if an SSLContext could not be created - // Unable to determine default ciphers/protocols so use none - } catch (KeyManagementException e) { - // Assume no RFC 5746 support if an SSLContext could not be created - // Unable to determine default ciphers/protocols so use none - } catch (IOException e) { - // Unable to determine default ciphers/protocols so use none - } catch (IllegalArgumentException e) { - // Assume no RFC 5746 support if an SSLContext could not be created - // Unable to determine default ciphers/protocols so use none - } - RFC_5746_SUPPORTED = result; - DEFAULT_SERVER_CIPHER_SUITES = ciphers; - DEFAULT_SERVER_PROTOCOLS = protocols; - } - - private AbstractEndpoint<?> endpoint; + private final boolean rfc5746Supported; + private final String[] defaultServerProtocols; + private final String[] defaultServerCipherSuites; + protected SSLServerSocketFactory sslProxy = null; protected String[] enabledCiphers; protected String[] enabledProtocols; @@ -178,8 +121,77 @@ public class JSSESocketFactory implement public JSSESocketFactory (AbstractEndpoint<?> endpoint) { this.endpoint = endpoint; + + String sslProtocol = endpoint.getSslProtocol(); + if (sslProtocol == null) { + sslProtocol = defaultProtocol; + } + + SSLContext context; + try { + context = SSLContext.getInstance(sslProtocol); + context.init(null, null, null); + } catch (NoSuchAlgorithmException e) { + // This is fatal for the connector so throw an exception to prevent + // it from starting + throw new IllegalArgumentException(e); + } catch (KeyManagementException e) { + // This is fatal for the connector so throw an exception to prevent + // it from starting + throw new IllegalArgumentException(e); + } + + // Supported cipher suites aren't accessible directly from the + // SSLContext so use the SSL server socket factory + SSLServerSocketFactory ssf = context.getServerSocketFactory(); + String supportedCiphers[] = ssf.getSupportedCipherSuites(); + boolean found = false; + for (String cipher : supportedCiphers) { + if ("TLS_EMPTY_RENEGOTIATION_INFO_SCSV".equals(cipher)) { + found = true; + break; + } + } + rfc5746Supported = found; + + // There is no standard way to determine the default protocols and + // cipher suites so create a server socket to see what the defaults are + SSLServerSocket socket; + try { + socket = (SSLServerSocket) ssf.createServerSocket(); + } catch (IOException e) { + // This is very likely to be fatal but there is a slim chance that + // the JSSE implementation just doesn't like creating unbound + // sockets so allow the code to proceed. + defaultServerCipherSuites = new String[0]; + defaultServerProtocols = new String[0]; + log.warn(sm.getString("jsse.noDefaultCiphers", endpoint.getName())); + log.warn(sm.getString("jsse.noDefaultProtocols", endpoint.getName())); + return; + } + + defaultServerCipherSuites = socket.getEnabledCipherSuites(); + if (defaultServerCipherSuites.length == 0) { + log.warn(sm.getString("jsse.noDefaultCiphers", endpoint.getName())); + } + + // Filter out all the SSL protocols (SSLv2 and SSLv3) from the defaults + // since they are no longer considered secure + List<String> filteredProtocols = new ArrayList<String>(); + for (String protocol : socket.getEnabledProtocols()) { + if (protocol.contains("SSL")) { + log.debug(sm.getString("jsse.excludeDefaultProtocol", protocol)); + continue; + } + filteredProtocols.add(protocol); + } + defaultServerProtocols = filteredProtocols.toArray(new String[filteredProtocols.size()]); + if (defaultServerProtocols.length == 0) { + log.warn(sm.getString("jsse.noDefaultProtocols", endpoint.getName())); + } } + @Override public ServerSocket createSocket (int port) throws IOException @@ -232,7 +244,7 @@ public class JSSESocketFactory implement if (session.getCipherSuite().equals("SSL_NULL_WITH_NULL_NULL")) throw new IOException("SSL handshake failed. Ciper suite in SSL Session is SSL_NULL_WITH_NULL_NULL"); - if (!allowUnsafeLegacyRenegotiation && !RFC_5746_SUPPORTED) { + if (!allowUnsafeLegacyRenegotiation && !rfc5746Supported) { // Prevent further handshakes by removing all cipher suites ((SSLSocket) sock).setEnabledCipherSuites(new String[0]); } @@ -247,7 +259,7 @@ public class JSSESocketFactory implement } if ((requestedCiphersStr == null) || (requestedCiphersStr.trim().length() == 0)) { - return DEFAULT_SERVER_CIPHER_SUITES; + return defaultServerCipherSuites; } List<String> requestedCiphers = new ArrayList<String>(); @@ -258,7 +270,7 @@ public class JSSESocketFactory implement } } if (requestedCiphers.isEmpty()) { - return DEFAULT_SERVER_CIPHER_SUITES; + return defaultServerCipherSuites; } List<String> ciphers = new ArrayList<String>(requestedCiphers); ciphers.retainAll(Arrays.asList(context.getSupportedSSLParameters() @@ -713,7 +725,7 @@ public class JSSESocketFactory implement public String[] getEnableableProtocols(SSLContext context) { String[] requestedProtocols = endpoint.getSslEnabledProtocolsArray(); if ((requestedProtocols == null) || (requestedProtocols.length == 0)) { - return DEFAULT_SERVER_PROTOCOLS; + return defaultServerProtocols; } List<String> protocols = new ArrayList<String>( Modified: tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/net/jsse/res/LocalStrings.properties URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/net/jsse/res/LocalStrings.properties?rev=1633788&r1=1633787&r2=1633788&view=diff ============================================================================== --- tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/net/jsse/res/LocalStrings.properties (original) +++ tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/net/jsse/res/LocalStrings.properties Thu Oct 23 10:17:26 2014 @@ -25,6 +25,8 @@ jsse.requested_protocols_not_supported=N jsse.enableable_protocols=Specified SSL protocols that are supported and enableable are : {0} jsse.unsupported_protocols=Some specified SSL protocols are not supported by the SSL engine : {0} jsse.excludeDefaultProtocol=The SSL protocol [{0}] which is enabled by default in this JRE was excluded from the defaults used by Tomcat +jsse.noDefaultCiphers=Unable to determine a default for ciphers for [{0}]. Set an explicit value to ensure the connector can start. +jsse.noDefaultProtocols=Unable to determine a default for sslEnabledProtocols for [{0}]. Set an explicit value to ensure the connector can start. jsseSupport.clientCertError=Error trying to obtain a certificate from the client jseeSupport.certTranslationError=Error translating certificate [{0}] jsseSupport.noCertWant=No client certificate sent for want --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org