| /* |
| * 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.File; |
| import java.io.FileNotFoundException; |
| import java.io.IOException; |
| import java.io.Serializable; |
| import java.security.KeyStore; |
| import java.security.UnrecoverableKeyException; |
| import java.util.EnumMap; |
| import java.util.HashSet; |
| import java.util.LinkedHashSet; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| |
| import javax.management.ObjectName; |
| import javax.net.ssl.KeyManagerFactory; |
| import javax.net.ssl.TrustManagerFactory; |
| |
| import org.apache.juli.logging.Log; |
| import org.apache.juli.logging.LogFactory; |
| import org.apache.tomcat.util.net.openssl.OpenSSLConf; |
| import org.apache.tomcat.util.net.openssl.ciphers.Cipher; |
| import org.apache.tomcat.util.net.openssl.ciphers.OpenSSLCipherConfigurationParser; |
| import org.apache.tomcat.util.res.StringManager; |
| |
| /** |
| * Represents the TLS configuration for a virtual host. |
| */ |
| public class SSLHostConfig implements Serializable { |
| |
| private static final long serialVersionUID = 1L; |
| |
| private static final Log log = LogFactory.getLog(SSLHostConfig.class); |
| private static final StringManager sm = StringManager.getManager(SSLHostConfig.class); |
| |
| protected static final String DEFAULT_SSL_HOST_NAME = "_default_"; |
| protected static final Set<String> SSL_PROTO_ALL_SET = new HashSet<>(); |
| |
| static { |
| /* Default used if protocols is not configured, also used if |
| * protocols="All" |
| */ |
| SSL_PROTO_ALL_SET.add(Constants.SSL_PROTO_SSLv2Hello); |
| SSL_PROTO_ALL_SET.add(Constants.SSL_PROTO_TLSv1); |
| SSL_PROTO_ALL_SET.add(Constants.SSL_PROTO_TLSv1_1); |
| SSL_PROTO_ALL_SET.add(Constants.SSL_PROTO_TLSv1_2); |
| SSL_PROTO_ALL_SET.add(Constants.SSL_PROTO_TLSv1_3); |
| } |
| |
| private Type configType = null; |
| private Type currentConfigType = null; |
| private Map<Type, Set<String>> configuredProperties = new EnumMap<>(Type.class); |
| |
| private String hostName = DEFAULT_SSL_HOST_NAME; |
| |
| private transient Long openSslConfContext = Long.valueOf(0); |
| // OpenSSL can handle multiple certs in a single config so the reference to |
| // the context is here at the virtual host level. JSSE can't so the |
| // reference is held on the certificate. |
| private transient Long openSslContext = Long.valueOf(0); |
| |
| // Configuration properties |
| |
| // Internal |
| private String[] enabledCiphers; |
| private String[] enabledProtocols; |
| private ObjectName oname; |
| // Need to know if TLS 1.3 has been explicitly requested as a warning needs |
| // to generated if it is explicitly requested for a JVM that does not |
| // support it. Uses a set so it is extensible for TLS 1.4 etc. |
| private Set<String> explicitlyRequestedProtocols = new HashSet<>(); |
| // Nested |
| private SSLHostConfigCertificate defaultCertificate = null; |
| private Set<SSLHostConfigCertificate> certificates = new HashSet<>(4); |
| // Common |
| private String certificateRevocationListFile; |
| private CertificateVerification certificateVerification = CertificateVerification.NONE; |
| private int certificateVerificationDepth = 10; |
| // Used to track if certificateVerificationDepth has been explicitly set |
| private boolean certificateVerificationDepthConfigured = false; |
| private String ciphers = "HIGH:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!kRSA"; |
| private LinkedHashSet<Cipher> cipherList = null; |
| private List<String> jsseCipherNames = null; |
| private boolean honorCipherOrder = false; |
| private Set<String> protocols = new HashSet<>(); |
| // JSSE |
| private String keyManagerAlgorithm = KeyManagerFactory.getDefaultAlgorithm(); |
| private boolean revocationEnabled = false; |
| private int sessionCacheSize = 0; |
| private int sessionTimeout = 86400; |
| private String sslProtocol = Constants.SSL_PROTO_TLS; |
| private String trustManagerClassName; |
| private String truststoreAlgorithm = TrustManagerFactory.getDefaultAlgorithm(); |
| private String truststoreFile = System.getProperty("javax.net.ssl.trustStore"); |
| private String truststorePassword = System.getProperty("javax.net.ssl.trustStorePassword"); |
| private String truststoreProvider = System.getProperty("javax.net.ssl.trustStoreProvider"); |
| private String truststoreType = System.getProperty("javax.net.ssl.trustStoreType"); |
| private transient KeyStore truststore = null; |
| // OpenSSL |
| private String certificateRevocationListPath; |
| private String caCertificateFile; |
| private String caCertificatePath; |
| private boolean disableCompression = true; |
| private boolean disableSessionTickets = false; |
| private boolean insecureRenegotiation = false; |
| private OpenSSLConf openSslConf = null; |
| |
| public SSLHostConfig() { |
| // Set defaults that can't be (easily) set when defining the fields. |
| setProtocols(Constants.SSL_PROTO_ALL); |
| } |
| |
| |
| public Long getOpenSslConfContext() { |
| return openSslConfContext; |
| } |
| |
| |
| public void setOpenSslConfContext(Long openSslConfContext) { |
| this.openSslConfContext = openSslConfContext; |
| } |
| |
| |
| public Long getOpenSslContext() { |
| return openSslContext; |
| } |
| |
| |
| public void setOpenSslContext(Long openSslContext) { |
| this.openSslContext = openSslContext; |
| } |
| |
| |
| // Expose in String form for JMX |
| public String getConfigType() { |
| return configType.name(); |
| } |
| public void setConfigType(Type configType) { |
| this.configType = configType; |
| if (configType == Type.EITHER) { |
| if (configuredProperties.remove(Type.JSSE) == null) { |
| configuredProperties.remove(Type.OPENSSL); |
| } |
| } else { |
| configuredProperties.remove(configType); |
| } |
| for (Map.Entry<Type,Set<String>> entry : configuredProperties.entrySet()) { |
| for (String property : entry.getValue()) { |
| log.warn(sm.getString("sslHostConfig.mismatch", |
| property, getHostName(), entry.getKey(), configType)); |
| } |
| } |
| } |
| |
| |
| void setProperty(String name, Type configType) { |
| if (this.configType == null) { |
| Set<String> properties = configuredProperties.get(configType); |
| if (properties == null) { |
| properties = new HashSet<>(); |
| configuredProperties.put(configType, properties); |
| } |
| properties.add(name); |
| } else if (this.configType == Type.EITHER) { |
| if (currentConfigType == null) { |
| currentConfigType = configType; |
| } else if (currentConfigType != configType) { |
| log.warn(sm.getString("sslHostConfig.mismatch", |
| name, getHostName(), configType, currentConfigType)); |
| } |
| } else { |
| if (configType != this.configType) { |
| log.warn(sm.getString("sslHostConfig.mismatch", |
| name, getHostName(), configType, this.configType)); |
| } |
| } |
| } |
| |
| |
| // ----------------------------------------------------- Internal properties |
| |
| /** |
| * @see SSLUtil#getEnabledProtocols() |
| * |
| * @return The protocols enabled for this TLS virtual host |
| */ |
| public String[] getEnabledProtocols() { |
| return enabledProtocols; |
| } |
| |
| |
| public void setEnabledProtocols(String[] enabledProtocols) { |
| this.enabledProtocols = enabledProtocols; |
| } |
| |
| |
| /** |
| * @see SSLUtil#getEnabledCiphers() |
| * |
| * @return The ciphers enabled for this TLS virtual host |
| */ |
| public String[] getEnabledCiphers() { |
| return enabledCiphers; |
| } |
| |
| |
| public void setEnabledCiphers(String[] enabledCiphers) { |
| this.enabledCiphers = enabledCiphers; |
| } |
| |
| |
| public ObjectName getObjectName() { |
| return oname; |
| } |
| |
| |
| public void setObjectName(ObjectName oname) { |
| this.oname = oname; |
| } |
| |
| |
| // ------------------------------------------- Nested configuration elements |
| |
| private void registerDefaultCertificate() { |
| if (defaultCertificate == null) { |
| defaultCertificate = new SSLHostConfigCertificate( |
| this, SSLHostConfigCertificate.Type.UNDEFINED); |
| certificates.add(defaultCertificate); |
| } |
| } |
| |
| |
| public void addCertificate(SSLHostConfigCertificate certificate) { |
| // Need to make sure that if there is more than one certificate, none of |
| // them have a type of undefined. |
| if (certificates.size() == 0) { |
| certificates.add(certificate); |
| return; |
| } |
| |
| if (certificates.size() == 1 && |
| certificates.iterator().next().getType() == SSLHostConfigCertificate.Type.UNDEFINED || |
| certificate.getType() == SSLHostConfigCertificate.Type.UNDEFINED) { |
| // Invalid config |
| throw new IllegalArgumentException(sm.getString("sslHostConfig.certificate.notype")); |
| } |
| |
| certificates.add(certificate); |
| } |
| |
| |
| public OpenSSLConf getOpenSslConf() { |
| return openSslConf; |
| } |
| |
| |
| public void setOpenSslConf(OpenSSLConf conf) { |
| if (conf == null) { |
| throw new IllegalArgumentException(sm.getString("sslHostConfig.opensslconf.null")); |
| } else if (openSslConf != null) { |
| throw new IllegalArgumentException(sm.getString("sslHostConfig.opensslconf.alreadySet")); |
| } |
| setProperty("<OpenSSLConf>", Type.OPENSSL); |
| openSslConf = conf; |
| } |
| |
| |
| public Set<SSLHostConfigCertificate> getCertificates() { |
| return getCertificates(false); |
| } |
| |
| |
| public Set<SSLHostConfigCertificate> getCertificates(boolean createDefaultIfEmpty) { |
| if (certificates.size() == 0 && createDefaultIfEmpty) { |
| registerDefaultCertificate(); |
| } |
| return certificates; |
| } |
| |
| |
| // ----------------------------------------- Common configuration properties |
| |
| // TODO: This certificate setter can be removed once it is no longer |
| // necessary to support the old configuration attributes (Tomcat 10?). |
| |
| public String getCertificateKeyPassword() { |
| registerDefaultCertificate(); |
| return defaultCertificate.getCertificateKeyPassword(); |
| } |
| public void setCertificateKeyPassword(String certificateKeyPassword) { |
| registerDefaultCertificate(); |
| defaultCertificate.setCertificateKeyPassword(certificateKeyPassword); |
| } |
| |
| |
| public void setCertificateRevocationListFile(String certificateRevocationListFile) { |
| this.certificateRevocationListFile = certificateRevocationListFile; |
| } |
| |
| |
| public String getCertificateRevocationListFile() { |
| return certificateRevocationListFile; |
| } |
| |
| |
| public void setCertificateVerification(String certificateVerification) { |
| try { |
| this.certificateVerification = |
| CertificateVerification.fromString(certificateVerification); |
| } catch (IllegalArgumentException iae) { |
| // If the specified value is not recognised, default to the |
| // strictest possible option. |
| this.certificateVerification = CertificateVerification.REQUIRED; |
| throw iae; |
| } |
| } |
| |
| |
| public CertificateVerification getCertificateVerification() { |
| return certificateVerification; |
| } |
| |
| |
| public void setCertificateVerificationAsString(String certificateVerification) { |
| setCertificateVerification(certificateVerification); |
| } |
| |
| |
| public String getCertificateVerificationAsString() { |
| return certificateVerification.toString(); |
| } |
| |
| |
| public void setCertificateVerificationDepth(int certificateVerificationDepth) { |
| this.certificateVerificationDepth = certificateVerificationDepth; |
| certificateVerificationDepthConfigured = true; |
| } |
| |
| |
| public int getCertificateVerificationDepth() { |
| return certificateVerificationDepth; |
| } |
| |
| |
| public boolean isCertificateVerificationDepthConfigured() { |
| return certificateVerificationDepthConfigured; |
| } |
| |
| |
| /** |
| * Set the new cipher configuration. Note: Regardless of the format used to |
| * set the configuration, it is always stored in OpenSSL format. |
| * |
| * @param ciphersList The new cipher configuration in OpenSSL or JSSE format |
| */ |
| public void setCiphers(String ciphersList) { |
| // Ciphers is stored in OpenSSL format. Convert the provided value if |
| // necessary. |
| if (ciphersList != null && !ciphersList.contains(":")) { |
| StringBuilder sb = new StringBuilder(); |
| // Not obviously in OpenSSL format. May be a single OpenSSL or JSSE |
| // cipher name. May be a comma separated list of cipher names |
| String ciphers[] = ciphersList.split(","); |
| for (String cipher : ciphers) { |
| String trimmed = cipher.trim(); |
| if (trimmed.length() > 0) { |
| String openSSLName = OpenSSLCipherConfigurationParser.jsseToOpenSSL(trimmed); |
| if (openSSLName == null) { |
| // Not a JSSE name. Maybe an OpenSSL name or alias |
| openSSLName = trimmed; |
| } |
| if (sb.length() > 0) { |
| sb.append(':'); |
| } |
| sb.append(openSSLName); |
| } |
| } |
| this.ciphers = sb.toString(); |
| } else { |
| this.ciphers = ciphersList; |
| } |
| this.cipherList = null; |
| this.jsseCipherNames = null; |
| } |
| |
| |
| /** |
| * @return An OpenSSL cipher string for the current configuration. |
| */ |
| public String getCiphers() { |
| return ciphers; |
| } |
| |
| |
| public LinkedHashSet<Cipher> getCipherList() { |
| if (cipherList == null) { |
| cipherList = OpenSSLCipherConfigurationParser.parse(ciphers); |
| } |
| return cipherList; |
| } |
| |
| |
| /** |
| * Obtain the list of JSSE cipher names for the current configuration. |
| * Ciphers included in the configuration but not supported by JSSE will be |
| * excluded from this list. |
| * |
| * @return A list of the JSSE cipher names |
| */ |
| public List<String> getJsseCipherNames() { |
| if (jsseCipherNames == null) { |
| jsseCipherNames = OpenSSLCipherConfigurationParser.convertForJSSE(getCipherList()); |
| } |
| return jsseCipherNames; |
| } |
| |
| |
| public void setHonorCipherOrder(boolean honorCipherOrder) { |
| this.honorCipherOrder = honorCipherOrder; |
| } |
| |
| |
| public boolean getHonorCipherOrder() { |
| return honorCipherOrder; |
| } |
| |
| |
| public void setHostName(String hostName) { |
| this.hostName = hostName; |
| } |
| |
| |
| public String getHostName() { |
| return hostName; |
| } |
| |
| |
| public void setProtocols(String input) { |
| protocols.clear(); |
| explicitlyRequestedProtocols.clear(); |
| |
| // List of protocol names, separated by ",", "+" or "-". |
| // Semantics is adding ("+") or removing ("-") from left |
| // to right, starting with an empty protocol set. |
| // Tokens are individual protocol names or "all" for a |
| // default set of supported protocols. |
| // Separator "," is only kept for compatibility and has the |
| // same semantics as "+", except that it warns about a potentially |
| // missing "+" or "-". |
| |
| // Split using a positive lookahead to keep the separator in |
| // the capture so we can check which case it is. |
| for (String value: input.split("(?=[-+,])")) { |
| String trimmed = value.trim(); |
| // Ignore token which only consists of prefix character |
| if (trimmed.length() > 1) { |
| if (trimmed.charAt(0) == '+') { |
| trimmed = trimmed.substring(1).trim(); |
| if (trimmed.equalsIgnoreCase(Constants.SSL_PROTO_ALL)) { |
| protocols.addAll(SSL_PROTO_ALL_SET); |
| } else { |
| protocols.add(trimmed); |
| explicitlyRequestedProtocols.add(trimmed); |
| } |
| } else if (trimmed.charAt(0) == '-') { |
| trimmed = trimmed.substring(1).trim(); |
| if (trimmed.equalsIgnoreCase(Constants.SSL_PROTO_ALL)) { |
| protocols.removeAll(SSL_PROTO_ALL_SET); |
| } else { |
| protocols.remove(trimmed); |
| explicitlyRequestedProtocols.remove(trimmed); |
| } |
| } else { |
| if (trimmed.charAt(0) == ',') { |
| trimmed = trimmed.substring(1).trim(); |
| } |
| if (!protocols.isEmpty()) { |
| log.warn(sm.getString("sslHostConfig.prefix_missing", |
| trimmed, getHostName())); |
| } |
| if (trimmed.equalsIgnoreCase(Constants.SSL_PROTO_ALL)) { |
| protocols.addAll(SSL_PROTO_ALL_SET); |
| } else { |
| protocols.add(trimmed); |
| explicitlyRequestedProtocols.add(trimmed); |
| } |
| } |
| } |
| } |
| } |
| |
| |
| public Set<String> getProtocols() { |
| return protocols; |
| } |
| |
| |
| boolean isExplicitlyRequestedProtocol(String protocol) { |
| return explicitlyRequestedProtocols.contains(protocol); |
| } |
| |
| |
| // ---------------------------------- JSSE specific configuration properties |
| |
| // TODO: These certificate setters can be removed once it is no longer |
| // necessary to support the old configuration attributes (Tomcat 10?). |
| |
| public String getCertificateKeyAlias() { |
| registerDefaultCertificate(); |
| return defaultCertificate.getCertificateKeyAlias(); |
| } |
| public void setCertificateKeyAlias(String certificateKeyAlias) { |
| registerDefaultCertificate(); |
| defaultCertificate.setCertificateKeyAlias(certificateKeyAlias); |
| } |
| |
| |
| public String getCertificateKeystoreFile() { |
| registerDefaultCertificate(); |
| return defaultCertificate.getCertificateKeystoreFile(); |
| } |
| public void setCertificateKeystoreFile(String certificateKeystoreFile) { |
| registerDefaultCertificate(); |
| defaultCertificate.setCertificateKeystoreFile(certificateKeystoreFile); |
| } |
| |
| |
| public String getCertificateKeystorePassword() { |
| registerDefaultCertificate(); |
| return defaultCertificate.getCertificateKeystorePassword(); |
| } |
| public void setCertificateKeystorePassword(String certificateKeystorePassword) { |
| registerDefaultCertificate(); |
| defaultCertificate.setCertificateKeystorePassword(certificateKeystorePassword); |
| } |
| |
| |
| public String getCertificateKeystoreProvider() { |
| registerDefaultCertificate(); |
| return defaultCertificate.getCertificateKeystoreProvider(); |
| } |
| public void setCertificateKeystoreProvider(String certificateKeystoreProvider) { |
| registerDefaultCertificate(); |
| defaultCertificate.setCertificateKeystoreProvider(certificateKeystoreProvider); |
| } |
| |
| |
| public String getCertificateKeystoreType() { |
| registerDefaultCertificate(); |
| return defaultCertificate.getCertificateKeystoreType(); |
| } |
| public void setCertificateKeystoreType(String certificateKeystoreType) { |
| registerDefaultCertificate(); |
| defaultCertificate.setCertificateKeystoreType(certificateKeystoreType); |
| } |
| |
| |
| public void setKeyManagerAlgorithm(String keyManagerAlgorithm) { |
| setProperty("keyManagerAlgorithm", Type.JSSE); |
| this.keyManagerAlgorithm = keyManagerAlgorithm; |
| } |
| |
| |
| public String getKeyManagerAlgorithm() { |
| return keyManagerAlgorithm; |
| } |
| |
| |
| public void setRevocationEnabled(boolean revocationEnabled) { |
| setProperty("revocationEnabled", Type.JSSE); |
| this.revocationEnabled = revocationEnabled; |
| } |
| |
| |
| public boolean getRevocationEnabled() { |
| return revocationEnabled; |
| } |
| |
| |
| public void setSessionCacheSize(int sessionCacheSize) { |
| setProperty("sessionCacheSize", Type.JSSE); |
| this.sessionCacheSize = sessionCacheSize; |
| } |
| |
| |
| public int getSessionCacheSize() { |
| return sessionCacheSize; |
| } |
| |
| |
| public void setSessionTimeout(int sessionTimeout) { |
| setProperty("sessionTimeout", Type.JSSE); |
| this.sessionTimeout = sessionTimeout; |
| } |
| |
| |
| public int getSessionTimeout() { |
| return sessionTimeout; |
| } |
| |
| |
| public void setSslProtocol(String sslProtocol) { |
| setProperty("sslProtocol", Type.JSSE); |
| this.sslProtocol = sslProtocol; |
| } |
| |
| |
| public String getSslProtocol() { |
| return sslProtocol; |
| } |
| |
| |
| public void setTrustManagerClassName(String trustManagerClassName) { |
| setProperty("trustManagerClassName", Type.JSSE); |
| this.trustManagerClassName = trustManagerClassName; |
| } |
| |
| |
| public String getTrustManagerClassName() { |
| return trustManagerClassName; |
| } |
| |
| |
| public void setTruststoreAlgorithm(String truststoreAlgorithm) { |
| setProperty("truststoreAlgorithm", Type.JSSE); |
| this.truststoreAlgorithm = truststoreAlgorithm; |
| } |
| |
| |
| public String getTruststoreAlgorithm() { |
| return truststoreAlgorithm; |
| } |
| |
| |
| public void setTruststoreFile(String truststoreFile) { |
| setProperty("truststoreFile", Type.JSSE); |
| this.truststoreFile = truststoreFile; |
| } |
| |
| |
| public String getTruststoreFile() { |
| return truststoreFile; |
| } |
| |
| |
| public void setTruststorePassword(String truststorePassword) { |
| setProperty("truststorePassword", Type.JSSE); |
| this.truststorePassword = truststorePassword; |
| } |
| |
| |
| public String getTruststorePassword() { |
| return truststorePassword; |
| } |
| |
| |
| public void setTruststoreProvider(String truststoreProvider) { |
| setProperty("truststoreProvider", Type.JSSE); |
| this.truststoreProvider = truststoreProvider; |
| } |
| |
| |
| public String getTruststoreProvider() { |
| if (truststoreProvider == null) { |
| Set<SSLHostConfigCertificate> certificates = getCertificates(); |
| if (certificates.size() == 1) { |
| return certificates.iterator().next().getCertificateKeystoreProvider(); |
| } |
| return SSLHostConfigCertificate.DEFAULT_KEYSTORE_PROVIDER; |
| } else { |
| return truststoreProvider; |
| } |
| } |
| |
| |
| public void setTruststoreType(String truststoreType) { |
| setProperty("truststoreType", Type.JSSE); |
| this.truststoreType = truststoreType; |
| } |
| |
| |
| public String getTruststoreType() { |
| if (truststoreType == null) { |
| Set<SSLHostConfigCertificate> certificates = getCertificates(); |
| if (certificates.size() == 1) { |
| String keystoreType = certificates.iterator().next().getCertificateKeystoreType(); |
| // Don't use keystore type as the default if we know it is not |
| // going to be used as a trust store type |
| if (!"PKCS12".equalsIgnoreCase(keystoreType)) { |
| return keystoreType; |
| } |
| } |
| return SSLHostConfigCertificate.DEFAULT_KEYSTORE_TYPE; |
| } else { |
| return truststoreType; |
| } |
| } |
| |
| |
| public void setTrustStore(KeyStore truststore) { |
| this.truststore = truststore; |
| } |
| |
| |
| public KeyStore getTruststore() throws IOException { |
| KeyStore result = truststore; |
| if (result == null) { |
| if (truststoreFile != null){ |
| try { |
| result = SSLUtilBase.getStore(getTruststoreType(), getTruststoreProvider(), |
| getTruststoreFile(), getTruststorePassword()); |
| } catch (IOException ioe) { |
| Throwable cause = ioe.getCause(); |
| if (cause instanceof UnrecoverableKeyException) { |
| // Log a warning we had a password issue |
| log.warn(sm.getString("jsse.invalid_truststore_password"), |
| cause); |
| // Re-try |
| result = SSLUtilBase.getStore(getTruststoreType(), getTruststoreProvider(), |
| getTruststoreFile(), null); |
| } else { |
| // Something else went wrong - re-throw |
| throw ioe; |
| } |
| } |
| } |
| } |
| return result; |
| } |
| |
| |
| // ------------------------------- OpenSSL specific configuration properties |
| |
| // TODO: These certificate setters can be removed once it is no longer |
| // necessary to support the old configuration attributes (Tomcat 10?). |
| |
| public String getCertificateChainFile() { |
| registerDefaultCertificate(); |
| return defaultCertificate.getCertificateChainFile(); |
| } |
| public void setCertificateChainFile(String certificateChainFile) { |
| registerDefaultCertificate(); |
| defaultCertificate.setCertificateChainFile(certificateChainFile); |
| } |
| |
| |
| public String getCertificateFile() { |
| registerDefaultCertificate(); |
| return defaultCertificate.getCertificateFile(); |
| } |
| public void setCertificateFile(String certificateFile) { |
| registerDefaultCertificate(); |
| defaultCertificate.setCertificateFile(certificateFile); |
| } |
| |
| |
| public String getCertificateKeyFile() { |
| registerDefaultCertificate(); |
| return defaultCertificate.getCertificateKeyFile(); |
| } |
| public void setCertificateKeyFile(String certificateKeyFile) { |
| registerDefaultCertificate(); |
| defaultCertificate.setCertificateKeyFile(certificateKeyFile); |
| } |
| |
| |
| public void setCertificateRevocationListPath(String certificateRevocationListPath) { |
| setProperty("certificateRevocationListPath", Type.OPENSSL); |
| this.certificateRevocationListPath = certificateRevocationListPath; |
| } |
| |
| |
| public String getCertificateRevocationListPath() { |
| return certificateRevocationListPath; |
| } |
| |
| |
| public void setCaCertificateFile(String caCertificateFile) { |
| setProperty("caCertificateFile", Type.OPENSSL); |
| this.caCertificateFile = caCertificateFile; |
| } |
| |
| |
| public String getCaCertificateFile() { |
| return caCertificateFile; |
| } |
| |
| |
| public void setCaCertificatePath(String caCertificatePath) { |
| setProperty("caCertificatePath", Type.OPENSSL); |
| this.caCertificatePath = caCertificatePath; |
| } |
| |
| |
| public String getCaCertificatePath() { |
| return caCertificatePath; |
| } |
| |
| |
| public void setDisableCompression(boolean disableCompression) { |
| setProperty("disableCompression", Type.OPENSSL); |
| this.disableCompression = disableCompression; |
| } |
| |
| |
| public boolean getDisableCompression() { |
| return disableCompression; |
| } |
| |
| |
| public void setDisableSessionTickets(boolean disableSessionTickets) { |
| setProperty("disableSessionTickets", Type.OPENSSL); |
| this.disableSessionTickets = disableSessionTickets; |
| } |
| |
| |
| public boolean getDisableSessionTickets() { |
| return disableSessionTickets; |
| } |
| |
| |
| public void setInsecureRenegotiation(boolean insecureRenegotiation) { |
| setProperty("insecureRenegotiation", Type.OPENSSL); |
| this.insecureRenegotiation = insecureRenegotiation; |
| } |
| |
| |
| public boolean getInsecureRenegotiation() { |
| return insecureRenegotiation; |
| } |
| |
| |
| // --------------------------------------------------------- Support methods |
| |
| public static String adjustRelativePath(String path) throws FileNotFoundException { |
| // Empty or null path can't point to anything useful. The assumption is |
| // that the value is deliberately empty / null so leave it that way. |
| if (path == null || path.length() == 0) { |
| return path; |
| } |
| String newPath = path; |
| File f = new File(newPath); |
| if ( !f.isAbsolute()) { |
| newPath = System.getProperty(Constants.CATALINA_BASE_PROP) + File.separator + newPath; |
| f = new File(newPath); |
| } |
| if (!f.exists()) { |
| throw new FileNotFoundException(sm.getString("sslHostConfig.fileNotFound", newPath)); |
| } |
| return newPath; |
| } |
| |
| |
| // ----------------------------------------------------------- Inner classes |
| |
| public enum Type { |
| JSSE, |
| OPENSSL, |
| EITHER |
| } |
| |
| |
| public enum CertificateVerification { |
| NONE, |
| OPTIONAL_NO_CA, |
| OPTIONAL, |
| REQUIRED; |
| |
| public static CertificateVerification fromString(String value) { |
| if ("true".equalsIgnoreCase(value) || |
| "yes".equalsIgnoreCase(value) || |
| "require".equalsIgnoreCase(value) || |
| "required".equalsIgnoreCase(value)) { |
| return REQUIRED; |
| } else if ("optional".equalsIgnoreCase(value) || |
| "want".equalsIgnoreCase(value)) { |
| return OPTIONAL; |
| } else if ("optionalNoCA".equalsIgnoreCase(value) || |
| "optional_no_ca".equalsIgnoreCase(value)) { |
| return OPTIONAL_NO_CA; |
| } else if ("false".equalsIgnoreCase(value) || |
| "no".equalsIgnoreCase(value) || |
| "none".equalsIgnoreCase(value)) { |
| return NONE; |
| } else { |
| // Could be a typo. Don't default to NONE since that is not |
| // secure. Force user to fix config. Could default to REQUIRED |
| // instead. |
| throw new IllegalArgumentException( |
| sm.getString("sslHostConfig.certificateVerificationInvalid", value)); |
| } |
| } |
| } |
| } |