init
This commit is contained in:
563
java/org/apache/tomcat/util/net/openssl/OpenSSLContext.java
Normal file
563
java/org/apache/tomcat/util/net/openssl/OpenSSLContext.java
Normal file
@@ -0,0 +1,563 @@
|
||||
/*
|
||||
* 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.openssl;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.SecureRandom;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.CertificateFactory;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import javax.net.ssl.KeyManager;
|
||||
import javax.net.ssl.SSLEngine;
|
||||
import javax.net.ssl.SSLException;
|
||||
import javax.net.ssl.SSLParameters;
|
||||
import javax.net.ssl.SSLServerSocketFactory;
|
||||
import javax.net.ssl.SSLSessionContext;
|
||||
import javax.net.ssl.TrustManager;
|
||||
import javax.net.ssl.X509KeyManager;
|
||||
import javax.net.ssl.X509TrustManager;
|
||||
|
||||
import org.apache.juli.logging.Log;
|
||||
import org.apache.juli.logging.LogFactory;
|
||||
import org.apache.tomcat.jni.CertificateVerifier;
|
||||
import org.apache.tomcat.jni.Pool;
|
||||
import org.apache.tomcat.jni.SSL;
|
||||
import org.apache.tomcat.jni.SSLConf;
|
||||
import org.apache.tomcat.jni.SSLContext;
|
||||
import org.apache.tomcat.util.codec.binary.Base64;
|
||||
import org.apache.tomcat.util.net.AbstractEndpoint;
|
||||
import org.apache.tomcat.util.net.Constants;
|
||||
import org.apache.tomcat.util.net.SSLHostConfig;
|
||||
import org.apache.tomcat.util.net.SSLHostConfig.CertificateVerification;
|
||||
import org.apache.tomcat.util.net.SSLHostConfigCertificate;
|
||||
import org.apache.tomcat.util.net.SSLHostConfigCertificate.Type;
|
||||
import org.apache.tomcat.util.res.StringManager;
|
||||
|
||||
public class OpenSSLContext implements org.apache.tomcat.util.net.SSLContext {
|
||||
|
||||
private static final Base64 BASE64_ENCODER = new Base64(64, new byte[] {'\n'});
|
||||
|
||||
private static final Log log = LogFactory.getLog(OpenSSLContext.class);
|
||||
|
||||
// Note: this uses the main "net" package strings as many are common with APR
|
||||
private static final StringManager netSm = StringManager.getManager(AbstractEndpoint.class);
|
||||
private static final StringManager sm = StringManager.getManager(OpenSSLContext.class);
|
||||
|
||||
private static final String defaultProtocol = "TLS";
|
||||
|
||||
private final SSLHostConfig sslHostConfig;
|
||||
private final SSLHostConfigCertificate certificate;
|
||||
private OpenSSLSessionContext sessionContext;
|
||||
private X509TrustManager x509TrustManager;
|
||||
|
||||
private final List<String> negotiableProtocols;
|
||||
|
||||
private String enabledProtocol;
|
||||
|
||||
public String getEnabledProtocol() {
|
||||
return enabledProtocol;
|
||||
}
|
||||
|
||||
public void setEnabledProtocol(String protocol) {
|
||||
enabledProtocol = (protocol == null) ? defaultProtocol : protocol;
|
||||
}
|
||||
|
||||
private final long aprPool;
|
||||
private final AtomicInteger aprPoolDestroyed = new AtomicInteger(0);
|
||||
|
||||
// OpenSSLConfCmd context
|
||||
protected final long cctx;
|
||||
// SSL context
|
||||
protected final long ctx;
|
||||
|
||||
static final CertificateFactory X509_CERT_FACTORY;
|
||||
|
||||
private static final String BEGIN_KEY = "-----BEGIN PRIVATE KEY-----\n";
|
||||
|
||||
private static final Object END_KEY = "\n-----END PRIVATE KEY-----";
|
||||
private boolean initialized = false;
|
||||
|
||||
static {
|
||||
try {
|
||||
X509_CERT_FACTORY = CertificateFactory.getInstance("X.509");
|
||||
} catch (CertificateException e) {
|
||||
throw new IllegalStateException(sm.getString("openssl.X509FactoryError"), e);
|
||||
}
|
||||
}
|
||||
|
||||
public OpenSSLContext(SSLHostConfigCertificate certificate, List<String> negotiableProtocols)
|
||||
throws SSLException {
|
||||
this.sslHostConfig = certificate.getSSLHostConfig();
|
||||
this.certificate = certificate;
|
||||
aprPool = Pool.create(0);
|
||||
boolean success = false;
|
||||
try {
|
||||
// Create OpenSSLConfCmd context if used
|
||||
OpenSSLConf openSslConf = sslHostConfig.getOpenSslConf();
|
||||
if (openSslConf != null) {
|
||||
try {
|
||||
if (log.isDebugEnabled())
|
||||
log.debug(sm.getString("openssl.makeConf"));
|
||||
cctx = SSLConf.make(aprPool,
|
||||
SSL.SSL_CONF_FLAG_FILE |
|
||||
SSL.SSL_CONF_FLAG_SERVER |
|
||||
SSL.SSL_CONF_FLAG_CERTIFICATE |
|
||||
SSL.SSL_CONF_FLAG_SHOW_ERRORS);
|
||||
} catch (Exception e) {
|
||||
throw new SSLException(sm.getString("openssl.errMakeConf"), e);
|
||||
}
|
||||
} else {
|
||||
cctx = 0;
|
||||
}
|
||||
sslHostConfig.setOpenSslConfContext(Long.valueOf(cctx));
|
||||
|
||||
// SSL protocol
|
||||
int value = SSL.SSL_PROTOCOL_NONE;
|
||||
for (String protocol : sslHostConfig.getEnabledProtocols()) {
|
||||
if (Constants.SSL_PROTO_SSLv2Hello.equalsIgnoreCase(protocol)) {
|
||||
// NO-OP. OpenSSL always supports SSLv2Hello
|
||||
} else if (Constants.SSL_PROTO_SSLv2.equalsIgnoreCase(protocol)) {
|
||||
value |= SSL.SSL_PROTOCOL_SSLV2;
|
||||
} else if (Constants.SSL_PROTO_SSLv3.equalsIgnoreCase(protocol)) {
|
||||
value |= SSL.SSL_PROTOCOL_SSLV3;
|
||||
} else if (Constants.SSL_PROTO_TLSv1.equalsIgnoreCase(protocol)) {
|
||||
value |= SSL.SSL_PROTOCOL_TLSV1;
|
||||
} else if (Constants.SSL_PROTO_TLSv1_1.equalsIgnoreCase(protocol)) {
|
||||
value |= SSL.SSL_PROTOCOL_TLSV1_1;
|
||||
} else if (Constants.SSL_PROTO_TLSv1_2.equalsIgnoreCase(protocol)) {
|
||||
value |= SSL.SSL_PROTOCOL_TLSV1_2;
|
||||
} else if (Constants.SSL_PROTO_TLSv1_3.equalsIgnoreCase(protocol)) {
|
||||
value |= SSL.SSL_PROTOCOL_TLSV1_3;
|
||||
} else if (Constants.SSL_PROTO_ALL.equalsIgnoreCase(protocol)) {
|
||||
value |= SSL.SSL_PROTOCOL_ALL;
|
||||
} else {
|
||||
// Should not happen since filtering to build
|
||||
// enabled protocols removes invalid values.
|
||||
throw new Exception(netSm.getString(
|
||||
"endpoint.apr.invalidSslProtocol", protocol));
|
||||
}
|
||||
}
|
||||
|
||||
// Create SSL Context
|
||||
try {
|
||||
ctx = SSLContext.make(aprPool, value, SSL.SSL_MODE_SERVER);
|
||||
} catch (Exception e) {
|
||||
// If the sslEngine is disabled on the AprLifecycleListener
|
||||
// there will be an Exception here but there is no way to check
|
||||
// the AprLifecycleListener settings from here
|
||||
throw new Exception(
|
||||
netSm.getString("endpoint.apr.failSslContextMake"), e);
|
||||
}
|
||||
|
||||
this.negotiableProtocols = negotiableProtocols;
|
||||
|
||||
success = true;
|
||||
} catch(Exception e) {
|
||||
throw new SSLException(sm.getString("openssl.errorSSLCtxInit"), e);
|
||||
} finally {
|
||||
if (!success) {
|
||||
destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void destroy() {
|
||||
// Guard against multiple destroyPools() calls triggered by construction exception and finalize() later
|
||||
if (aprPoolDestroyed.compareAndSet(0, 1)) {
|
||||
if (ctx != 0) {
|
||||
SSLContext.free(ctx);
|
||||
}
|
||||
if (cctx != 0) {
|
||||
SSLConf.free(cctx);
|
||||
}
|
||||
if (aprPool != 0) {
|
||||
Pool.destroy(aprPool);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup the SSL_CTX.
|
||||
*
|
||||
* @param kms Must contain a KeyManager of the type
|
||||
* {@code OpenSSLKeyManager}
|
||||
* @param tms Must contain a TrustManager of the type
|
||||
* {@code X509TrustManager}
|
||||
* @param sr Is not used for this implementation.
|
||||
*/
|
||||
@Override
|
||||
public synchronized void init(KeyManager[] kms, TrustManager[] tms, SecureRandom sr) {
|
||||
if (initialized) {
|
||||
log.warn(sm.getString("openssl.doubleInit"));
|
||||
return;
|
||||
}
|
||||
try {
|
||||
if (sslHostConfig.getInsecureRenegotiation()) {
|
||||
SSLContext.setOptions(ctx, SSL.SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION);
|
||||
} else {
|
||||
SSLContext.clearOptions(ctx, SSL.SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION);
|
||||
}
|
||||
|
||||
// Use server's preference order for ciphers (rather than
|
||||
// client's)
|
||||
String honorCipherOrderStr = sslHostConfig.getHonorCipherOrder();
|
||||
if (honorCipherOrderStr != null) {
|
||||
if (Boolean.parseBoolean(honorCipherOrderStr)) {
|
||||
SSLContext.setOptions(ctx, SSL.SSL_OP_CIPHER_SERVER_PREFERENCE);
|
||||
} else {
|
||||
SSLContext.clearOptions(ctx, SSL.SSL_OP_CIPHER_SERVER_PREFERENCE);
|
||||
}
|
||||
}
|
||||
|
||||
// Disable compression if requested
|
||||
if (sslHostConfig.getDisableCompression()) {
|
||||
SSLContext.setOptions(ctx, SSL.SSL_OP_NO_COMPRESSION);
|
||||
} else {
|
||||
SSLContext.clearOptions(ctx, SSL.SSL_OP_NO_COMPRESSION);
|
||||
}
|
||||
|
||||
// Disable TLS Session Tickets (RFC4507) to protect perfect forward secrecy
|
||||
if (sslHostConfig.getDisableSessionTickets()) {
|
||||
SSLContext.setOptions(ctx, SSL.SSL_OP_NO_TICKET);
|
||||
} else {
|
||||
SSLContext.clearOptions(ctx, SSL.SSL_OP_NO_TICKET);
|
||||
}
|
||||
|
||||
// List the ciphers that the client is permitted to negotiate
|
||||
SSLContext.setCipherSuite(ctx, sslHostConfig.getCiphers());
|
||||
|
||||
if (certificate.getCertificateFile() == null) {
|
||||
certificate.setCertificateKeyManager(OpenSSLUtil.chooseKeyManager(kms));
|
||||
}
|
||||
|
||||
addCertificate(certificate);
|
||||
|
||||
// Client certificate verification
|
||||
int value = 0;
|
||||
switch (sslHostConfig.getCertificateVerification()) {
|
||||
case NONE:
|
||||
value = SSL.SSL_CVERIFY_NONE;
|
||||
break;
|
||||
case OPTIONAL:
|
||||
value = SSL.SSL_CVERIFY_OPTIONAL;
|
||||
break;
|
||||
case OPTIONAL_NO_CA:
|
||||
value = SSL.SSL_CVERIFY_OPTIONAL_NO_CA;
|
||||
break;
|
||||
case REQUIRED:
|
||||
value = SSL.SSL_CVERIFY_REQUIRE;
|
||||
break;
|
||||
}
|
||||
SSLContext.setVerify(ctx, value, sslHostConfig.getCertificateVerificationDepth());
|
||||
|
||||
if (tms != null) {
|
||||
// Client certificate verification based on custom trust managers
|
||||
x509TrustManager = chooseTrustManager(tms);
|
||||
SSLContext.setCertVerifyCallback(ctx, new CertificateVerifier() {
|
||||
@Override
|
||||
public boolean verify(long ssl, byte[][] chain, String auth) {
|
||||
X509Certificate[] peerCerts = certificates(chain);
|
||||
try {
|
||||
x509TrustManager.checkClientTrusted(peerCerts, auth);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
log.debug(sm.getString("openssl.certificateVerificationFailed"), e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
// Pass along the DER encoded certificates of the accepted client
|
||||
// certificate issuers, so that their subjects can be presented
|
||||
// by the server during the handshake to allow the client choosing
|
||||
// an acceptable certificate
|
||||
for (X509Certificate caCert : x509TrustManager.getAcceptedIssuers()) {
|
||||
SSLContext.addClientCACertificateRaw(ctx, caCert.getEncoded());
|
||||
if (log.isDebugEnabled())
|
||||
log.debug(sm.getString("openssl.addedClientCaCert", caCert.toString()));
|
||||
}
|
||||
} else {
|
||||
// Client certificate verification based on trusted CA files and dirs
|
||||
SSLContext.setCACertificate(ctx,
|
||||
SSLHostConfig.adjustRelativePath(sslHostConfig.getCaCertificateFile()),
|
||||
SSLHostConfig.adjustRelativePath(sslHostConfig.getCaCertificatePath()));
|
||||
}
|
||||
|
||||
if (negotiableProtocols != null && negotiableProtocols.size() > 0) {
|
||||
List<String> protocols = new ArrayList<>();
|
||||
protocols.addAll(negotiableProtocols);
|
||||
protocols.add("http/1.1");
|
||||
String[] protocolsArray = protocols.toArray(new String[0]);
|
||||
SSLContext.setAlpnProtos(ctx, protocolsArray, SSL.SSL_SELECTOR_FAILURE_NO_ADVERTISE);
|
||||
SSLContext.setNpnProtos(ctx, protocolsArray, SSL.SSL_SELECTOR_FAILURE_NO_ADVERTISE);
|
||||
}
|
||||
|
||||
// Apply OpenSSLConfCmd if used
|
||||
OpenSSLConf openSslConf = sslHostConfig.getOpenSslConf();
|
||||
if (openSslConf != null && cctx != 0) {
|
||||
// Check OpenSSLConfCmd if used
|
||||
if (log.isDebugEnabled())
|
||||
log.debug(sm.getString("openssl.checkConf"));
|
||||
try {
|
||||
if (!openSslConf.check(cctx)) {
|
||||
log.error(sm.getString("openssl.errCheckConf"));
|
||||
throw new Exception(sm.getString("openssl.errCheckConf"));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new Exception(sm.getString("openssl.errCheckConf"), e);
|
||||
}
|
||||
if (log.isDebugEnabled())
|
||||
log.debug(sm.getString("openssl.applyConf"));
|
||||
try {
|
||||
if (!openSslConf.apply(cctx, ctx)) {
|
||||
log.error(sm.getString("openssl.errApplyConf"));
|
||||
throw new SSLException(sm.getString("openssl.errApplyConf"));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new SSLException(sm.getString("openssl.errApplyConf"), e);
|
||||
}
|
||||
// Reconfigure the enabled protocols
|
||||
int opts = SSLContext.getOptions(ctx);
|
||||
List<String> enabled = new ArrayList<>();
|
||||
// Seems like there is no way to explicitly disable SSLv2Hello
|
||||
// in OpenSSL so it is always enabled
|
||||
enabled.add(Constants.SSL_PROTO_SSLv2Hello);
|
||||
if ((opts & SSL.SSL_OP_NO_TLSv1) == 0) {
|
||||
enabled.add(Constants.SSL_PROTO_TLSv1);
|
||||
}
|
||||
if ((opts & SSL.SSL_OP_NO_TLSv1_1) == 0) {
|
||||
enabled.add(Constants.SSL_PROTO_TLSv1_1);
|
||||
}
|
||||
if ((opts & SSL.SSL_OP_NO_TLSv1_2) == 0) {
|
||||
enabled.add(Constants.SSL_PROTO_TLSv1_2);
|
||||
}
|
||||
if ((opts & SSL.SSL_OP_NO_SSLv2) == 0) {
|
||||
enabled.add(Constants.SSL_PROTO_SSLv2);
|
||||
}
|
||||
if ((opts & SSL.SSL_OP_NO_SSLv3) == 0) {
|
||||
enabled.add(Constants.SSL_PROTO_SSLv3);
|
||||
}
|
||||
sslHostConfig.setEnabledProtocols(
|
||||
enabled.toArray(new String[enabled.size()]));
|
||||
// Reconfigure the enabled ciphers
|
||||
sslHostConfig.setEnabledCiphers(SSLContext.getCiphers(ctx));
|
||||
}
|
||||
|
||||
sessionContext = new OpenSSLSessionContext(this);
|
||||
// If client authentication is being used, OpenSSL requires that
|
||||
// this is set so always set it in case an app is configured to
|
||||
// require it
|
||||
sessionContext.setSessionIdContext(SSLContext.DEFAULT_SESSION_ID_CONTEXT);
|
||||
sslHostConfig.setOpenSslContext(Long.valueOf(ctx));
|
||||
initialized = true;
|
||||
} catch (Exception e) {
|
||||
log.warn(sm.getString("openssl.errorSSLCtxInit"), e);
|
||||
destroy();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void addCertificate(SSLHostConfigCertificate certificate) throws Exception {
|
||||
// Load Server key and certificate
|
||||
if (certificate.getCertificateFile() != null) {
|
||||
// Set certificate
|
||||
SSLContext.setCertificate(ctx,
|
||||
SSLHostConfig.adjustRelativePath(certificate.getCertificateFile()),
|
||||
SSLHostConfig.adjustRelativePath(certificate.getCertificateKeyFile()),
|
||||
certificate.getCertificateKeyPassword(), getCertificateIndex(certificate));
|
||||
// Set certificate chain file
|
||||
SSLContext.setCertificateChainFile(ctx,
|
||||
SSLHostConfig.adjustRelativePath(certificate.getCertificateChainFile()), false);
|
||||
// Set revocation
|
||||
SSLContext.setCARevocation(ctx,
|
||||
SSLHostConfig.adjustRelativePath(
|
||||
sslHostConfig.getCertificateRevocationListFile()),
|
||||
SSLHostConfig.adjustRelativePath(
|
||||
sslHostConfig.getCertificateRevocationListPath()));
|
||||
} else {
|
||||
String alias = certificate.getCertificateKeyAlias();
|
||||
X509KeyManager x509KeyManager = certificate.getCertificateKeyManager();
|
||||
if (alias == null) {
|
||||
alias = "tomcat";
|
||||
}
|
||||
X509Certificate[] chain = x509KeyManager.getCertificateChain(alias);
|
||||
if (chain == null) {
|
||||
alias = findAlias(x509KeyManager, certificate);
|
||||
chain = x509KeyManager.getCertificateChain(alias);
|
||||
}
|
||||
PrivateKey key = x509KeyManager.getPrivateKey(alias);
|
||||
StringBuilder sb = new StringBuilder(BEGIN_KEY);
|
||||
String encoded = BASE64_ENCODER.encodeToString(key.getEncoded());
|
||||
if (encoded.endsWith("\n")) {
|
||||
encoded = encoded.substring(0, encoded.length() - 1);
|
||||
}
|
||||
sb.append(encoded);
|
||||
sb.append(END_KEY);
|
||||
SSLContext.setCertificateRaw(ctx, chain[0].getEncoded(),
|
||||
sb.toString().getBytes(StandardCharsets.US_ASCII),
|
||||
getCertificateIndex(certificate));
|
||||
for (int i = 1; i < chain.length; i++) {
|
||||
SSLContext.addChainCertificateRaw(ctx, chain[i].getEncoded());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static int getCertificateIndex(SSLHostConfigCertificate certificate) {
|
||||
int result;
|
||||
// If the type is undefined there will only be one certificate (enforced
|
||||
// in SSLHostConfig) so use the RSA slot.
|
||||
if (certificate.getType() == Type.RSA || certificate.getType() == Type.UNDEFINED) {
|
||||
result = SSL.SSL_AIDX_RSA;
|
||||
} else if (certificate.getType() == Type.EC) {
|
||||
result = SSL.SSL_AIDX_ECC;
|
||||
} else if (certificate.getType() == Type.DSA) {
|
||||
result = SSL.SSL_AIDX_DSA;
|
||||
} else {
|
||||
result = SSL.SSL_AIDX_MAX;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Find a valid alias when none was specified in the config.
|
||||
*/
|
||||
private static String findAlias(X509KeyManager keyManager,
|
||||
SSLHostConfigCertificate certificate) {
|
||||
|
||||
Type type = certificate.getType();
|
||||
String result = null;
|
||||
|
||||
List<Type> candidateTypes = new ArrayList<>();
|
||||
if (Type.UNDEFINED.equals(type)) {
|
||||
// Try all types to find an suitable alias
|
||||
candidateTypes.addAll(Arrays.asList(Type.values()));
|
||||
candidateTypes.remove(Type.UNDEFINED);
|
||||
} else {
|
||||
// Look for the specific type to find a suitable alias
|
||||
candidateTypes.add(type);
|
||||
}
|
||||
|
||||
Iterator<Type> iter = candidateTypes.iterator();
|
||||
while (result == null && iter.hasNext()) {
|
||||
result = keyManager.chooseServerAlias(iter.next().toString(), null, null);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static X509TrustManager chooseTrustManager(TrustManager[] managers) {
|
||||
for (TrustManager m : managers) {
|
||||
if (m instanceof X509TrustManager) {
|
||||
return (X509TrustManager) m;
|
||||
}
|
||||
}
|
||||
throw new IllegalStateException(sm.getString("openssl.trustManagerMissing"));
|
||||
}
|
||||
|
||||
private static X509Certificate[] certificates(byte[][] chain) {
|
||||
X509Certificate[] peerCerts = new X509Certificate[chain.length];
|
||||
for (int i = 0; i < peerCerts.length; i++) {
|
||||
peerCerts[i] = new OpenSSLX509Certificate(chain[i]);
|
||||
}
|
||||
return peerCerts;
|
||||
}
|
||||
|
||||
|
||||
long getSSLContextID() {
|
||||
return ctx;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public SSLSessionContext getServerSessionContext() {
|
||||
return sessionContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SSLEngine createSSLEngine() {
|
||||
return new OpenSSLEngine(ctx, defaultProtocol, false, sessionContext,
|
||||
(negotiableProtocols != null && negotiableProtocols.size() > 0), initialized,
|
||||
sslHostConfig.getCertificateVerificationDepth(),
|
||||
sslHostConfig.getCertificateVerification() == CertificateVerification.OPTIONAL_NO_CA);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SSLServerSocketFactory getServerSocketFactory() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SSLParameters getSupportedSSLParameters() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public X509Certificate[] getCertificateChain(String alias) {
|
||||
X509Certificate[] chain = null;
|
||||
X509KeyManager x509KeyManager = certificate.getCertificateKeyManager();
|
||||
if (x509KeyManager != null) {
|
||||
if (alias == null) {
|
||||
alias = "tomcat";
|
||||
}
|
||||
chain = x509KeyManager.getCertificateChain(alias);
|
||||
if (chain == null) {
|
||||
alias = findAlias(x509KeyManager, certificate);
|
||||
chain = x509KeyManager.getCertificateChain(alias);
|
||||
}
|
||||
}
|
||||
|
||||
return chain;
|
||||
}
|
||||
|
||||
@Override
|
||||
public X509Certificate[] getAcceptedIssuers() {
|
||||
X509Certificate[] acceptedCerts = null;
|
||||
if (x509TrustManager != null) {
|
||||
acceptedCerts = x509TrustManager.getAcceptedIssuers();
|
||||
}
|
||||
return acceptedCerts;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finalize() throws Throwable {
|
||||
/*
|
||||
* When an SSLHostConfig is replaced at runtime, it is not possible to
|
||||
* call destroy() on the associated OpenSSLContext since it is likely
|
||||
* that there will be in-progress connections using the OpenSSLContext.
|
||||
* A reference chain has been deliberately established (see
|
||||
* OpenSSLSessionContext) to ensure that the OpenSSLContext remains
|
||||
* ineligible for GC while those connections are alive. Once those
|
||||
* connections complete, the OpenSSLContext will become eligible for GC
|
||||
* and this method will ensure that the associated native resources are
|
||||
* cleaned up.
|
||||
*/
|
||||
try {
|
||||
destroy();
|
||||
} finally {
|
||||
super.finalize();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user