Add supported for X509ExtendedTrustManager when using OpenSslEngine
Motivation: For some use cases X509ExtendedTrustManager is needed as it allows to also access the SslEngine during validation. Modifications: Add support for X509ExtendedTrustManager on java >= 7 Result: It's now possible to use X509ExtendedTrustManager with OpenSslEngine
This commit is contained in:
parent
0222f41233
commit
0c6ba4aab6
@ -17,15 +17,13 @@ package io.netty.handler.ssl;
|
|||||||
|
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import io.netty.buffer.ByteBufInputStream;
|
import io.netty.buffer.ByteBufInputStream;
|
||||||
import io.netty.util.internal.logging.InternalLogger;
|
|
||||||
import io.netty.util.internal.logging.InternalLoggerFactory;
|
|
||||||
import org.apache.tomcat.jni.CertificateVerifier;
|
|
||||||
import org.apache.tomcat.jni.SSL;
|
import org.apache.tomcat.jni.SSL;
|
||||||
import org.apache.tomcat.jni.SSLContext;
|
import org.apache.tomcat.jni.SSLContext;
|
||||||
|
|
||||||
import javax.net.ssl.SSLException;
|
import javax.net.ssl.SSLException;
|
||||||
import javax.net.ssl.TrustManager;
|
import javax.net.ssl.TrustManager;
|
||||||
import javax.net.ssl.TrustManagerFactory;
|
import javax.net.ssl.TrustManagerFactory;
|
||||||
|
import javax.net.ssl.X509ExtendedTrustManager;
|
||||||
import javax.net.ssl.X509TrustManager;
|
import javax.net.ssl.X509TrustManager;
|
||||||
import javax.security.auth.x500.X500Principal;
|
import javax.security.auth.x500.X500Principal;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
@ -40,8 +38,8 @@ import java.security.cert.X509Certificate;
|
|||||||
* A client-side {@link SslContext} which uses OpenSSL's SSL/TLS implementation.
|
* A client-side {@link SslContext} which uses OpenSSL's SSL/TLS implementation.
|
||||||
*/
|
*/
|
||||||
public final class OpenSslClientContext extends OpenSslContext {
|
public final class OpenSslClientContext extends OpenSslContext {
|
||||||
private static final InternalLogger logger = InternalLoggerFactory.getInstance(OpenSslClientContext.class);
|
|
||||||
private final OpenSslSessionContext sessionContext;
|
private final OpenSslSessionContext sessionContext;
|
||||||
|
private final OpenSslEngineMap engineMap;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new instance.
|
* Creates a new instance.
|
||||||
@ -132,19 +130,26 @@ public final class OpenSslClientContext extends OpenSslContext {
|
|||||||
initTrustManagerFactory(certChainFile, trustManagerFactory);
|
initTrustManagerFactory(certChainFile, trustManagerFactory);
|
||||||
final X509TrustManager manager = chooseTrustManager(trustManagerFactory.getTrustManagers());
|
final X509TrustManager manager = chooseTrustManager(trustManagerFactory.getTrustManagers());
|
||||||
|
|
||||||
SSLContext.setCertVerifyCallback(ctx, new CertificateVerifier() {
|
engineMap = newEngineMap(manager);
|
||||||
|
|
||||||
|
// Use this to prevent an error when running on java < 7
|
||||||
|
if (useExtendedTrustManager(manager)) {
|
||||||
|
final X509ExtendedTrustManager extendedManager = (X509ExtendedTrustManager) manager;
|
||||||
|
SSLContext.setCertVerifyCallback(ctx, new AbstractCertificateVerifier() {
|
||||||
@Override
|
@Override
|
||||||
public boolean verify(long ssl, byte[][] chain, String auth) {
|
void verify(long ssl, X509Certificate[] peerCerts, String auth) throws Exception {
|
||||||
X509Certificate[] peerCerts = certificates(chain);
|
OpenSslEngine engine = engineMap.remove(ssl);
|
||||||
try {
|
extendedManager.checkServerTrusted(peerCerts, auth, engine);
|
||||||
manager.checkServerTrusted(peerCerts, auth);
|
|
||||||
return true;
|
|
||||||
} catch (Exception e) {
|
|
||||||
logger.debug("verification of certificate failed", e);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
SSLContext.setCertVerifyCallback(ctx, new AbstractCertificateVerifier() {
|
||||||
|
@Override
|
||||||
|
void verify(long ssl, X509Certificate[] peerCerts, String auth) throws Exception {
|
||||||
|
manager.checkServerTrusted(peerCerts, auth);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new SSLException("unable to setup trustmanager", e);
|
throw new SSLException("unable to setup trustmanager", e);
|
||||||
}
|
}
|
||||||
@ -185,6 +190,11 @@ public final class OpenSslClientContext extends OpenSslContext {
|
|||||||
return sessionContext;
|
return sessionContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
OpenSslEngineMap engineMap() {
|
||||||
|
return engineMap;
|
||||||
|
}
|
||||||
|
|
||||||
// No cache is currently supported for client side mode.
|
// No cache is currently supported for client side mode.
|
||||||
private static final class OpenSslClientSessionContext extends OpenSslSessionContext {
|
private static final class OpenSslClientSessionContext extends OpenSslSessionContext {
|
||||||
private OpenSslClientSessionContext(long context) {
|
private OpenSslClientSessionContext(long context) {
|
||||||
|
@ -19,6 +19,7 @@ import io.netty.buffer.ByteBufAllocator;
|
|||||||
import io.netty.util.internal.PlatformDependent;
|
import io.netty.util.internal.PlatformDependent;
|
||||||
import io.netty.util.internal.logging.InternalLogger;
|
import io.netty.util.internal.logging.InternalLogger;
|
||||||
import io.netty.util.internal.logging.InternalLoggerFactory;
|
import io.netty.util.internal.logging.InternalLoggerFactory;
|
||||||
|
import org.apache.tomcat.jni.CertificateVerifier;
|
||||||
import org.apache.tomcat.jni.Pool;
|
import org.apache.tomcat.jni.Pool;
|
||||||
import org.apache.tomcat.jni.SSL;
|
import org.apache.tomcat.jni.SSL;
|
||||||
import org.apache.tomcat.jni.SSLContext;
|
import org.apache.tomcat.jni.SSLContext;
|
||||||
@ -26,11 +27,13 @@ import org.apache.tomcat.jni.SSLContext;
|
|||||||
import javax.net.ssl.SSLEngine;
|
import javax.net.ssl.SSLEngine;
|
||||||
import javax.net.ssl.SSLException;
|
import javax.net.ssl.SSLException;
|
||||||
import javax.net.ssl.TrustManager;
|
import javax.net.ssl.TrustManager;
|
||||||
|
import javax.net.ssl.X509ExtendedTrustManager;
|
||||||
import javax.net.ssl.X509TrustManager;
|
import javax.net.ssl.X509TrustManager;
|
||||||
import java.security.cert.X509Certificate;
|
import java.security.cert.X509Certificate;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
|
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
|
||||||
|
|
||||||
import static io.netty.util.internal.ObjectUtil.checkNotNull;
|
import static io.netty.util.internal.ObjectUtil.checkNotNull;
|
||||||
@ -226,13 +229,20 @@ public abstract class OpenSslContext extends SslContext {
|
|||||||
@Override
|
@Override
|
||||||
public final SSLEngine newEngine(ByteBufAllocator alloc) {
|
public final SSLEngine newEngine(ByteBufAllocator alloc) {
|
||||||
List<String> protos = applicationProtocolNegotiator().protocols();
|
List<String> protos = applicationProtocolNegotiator().protocols();
|
||||||
|
OpenSslEngineMap engineMap = engineMap();
|
||||||
|
final OpenSslEngine engine;
|
||||||
if (protos.isEmpty()) {
|
if (protos.isEmpty()) {
|
||||||
return new OpenSslEngine(ctx, alloc, null, isClient(), sessionContext());
|
engine = new OpenSslEngine(ctx, alloc, null, isClient(), sessionContext(), engineMap);
|
||||||
} else {
|
} else {
|
||||||
return new OpenSslEngine(ctx, alloc, protos.get(protos.size() - 1), isClient(), sessionContext());
|
engine = new OpenSslEngine(ctx, alloc, protos.get(protos.size() - 1), isClient(),
|
||||||
|
sessionContext(), engineMap);
|
||||||
}
|
}
|
||||||
|
engineMap.add(engine);
|
||||||
|
return engine;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
abstract OpenSslEngineMap engineMap();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the {@code SSL_CTX} object of this context.
|
* Returns the {@code SSL_CTX} object of this context.
|
||||||
*/
|
*/
|
||||||
@ -333,4 +343,44 @@ public abstract class OpenSslContext extends SslContext {
|
|||||||
.append(config.protocol()).append(" protocol").toString());
|
.append(config.protocol()).append(" protocol").toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static OpenSslEngineMap newEngineMap(X509TrustManager trustManager) {
|
||||||
|
if (useExtendedTrustManager(trustManager)) {
|
||||||
|
return new DefaultOpenSslEngineMap();
|
||||||
|
}
|
||||||
|
return OpenSslEngineMap.EMPTY;
|
||||||
|
}
|
||||||
|
|
||||||
|
static boolean useExtendedTrustManager(X509TrustManager trustManager) {
|
||||||
|
return PlatformDependent.javaVersion() >= 7 && trustManager instanceof X509ExtendedTrustManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract static class AbstractCertificateVerifier implements CertificateVerifier {
|
||||||
|
@Override
|
||||||
|
public final boolean verify(long ssl, byte[][] chain, String auth) {
|
||||||
|
X509Certificate[] peerCerts = certificates(chain);
|
||||||
|
try {
|
||||||
|
verify(ssl, peerCerts, auth);
|
||||||
|
return true;
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.debug("verification of certificate failed", e);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract void verify(long ssl, X509Certificate[] peerCerts, String auth) throws Exception;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class DefaultOpenSslEngineMap implements OpenSslEngineMap {
|
||||||
|
private final Map<Long, OpenSslEngine> engines = PlatformDependent.newConcurrentHashMap();
|
||||||
|
@Override
|
||||||
|
public OpenSslEngine remove(long ssl) {
|
||||||
|
return engines.remove(ssl);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void add(OpenSslEngine engine) {
|
||||||
|
engines.put(engine.ssl(), engine);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,7 @@ import io.netty.buffer.ByteBuf;
|
|||||||
import io.netty.buffer.ByteBufAllocator;
|
import io.netty.buffer.ByteBufAllocator;
|
||||||
import io.netty.buffer.Unpooled;
|
import io.netty.buffer.Unpooled;
|
||||||
import io.netty.util.internal.EmptyArrays;
|
import io.netty.util.internal.EmptyArrays;
|
||||||
|
import io.netty.util.internal.ObjectUtil;
|
||||||
import io.netty.util.internal.PlatformDependent;
|
import io.netty.util.internal.PlatformDependent;
|
||||||
import io.netty.util.internal.logging.InternalLogger;
|
import io.netty.util.internal.logging.InternalLogger;
|
||||||
import io.netty.util.internal.logging.InternalLoggerFactory;
|
import io.netty.util.internal.logging.InternalLoggerFactory;
|
||||||
@ -47,7 +48,6 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
|
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
|
||||||
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
|
|
||||||
|
|
||||||
import static javax.net.ssl.SSLEngineResult.HandshakeStatus.*;
|
import static javax.net.ssl.SSLEngineResult.HandshakeStatus.*;
|
||||||
import static javax.net.ssl.SSLEngineResult.Status.*;
|
import static javax.net.ssl.SSLEngineResult.Status.*;
|
||||||
@ -75,12 +75,6 @@ public final class OpenSslEngine extends SSLEngine {
|
|||||||
destroyedUpdater = AtomicIntegerFieldUpdater.newUpdater(OpenSslEngine.class, "destroyed");
|
destroyedUpdater = AtomicIntegerFieldUpdater.newUpdater(OpenSslEngine.class, "destroyed");
|
||||||
}
|
}
|
||||||
DESTROYED_UPDATER = destroyedUpdater;
|
DESTROYED_UPDATER = destroyedUpdater;
|
||||||
AtomicReferenceFieldUpdater<OpenSslEngine, SSLSession> sessionUpdater =
|
|
||||||
PlatformDependent.newAtomicReferenceFieldUpdater(OpenSslEngine.class, "session");
|
|
||||||
if (sessionUpdater == null) {
|
|
||||||
sessionUpdater = AtomicReferenceFieldUpdater.newUpdater(OpenSslEngine.class, SSLSession.class, "session");
|
|
||||||
}
|
|
||||||
SESSION_UPDATER = sessionUpdater;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final int MAX_PLAINTEXT_LENGTH = 16 * 1024; // 2^14
|
private static final int MAX_PLAINTEXT_LENGTH = 16 * 1024; // 2^14
|
||||||
@ -117,7 +111,6 @@ public final class OpenSslEngine extends SSLEngine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static final AtomicIntegerFieldUpdater<OpenSslEngine> DESTROYED_UPDATER;
|
private static final AtomicIntegerFieldUpdater<OpenSslEngine> DESTROYED_UPDATER;
|
||||||
private static final AtomicReferenceFieldUpdater<OpenSslEngine, SSLSession> SESSION_UPDATER;
|
|
||||||
|
|
||||||
private static final String INVALID_CIPHER = "SSL_NULL_WITH_NULL_NULL";
|
private static final String INVALID_CIPHER = "SSL_NULL_WITH_NULL_NULL";
|
||||||
|
|
||||||
@ -154,9 +147,9 @@ public final class OpenSslEngine extends SSLEngine {
|
|||||||
private final ByteBufAllocator alloc;
|
private final ByteBufAllocator alloc;
|
||||||
private final String fallbackApplicationProtocol;
|
private final String fallbackApplicationProtocol;
|
||||||
private final OpenSslSessionContext sessionContext;
|
private final OpenSslSessionContext sessionContext;
|
||||||
|
private final OpenSslEngineMap engineMap;
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
private final SSLSession session = new OpenSslSession();
|
||||||
private volatile SSLSession session;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new instance
|
* Creates a new instance
|
||||||
@ -166,7 +159,7 @@ public final class OpenSslEngine extends SSLEngine {
|
|||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public OpenSslEngine(long sslCtx, ByteBufAllocator alloc, String fallbackApplicationProtocol) {
|
public OpenSslEngine(long sslCtx, ByteBufAllocator alloc, String fallbackApplicationProtocol) {
|
||||||
this(sslCtx, alloc, fallbackApplicationProtocol, false, null);
|
this(sslCtx, alloc, fallbackApplicationProtocol, false, null, OpenSslEngineMap.EMPTY);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -178,21 +171,33 @@ public final class OpenSslEngine extends SSLEngine {
|
|||||||
* @param sessionContext the {@link OpenSslSessionContext} this {@link SSLEngine} belongs to.
|
* @param sessionContext the {@link OpenSslSessionContext} this {@link SSLEngine} belongs to.
|
||||||
*/
|
*/
|
||||||
OpenSslEngine(long sslCtx, ByteBufAllocator alloc, String fallbackApplicationProtocol,
|
OpenSslEngine(long sslCtx, ByteBufAllocator alloc, String fallbackApplicationProtocol,
|
||||||
boolean clientMode, OpenSslSessionContext sessionContext) {
|
boolean clientMode, OpenSslSessionContext sessionContext, OpenSslEngineMap engineMap) {
|
||||||
OpenSsl.ensureAvailability();
|
OpenSsl.ensureAvailability();
|
||||||
if (sslCtx == 0) {
|
if (sslCtx == 0) {
|
||||||
throw new NullPointerException("sslContext");
|
throw new NullPointerException("sslCtx");
|
||||||
}
|
|
||||||
if (alloc == null) {
|
|
||||||
throw new NullPointerException("alloc");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.alloc = alloc;
|
this.alloc = ObjectUtil.checkNotNull(alloc, "alloc");
|
||||||
ssl = SSL.newSSL(sslCtx, !clientMode);
|
ssl = SSL.newSSL(sslCtx, !clientMode);
|
||||||
networkBIO = SSL.makeNetworkBIO(ssl);
|
networkBIO = SSL.makeNetworkBIO(ssl);
|
||||||
this.fallbackApplicationProtocol = fallbackApplicationProtocol;
|
this.fallbackApplicationProtocol = fallbackApplicationProtocol;
|
||||||
this.clientMode = clientMode;
|
this.clientMode = clientMode;
|
||||||
this.sessionContext = sessionContext;
|
this.sessionContext = sessionContext;
|
||||||
|
this.engineMap = engineMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SSLSession getHandshakeSession() {
|
||||||
|
if (accepted > 0) {
|
||||||
|
// handshake started we are able to return the session.
|
||||||
|
return session;
|
||||||
|
}
|
||||||
|
// As stated by the javadocs of getHandshakeSession() we should return null if the handshake not started yet.
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
long ssl() {
|
||||||
|
return ssl;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -200,6 +205,7 @@ public final class OpenSslEngine extends SSLEngine {
|
|||||||
*/
|
*/
|
||||||
public synchronized void shutdown() {
|
public synchronized void shutdown() {
|
||||||
if (DESTROYED_UPDATER.compareAndSet(this, 0, 1)) {
|
if (DESTROYED_UPDATER.compareAndSet(this, 0, 1)) {
|
||||||
|
engineMap.remove(ssl);
|
||||||
SSL.freeSSL(ssl);
|
SSL.freeSSL(ssl);
|
||||||
SSL.freeBIO(networkBIO);
|
SSL.freeBIO(networkBIO);
|
||||||
ssl = networkBIO = 0;
|
ssl = networkBIO = 0;
|
||||||
@ -733,9 +739,7 @@ public final class OpenSslEngine extends SSLEngine {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setEnabledCipherSuites(String[] cipherSuites) {
|
public void setEnabledCipherSuites(String[] cipherSuites) {
|
||||||
if (cipherSuites == null) {
|
ObjectUtil.checkNotNull(cipherSuites, "cipherSuites");
|
||||||
throw new NullPointerException("cipherSuites");
|
|
||||||
}
|
|
||||||
|
|
||||||
final StringBuilder buf = new StringBuilder();
|
final StringBuilder buf = new StringBuilder();
|
||||||
for (String c: cipherSuites) {
|
for (String c: cipherSuites) {
|
||||||
@ -850,283 +854,8 @@ public final class OpenSslEngine extends SSLEngine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Certificate[] initPeerCertChain() throws SSLPeerUnverifiedException {
|
|
||||||
byte[][] chain = SSL.getPeerCertChain(ssl);
|
|
||||||
byte[] clientCert;
|
|
||||||
if (!clientMode) {
|
|
||||||
// if used on the server side SSL_get_peer_cert_chain(...) will not include the remote peer certificate.
|
|
||||||
// We use SSL_get_peer_certificate to get it in this case and add it to our array later.
|
|
||||||
//
|
|
||||||
// See https://www.openssl.org/docs/ssl/SSL_get_peer_cert_chain.html
|
|
||||||
clientCert = SSL.getPeerCertificate(ssl);
|
|
||||||
} else {
|
|
||||||
clientCert = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (chain == null && clientCert == null) {
|
|
||||||
throw new SSLPeerUnverifiedException("peer not verified");
|
|
||||||
}
|
|
||||||
int len = 0;
|
|
||||||
if (chain != null) {
|
|
||||||
len += chain.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
Certificate[] peerCerts;
|
|
||||||
if (clientCert != null) {
|
|
||||||
len++;
|
|
||||||
peerCerts = new Certificate[len];
|
|
||||||
peerCerts[i++] = new OpenSslX509Certificate(clientCert);
|
|
||||||
} else {
|
|
||||||
peerCerts = new Certificate[len];
|
|
||||||
}
|
|
||||||
if (chain != null) {
|
|
||||||
int a = 0;
|
|
||||||
for (; i < peerCerts.length; i++) {
|
|
||||||
peerCerts[i] = new OpenSslX509Certificate(chain[a++]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return peerCerts;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SSLSession getSession() {
|
public SSLSession getSession() {
|
||||||
// A other methods on SSLEngine are thread-safe we also need to make this thread-safe...
|
|
||||||
SSLSession session = this.session;
|
|
||||||
if (session == null) {
|
|
||||||
session = new SSLSession() {
|
|
||||||
// SSLSession implementation seems to not need to be thread-safe so no need for volatile etc.
|
|
||||||
private X509Certificate[] x509PeerCerts;
|
|
||||||
|
|
||||||
// lazy init for memory reasons
|
|
||||||
private Map<String, Object> values;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public byte[] getId() {
|
|
||||||
// We don't cache that to keep memory usage to a minimum.
|
|
||||||
byte[] id = SSL.getSessionId(ssl);
|
|
||||||
if (id == null) {
|
|
||||||
// The id should never be null, if it was null then the SESSION itself was not valid.
|
|
||||||
throw new IllegalStateException("SSL session ID not available");
|
|
||||||
}
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public SSLSessionContext getSessionContext() {
|
|
||||||
return sessionContext;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long getCreationTime() {
|
|
||||||
// We need ot multiple by 1000 as openssl uses seconds and we need milli-seconds.
|
|
||||||
return SSL.getTime(ssl) * 1000L;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long getLastAccessedTime() {
|
|
||||||
// TODO: Add proper implementation
|
|
||||||
return getCreationTime();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void invalidate() {
|
|
||||||
// NOOP
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isValid() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void putValue(String name, Object value) {
|
|
||||||
if (name == null) {
|
|
||||||
throw new NullPointerException("name");
|
|
||||||
}
|
|
||||||
if (value == null) {
|
|
||||||
throw new NullPointerException("value");
|
|
||||||
}
|
|
||||||
Map<String, Object> values = this.values;
|
|
||||||
if (values == null) {
|
|
||||||
// Use size of 2 to keep the memory overhead small
|
|
||||||
values = this.values = new HashMap<String, Object>(2);
|
|
||||||
}
|
|
||||||
Object old = values.put(name, value);
|
|
||||||
if (value instanceof SSLSessionBindingListener) {
|
|
||||||
((SSLSessionBindingListener) value).valueBound(new SSLSessionBindingEvent(this, name));
|
|
||||||
}
|
|
||||||
notifyUnbound(old, name);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object getValue(String name) {
|
|
||||||
if (name == null) {
|
|
||||||
throw new NullPointerException("name");
|
|
||||||
}
|
|
||||||
if (values == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return values.get(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void removeValue(String name) {
|
|
||||||
if (name == null) {
|
|
||||||
throw new NullPointerException("name");
|
|
||||||
}
|
|
||||||
Map<String, Object> values = this.values;
|
|
||||||
if (values == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Object old = values.remove(name);
|
|
||||||
notifyUnbound(old, name);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String[] getValueNames() {
|
|
||||||
Map<String, Object> values = this.values;
|
|
||||||
if (values == null || values.isEmpty()) {
|
|
||||||
return EmptyArrays.EMPTY_STRINGS;
|
|
||||||
}
|
|
||||||
return values.keySet().toArray(new String[values.size()]);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void notifyUnbound(Object value, String name) {
|
|
||||||
if (value instanceof SSLSessionBindingListener) {
|
|
||||||
((SSLSessionBindingListener) value).valueUnbound(new SSLSessionBindingEvent(this, name));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Certificate[] getPeerCertificates() throws SSLPeerUnverifiedException {
|
|
||||||
// these are lazy created to reduce memory overhead
|
|
||||||
Certificate[] c = peerCerts;
|
|
||||||
if (c == null) {
|
|
||||||
if (SSL.isInInit(ssl) != 0) {
|
|
||||||
throw new SSLPeerUnverifiedException("peer not verified");
|
|
||||||
}
|
|
||||||
c = peerCerts = initPeerCertChain();
|
|
||||||
}
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Certificate[] getLocalCertificates() {
|
|
||||||
// TODO: Find out how to get these
|
|
||||||
return EMPTY_CERTIFICATES;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public X509Certificate[] getPeerCertificateChain() throws SSLPeerUnverifiedException {
|
|
||||||
// these are lazy created to reduce memory overhead
|
|
||||||
X509Certificate[] c = x509PeerCerts;
|
|
||||||
if (c == null) {
|
|
||||||
if (SSL.isInInit(ssl) != 0) {
|
|
||||||
throw new SSLPeerUnverifiedException("peer not verified");
|
|
||||||
}
|
|
||||||
byte[][] chain = SSL.getPeerCertChain(ssl);
|
|
||||||
if (chain == null) {
|
|
||||||
throw new SSLPeerUnverifiedException("peer not verified");
|
|
||||||
}
|
|
||||||
X509Certificate[] peerCerts = new X509Certificate[chain.length];
|
|
||||||
for (int i = 0; i < peerCerts.length; i++) {
|
|
||||||
try {
|
|
||||||
peerCerts[i] = X509Certificate.getInstance(chain[i]);
|
|
||||||
} catch (CertificateException e) {
|
|
||||||
throw new IllegalStateException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
c = x509PeerCerts = peerCerts;
|
|
||||||
}
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Principal getPeerPrincipal() throws SSLPeerUnverifiedException {
|
|
||||||
Certificate[] peer = getPeerCertificates();
|
|
||||||
if (peer == null || peer.length == 0) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return principal(peer);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Principal getLocalPrincipal() {
|
|
||||||
Certificate[] local = getLocalCertificates();
|
|
||||||
if (local == null || local.length == 0) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return principal(local);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Principal principal(Certificate[] certs) {
|
|
||||||
return ((java.security.cert.X509Certificate) certs[0]).getIssuerX500Principal();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getCipherSuite() {
|
|
||||||
if (!handshakeFinished) {
|
|
||||||
return INVALID_CIPHER;
|
|
||||||
}
|
|
||||||
if (cipher == null) {
|
|
||||||
String c = toJavaCipherSuite(SSL.getCipherForSSL(ssl));
|
|
||||||
if (c != null) {
|
|
||||||
cipher = c;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return cipher;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getProtocol() {
|
|
||||||
String applicationProtocol = OpenSslEngine.this.applicationProtocol;
|
|
||||||
if (applicationProtocol == null) {
|
|
||||||
applicationProtocol = SSL.getNextProtoNegotiated(ssl);
|
|
||||||
if (applicationProtocol == null) {
|
|
||||||
applicationProtocol = fallbackApplicationProtocol;
|
|
||||||
}
|
|
||||||
if (applicationProtocol != null) {
|
|
||||||
OpenSslEngine.this.applicationProtocol = applicationProtocol.replace(':', '_');
|
|
||||||
} else {
|
|
||||||
OpenSslEngine.this.applicationProtocol = applicationProtocol = "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
String version = SSL.getVersion(ssl);
|
|
||||||
if (applicationProtocol.isEmpty()) {
|
|
||||||
return version;
|
|
||||||
} else {
|
|
||||||
return version + ':' + applicationProtocol;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getPeerHost() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getPeerPort() {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getPacketBufferSize() {
|
|
||||||
return MAX_ENCRYPTED_PACKET_LENGTH;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getApplicationBufferSize() {
|
|
||||||
return MAX_PLAINTEXT_LENGTH;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!SESSION_UPDATER.compareAndSet(this, null, session)) {
|
|
||||||
// Was lazy created in the meantime so get the current reference.
|
|
||||||
session = this.session;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return session;
|
return session;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1349,4 +1078,265 @@ public final class OpenSslEngine extends SSLEngine {
|
|||||||
// Call shutdown as the user may have created the OpenSslEngine and not used it at all.
|
// Call shutdown as the user may have created the OpenSslEngine and not used it at all.
|
||||||
shutdown();
|
shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private final class OpenSslSession implements SSLSession {
|
||||||
|
// SSLSession implementation seems to not need to be thread-safe so no need for volatile etc.
|
||||||
|
private X509Certificate[] x509PeerCerts;
|
||||||
|
|
||||||
|
// lazy init for memory reasons
|
||||||
|
private Map<String, Object> values;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] getId() {
|
||||||
|
// We don't cache that to keep memory usage to a minimum.
|
||||||
|
byte[] id = SSL.getSessionId(ssl);
|
||||||
|
if (id == null) {
|
||||||
|
// The id should never be null, if it was null then the SESSION itself was not valid.
|
||||||
|
throw new IllegalStateException("SSL session ID not available");
|
||||||
|
}
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SSLSessionContext getSessionContext() {
|
||||||
|
return sessionContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getCreationTime() {
|
||||||
|
// We need ot multiple by 1000 as openssl uses seconds and we need milli-seconds.
|
||||||
|
return SSL.getTime(ssl) * 1000L;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getLastAccessedTime() {
|
||||||
|
// TODO: Add proper implementation
|
||||||
|
return getCreationTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void invalidate() {
|
||||||
|
// NOOP
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isValid() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void putValue(String name, Object value) {
|
||||||
|
ObjectUtil.checkNotNull(name, "name");
|
||||||
|
ObjectUtil.checkNotNull(value, "value");
|
||||||
|
|
||||||
|
Map<String, Object> values = this.values;
|
||||||
|
if (values == null) {
|
||||||
|
// Use size of 2 to keep the memory overhead small
|
||||||
|
values = this.values = new HashMap<String, Object>(2);
|
||||||
|
}
|
||||||
|
Object old = values.put(name, value);
|
||||||
|
if (value instanceof SSLSessionBindingListener) {
|
||||||
|
((SSLSessionBindingListener) value).valueBound(new SSLSessionBindingEvent(this, name));
|
||||||
|
}
|
||||||
|
notifyUnbound(old, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getValue(String name) {
|
||||||
|
ObjectUtil.checkNotNull(name, "name");
|
||||||
|
|
||||||
|
if (values == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return values.get(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeValue(String name) {
|
||||||
|
ObjectUtil.checkNotNull(name, "name");
|
||||||
|
|
||||||
|
Map<String, Object> values = this.values;
|
||||||
|
if (values == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Object old = values.remove(name);
|
||||||
|
notifyUnbound(old, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String[] getValueNames() {
|
||||||
|
Map<String, Object> values = this.values;
|
||||||
|
if (values == null || values.isEmpty()) {
|
||||||
|
return EmptyArrays.EMPTY_STRINGS;
|
||||||
|
}
|
||||||
|
return values.keySet().toArray(new String[values.size()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void notifyUnbound(Object value, String name) {
|
||||||
|
if (value instanceof SSLSessionBindingListener) {
|
||||||
|
((SSLSessionBindingListener) value).valueUnbound(new SSLSessionBindingEvent(this, name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Certificate[] getPeerCertificates() throws SSLPeerUnverifiedException {
|
||||||
|
// these are lazy created to reduce memory overhead
|
||||||
|
Certificate[] c = peerCerts;
|
||||||
|
if (c == null) {
|
||||||
|
if (SSL.isInInit(ssl) != 0) {
|
||||||
|
throw new SSLPeerUnverifiedException("peer not verified");
|
||||||
|
}
|
||||||
|
c = peerCerts = initPeerCertChain();
|
||||||
|
}
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Certificate[] initPeerCertChain() throws SSLPeerUnverifiedException {
|
||||||
|
byte[][] chain = SSL.getPeerCertChain(ssl);
|
||||||
|
byte[] clientCert;
|
||||||
|
if (!clientMode) {
|
||||||
|
// if used on the server side SSL_get_peer_cert_chain(...) will not include the remote peer certificate.
|
||||||
|
// We use SSL_get_peer_certificate to get it in this case and add it to our array later.
|
||||||
|
//
|
||||||
|
// See https://www.openssl.org/docs/ssl/SSL_get_peer_cert_chain.html
|
||||||
|
clientCert = SSL.getPeerCertificate(ssl);
|
||||||
|
} else {
|
||||||
|
clientCert = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chain == null && clientCert == null) {
|
||||||
|
throw new SSLPeerUnverifiedException("peer not verified");
|
||||||
|
}
|
||||||
|
int len = 0;
|
||||||
|
if (chain != null) {
|
||||||
|
len += chain.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
Certificate[] peerCerts;
|
||||||
|
if (clientCert != null) {
|
||||||
|
len++;
|
||||||
|
peerCerts = new Certificate[len];
|
||||||
|
peerCerts[i++] = new OpenSslX509Certificate(clientCert);
|
||||||
|
} else {
|
||||||
|
peerCerts = new Certificate[len];
|
||||||
|
}
|
||||||
|
if (chain != null) {
|
||||||
|
int a = 0;
|
||||||
|
for (; i < peerCerts.length; i++) {
|
||||||
|
peerCerts[i] = new OpenSslX509Certificate(chain[a++]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return peerCerts;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Certificate[] getLocalCertificates() {
|
||||||
|
// TODO: Find out how to get these
|
||||||
|
return EMPTY_CERTIFICATES;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public X509Certificate[] getPeerCertificateChain() throws SSLPeerUnverifiedException {
|
||||||
|
// these are lazy created to reduce memory overhead
|
||||||
|
X509Certificate[] c = x509PeerCerts;
|
||||||
|
if (c == null) {
|
||||||
|
if (SSL.isInInit(ssl) != 0) {
|
||||||
|
throw new SSLPeerUnverifiedException("peer not verified");
|
||||||
|
}
|
||||||
|
byte[][] chain = SSL.getPeerCertChain(ssl);
|
||||||
|
if (chain == null) {
|
||||||
|
throw new SSLPeerUnverifiedException("peer not verified");
|
||||||
|
}
|
||||||
|
X509Certificate[] peerCerts = new X509Certificate[chain.length];
|
||||||
|
for (int i = 0; i < peerCerts.length; i++) {
|
||||||
|
try {
|
||||||
|
peerCerts[i] = X509Certificate.getInstance(chain[i]);
|
||||||
|
} catch (CertificateException e) {
|
||||||
|
throw new IllegalStateException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c = x509PeerCerts = peerCerts;
|
||||||
|
}
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Principal getPeerPrincipal() throws SSLPeerUnverifiedException {
|
||||||
|
Certificate[] peer = getPeerCertificates();
|
||||||
|
if (peer == null || peer.length == 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return principal(peer);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Principal getLocalPrincipal() {
|
||||||
|
Certificate[] local = getLocalCertificates();
|
||||||
|
if (local == null || local.length == 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return principal(local);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Principal principal(Certificate[] certs) {
|
||||||
|
return ((java.security.cert.X509Certificate) certs[0]).getIssuerX500Principal();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getCipherSuite() {
|
||||||
|
if (!handshakeFinished) {
|
||||||
|
return INVALID_CIPHER;
|
||||||
|
}
|
||||||
|
if (cipher == null) {
|
||||||
|
String c = toJavaCipherSuite(SSL.getCipherForSSL(ssl));
|
||||||
|
if (c != null) {
|
||||||
|
cipher = c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cipher;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getProtocol() {
|
||||||
|
String applicationProtocol = OpenSslEngine.this.applicationProtocol;
|
||||||
|
if (applicationProtocol == null) {
|
||||||
|
applicationProtocol = SSL.getNextProtoNegotiated(ssl);
|
||||||
|
if (applicationProtocol == null) {
|
||||||
|
applicationProtocol = fallbackApplicationProtocol;
|
||||||
|
}
|
||||||
|
if (applicationProtocol != null) {
|
||||||
|
OpenSslEngine.this.applicationProtocol = applicationProtocol.replace(':', '_');
|
||||||
|
} else {
|
||||||
|
OpenSslEngine.this.applicationProtocol = applicationProtocol = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
String version = SSL.getVersion(ssl);
|
||||||
|
if (applicationProtocol.isEmpty()) {
|
||||||
|
return version;
|
||||||
|
} else {
|
||||||
|
return version + ':' + applicationProtocol;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPeerHost() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getPeerPort() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getPacketBufferSize() {
|
||||||
|
return MAX_ENCRYPTED_PACKET_LENGTH;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getApplicationBufferSize() {
|
||||||
|
return MAX_PLAINTEXT_LENGTH;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2014 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project 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 io.netty.handler.ssl;
|
||||||
|
|
||||||
|
interface OpenSslEngineMap {
|
||||||
|
|
||||||
|
OpenSslEngineMap EMPTY = new OpenSslEngineMap() {
|
||||||
|
@Override
|
||||||
|
public OpenSslEngine remove(long ssl) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void add(OpenSslEngine engine) {
|
||||||
|
// NOOP
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the {@link OpenSslEngine} with the given {@code ssl} address and
|
||||||
|
* return it.
|
||||||
|
*/
|
||||||
|
OpenSslEngine remove(long ssl);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a {@link OpenSslEngine} to this {@link OpenSslEngineMap}.
|
||||||
|
*/
|
||||||
|
void add(OpenSslEngine engine);
|
||||||
|
}
|
@ -17,14 +17,12 @@ package io.netty.handler.ssl;
|
|||||||
|
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import io.netty.buffer.ByteBufInputStream;
|
import io.netty.buffer.ByteBufInputStream;
|
||||||
import io.netty.util.internal.logging.InternalLogger;
|
|
||||||
import io.netty.util.internal.logging.InternalLoggerFactory;
|
|
||||||
import org.apache.tomcat.jni.CertificateVerifier;
|
|
||||||
import org.apache.tomcat.jni.SSL;
|
import org.apache.tomcat.jni.SSL;
|
||||||
import org.apache.tomcat.jni.SSLContext;
|
import org.apache.tomcat.jni.SSLContext;
|
||||||
|
|
||||||
import javax.net.ssl.SSLException;
|
import javax.net.ssl.SSLException;
|
||||||
import javax.net.ssl.TrustManagerFactory;
|
import javax.net.ssl.TrustManagerFactory;
|
||||||
|
import javax.net.ssl.X509ExtendedTrustManager;
|
||||||
import javax.net.ssl.X509TrustManager;
|
import javax.net.ssl.X509TrustManager;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.security.KeyFactory;
|
import java.security.KeyFactory;
|
||||||
@ -44,9 +42,8 @@ import static io.netty.util.internal.ObjectUtil.*;
|
|||||||
* A server-side {@link SslContext} which uses OpenSSL's SSL/TLS implementation.
|
* A server-side {@link SslContext} which uses OpenSSL's SSL/TLS implementation.
|
||||||
*/
|
*/
|
||||||
public final class OpenSslServerContext extends OpenSslContext {
|
public final class OpenSslServerContext extends OpenSslContext {
|
||||||
private static final InternalLogger logger = InternalLoggerFactory.getInstance(OpenSslServerContext.class);
|
|
||||||
|
|
||||||
private final OpenSslServerSessionContext sessionContext;
|
private final OpenSslServerSessionContext sessionContext;
|
||||||
|
private final OpenSslEngineMap engineMap;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new instance.
|
* Creates a new instance.
|
||||||
@ -258,19 +255,26 @@ public final class OpenSslServerContext extends OpenSslContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final X509TrustManager manager = chooseTrustManager(trustManagerFactory.getTrustManagers());
|
final X509TrustManager manager = chooseTrustManager(trustManagerFactory.getTrustManagers());
|
||||||
SSLContext.setCertVerifyCallback(ctx, new CertificateVerifier() {
|
|
||||||
|
engineMap = newEngineMap(manager);
|
||||||
|
// Use this to prevent an error when running on java < 7
|
||||||
|
if (useExtendedTrustManager(manager)) {
|
||||||
|
final X509ExtendedTrustManager extendedManager = (X509ExtendedTrustManager) manager;
|
||||||
|
SSLContext.setCertVerifyCallback(ctx, new AbstractCertificateVerifier() {
|
||||||
@Override
|
@Override
|
||||||
public boolean verify(long ssl, byte[][] chain, String auth) {
|
void verify(long ssl, X509Certificate[] peerCerts, String auth) throws Exception {
|
||||||
X509Certificate[] peerCerts = certificates(chain);
|
OpenSslEngine engine = engineMap.remove(ssl);
|
||||||
try {
|
extendedManager.checkClientTrusted(peerCerts, auth, engine);
|
||||||
manager.checkClientTrusted(peerCerts, auth);
|
|
||||||
return true;
|
|
||||||
} catch (Exception e) {
|
|
||||||
logger.debug("verification of certificate failed", e);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
SSLContext.setCertVerifyCallback(ctx, new AbstractCertificateVerifier() {
|
||||||
|
@Override
|
||||||
|
void verify(long ssl, X509Certificate[] peerCerts, String auth) throws Exception {
|
||||||
|
manager.checkClientTrusted(peerCerts, auth);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new SSLException("unable to setup trustmanager", e);
|
throw new SSLException("unable to setup trustmanager", e);
|
||||||
}
|
}
|
||||||
@ -288,4 +292,9 @@ public final class OpenSslServerContext extends OpenSslContext {
|
|||||||
public OpenSslServerSessionContext sessionContext() {
|
public OpenSslServerSessionContext sessionContext() {
|
||||||
return sessionContext;
|
return sessionContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
OpenSslEngineMap engineMap() {
|
||||||
|
return engineMap;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
3
pom.xml
3
pom.xml
@ -924,8 +924,9 @@
|
|||||||
<ignore>sun.security.x509.X509CertInfo</ignore>
|
<ignore>sun.security.x509.X509CertInfo</ignore>
|
||||||
<ignore>sun.security.x509.X509CertImpl</ignore>
|
<ignore>sun.security.x509.X509CertImpl</ignore>
|
||||||
|
|
||||||
<!-- SSLSession implelementation -->
|
<!-- SSLSession implementation -->
|
||||||
<ignore>javax.net.ssl.SSLEngine</ignore>
|
<ignore>javax.net.ssl.SSLEngine</ignore>
|
||||||
|
<ignore>javax.net.ssl.X509ExtendedTrustManager</ignore>
|
||||||
</ignores>
|
</ignores>
|
||||||
</configuration>
|
</configuration>
|
||||||
<executions>
|
<executions>
|
||||||
|
Loading…
Reference in New Issue
Block a user