Author: markt Date: Thu Feb 21 20:59:10 2019 New Revision: 1854097 URL: http://svn.apache.org/viewvc?rev=1854097&view=rev Log: More alignment of JSSE and OpenSSL (and a little code reduction)
Modified: tomcat/trunk/java/org/apache/tomcat/util/net/SSLUtilBase.java tomcat/trunk/java/org/apache/tomcat/util/net/jsse/JSSEUtil.java tomcat/trunk/java/org/apache/tomcat/util/net/openssl/OpenSSLUtil.java Modified: tomcat/trunk/java/org/apache/tomcat/util/net/SSLUtilBase.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/net/SSLUtilBase.java?rev=1854097&r1=1854096&r2=1854097&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/tomcat/util/net/SSLUtilBase.java (original) +++ tomcat/trunk/java/org/apache/tomcat/util/net/SSLUtilBase.java Thu Feb 21 20:59:10 2019 @@ -21,6 +21,7 @@ import java.io.IOException; import java.io.InputStream; import java.net.URI; import java.security.DomainLoadStoreParameter; +import java.security.Key; import java.security.KeyStore; import java.security.cert.CRL; import java.security.cert.CRLException; @@ -42,18 +43,24 @@ import java.util.Collections; import java.util.Date; import java.util.Enumeration; import java.util.List; +import java.util.Locale; import java.util.Set; import javax.net.ssl.CertPathTrustManagerParameters; +import javax.net.ssl.KeyManager; +import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.ManagerFactoryParameters; import javax.net.ssl.SSLSessionContext; import javax.net.ssl.TrustManager; import javax.net.ssl.TrustManagerFactory; +import javax.net.ssl.X509KeyManager; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.file.ConfigFileLoader; import org.apache.tomcat.util.net.SSLHostConfig.CertificateVerification; +import org.apache.tomcat.util.net.jsse.JSSEKeyManager; +import org.apache.tomcat.util.net.jsse.PEMFile; import org.apache.tomcat.util.res.StringManager; /** @@ -250,6 +257,120 @@ public abstract class SSLUtilBase implem } + @Override + public KeyManager[] getKeyManagers() throws Exception { + String keyAlias = certificate.getCertificateKeyAlias(); + String algorithm = sslHostConfig.getKeyManagerAlgorithm(); + String keyPass = certificate.getCertificateKeyPassword(); + // This has to be here as it can't be moved to SSLHostConfig since the + // defaults vary between JSSE and OpenSSL. + if (keyPass == null) { + keyPass = certificate.getCertificateKeystorePassword(); + } + + KeyStore ks = certificate.getCertificateKeystore(); + KeyStore ksUsed = ks; + + /* + * Use an in memory key store where possible. + * For PEM format keys and certificates, it allows them to be imported + * into the expected format. + * For Java key stores with PKCS8 encoded keys (e.g. JKS files), it + * enables Tomcat to handle the case where multiple keys exist in the + * key store, each with a different password. The KeyManagerFactory + * can't handle that so using an in memory key store with just the + * required key works around that. + * Other keys stores (hardware, MS, etc.) will be used as is. + */ + + char[] keyPassArray = keyPass.toCharArray(); + + if (ks == null) { + if (certificate.getCertificateFile() == null) { + throw new IOException(sm.getString("jsse.noCertFile")); + } + + PEMFile privateKeyFile = new PEMFile( + certificate.getCertificateKeyFile() != null ? certificate.getCertificateKeyFile() : certificate.getCertificateFile(), + keyPass); + PEMFile certificateFile = new PEMFile(certificate.getCertificateFile()); + + Collection<Certificate> chain = new ArrayList<>(); + chain.addAll(certificateFile.getCertificates()); + if (certificate.getCertificateChainFile() != null) { + PEMFile certificateChainFile = new PEMFile(certificate.getCertificateChainFile()); + chain.addAll(certificateChainFile.getCertificates()); + } + + if (keyAlias == null) { + keyAlias = "tomcat"; + } + + // Switch to in-memory key store + ksUsed = KeyStore.getInstance("JKS"); + ksUsed.load(null, null); + ksUsed.setKeyEntry(keyAlias, privateKeyFile.getPrivateKey(), keyPass.toCharArray(), + chain.toArray(new Certificate[chain.size()])); + } else { + if (keyAlias != null && !ks.isKeyEntry(keyAlias)) { + throw new IOException(sm.getString("jsse.alias_no_key_entry", keyAlias)); + } else if (keyAlias == null) { + Enumeration<String> aliases = ks.aliases(); + if (!aliases.hasMoreElements()) { + throw new IOException(sm.getString("jsse.noKeys")); + } + while (aliases.hasMoreElements() && keyAlias == null) { + keyAlias = aliases.nextElement(); + if (!ks.isKeyEntry(keyAlias)) { + keyAlias = null; + } + } + if (keyAlias == null) { + throw new IOException(sm.getString("jsse.alias_no_key_entry", (Object) null)); + } + } + + Key k = ks.getKey(keyAlias, keyPassArray); + if (k != null && !"DKS".equalsIgnoreCase(certificate.getCertificateKeystoreType()) && + "PKCS#8".equalsIgnoreCase(k.getFormat())) { + // Switch to in-memory key store + String provider = certificate.getCertificateKeystoreProvider(); + if (provider == null) { + ksUsed = KeyStore.getInstance(certificate.getCertificateKeystoreType()); + } else { + ksUsed = KeyStore.getInstance(certificate.getCertificateKeystoreType(), + provider); + } + ksUsed.load(null, null); + ksUsed.setKeyEntry(keyAlias, k, keyPassArray, ks.getCertificateChain(keyAlias)); + } + // Non-PKCS#8 key stores will use the original key store + } + + + KeyManagerFactory kmf = KeyManagerFactory.getInstance(algorithm); + kmf.init(ksUsed, keyPassArray); + + KeyManager[] kms = kmf.getKeyManagers(); + + // Only need to filter keys by alias if there are key managers to filter + // and the original key store was used. The in memory key stores only + // have a single key so don't need filtering + if (kms != null && ksUsed == ks) { + String alias = keyAlias; + // JKS keystores always convert the alias name to lower case + if ("JKS".equals(certificate.getCertificateKeystoreType())) { + alias = alias.toLowerCase(Locale.ENGLISH); + } + for(int i = 0; i < kms.length; i++) { + kms[i] = new JSSEKeyManager((X509KeyManager)kms[i], alias); + } + } + + return kms; + } + + @Override public String[] getEnabledProtocols() { return enabledProtocols; Modified: tomcat/trunk/java/org/apache/tomcat/util/net/jsse/JSSEUtil.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/net/jsse/JSSEUtil.java?rev=1854097&r1=1854096&r2=1854097&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/tomcat/util/net/jsse/JSSEUtil.java (original) +++ tomcat/trunk/java/org/apache/tomcat/util/net/jsse/JSSEUtil.java Thu Feb 21 20:59:10 2019 @@ -16,25 +16,14 @@ */ package org.apache.tomcat.util.net.jsse; -import java.io.IOException; -import java.security.Key; import java.security.KeyManagementException; -import java.security.KeyStore; import java.security.NoSuchAlgorithmException; -import java.security.cert.Certificate; -import java.util.ArrayList; import java.util.Arrays; -import java.util.Collection; -import java.util.Enumeration; import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Set; -import javax.net.ssl.KeyManager; -import javax.net.ssl.KeyManagerFactory; -import javax.net.ssl.X509KeyManager; - import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.compat.JreVendor; @@ -162,118 +151,4 @@ public class JSSEUtil extends SSLUtilBas throws NoSuchAlgorithmException { return new JSSESSLContext(sslHostConfig.getSslProtocol()); } - - - @Override - public KeyManager[] getKeyManagers() throws Exception { - String keyAlias = certificate.getCertificateKeyAlias(); - String algorithm = sslHostConfig.getKeyManagerAlgorithm(); - String keyPass = certificate.getCertificateKeyPassword(); - // This has to be here as it can't be moved to SSLHostConfig since the - // defaults vary between JSSE and OpenSSL. - if (keyPass == null) { - keyPass = certificate.getCertificateKeystorePassword(); - } - - KeyStore ks = certificate.getCertificateKeystore(); - KeyStore ksUsed = ks; - - /* - * Use an in memory key store where possible. - * For PEM format keys and certificates, it allows them to be imported - * into the expected format. - * For Java key stores with PKCS8 encoded keys (e.g. JKS files), it - * enables Tomcat to handle the case where multiple keys exist in the - * key store, each with a different password. The KeyManagerFactory - * can't handle that so using an in memory key store with just the - * required key works around that. - * Other keys stores (hardware, MS, etc.) will be used as is. - */ - - char[] keyPassArray = keyPass.toCharArray(); - - if (ks == null) { - if (certificate.getCertificateFile() == null) { - throw new IOException(sm.getString("jsse.noCertFile")); - } - - PEMFile privateKeyFile = new PEMFile( - certificate.getCertificateKeyFile() != null ? certificate.getCertificateKeyFile() : certificate.getCertificateFile(), - keyPass); - PEMFile certificateFile = new PEMFile(certificate.getCertificateFile()); - - Collection<Certificate> chain = new ArrayList<>(); - chain.addAll(certificateFile.getCertificates()); - if (certificate.getCertificateChainFile() != null) { - PEMFile certificateChainFile = new PEMFile(certificate.getCertificateChainFile()); - chain.addAll(certificateChainFile.getCertificates()); - } - - if (keyAlias == null) { - keyAlias = "tomcat"; - } - - // Switch to in-memory key store - ksUsed = KeyStore.getInstance("JKS"); - ksUsed.load(null, null); - ksUsed.setKeyEntry(keyAlias, privateKeyFile.getPrivateKey(), keyPass.toCharArray(), - chain.toArray(new Certificate[chain.size()])); - } else { - if (keyAlias != null && !ks.isKeyEntry(keyAlias)) { - throw new IOException(sm.getString("jsse.alias_no_key_entry", keyAlias)); - } else if (keyAlias == null) { - Enumeration<String> aliases = ks.aliases(); - if (!aliases.hasMoreElements()) { - throw new IOException(sm.getString("jsse.noKeys")); - } - while (aliases.hasMoreElements() && keyAlias == null) { - keyAlias = aliases.nextElement(); - if (!ks.isKeyEntry(keyAlias)) { - keyAlias = null; - } - } - if (keyAlias == null) { - throw new IOException(sm.getString("jsse.alias_no_key_entry", (Object) null)); - } - } - - Key k = ks.getKey(keyAlias, keyPassArray); - if (k != null && !"DKS".equalsIgnoreCase(certificate.getCertificateKeystoreType()) && - "PKCS#8".equalsIgnoreCase(k.getFormat())) { - // Switch to in-memory key store - String provider = certificate.getCertificateKeystoreProvider(); - if (provider == null) { - ksUsed = KeyStore.getInstance(certificate.getCertificateKeystoreType()); - } else { - ksUsed = KeyStore.getInstance(certificate.getCertificateKeystoreType(), - provider); - } - ksUsed.load(null, null); - ksUsed.setKeyEntry(keyAlias, k, keyPassArray, ks.getCertificateChain(keyAlias)); - } - // Non-PKCS#8 key stores will use the original key store - } - - - KeyManagerFactory kmf = KeyManagerFactory.getInstance(algorithm); - kmf.init(ksUsed, keyPassArray); - - KeyManager[] kms = kmf.getKeyManagers(); - - // Only need to filter keys by alias if there are key managers to filter - // and the original key store was used. The in memory key stores only - // have a single key so don't need filtering - if (kms != null && ksUsed == ks) { - String alias = keyAlias; - // JKS keystores always convert the alias name to lower case - if ("JKS".equals(certificate.getCertificateKeystoreType())) { - alias = alias.toLowerCase(Locale.ENGLISH); - } - for(int i = 0; i < kms.length; i++) { - kms[i] = new JSSEKeyManager((X509KeyManager)kms[i], alias); - } - } - - return kms; - } } Modified: tomcat/trunk/java/org/apache/tomcat/util/net/openssl/OpenSSLUtil.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/net/openssl/OpenSSLUtil.java?rev=1854097&r1=1854096&r2=1854097&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/tomcat/util/net/openssl/OpenSSLUtil.java (original) +++ tomcat/trunk/java/org/apache/tomcat/util/net/openssl/OpenSSLUtil.java Thu Feb 21 20:59:10 2019 @@ -19,33 +19,19 @@ package org.apache.tomcat.util.net.opens import java.util.List; import java.util.Set; -import javax.net.ssl.KeyManager; - import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.jni.SSL; import org.apache.tomcat.util.net.SSLContext; import org.apache.tomcat.util.net.SSLHostConfigCertificate; import org.apache.tomcat.util.net.SSLUtilBase; -import org.apache.tomcat.util.net.jsse.JSSEUtil; public class OpenSSLUtil extends SSLUtilBase { private static final Log log = LogFactory.getLog(OpenSSLUtil.class); - private final JSSEUtil jsseUtil; - public OpenSSLUtil(SSLHostConfigCertificate certificate) { super(certificate); - - if (certificate.getCertificateFile() == null) { - // Using JSSE configuration for keystore and truststore - // Missing protocols not a concern so don't warn on skip - jsseUtil = new JSSEUtil(certificate, false); - } else { - // Use OpenSSL configuration for certificates - jsseUtil = null; - } } @@ -84,14 +70,4 @@ public class OpenSSLUtil extends SSLUtil public SSLContext createSSLContextInternal(List<String> negotiableProtocols) throws Exception { return new OpenSSLContext(certificate, negotiableProtocols); } - - - @Override - public KeyManager[] getKeyManagers() throws Exception { - if (jsseUtil != null) { - return jsseUtil.getKeyManagers(); - } else { - return null; - } - } } --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org