/* * 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;
/** * Represents the TLS configuration for a virtual host.
*/ publicclass SSLHostConfig implements Serializable {
privatestaticfinallong serialVersionUID = 1L;
privatestaticfinal Log log = LogFactory.getLog(SSLHostConfig.class); privatestaticfinal StringManager sm = StringManager.getManager(SSLHostConfig.class);
// Must be lower case. SSL host names are always stored using lower case as // they are case insensitive but are used by case sensitive code such as // keys in Maps. protectedstaticfinal String DEFAULT_SSL_HOST_NAME = "_default_"; protectedstaticfinal Set<String> SSL_PROTO_ALL_SET = new HashSet<>(); publicstaticfinal String DEFAULT_TLS_CIPHERS = "HIGH:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!kRSA";
static { /* Default used if protocols are 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 String hostName = DEFAULT_SSL_HOST_NAME;
privatetransientvolatileLong 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. privatetransientvolatileLong openSslContext = Long.valueOf(0);
// Expose in String form for JMX public String getConfigType() { return configType.name();
}
/** * Set property which belongs to the specified configuration type. * @param name the property name * @param configType the configuration type * @return true if the property belongs to the current configuration, * and false otherwise
*/ boolean setProperty(String name, Type configType) { if (this.configType == null) { this.configType = configType;
} else { if (configType != this.configType) {
log.warn(sm.getString("sslHostConfig.mismatch",
name, getHostName(), configType, this.configType)); returnfalse;
}
} returntrue;
}
publicvoid 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;
}
public String getCertificateRevocationListFile() { return certificateRevocationListFile;
}
publicvoid 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;
}
/** * 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
*/ publicvoid 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(getCiphers());
} 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;
}
// 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);
}
} elseif (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;
}
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;
}
}
// --------------------------------------------------------- Support methods
public Set<X509Certificate> certificatesExpiringBefore(Date date) {
Set<X509Certificate> result = new HashSet<>();
Set<SSLHostConfigCertificate> sslHostConfigCertificates = getCertificates(); for (SSLHostConfigCertificate sslHostConfigCertificate : sslHostConfigCertificates) {
SSLContext sslContext = sslHostConfigCertificate.getSslContext(); if (sslContext != null) {
String alias = sslHostConfigCertificate.getCertificateKeyAlias(); if (alias == null) {
alias = SSLUtilBase.DEFAULT_KEY_ALIAS;
}
X509Certificate[] certificates = sslContext.getCertificateChain(alias); if (certificates != null && certificates.length > 0) {
X509Certificate certificate = certificates[0];
Date expirationDate = certificate.getNotAfter(); if (date.after(expirationDate)) {
result.add(certificate);
}
}
}
} return result;
}
publicstatic 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()) { thrownew FileNotFoundException(sm.getString("sslHostConfig.fileNotFound", newPath));
} return newPath;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.