ReferenceCountedOpenSslEngines SSLSession must provide local certific… (#8918)
Motivation: The SSLSession that is returned by SSLEngine.getHandshakeSession() must be able to provide the local certificates when the TrustManager is invoked on the server-side. Modifications: - Correctly return the local certificates - Add unit test Result: Be able to obtain local certificates from handshake SSLSession during verification on the server side.
This commit is contained in:
parent
10f06a04e6
commit
7e76d02fe7
@ -2002,7 +2002,6 @@ public class ReferenceCountedOpenSslEngine extends SSLEngine implements Referenc
|
|||||||
// thread.
|
// thread.
|
||||||
private X509Certificate[] x509PeerCerts;
|
private X509Certificate[] x509PeerCerts;
|
||||||
private Certificate[] peerCerts;
|
private Certificate[] peerCerts;
|
||||||
private Certificate[] localCerts;
|
|
||||||
|
|
||||||
private String protocol;
|
private String protocol;
|
||||||
private String cipher;
|
private String cipher;
|
||||||
@ -2149,7 +2148,6 @@ public class ReferenceCountedOpenSslEngine extends SSLEngine implements Referenc
|
|||||||
id = SSL.getSessionId(ssl);
|
id = SSL.getSessionId(ssl);
|
||||||
cipher = toJavaCipherSuite(SSL.getCipherForSSL(ssl));
|
cipher = toJavaCipherSuite(SSL.getCipherForSSL(ssl));
|
||||||
protocol = SSL.getVersion(ssl);
|
protocol = SSL.getVersion(ssl);
|
||||||
localCerts = localCertificateChain;
|
|
||||||
|
|
||||||
initPeerCerts();
|
initPeerCerts();
|
||||||
selectApplicationProtocol();
|
selectApplicationProtocol();
|
||||||
@ -2284,6 +2282,7 @@ public class ReferenceCountedOpenSslEngine extends SSLEngine implements Referenc
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Certificate[] getLocalCertificates() {
|
public Certificate[] getLocalCertificates() {
|
||||||
|
Certificate[] localCerts = ReferenceCountedOpenSslEngine.this.localCertificateChain;
|
||||||
if (localCerts == null) {
|
if (localCerts == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -2310,7 +2309,7 @@ public class ReferenceCountedOpenSslEngine extends SSLEngine implements Referenc
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Principal getLocalPrincipal() {
|
public Principal getLocalPrincipal() {
|
||||||
Certificate[] local = localCerts;
|
Certificate[] local = ReferenceCountedOpenSslEngine.this.localCertificateChain;
|
||||||
if (local == null || local.length == 0) {
|
if (local == null || local.length == 0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -87,4 +87,11 @@ public class ConscryptJdkSslEngineInteropTest extends SSLEngineTest {
|
|||||||
// Ignore due bug in Conscrypt where the incorrect SSLSession object is used in the SSLSessionBindingEvent.
|
// Ignore due bug in Conscrypt where the incorrect SSLSession object is used in the SSLSessionBindingEvent.
|
||||||
// See https://github.com/google/conscrypt/issues/593
|
// See https://github.com/google/conscrypt/issues/593
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Ignore("Ignore due bug in Conscrypt")
|
||||||
|
@Override
|
||||||
|
public void testHandshakeSession() throws Exception {
|
||||||
|
// Ignore as Conscrypt does not correctly return the local certificates while the TrustManager is invoked.
|
||||||
|
// See https://github.com/google/conscrypt/issues/634
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -85,4 +85,11 @@ public class ConscryptSslEngineTest extends SSLEngineTest {
|
|||||||
// Ignore due bug in Conscrypt where the incorrect SSLSession object is used in the SSLSessionBindingEvent.
|
// Ignore due bug in Conscrypt where the incorrect SSLSession object is used in the SSLSessionBindingEvent.
|
||||||
// See https://github.com/google/conscrypt/issues/593
|
// See https://github.com/google/conscrypt/issues/593
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Ignore("Ignore due bug in Conscrypt")
|
||||||
|
@Override
|
||||||
|
public void testHandshakeSession() throws Exception {
|
||||||
|
// Ignore as Conscrypt does not correctly return the local certificates while the TrustManager is invoked.
|
||||||
|
// See https://github.com/google/conscrypt/issues/634
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -85,4 +85,11 @@ public class JdkConscryptSslEngineInteropTest extends SSLEngineTest {
|
|||||||
// TODO(scott): work around for a JDK issue. The exception should be SSLHandshakeException.
|
// TODO(scott): work around for a JDK issue. The exception should be SSLHandshakeException.
|
||||||
return super.mySetupMutualAuthServerIsValidClientException(cause) || causedBySSLException(cause);
|
return super.mySetupMutualAuthServerIsValidClientException(cause) || causedBySSLException(cause);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Ignore("Ignore due bug in Conscrypt")
|
||||||
|
@Override
|
||||||
|
public void testHandshakeSession() throws Exception {
|
||||||
|
// Ignore as Conscrypt does not correctly return the local certificates while the TrustManager is invoked.
|
||||||
|
// See https://github.com/google/conscrypt/issues/634
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -128,6 +128,12 @@ public class JdkOpenSslEngineInteroptTest extends SSLEngineTest {
|
|||||||
return super.mySetupMutualAuthServerIsValidClientException(cause) || causedBySSLException(cause);
|
return super.mySetupMutualAuthServerIsValidClientException(cause) || causedBySSLException(cause);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void testHandshakeSession() throws Exception {
|
||||||
|
checkShouldUseKeyManagerFactory();
|
||||||
|
super.testHandshakeSession();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected SSLEngine wrapEngine(SSLEngine engine) {
|
protected SSLEngine wrapEngine(SSLEngine engine) {
|
||||||
return Java8SslTestUtils.wrapSSLEngineForTesting(engine);
|
return Java8SslTestUtils.wrapSSLEngineForTesting(engine);
|
||||||
|
@ -161,6 +161,12 @@ public class OpenSslEngineTest extends SSLEngineTest {
|
|||||||
super.testClientHostnameValidationFail();
|
super.testClientHostnameValidationFail();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void testHandshakeSession() throws Exception {
|
||||||
|
checkShouldUseKeyManagerFactory();
|
||||||
|
super.testHandshakeSession();
|
||||||
|
}
|
||||||
|
|
||||||
private static boolean isNpnSupported(String versionString) {
|
private static boolean isNpnSupported(String versionString) {
|
||||||
String[] versionStringParts = versionString.split(" ", -1);
|
String[] versionStringParts = versionString.split(" ", -1);
|
||||||
if (versionStringParts.length == 2 && "LibreSSL".equals(versionStringParts[0])) {
|
if (versionStringParts.length == 2 && "LibreSSL".equals(versionStringParts[0])) {
|
||||||
|
@ -127,6 +127,12 @@ public class OpenSslJdkSslEngineInteroptTest extends SSLEngineTest {
|
|||||||
return super.mySetupMutualAuthServerIsValidServerException(cause) || causedBySSLException(cause);
|
return super.mySetupMutualAuthServerIsValidServerException(cause) || causedBySSLException(cause);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void testHandshakeSession() throws Exception {
|
||||||
|
checkShouldUseKeyManagerFactory();
|
||||||
|
super.testHandshakeSession();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected SSLEngine wrapEngine(SSLEngine engine) {
|
protected SSLEngine wrapEngine(SSLEngine engine) {
|
||||||
return Java8SslTestUtils.wrapSSLEngineForTesting(engine);
|
return Java8SslTestUtils.wrapSSLEngineForTesting(engine);
|
||||||
|
@ -37,6 +37,7 @@ import io.netty.channel.socket.nio.NioSocketChannel;
|
|||||||
import io.netty.handler.ssl.ApplicationProtocolConfig.Protocol;
|
import io.netty.handler.ssl.ApplicationProtocolConfig.Protocol;
|
||||||
import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
|
import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
|
||||||
import io.netty.handler.ssl.util.SelfSignedCertificate;
|
import io.netty.handler.ssl.util.SelfSignedCertificate;
|
||||||
|
import io.netty.handler.ssl.util.SimpleTrustManagerFactory;
|
||||||
import io.netty.util.CharsetUtil;
|
import io.netty.util.CharsetUtil;
|
||||||
import io.netty.util.NetUtil;
|
import io.netty.util.NetUtil;
|
||||||
import io.netty.util.ReferenceCountUtil;
|
import io.netty.util.ReferenceCountUtil;
|
||||||
@ -71,18 +72,24 @@ import javax.net.ssl.SSLSocketFactory;
|
|||||||
import javax.net.ssl.TrustManager;
|
import javax.net.ssl.TrustManager;
|
||||||
import javax.net.ssl.TrustManagerFactory;
|
import javax.net.ssl.TrustManagerFactory;
|
||||||
import javax.net.ssl.TrustManagerFactorySpi;
|
import javax.net.ssl.TrustManagerFactorySpi;
|
||||||
|
import javax.net.ssl.X509ExtendedTrustManager;
|
||||||
import javax.net.ssl.X509TrustManager;
|
import javax.net.ssl.X509TrustManager;
|
||||||
import javax.security.cert.X509Certificate;
|
import javax.security.cert.X509Certificate;
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
|
import java.net.Socket;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.channels.ClosedChannelException;
|
import java.nio.channels.ClosedChannelException;
|
||||||
import java.security.KeyStore;
|
import java.security.KeyStore;
|
||||||
|
import java.security.KeyStoreException;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.security.Principal;
|
import java.security.Principal;
|
||||||
import java.security.Provider;
|
import java.security.Provider;
|
||||||
|
import java.security.UnrecoverableKeyException;
|
||||||
import java.security.cert.Certificate;
|
import java.security.cert.Certificate;
|
||||||
import java.security.cert.CertificateException;
|
import java.security.cert.CertificateException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -107,6 +114,7 @@ import static io.netty.handler.ssl.SslUtils.PROTOCOL_TLS_V1_1;
|
|||||||
import static io.netty.handler.ssl.SslUtils.PROTOCOL_TLS_V1_2;
|
import static io.netty.handler.ssl.SslUtils.PROTOCOL_TLS_V1_2;
|
||||||
import static io.netty.handler.ssl.SslUtils.PROTOCOL_TLS_V1_3;
|
import static io.netty.handler.ssl.SslUtils.PROTOCOL_TLS_V1_3;
|
||||||
import static io.netty.handler.ssl.SslUtils.SSL_RECORD_HEADER_LENGTH;
|
import static io.netty.handler.ssl.SslUtils.SSL_RECORD_HEADER_LENGTH;
|
||||||
|
|
||||||
import static org.junit.Assert.assertArrayEquals;
|
import static org.junit.Assert.assertArrayEquals;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
@ -3060,6 +3068,149 @@ public abstract class SSLEngineTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testHandshakeSession() throws Exception {
|
||||||
|
final SelfSignedCertificate ssc = new SelfSignedCertificate();
|
||||||
|
|
||||||
|
final TestTrustManagerFactory clientTmf = new TestTrustManagerFactory(ssc.cert());
|
||||||
|
final TestTrustManagerFactory serverTmf = new TestTrustManagerFactory(ssc.cert());
|
||||||
|
|
||||||
|
clientSslCtx = SslContextBuilder.forClient()
|
||||||
|
.trustManager(new SimpleTrustManagerFactory() {
|
||||||
|
@Override
|
||||||
|
protected void engineInit(KeyStore keyStore) {
|
||||||
|
// NOOP
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void engineInit(ManagerFactoryParameters managerFactoryParameters) {
|
||||||
|
// NOOP
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected TrustManager[] engineGetTrustManagers() {
|
||||||
|
return new TrustManager[] { clientTmf };
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.keyManager(newKeyManagerFactory(ssc))
|
||||||
|
.sslProvider(sslClientProvider())
|
||||||
|
.sslContextProvider(clientSslContextProvider())
|
||||||
|
.protocols(protocols())
|
||||||
|
.ciphers(ciphers())
|
||||||
|
.build();
|
||||||
|
serverSslCtx = SslContextBuilder.forServer(newKeyManagerFactory(ssc))
|
||||||
|
.trustManager(new SimpleTrustManagerFactory() {
|
||||||
|
@Override
|
||||||
|
protected void engineInit(KeyStore keyStore) {
|
||||||
|
// NOOP
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void engineInit(ManagerFactoryParameters managerFactoryParameters) {
|
||||||
|
// NOOP
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected TrustManager[] engineGetTrustManagers() {
|
||||||
|
return new TrustManager[] { serverTmf };
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.sslProvider(sslServerProvider())
|
||||||
|
.sslContextProvider(serverSslContextProvider())
|
||||||
|
.protocols(protocols())
|
||||||
|
.ciphers(ciphers())
|
||||||
|
.clientAuth(ClientAuth.REQUIRE)
|
||||||
|
.build();
|
||||||
|
SSLEngine clientEngine = null;
|
||||||
|
SSLEngine serverEngine = null;
|
||||||
|
try {
|
||||||
|
clientEngine = wrapEngine(clientSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT));
|
||||||
|
serverEngine = wrapEngine(serverSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT));
|
||||||
|
handshake(clientEngine, serverEngine);
|
||||||
|
|
||||||
|
assertTrue(clientTmf.isVerified());
|
||||||
|
assertTrue(serverTmf.isVerified());
|
||||||
|
} finally {
|
||||||
|
cleanupClientSslEngine(clientEngine);
|
||||||
|
cleanupServerSslEngine(serverEngine);
|
||||||
|
ssc.delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private KeyManagerFactory newKeyManagerFactory(SelfSignedCertificate ssc)
|
||||||
|
throws UnrecoverableKeyException, KeyStoreException, NoSuchAlgorithmException,
|
||||||
|
CertificateException, IOException {
|
||||||
|
return SslContext.buildKeyManagerFactory(
|
||||||
|
new java.security.cert.X509Certificate[] { ssc.cert() }, ssc.key(), null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private final class TestTrustManagerFactory extends X509ExtendedTrustManager {
|
||||||
|
private final Certificate localCert;
|
||||||
|
private volatile boolean verified;
|
||||||
|
|
||||||
|
TestTrustManagerFactory(Certificate localCert) {
|
||||||
|
this.localCert = localCert;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isVerified() {
|
||||||
|
return verified;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void checkClientTrusted(
|
||||||
|
java.security.cert.X509Certificate[] x509Certificates, String s, Socket socket) {
|
||||||
|
fail();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void checkServerTrusted(
|
||||||
|
java.security.cert.X509Certificate[] x509Certificates, String s, Socket socket) {
|
||||||
|
fail();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void checkClientTrusted(
|
||||||
|
java.security.cert.X509Certificate[] x509Certificates, String s, SSLEngine sslEngine) {
|
||||||
|
verified = true;
|
||||||
|
assertFalse(sslEngine.getUseClientMode());
|
||||||
|
SSLSession session = sslEngine.getHandshakeSession();
|
||||||
|
assertNotNull(session);
|
||||||
|
Certificate[] localCertificates = session.getLocalCertificates();
|
||||||
|
assertNotNull(localCertificates);
|
||||||
|
assertEquals(1, localCertificates.length);
|
||||||
|
assertEquals(localCert, localCertificates[0]);
|
||||||
|
assertNotNull(session.getLocalPrincipal());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void checkServerTrusted(
|
||||||
|
java.security.cert.X509Certificate[] x509Certificates, String s, SSLEngine sslEngine) {
|
||||||
|
verified = true;
|
||||||
|
assertTrue(sslEngine.getUseClientMode());
|
||||||
|
SSLSession session = sslEngine.getHandshakeSession();
|
||||||
|
assertNotNull(session);
|
||||||
|
assertNull(session.getLocalCertificates());
|
||||||
|
assertNull(session.getLocalPrincipal());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void checkClientTrusted(
|
||||||
|
java.security.cert.X509Certificate[] x509Certificates, String s) {
|
||||||
|
fail();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void checkServerTrusted(
|
||||||
|
java.security.cert.X509Certificate[] x509Certificates, String s) {
|
||||||
|
fail();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
|
||||||
|
return EmptyArrays.EMPTY_X509_CERTIFICATES;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected SSLEngine wrapEngine(SSLEngine engine) {
|
protected SSLEngine wrapEngine(SSLEngine engine) {
|
||||||
return engine;
|
return engine;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user