You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by ti...@apache.org on 2013/01/13 23:04:32 UTC

svn commit: r1432751 - in /tomcat/trunk: java/org/apache/tomcat/util/net/ java/org/apache/tomcat/util/net/jsse/ java/org/apache/tomcat/util/net/jsse/res/ webapps/docs/config/

Author: timw
Date: Sun Jan 13 22:04:31 2013
New Revision: 1432751

URL: http://svn.apache.org/viewvc?rev=1432751&view=rev
Log:
Fix for https://issues.apache.org/bugzilla/show_bug.cgi?id=54406.

Make NIO connector use the same logic as BIO connector to prune specified ciphers and sslEnableProtocols to supported options.
Fix option pruning to not silently use defaults when no specified options are supported by SSL implementation.

Modified:
    tomcat/trunk/java/org/apache/tomcat/util/net/NioEndpoint.java
    tomcat/trunk/java/org/apache/tomcat/util/net/SSLUtil.java
    tomcat/trunk/java/org/apache/tomcat/util/net/jsse/JSSESocketFactory.java
    tomcat/trunk/java/org/apache/tomcat/util/net/jsse/res/LocalStrings.properties
    tomcat/trunk/webapps/docs/config/http.xml

Modified: tomcat/trunk/java/org/apache/tomcat/util/net/NioEndpoint.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/net/NioEndpoint.java?rev=1432751&r1=1432750&r2=1432751&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/util/net/NioEndpoint.java (original)
+++ tomcat/trunk/java/org/apache/tomcat/util/net/NioEndpoint.java Sun Jan 13 22:04:31 2013
@@ -261,7 +261,8 @@ public class NioEndpoint extends Abstrac
     private SSLContext sslContext = null;
     public SSLContext getSSLContext() { return sslContext;}
     public void setSSLContext(SSLContext c) { sslContext = c;}
-
+    private String[] enabledCiphers;
+    private String[] enabledProtocols;
 
     /**
      * Port in use.
@@ -284,16 +285,7 @@ public class NioEndpoint extends Abstrac
 
     @Override
     public String[] getCiphersUsed() {
-        SSLContext sslContext = getSSLContext();
-        if (sslContext != null) {
-            SSLEngine engine = getSSLContext().createSSLEngine();
-            if (getCiphersArray().length > 0) {
-                engine.setEnabledCipherSuites(getCiphersArray());
-            }
-            return engine.getEnabledCipherSuites();
-        } else {
-            return new String[0];
-        }
+        return enabledCiphers;
     }
 
 
@@ -384,6 +376,9 @@ public class NioEndpoint extends Abstrac
             if (sessionContext != null) {
                 sslUtil.configureSessionContext(sessionContext);
             }
+            // Determine which cipher suites and protocols to enable
+            enabledCiphers = sslUtil.getEnableableCiphers(sslContext);
+            enabledProtocols = sslUtil.getEnableableProtocols(sslContext);
         }
 
         if (oomParachute>0) reclaimParachute(true);
@@ -589,8 +584,8 @@ public class NioEndpoint extends Abstrac
             engine.setWantClientAuth(true);
         }
         engine.setUseClientMode(false);
-        if ( getCiphersArray().length > 0 ) engine.setEnabledCipherSuites(getCiphersArray());
-        if ( getSslEnabledProtocolsArray().length > 0 ) engine.setEnabledProtocols(getSslEnabledProtocolsArray());
+        engine.setEnabledCipherSuites(enabledCiphers);
+        engine.setEnabledProtocols(enabledProtocols);
 
         handler.onCreateSSLEngine(engine);
         return engine;

Modified: tomcat/trunk/java/org/apache/tomcat/util/net/SSLUtil.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/net/SSLUtil.java?rev=1432751&r1=1432750&r2=1432751&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/util/net/SSLUtil.java (original)
+++ tomcat/trunk/java/org/apache/tomcat/util/net/SSLUtil.java Sun Jan 13 22:04:31 2013
@@ -30,4 +30,33 @@ public interface SSLUtil {
     public TrustManager[] getTrustManagers() throws Exception;
 
     public void configureSessionContext(SSLSessionContext sslSessionContext);
+
+    /**
+     * Determines the SSL cipher suites that can be enabled, based on the
+     * configuration of the endpoint and the ciphers supported by the SSL
+     * implementation.
+     *
+     * @param context An initialized context to obtain the supported ciphers from.
+     *
+     * @return Array of SSL cipher suites that may be enabled (which may be
+     *         empty if none of the specified ciphers are supported), or
+     *         the defaults for the underlying SSL implementation if 
+     *         the endpoint configuration does not specify any ciphers.
+     */
+    public String[] getEnableableCiphers(SSLContext context);
+	
+    /**
+     * Determines the SSL protocol variants that can be enabled, based on the
+     * configuration of the endpoint and the ciphers supported by the SSL
+     * implementation.
+     *
+     * @param context An initialized context to obtain the supported protocols from.
+     *
+     * @return Array of SSL protocol variants that may be enabled (which may be
+     *         empty if none of the specified protocols are supported), or
+     *         the defaults for the underlying SSL implementation if 
+     *         the endpoint configuration does not specify any protocols.
+     */
+    public String[] getEnableableProtocols(SSLContext context);
+
 }

Modified: tomcat/trunk/java/org/apache/tomcat/util/net/jsse/JSSESocketFactory.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/net/jsse/JSSESocketFactory.java?rev=1432751&r1=1432750&r2=1432751&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/util/net/jsse/JSSESocketFactory.java (original)
+++ tomcat/trunk/java/org/apache/tomcat/util/net/jsse/JSSESocketFactory.java Sun Jan 13 22:04:31 2013
@@ -40,9 +40,11 @@ import java.security.cert.CertificateFac
 import java.security.cert.CollectionCertStoreParameters;
 import java.security.cert.PKIXBuilderParameters;
 import java.security.cert.X509CertSelector;
+import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
+import java.util.List;
 import java.util.Locale;
-import java.util.Vector;
 
 import javax.net.ssl.CertPathTrustManagerParameters;
 import javax.net.ssl.KeyManager;
@@ -124,6 +126,7 @@ public class JSSESocketFactory implement
 
     protected SSLServerSocketFactory sslProxy = null;
     protected String[] enabledCiphers;
+    protected String[] enabledProtocols;
     protected boolean allowUnsafeLegacyRenegotiation = false;
 
     /**
@@ -199,84 +202,46 @@ public class JSSESocketFactory implement
         }
     }
 
-    /*
-     * Determines the SSL cipher suites to be enabled.
-     *
-     * @param requestedCiphers Comma-separated list of requested ciphers
-     * @param supportedCiphers Array of supported ciphers
-     *
-     * @return Array of SSL cipher suites to be enabled, or null if none of the
-     * requested ciphers are supported
-     */
-    protected String[] getEnabledCiphers(String requestedCiphers,
-                                         String[] supportedCiphers) {
+    @Override
+    public String[] getEnableableCiphers(SSLContext context) {
+        String requestedCiphersStr = endpoint.getCiphers();
 
-        String[] result = null;
+        if (ALLOW_ALL_SUPPORTED_CIPHERS.equals(requestedCiphersStr)) {
+            return context.getSupportedSSLParameters().getCipherSuites();
+        }
+        if ((requestedCiphersStr == null)
+                || (requestedCiphersStr.trim().length() == 0)) {
+            return context.getDefaultSSLParameters().getCipherSuites();
+        }
 
-        if (ALLOW_ALL_SUPPORTED_CIPHERS.equals(requestedCiphers)) {
-            return supportedCiphers;
-        }
-
-        if (requestedCiphers != null) {
-            Vector<String> vec = null;
-            String cipher = requestedCiphers;
-            int index = requestedCiphers.indexOf(',');
-            if (index != -1) {
-                int fromIndex = 0;
-                while (index != -1) {
-                    cipher =
-                        requestedCiphers.substring(fromIndex, index).trim();
-                    if (cipher.length() > 0) {
-                        /*
-                         * Check to see if the requested cipher is among the
-                         * supported ciphers, i.e., may be enabled
-                         */
-                        for (int i=0; supportedCiphers != null
-                                     && i<supportedCiphers.length; i++) {
-                            if (supportedCiphers[i].equals(cipher)) {
-                                if (vec == null) {
-                                    vec = new Vector<>();
-                                }
-                                vec.addElement(cipher);
-                                break;
-                            }
-                        }
-                    }
-                    fromIndex = index+1;
-                    index = requestedCiphers.indexOf(',', fromIndex);
-                } // while
-                cipher = requestedCiphers.substring(fromIndex);
-            }
-
-            if (cipher != null) {
-                cipher = cipher.trim();
-                if (cipher.length() > 0) {
-                    /*
-                     * Check to see if the requested cipher is among the
-                     * supported ciphers, i.e., may be enabled
-                     */
-                    for (int i=0; supportedCiphers != null
-                                 && i<supportedCiphers.length; i++) {
-                        if (supportedCiphers[i].equals(cipher)) {
-                            if (vec == null) {
-                                vec = new Vector<>();
-                            }
-                            vec.addElement(cipher);
-                            break;
-                        }
-                    }
-                }
+        List<String> requestedCiphers = new ArrayList<String>();
+        for (String rc : requestedCiphersStr.split(",")) {
+            final String cipher = rc.trim();
+            if (cipher.length() > 0) {
+                requestedCiphers.add(cipher);
             }
+        }
+        if (requestedCiphers.isEmpty()) {
+            return context.getDefaultSSLParameters().getCipherSuites();
+        }
+        List<String> ciphers = new ArrayList<String>(requestedCiphers);
+        ciphers.retainAll(Arrays.asList(context.getSupportedSSLParameters()
+                .getCipherSuites()));
 
-            if (vec != null) {
-                result = new String[vec.size()];
-                vec.copyInto(result);
+        if (ciphers.isEmpty()) {
+            log.warn(sm.getString("jsse.requested_ciphers_not_supported",
+                    requestedCiphersStr));
+        }
+        if (log.isDebugEnabled()) {
+            log.debug(sm.getString("jsse.enableable_ciphers", ciphers));
+            if (ciphers.size() != requestedCiphers.size()) {
+                List<String> skipped = new ArrayList<String>(requestedCiphers);
+                skipped.removeAll(ciphers);
+                log.debug(sm.getString("jsse.unsupported_ciphers", skipped));
             }
-        } else {
-            result = sslProxy.getDefaultCipherSuites();
         }
 
-        return result;
+        return ciphers.toArray(new String[ciphers.size()]);
     }
 
     public String[] getEnabledCiphers() {
@@ -463,9 +428,8 @@ public class JSSESocketFactory implement
             sslProxy = context.getServerSocketFactory();
 
             // Determine which cipher suites to enable
-            String requestedCiphers = endpoint.getCiphers();
-            enabledCiphers = getEnabledCiphers(requestedCiphers,
-                    sslProxy.getSupportedCipherSuites());
+            enabledCiphers = getEnableableCiphers(context);
+            enabledProtocols = getEnableableProtocols(context);
 
             allowUnsafeLegacyRenegotiation = "true".equals(
                     endpoint.getAllowUnsafeLegacyRenegotiation());
@@ -713,60 +677,32 @@ public class JSSESocketFactory implement
         return crls;
     }
 
-    /**
-     * Set the SSL protocol variants to be enabled.
-     * @param socket the SSLServerSocket.
-     * @param protocols the protocols to use.
-     */
-    protected void setEnabledProtocols(SSLServerSocket socket,
-            String[] protocols){
-        if (protocols != null) {
-            socket.setEnabledProtocols(protocols);
+    @Override
+    public String[] getEnableableProtocols(SSLContext context) {
+        String[] requestedProtocols = endpoint.getSslEnabledProtocolsArray();
+        if ((requestedProtocols == null) || (requestedProtocols.length == 0)) {
+            return context.getDefaultSSLParameters().getProtocols();
         }
-    }
 
-    /**
-     * Determines the SSL protocol variants to be enabled.
-     *
-     * @param socket The socket to get supported list from.
-     * @param requestedProtocols Array of requested protocol names all of which
-     *                           must be non-null and non-zero length
-     *
-     * @return Array of SSL protocol variants to be enabled, or null if none of
-     * the requested protocol variants are supported
-     */
-    protected String[] getEnabledProtocols(SSLServerSocket socket,
-                                           String[] requestedProtocols){
-        String[] supportedProtocols = socket.getSupportedProtocols();
-
-        String[] enabledProtocols = null;
-
-        if (requestedProtocols != null && requestedProtocols.length > 0) {
-            Vector<String> vec = null;
-            for (String protocol : requestedProtocols) {
-                /*
-                 * Check to see if the requested protocol is among the supported
-                 * protocols, i.e., may be enabled
-                 */
-                for (int i=0; supportedProtocols != null &&
-                        i < supportedProtocols.length; i++) {
-                    if (supportedProtocols[i].equals(protocol)) {
-                        if (vec == null) {
-                            vec = new Vector<>();
-                        }
-                        vec.addElement(protocol);
-                        break;
-                    }
-                }
-            }
+        List<String> protocols = new ArrayList<String>(
+                Arrays.asList(requestedProtocols));
+        protocols.retainAll(Arrays.asList(context.getSupportedSSLParameters()
+                .getProtocols()));
 
-            if (vec != null) {
-                enabledProtocols = new String[vec.size()];
-                vec.copyInto(enabledProtocols);
+        if (protocols.isEmpty()) {
+            log.warn(sm.getString("jsse.requested_protocols_not_supported",
+                    Arrays.asList(requestedProtocols)));
+        }
+        if (log.isDebugEnabled()) {
+            log.debug(sm.getString("jsse.enableable_protocols", protocols));
+            if (protocols.size() != requestedProtocols.length) {
+                List<String> skipped = new ArrayList<String>(
+                        Arrays.asList(requestedProtocols));
+                skipped.removeAll(protocols);
+                log.debug(sm.getString("jsse.unsupported_protocols", skipped));
             }
         }
-
-        return enabledProtocols;
+        return protocols.toArray(new String[protocols.size()]);
     }
 
     /**
@@ -791,14 +727,9 @@ public class JSSESocketFactory implement
 
         SSLServerSocket socket = (SSLServerSocket) ssocket;
 
-        if (enabledCiphers != null) {
-            socket.setEnabledCipherSuites(enabledCiphers);
-        }
-
-        String[] requestedProtocols = endpoint.getSslEnabledProtocolsArray();
-        setEnabledProtocols(socket, getEnabledProtocols(socket,
-                                                         requestedProtocols));
-
+        socket.setEnabledCipherSuites(enabledCiphers);
+        socket.setEnabledProtocols(enabledProtocols);
+        
         // we don't know if client auth is needed -
         // after parsing the request we may re-handshake
         configureClientAuth(socket);

Modified: tomcat/trunk/java/org/apache/tomcat/util/net/jsse/res/LocalStrings.properties
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/net/jsse/res/LocalStrings.properties?rev=1432751&r1=1432750&r2=1432751&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/util/net/jsse/res/LocalStrings.properties (original)
+++ tomcat/trunk/java/org/apache/tomcat/util/net/jsse/res/LocalStrings.properties Sun Jan 13 22:04:31 2013
@@ -18,6 +18,12 @@ jsse.keystore_load_failed=Failed to load
 jsse.invalid_ssl_conf=SSL configuration is invalid due to {0}
 jsse.invalid_truststore_password=The provided trust store password could not be used to unlock and/or validate the trust store. Retrying to access the trust store with a null password which will skip validation.
 jsse.invalidTrustManagerClassName=The trustManagerClassName provided [{0}] does not implement javax.net.ssl.TrustManager
+jsse.requested_ciphers_not_supported=None of the ciphers specified are supported by the SSL engine : {0}
+jsse.enableable_ciphers=Specified SSL ciphers that are supported and enableable are : {0}
+jsse.unsupported_ciphers=Some specified SSL ciphers are not supported by the SSL engine : {0}
+jsse.requested_protocols_not_supported=None of the SSL protocols specified are supported by the SSL engine : {0}
+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}
 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

Modified: tomcat/trunk/webapps/docs/config/http.xml
URL: http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/config/http.xml?rev=1432751&r1=1432750&r2=1432751&view=diff
==============================================================================
--- tomcat/trunk/webapps/docs/config/http.xml (original)
+++ tomcat/trunk/webapps/docs/config/http.xml Sun Jan 13 22:04:31 2013
@@ -930,13 +930,15 @@
     </attribute>
 
     <attribute name="ciphers" required="false">
-      <p>The comma separated list of encryption ciphers that this socket is
-      allowed to use. By default, the default ciphers for the JVM will be used.
-      Note that this usually means that the weak export grade ciphers will be
-      included in the list of available ciphers. The ciphers are specified using
-      the JSSE cipher naming convention. The special value of <code>ALL</code>
-      will enable all supported ciphers. This will include many that are not
-      secure. <code>ALL</code> is intended for testing purposes only.</p>
+      <p>The comma separated list of encryption ciphers to support for HTTPS
+      connections. If specified, only the ciphers that are listed and supported
+      by the SSL implementation will be used. By default, the default ciphers
+      for the JVM will be used. Note that this usually means that the weak
+      export grade ciphers will be included in the list of available ciphers.
+      The ciphers are specified using the JSSE cipher naming convention. The
+      special value of <code>ALL</code> will enable all supported ciphers. This
+      will include many that are not secure. <code>ALL</code> is intended for
+      testing purposes only.</p>
     </attribute>
 
     <attribute name="clientAuth" required="false">
@@ -1019,9 +1021,10 @@
 
     <attribute name="sslEnabledProtocols" required="false">
       <p>The comma separated list of SSL protocols to support for HTTPS
-      connections. If specified, only the protocols listed will be supported. If
-      not specified, the JVM default is used. The permitted values may be
-      obtained from the JVM documentation for the allowed values for
+      connections. If specified, only the protocols that are listed and
+      supported by the SSL implementation will be enabled. If not specified,
+      the JVM default is used. The permitted values may be obtained from the
+      JVM documentation for the allowed values for 
       <code>SSLSocket.setEnabledProtocols()</code> e.g.
       <a href="http://docs.oracle.com/javase/6/docs/technotes/guides/security/StandardNames.html#jssenames">
       Oracle Java 6</a> and



---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org