ttomcat-1778514358873.zip-extract/apache-tomcat-11.0.18-src/java/org/apache/tomcat/util/net/SSLUtilBase.java

Path
ttomcat-1778514358873.zip-extract/apache-tomcat-11.0.18-src/java/org/apache/tomcat/util/net/SSLUtilBase.java
Status
scanned
Type
file
Name
SSLUtilBase.java
Extension
.java
Programming language
Java
Mime type
text/plain
File type
ASCII text, with CRLF line terminators
Tag

      
    
Rootfs path

      
    
Size
25634 (25.0 KB)
MD5
ad4a07f4e7d663a467c655c4b0d5d72f
SHA1
4ea3b96db5f35d49727049337760d0d26a60355e
SHA256
1e992f4facfc6bf367c080a001e97450621453e91da93b0dc5140d07b2861651
SHA512

      
    
SHA1_git
c811ad4dd2877484220aebdb0a48afecb1fbee36
Is binary

      
    
Is text
True
Is archive

      
    
Is media

      
    
Is legal

      
    
Is manifest

      
    
Is readme

      
    
Is top level

      
    
Is key file

      
    
SSLUtilBase.java | 25.0 KB |

/* * 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.tomcat.util.net; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.URI; import java.nio.charset.StandardCharsets; import java.security.DomainLoadStoreParameter; import java.security.Key; import java.security.KeyStore; import java.security.cert.CRL; import java.security.cert.CRLException; import java.security.cert.CertPathParameters; import java.security.cert.CertPathValidator; import java.security.cert.CertStore; import java.security.cert.CertStoreParameters; import java.security.cert.Certificate; import java.security.cert.CertificateException; import java.security.cert.CertificateExpiredException; import java.security.cert.CertificateFactory; import java.security.cert.CertificateNotYetValidException; import java.security.cert.CollectionCertStoreParameters; import java.security.cert.PKIXBuilderParameters; import java.security.cert.PKIXRevocationChecker; import java.security.cert.X509CertSelector; import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.EnumSet; 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.compat.JreCompat; import org.apache.tomcat.util.file.ConfigFileLoader; import org.apache.tomcat.util.net.jsse.JSSEKeyManager; import org.apache.tomcat.util.net.jsse.PEMFile; import org.apache.tomcat.util.res.StringManager; /** * Common base class for {@link SSLUtil} implementations. */ public abstract class SSLUtilBase implements SSLUtil { private static final Log log = LogFactory.getLog(SSLUtilBase.class); private static final StringManager sm = StringManager.getManager(SSLUtilBase.class); public static final String DEFAULT_KEY_ALIAS = "tomcat"; protected final SSLHostConfig sslHostConfig; protected final SSLHostConfigCertificate certificate; private final String[] enabledProtocols; private final String[] enabledCiphers; protected SSLUtilBase(SSLHostConfigCertificate certificate) { this(certificate, true); } protected SSLUtilBase(SSLHostConfigCertificate certificate, boolean warnTls13) { this.certificate = certificate; this.sslHostConfig = certificate.getSSLHostConfig(); // Calculate the enabled protocols Set<String> configuredProtocols = sslHostConfig.getProtocols(); Set<String> implementedProtocols = getImplementedProtocols(); // If TLSv1.3 is not implemented and not explicitly requested we can // ignore it. It is included in the defaults so it may be configured. if (!implementedProtocols.contains(Constants.SSL_PROTO_TLSv1_3) && !sslHostConfig.isExplicitlyRequestedProtocol(Constants.SSL_PROTO_TLSv1_3)) { configuredProtocols.remove(Constants.SSL_PROTO_TLSv1_3); } // Newer JREs are dropping support for SSLv2Hello. If it is not // implemented and not explicitly requested we can ignore it. It is // included in the defaults so it may be configured. if (!implementedProtocols.contains(Constants.SSL_PROTO_SSLv2Hello) && !sslHostConfig.isExplicitlyRequestedProtocol(Constants.SSL_PROTO_SSLv2Hello)) { configuredProtocols.remove(Constants.SSL_PROTO_SSLv2Hello); } List<String> enabledProtocols = getEnabled("protocols", getLog(), warnTls13, configuredProtocols, implementedProtocols); if (enabledProtocols.contains("SSLv3")) { log.warn(sm.getString("sslUtilBase.ssl3")); } this.enabledProtocols = enabledProtocols.toArray(new String[0]); if (enabledProtocols.contains(Constants.SSL_PROTO_TLSv1_3) && sslHostConfig.getCertificateVerification().isOptional() && !isTls13RenegAuthAvailable() && warnTls13) { log.warn(sm.getString("sslUtilBase.tls13.auth")); } // Make TLS 1.3 renegotiation status visible further up the stack sslHostConfig.setTls13RenegotiationAvailable(isTls13RenegAuthAvailable()); // Calculate the enabled ciphers if (!JreCompat.isJre22Available() && sslHostConfig.getCiphers().startsWith("PROFILE=")) { // OpenSSL profiles cannot be resolved without Java 22 this.enabledCiphers = new String[0]; } else { boolean warnOnSkip = !sslHostConfig.getCiphers().equals(SSLHostConfig.DEFAULT_TLS_CIPHERS_12); List<String> configuredCiphers = sslHostConfig.getJsseCipherNames(); Set<String> implementedCiphers = getImplementedCiphers(); List<String> enabledCiphers = getEnabled("ciphers", getLog(), warnOnSkip, configuredCiphers, implementedCiphers); this.enabledCiphers = enabledCiphers.toArray(new String[0]); } } static <T> List<T> getEnabled(String name, Log log, boolean warnOnSkip, Collection<T> configured, Collection<T> implemented) { List<T> enabled = new ArrayList<>(); if (implemented.isEmpty()) { // Unable to determine the list of available protocols. This will // have been logged previously. // Use the configuredProtocols and hope they work. If not, an error // will be generated when the list is used. Not ideal but no more // can be done at this point. enabled.addAll(configured); } else { enabled.addAll(configured); enabled.retainAll(implemented); if (enabled.isEmpty()) { // Don't use the defaults in this case. They may be less secure // than the configuration the user intended. // Force the failure of the connector throw new IllegalArgumentException(sm.getString("sslUtilBase.noneSupported", name, configured)); } if (log.isDebugEnabled()) { log.debug(sm.getString("sslUtilBase.active", name, enabled)); } if (log.isDebugEnabled() || warnOnSkip) { if (enabled.size() != configured.size()) { List<T> skipped = new ArrayList<>(configured); skipped.removeAll(enabled); String msg = sm.getString("sslUtilBase.skipped", name, skipped); if (warnOnSkip) { log.warn(msg); } else { log.debug(msg); } } } } return enabled; } /* * Gets the key- or truststore with the specified type, path, password and password file. */ static KeyStore getStore(String type, String provider, String path, String pass, String passFile) throws IOException { KeyStore ks; InputStream istream = null; try { if (provider == null) { ks = KeyStore.getInstance(type); } else { ks = KeyStore.getInstance(type, provider); } if ("DKS".equalsIgnoreCase(type)) { URI uri = ConfigFileLoader.getSource().getURI(path); ks.load(new DomainLoadStoreParameter(uri, Collections.emptyMap())); } else { // Some key store types (e.g. hardware) expect the InputStream // to be null if (!("PKCS11".equalsIgnoreCase(type) || path.isEmpty() || "NONE".equalsIgnoreCase(path))) { istream = ConfigFileLoader.getSource().getResource(path).getInputStream(); } // The digester cannot differentiate between null and "". // Unfortunately, some key stores behave differently with null // and "". // JKS key stores treat null and "" interchangeably. // PKCS12 key stores don't return the cert if null is used. // Key stores that do not use passwords expect null // Therefore: // - generally use null if pass is null or "" // - for JKS or PKCS12 only use null if pass is null // (because JKS will auto-switch to PKCS12) char[] storePass = null; String passToUse; if (passFile != null) { try (BufferedReader reader = new BufferedReader( new InputStreamReader(ConfigFileLoader.getSource().getResource(passFile).getInputStream(), StandardCharsets.UTF_8))) { passToUse = reader.readLine(); } } else { passToUse = pass; } if (passToUse != null && (!passToUse.isEmpty() || "JKS".equalsIgnoreCase(type) || "PKCS12".equalsIgnoreCase(type))) { storePass = passToUse.toCharArray(); } ks.load(istream, storePass); } } catch (IOException ioe) { // May be expected when working with a trust store // Re-throw. Caller will catch and log as required throw ioe; } catch (Exception e) { String msg = sm.getString("sslUtilBase.keystore_load_failed", type, path, e.getMessage()); log.error(msg, e); throw new IOException(msg); } finally { if (istream != null) { try { istream.close(); } catch (IOException ioe) { // Do nothing } } } return ks; } @Override public final SSLContext createSSLContext(List<String> negotiableProtocols) throws Exception { SSLContext sslContext = createSSLContextInternal(negotiableProtocols); sslContext.init(getKeyManagers(), getTrustManagers(), null); SSLSessionContext sessionContext = sslContext.getServerSessionContext(); if (sessionContext != null) { configureSessionContext(sessionContext); } return sslContext; } @Override public void configureSessionContext(SSLSessionContext sslSessionContext) { // <0 - don't set anything - use the implementation default if (sslHostConfig.getSessionCacheSize() >= 0) { sslSessionContext.setSessionCacheSize(sslHostConfig.getSessionCacheSize()); } // <0 - don't set anything - use the implementation default if (sslHostConfig.getSessionTimeout() >= 0) { sslSessionContext.setSessionTimeout(sslHostConfig.getSessionTimeout()); } } @Override public KeyManager[] getKeyManagers() throws Exception { String keyAlias = certificate.getCertificateKeyAlias(); String algorithm = sslHostConfig.getKeyManagerAlgorithm(); String keyPassFile = certificate.getCertificateKeyPasswordFile(); 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 (keyPassFile == null) { keyPassFile = certificate.getCertificateKeystorePasswordFile(); } 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 = null; String keyPassToUse = null; if (keyPassFile != null) { try (BufferedReader reader = new BufferedReader(new InputStreamReader( ConfigFileLoader.getSource().getResource(keyPassFile).getInputStream(), StandardCharsets.UTF_8))) { keyPassToUse = reader.readLine(); } } else { keyPassToUse = keyPass; } if (keyPassToUse != null) { keyPassArray = keyPassToUse.toCharArray(); } KeyManagerFactory kmf = KeyManagerFactory.getInstance(algorithm); if (kmf.getProvider().getInfo().contains("FIPS")) { // FIPS doesn't like ANY wrapping nor key manipulation. if (keyAlias != null) { log.warn(sm.getString("sslUtilBase.aliasIgnored", keyAlias)); } kmf.init(ksUsed, keyPassArray); return kmf.getKeyManagers(); } if (ks == null) { if (certificate.getCertificateFile() == null) { throw new IOException(sm.getString("sslUtilBase.noCertFile")); } PEMFile privateKeyFile = new PEMFile(certificate.getCertificateKeyFile() != null ? certificate.getCertificateKeyFile() : certificate.getCertificateFile(), keyPass, keyPassFile, null); PEMFile certificateFile = new PEMFile(certificate.getCertificateFile()); Collection<Certificate> chain = new ArrayList<>(certificateFile.getCertificates()); if (certificate.getCertificateChainFile() != null) { PEMFile certificateChainFile = new PEMFile(certificate.getCertificateChainFile()); chain.addAll(certificateChainFile.getCertificates()); } if (keyAlias == null) { keyAlias = DEFAULT_KEY_ALIAS; } // Switch to in-memory key store ksUsed = KeyStore.getInstance("JKS"); ksUsed.load(null, null); ksUsed.setKeyEntry(keyAlias, privateKeyFile.getPrivateKey(), keyPassArray, chain.toArray(new Certificate[0])); } else { if (keyAlias != null && !ks.isKeyEntry(keyAlias)) { throw new IOException(sm.getString("sslUtilBase.alias_no_key_entry", keyAlias)); } else if (keyAlias == null) { Enumeration<String> aliases = ks.aliases(); if (!aliases.hasMoreElements()) { throw new IOException(sm.getString("sslUtilBase.noKeys")); } while (aliases.hasMoreElements() && keyAlias == null) { keyAlias = aliases.nextElement(); if (!ks.isKeyEntry(keyAlias)) { keyAlias = null; } } if (keyAlias == null) { throw new IOException(sm.getString("sslUtilBase.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 } 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; } @Override public String[] getEnabledCiphers() { return enabledCiphers; } @Override public TrustManager[] getTrustManagers() throws Exception { String className = sslHostConfig.getTrustManagerClassName(); if (className != null && !className.isEmpty()) { ClassLoader classLoader = getClass().getClassLoader(); Class<?> clazz = classLoader.loadClass(className); if (!(TrustManager.class.isAssignableFrom(clazz))) { throw new InstantiationException(sm.getString("sslUtilBase.invalidTrustManagerClassName", className)); } Object trustManagerObject = clazz.getConstructor().newInstance(); TrustManager trustManager = (TrustManager) trustManagerObject; return new TrustManager[] { trustManager }; } TrustManager[] tms = null; KeyStore trustStore = sslHostConfig.getTruststore(); if (trustStore != null) { checkTrustStoreEntries(trustStore); String algorithm = sslHostConfig.getTruststoreAlgorithm(); String crlf = sslHostConfig.getCertificateRevocationListFile(); boolean revocationEnabled = sslHostConfig.getRevocationEnabled(); TrustManagerFactory tmf = TrustManagerFactory.getInstance(algorithm); if ("PKIX".equalsIgnoreCase(algorithm)) { CertPathParameters params = getParameters(crlf, trustStore, revocationEnabled); ManagerFactoryParameters mfp = new CertPathTrustManagerParameters(params); tmf.init(mfp); tms = tmf.getTrustManagers(); } else { tmf.init(trustStore); tms = tmf.getTrustManagers(); if (crlf != null && !crlf.isEmpty()) { throw new CRLException(sm.getString("sslUtilBase.noCrlSupport", algorithm)); } // Only warn if the attribute has been explicitly configured if (sslHostConfig.isCertificateVerificationDepthConfigured()) { log.warn(sm.getString("sslUtilBase.noVerificationDepth", algorithm)); } } } return tms; } private void checkTrustStoreEntries(KeyStore trustStore) throws Exception { Enumeration<String> aliases = trustStore.aliases(); if (aliases != null) { Date now = new Date(); while (aliases.hasMoreElements()) { String alias = aliases.nextElement(); if (trustStore.isCertificateEntry(alias)) { Certificate cert = trustStore.getCertificate(alias); if (cert instanceof X509Certificate) { try { ((X509Certificate) cert).checkValidity(now); } catch (CertificateExpiredException | CertificateNotYetValidException e) { String msg = sm.getString("sslUtilBase.trustedCertNotValid", alias, ((X509Certificate) cert).getSubjectX500Principal(), e.getMessage()); if (log.isDebugEnabled()) { log.warn(msg, e); } else { log.warn(msg); } } } else { if (log.isDebugEnabled()) { log.debug(sm.getString("sslUtilBase.trustedCertNotChecked", alias)); } } } } } } /** * Return the initialization parameters for the TrustManager. Currently, only the default <code>PKIX</code> is * supported. * * @param crlf The path to the CRL file. * @param trustStore The configured TrustStore. * @param revocationEnabled Should the JSSE provider perform revocation checks? Ignored if {@code crlf} is non-null. * Configuration of revocation checks are expected to be via proprietary JSSE provider * methods. * * @return The parameters including the CRLs and TrustStore. * * @throws Exception An error occurred */ protected CertPathParameters getParameters(final String crlf, final KeyStore trustStore, final boolean revocationEnabled) throws Exception { boolean enableRevocation = revocationEnabled; PKIXBuilderParameters xparams = new PKIXBuilderParameters(trustStore, new X509CertSelector()); if (crlf != null && !crlf.isEmpty()) { Collection<? extends CRL> crls = getCRLs(crlf); CertStoreParameters csp = new CollectionCertStoreParameters(crls); CertStore store = CertStore.getInstance("Collection", csp); xparams.addCertStore(store); enableRevocation = true; } if (sslHostConfig.getOcspEnabled()) { PKIXRevocationChecker revocationChecker =(PKIXRevocationChecker) CertPathValidator.getInstance("PKIX").getRevocationChecker(); if (sslHostConfig.getOcspSoftFail()) { revocationChecker.setOptions(EnumSet.of(PKIXRevocationChecker.Option.SOFT_FAIL)); } else { revocationChecker.setOptions(Collections.emptySet()); } xparams.addCertPathChecker(revocationChecker); enableRevocation = true; } xparams.setRevocationEnabled(enableRevocation); xparams.setMaxPathLength(sslHostConfig.getCertificateVerificationDepth()); return xparams; } /** * Load the collection of CRLs. * * @param crlf The path to the CRL file. * * @return the CRLs collection * * @throws IOException Error reading CRL file * @throws CRLException CRL error * @throws CertificateException Error processing certificate */ protected Collection<? extends CRL> getCRLs(String crlf) throws IOException, CRLException, CertificateException { Collection<? extends CRL> crls; CertificateFactory cf = CertificateFactory.getInstance("X.509"); try (InputStream is = ConfigFileLoader.getSource().getResource(crlf).getInputStream()) { crls = cf.generateCRLs(is); } return crls; } protected abstract Set<String> getImplementedProtocols(); protected abstract Set<String> getImplementedCiphers(); protected abstract Log getLog(); protected abstract boolean isTls13RenegAuthAvailable(); protected abstract SSLContext createSSLContextInternal(List<String> negotiableProtocols) throws Exception; }
Detected license expression
apache-2.0
Detected license expression (SPDX)
Apache-2.0
Percentage of license text
5.43
Copyrights

      
    
Holders

      
    
Authors

      
    
License detections License expression License expression SPDX
apache_2_0-4bde3f57-78aa-4201-96bf-531cba09e7de apache-2.0 Apache-2.0
URL Start line End line
http://www.apache.org/licenses/LICENSE-2.0 9 9