SSL SSLUtilBase.java
Interaktion und PortierbarkeitJAVA
/* * 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;
// 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);
}
if (implemented.size() == 0) { // 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 thrownew 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 = null;
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 = null; 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 && (!"".equals(passToUse) || "JKS".equalsIgnoreCase(type) || "PKCS12".equalsIgnoreCase(type))) {
storePass = passToUse.toCharArray();
}
KeyStoreUtil.load(ks, 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 ex) {
String msg = sm.getString("sslUtilBase.keystore_load_failed", type, path,
ex.getMessage());
log.error(msg, ex); thrownew IOException(msg);
} finally { if (istream != null) { try {
istream.close();
} catch (IOException ioe) { // Do nothing
}
}
}
@Override publicvoid 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();
}
/* * 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) { thrownew 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;
}
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 {
if ("PKIX".equalsIgnoreCase(algorithm)) {
TrustManagerFactory tmf = TrustManagerFactory.getInstance(algorithm);
CertPathParameters params = getParameters(crlf, trustStore, revocationEnabled);
ManagerFactoryParameters mfp = new CertPathTrustManagerParameters(params);
tmf.init(mfp);
tms = tmf.getTrustManagers();
} else {
TrustManagerFactory tmf = TrustManagerFactory.getInstance(algorithm);
tmf.init(trustStore);
tms = tmf.getTrustManagers(); if (crlf != null && crlf.length() > 0) { thrownew 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;
}
privatevoid 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(String crlf, KeyStore trustStore, boolean revocationEnabled) throws Exception {
PKIXBuilderParameters xparams = new PKIXBuilderParameters(trustStore, new X509CertSelector()); if (crlf != null && crlf.length() > 0) {
Collection<? extends CRL> crls = getCRLs(crlf);
CertStoreParameters csp = new CollectionCertStoreParameters(crls);
CertStore store = CertStore.getInstance("Collection", csp);
xparams.addCertStore(store);
xparams.setRevocationEnabled(true);
} else {
xparams.setRevocationEnabled(revocationEnabled);
}
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 {
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 ist noch experimentell.