Author: markt Date: Mon Jun 22 21:50:31 2015 New Revision: 1686949 URL: http://svn.apache.org/r1686949 Log: Add configuration support for SSLHostConfigCertificate Document the new configuration Get multiple certificates working with NIO (tested with SSLLabs). Should also be working for NIO2 but untested.
Added: tomcat/trunk/java/org/apache/catalina/startup/CertificateCreateRule.java (with props) Modified: tomcat/trunk/java/org/apache/catalina/startup/Catalina.java tomcat/trunk/java/org/apache/tomcat/util/net/SecureNio2Channel.java tomcat/trunk/java/org/apache/tomcat/util/net/SecureNioChannel.java tomcat/trunk/java/org/apache/tomcat/util/net/TLSClientHelloExtractor.java tomcat/trunk/webapps/docs/config/http.xml Modified: tomcat/trunk/java/org/apache/catalina/startup/Catalina.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/startup/Catalina.java?rev=1686949&r1=1686948&r2=1686949&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/startup/Catalina.java (original) +++ tomcat/trunk/java/org/apache/catalina/startup/Catalina.java Mon Jun 22 21:50:31 2015 @@ -340,8 +340,15 @@ public class Catalina { "org.apache.tomcat.util.net.SSLHostConfig"); digester.addSetProperties("Server/Service/Connector/SSLHostConfig"); digester.addSetNext("Server/Service/Connector/SSLHostConfig", - "addSslHostConfig", - "org.apache.tomcat.util.net.SSLHostConfig"); + "addSslHostConfig", + "org.apache.tomcat.util.net.SSLHostConfig"); + + digester.addRule("Server/Service/Connector/SSLHostConfig/Certificate", + new CertificateCreateRule()); + digester.addSetProperties("Server/Service/Connector/SSLHostConfig/Certificate"); + digester.addSetNext("Server/Service/Connector/SSLHostConfig/Certificate", + "addCertificate", + "org.apache.tomcat.util.net.SSLHostConfigCertificate"); digester.addObjectCreate("Server/Service/Connector/Listener", null, // MUST be specified in the element Added: tomcat/trunk/java/org/apache/catalina/startup/CertificateCreateRule.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/startup/CertificateCreateRule.java?rev=1686949&view=auto ============================================================================== --- tomcat/trunk/java/org/apache/catalina/startup/CertificateCreateRule.java (added) +++ tomcat/trunk/java/org/apache/catalina/startup/CertificateCreateRule.java Mon Jun 22 21:50:31 2015 @@ -0,0 +1,61 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.catalina.startup; + +import org.apache.tomcat.util.digester.Rule; +import org.apache.tomcat.util.net.SSLHostConfig; +import org.apache.tomcat.util.net.SSLHostConfigCertificate; +import org.apache.tomcat.util.net.SSLHostConfigCertificate.Type; +import org.xml.sax.Attributes; + +/** + * Rule implementation that creates a SSLHostConfigCertificate. + */ +public class CertificateCreateRule extends Rule { + + @Override + public void begin(String namespace, String name, Attributes attributes) throws Exception { + SSLHostConfig sslHostConfig = (SSLHostConfig)digester.peek(); + + Type type; + String typeValue = attributes.getValue("type"); + if (typeValue == null || typeValue.length() == 0) { + type = Type.UNDEFINED; + } else { + type = Type.valueOf(typeValue); + } + + SSLHostConfigCertificate certificate = new SSLHostConfigCertificate(sslHostConfig, type); + + digester.push(certificate); + } + + + /** + * Process the end of this element. + * + * @param namespace the namespace URI of the matching element, or an + * empty string if the parser is not namespace aware or the element has + * no namespace + * @param name the local name if the parser is namespace aware, or just + * the element name otherwise + */ + @Override + public void end(String namespace, String name) throws Exception { + digester.pop(); + } +} Propchange: tomcat/trunk/java/org/apache/catalina/startup/CertificateCreateRule.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: tomcat/trunk/java/org/apache/catalina/startup/CertificateCreateRule.java ------------------------------------------------------------------------------ svn:mime-type = text/plain Modified: tomcat/trunk/java/org/apache/tomcat/util/net/SecureNio2Channel.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/net/SecureNio2Channel.java?rev=1686949&r1=1686948&r2=1686949&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/tomcat/util/net/SecureNio2Channel.java (original) +++ tomcat/trunk/java/org/apache/tomcat/util/net/SecureNio2Channel.java Mon Jun 22 21:50:31 2015 @@ -22,6 +22,7 @@ import java.nio.ByteBuffer; import java.nio.channels.AsynchronousSocketChannel; import java.nio.channels.CompletionHandler; import java.nio.channels.WritePendingException; +import java.util.Collections; import java.util.List; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; @@ -336,10 +337,9 @@ public class SecureNio2Channel extends N switch (extractor.getResult()) { case COMPLETE: hostName = extractor.getSNIValue(); - clientRequestedCiphers = extractor.getClientRequestedCiphers(); - break; + //$FALL-THROUGH$ to set the client requested ciphers case NOT_PRESENT: - // NO-OP + clientRequestedCiphers = extractor.getClientRequestedCiphers(); break; case NEED_READ: sc.read(netInBuffer, socket, handshakeReadCompletionHandler); @@ -350,6 +350,7 @@ public class SecureNio2Channel extends N log.debug(sm.getString("channel.nio.ssl.sniDefault")); } hostName = endpoint.getDefaultSSLHostConfigName(); + clientRequestedCiphers = Collections.emptyList(); break; } Modified: tomcat/trunk/java/org/apache/tomcat/util/net/SecureNioChannel.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/net/SecureNioChannel.java?rev=1686949&r1=1686948&r2=1686949&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/tomcat/util/net/SecureNioChannel.java (original) +++ tomcat/trunk/java/org/apache/tomcat/util/net/SecureNioChannel.java Mon Jun 22 21:50:31 2015 @@ -23,6 +23,7 @@ import java.nio.ByteBuffer; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.SocketChannel; +import java.util.Collections; import java.util.List; import javax.net.ssl.SSLEngine; @@ -274,10 +275,9 @@ public class SecureNioChannel extends Ni switch (extractor.getResult()) { case COMPLETE: hostName = extractor.getSNIValue(); - clientRequestedCiphers = extractor.getClientRequestedCiphers(); - break; + //$FALL-THROUGH$ to set the client requested ciphers case NOT_PRESENT: - // NO-OP + clientRequestedCiphers = extractor.getClientRequestedCiphers(); break; case NEED_READ: return SelectionKey.OP_READ; @@ -287,6 +287,7 @@ public class SecureNioChannel extends Ni log.debug(sm.getString("channel.nio.ssl.sniDefault")); } hostName = endpoint.getDefaultSSLHostConfigName(); + clientRequestedCiphers = Collections.emptyList(); break; } Modified: tomcat/trunk/java/org/apache/tomcat/util/net/TLSClientHelloExtractor.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/net/TLSClientHelloExtractor.java?rev=1686949&r1=1686948&r2=1686949&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/tomcat/util/net/TLSClientHelloExtractor.java (original) +++ tomcat/trunk/java/org/apache/tomcat/util/net/TLSClientHelloExtractor.java Mon Jun 22 21:50:31 2015 @@ -58,7 +58,7 @@ public class TLSClientHelloExtractor { int pos = netInBuffer.position(); int limit = netInBuffer.limit(); ExtractorResult result = ExtractorResult.NOT_PRESENT; - List<Cipher> clientRequestedCiphers = null; + List<Cipher> clientRequestedCiphers = new ArrayList<>(); String sniValue = null; try { // Switch to read mode. @@ -101,7 +101,6 @@ public class TLSClientHelloExtractor { // Cipher Suites // (2 bytes for length, each cipher ID is 2 bytes) int cipherCount = netInBuffer.getChar() / 2; - clientRequestedCiphers = new ArrayList<>(cipherCount); for (int i = 0; i < cipherCount; i++) { int cipherId = netInBuffer.getChar(); clientRequestedCiphers.add(Cipher.valueOf(cipherId)); @@ -150,7 +149,7 @@ public class TLSClientHelloExtractor { public List<Cipher> getClientRequestedCiphers() { - if (result == ExtractorResult.COMPLETE) { + if (result == ExtractorResult.COMPLETE || result == ExtractorResult.NOT_PRESENT) { return clientRequestedCiphers; } else { throw new IllegalStateException(); Modified: tomcat/trunk/webapps/docs/config/http.xml URL: http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/config/http.xml?rev=1686949&r1=1686948&r2=1686949&view=diff ============================================================================== --- tomcat/trunk/webapps/docs/config/http.xml (original) +++ tomcat/trunk/webapps/docs/config/http.xml Mon Jun 22 21:50:31 2015 @@ -929,8 +929,12 @@ the host name requested by the client. To facilitate this, Tomcat 9 added the <strong>SSLHostConfig</strong> element which can be used to define one of these configurations. Any number of <strong>SSLHostConfig</strong> may be - nested in a <strong>Connector</strong>. For further information, see the - SSL Support section below.</p> + nested in a <strong>Connector</strong>. Tomcat 9 also adds support for + mutliple cerificates to be associated with a single + <strong>SSLHostConfig</strong>. Each SSL certificate is therefore configured + in a <strong>Certificate</strong> element with in an + <strong>SSLHostConfig</strong>. For further information, see the SSL Support + section below.</p> </section> @@ -998,10 +1002,14 @@ match the <code>sslDefaultHost</code> attribute of the <strong>Connector</strong>.</p> + <p>Each <strong>SSLHostConfig</strong> must in turn define at least one + <strong>Certificate</strong>. The types of the <strong>Certificate</strong>s + must be unique.</p> + <p>As of Tomcat 9, the majority of the SSL configuration attributes in the <strong>Connector</strong> are deprecated. If specified, they will be used to - configure a <strong>SSLHostConfig</strong> for the - <code>sslDefaultHost</code>. Note that if an explicit + configure a <strong>SSLHostConfig</strong> and <strong>Certificate</strong>for + the <code>sslDefaultHost</code>. Note that if an explicit <strong>SSLHostConfig</strong> element also exists for the <code>sslDefaultHost</code> then that will be treated as a configuration error. It is expected that Tomcat 10 will drop support for the SSL @@ -1018,84 +1026,6 @@ <attributes> - <attribute name="certificateFile" required="true"> - <p>OpenSSL only.</p> - <p>Name of the file that contains the server certificate. The format is - PEM-encoded. Relative paths will be resolved against - <code>$CATALINA_BASE</code>.</p> - <p>In addition to the certificate, the file can also contain as optional - elements DH parameters and/or an EC curve name for ephemeral keys, as - generated by <code>openssl dhparam</code> and <code>openssl ecparam</code>, - respectively. The output of the respective OpenSSL command can simply - be concatenated to the certificate file.</p> - </attribute> - - <attribute name="certificateKeyAlias" required="false"> - <p>JSSE only.</p> - <p>The alias used for the server key and certificate in the keystore. If - not specified, the first key read from the keystore will be used. The - order in which keys are read from the keystore is implementation - dependent. It may not be the case that keys are read from the keystore in - the same order as they were added. If more than one key is present in the - kesytore it is strongly recommended that a keyAlias is configured to - ensure that the correct key is used.</p> - </attribute> - - <attribute name="certificateKeyFile" required="false"> - <p>OpenSSL only.</p> - <p>Name of the file that contains the server private key. The format is - PEM-encoded. The default value is the value of - <strong>certificateFile</strong> and in this case both certificate and - private key have to be in this file (NOT RECOMMENDED). Relative paths will - be resolved against <code>$CATALINA_BASE</code>.</p> - </attribute> - - <attribute name="certificateKeyPassword" required="false"> - <p>The password used to access the private key associated with the server - certificate from the specified file.</p> - <p>If not specified, the default behaviour for JSSE is to use the - <strong>certificateKeystorePassword</strong>. For OpenSSL the default - behaviour is not to use a password.</p> - </attribute> - - <attribute name="certificateKeystoreFile" required="false"> - <p>JSSE only.</p> - <p>The pathname of the keystore file where you have stored the server - certificate and key to be loaded. By default, the pathname is the file - <code>.keystore</code> in the operating system home directory of the user - that is running Tomcat. If your <code>keystoreType</code> doesn't need a - file use <code>""</code> (empty string) or <code>NONE</code> for this - parameter. Relative paths will be resolved against - <code>$CATALINA_BASE</code>.</p> - </attribute> - - <attribute name="certificateKeystorePassword" required="false"> - <p>JSSE only.</p> - <p>The password to use to access the keystore containing the server's - private key and certificate. If not specified, a default of - <code>changeit</code> will be used.</p> - </attribute> - - <attribute name="certificateKeystoreProvider" required="false"> - <p>JSSE only.</p> - <p>The name of the keystore provider to be used for the server - certificate. If not specified, the value of the system property - <code>javax.net.ssl.keyStoreProvider</code> is used. If neither this - attribute nor the system property are set, the list of registered - providers is traversed in preference order and the first provider that - supports the <code>keystoreType</code> is used. - </p> - </attribute> - - <attribute name="certificateKeystoreType" required="false"> - <p>JSSE only.</p> - <p>The type of keystore file to be used for the server certificate. - If not specified, the value of the system property - <code>javax.net.ssl.keyStoreType</code> is used. If neither this attribute - nor the system property are set, a default value of "<code>JKS</code>". is - used.</p> - </attribute> - <attribute name="certificateRevocationFile" required="false"> <p>Name of the file that contains the concatenated certificate revocation lists for the certificate authorities. The format is PEM-encoded. If not @@ -1310,6 +1240,105 @@ </attributes> + </subsection> + + <subsection name="SSL Support - Certificate"> + + <p></p> + + <attributes> + + <attribute name="certificateFile" required="true"> + <p>OpenSSL only.</p> + <p>Name of the file that contains the server certificate. The format is + PEM-encoded. Relative paths will be resolved against + <code>$CATALINA_BASE</code>.</p> + <p>In addition to the certificate, the file can also contain as optional + elements DH parameters and/or an EC curve name for ephemeral keys, as + generated by <code>openssl dhparam</code> and <code>openssl ecparam</code>, + respectively. The output of the respective OpenSSL command can simply + be concatenated to the certificate file.</p> + </attribute> + + <attribute name="certificateKeyAlias" required="false"> + <p>JSSE only.</p> + <p>The alias used for the server key and certificate in the keystore. If + not specified, the first key read from the keystore will be used. The + order in which keys are read from the keystore is implementation + dependent. It may not be the case that keys are read from the keystore in + the same order as they were added. If more than one key is present in the + kesytore it is strongly recommended that a keyAlias is configured to + ensure that the correct key is used.</p> + </attribute> + + <attribute name="certificateKeyFile" required="false"> + <p>OpenSSL only.</p> + <p>Name of the file that contains the server private key. The format is + PEM-encoded. The default value is the value of + <strong>certificateFile</strong> and in this case both certificate and + private key have to be in this file (NOT RECOMMENDED). Relative paths will + be resolved against <code>$CATALINA_BASE</code>.</p> + </attribute> + + <attribute name="certificateKeyPassword" required="false"> + <p>The password used to access the private key associated with the server + certificate from the specified file.</p> + <p>If not specified, the default behaviour for JSSE is to use the + <strong>certificateKeystorePassword</strong>. For OpenSSL the default + behaviour is not to use a password.</p> + </attribute> + + <attribute name="certificateKeystoreFile" required="false"> + <p>JSSE only.</p> + <p>The pathname of the keystore file where you have stored the server + certificate and key to be loaded. By default, the pathname is the file + <code>.keystore</code> in the operating system home directory of the user + that is running Tomcat. If your <code>keystoreType</code> doesn't need a + file use <code>""</code> (empty string) or <code>NONE</code> for this + parameter. Relative paths will be resolved against + <code>$CATALINA_BASE</code>.</p> + </attribute> + + <attribute name="certificateKeystorePassword" required="false"> + <p>JSSE only.</p> + <p>The password to use to access the keystore containing the server's + private key and certificate. If not specified, a default of + <code>changeit</code> will be used.</p> + </attribute> + + <attribute name="certificateKeystoreProvider" required="false"> + <p>JSSE only.</p> + <p>The name of the keystore provider to be used for the server + certificate. If not specified, the value of the system property + <code>javax.net.ssl.keyStoreProvider</code> is used. If neither this + attribute nor the system property are set, the list of registered + providers is traversed in preference order and the first provider that + supports the <code>keystoreType</code> is used. + </p> + </attribute> + + <attribute name="certificateKeystoreType" required="false"> + <p>JSSE only.</p> + <p>The type of keystore file to be used for the server certificate. + If not specified, the value of the system property + <code>javax.net.ssl.keyStoreType</code> is used. If neither this attribute + nor the system property are set, a default value of "<code>JKS</code>". is + used.</p> + </attribute> + + <attribute name="type" required="false"> + <p>The type of certificate. This is used to idenitfy the ciphers that are + compatible with the certificate. It must be one of <code>UNDEFINED</code>, + <code>RSA</code>, <code>DSS</code> or <code>EC</code>. If only one + <strong>Certificate</strong> is nested within a <code>SSLHostConfig</code> + then this attribute is not required and will default to + <code>UNDEFINED</code>. If multiple <strong>Certificate</strong>s are + nested within a <code>SSLHostConfig</code> then this attribute is required + and each <strong>Certificate</strong> must have a unique type.</p> + </attribute> + + </attributes> + </subsection> <subsection name="SSL Support - Connector - NIO and NIO2"> --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org