From f5fab3898823cb9b4052595335579e8c4cf9f98a Mon Sep 17 00:00:00 2001 From: Bruno Harbulot Date: Sun, 13 Mar 2016 16:34:25 +0000 Subject: [PATCH] Using distinct aliases when building the trust manager factory, and renamed trustCertChain into trustCertCollection. Motivation: SSLContext.buildTrustManagerFactory(...) builds a KeyStore to initialize the TrustManagerFactory from an array of X509Certificates, assuming that array is a chain and that each certificate will have a unique Subject Distinguised Name. However, the collection of certificates used as trust anchors is generally not a chain (it is an unordered collection), and it is legitimate for it to contain multiple certificates with the same Subject DN. The existing code uses the Subject DN as the alias name when filling in the `KeyStore`, thereby overwriting other certificates with the same Subject DN in this collection, so some certificates may be discarded. In addition, the code related to building trust managers can take an array of X509Certificate instances to use as trust anchors. The variable name is usually trustCertChain, and the documentation refers to them as a "chain". However, while it makes sense to talk about a "chain" from a keymanager point of view, these certificates are just an unordered collection in a trust manager. (There is no chaining requirement, having the Subject DN matching its predecessor's Issuer DN.) This can create confusion to for users not used with PKI concepts. Modifications: SSLContext.buildTrustManagerFactory(...) now uses a distinct alias for each array (simply using a counter, since this name is never used for reference later). This patch also includes a unit test with CA certificates using the same Subject DN. Also renamed trustCertChain into trustCertCollection, and changed the references to "chain" in the Javadoc. Result: Each loaded certificate now has a unique identifier when loaded, so it is now possible to use multiple certificates with the same Subject DN as trust anchors. Hopefully, renaming the parameter should also reduce confusion around PKI concepts. --- .../handler/ssl/JdkSslClientContext.java | 34 ++-- .../handler/ssl/JdkSslServerContext.java | 37 +++-- .../handler/ssl/OpenSslClientContext.java | 15 +- .../handler/ssl/OpenSslServerContext.java | 32 ++-- .../java/io/netty/handler/ssl/SslContext.java | 38 +++-- .../netty/handler/ssl/SslContextBuilder.java | 27 ++-- .../ssl/SslContextTrustManagerTest.java | 147 ++++++++++++++++++ .../io/netty/handler/ssl/tm_test_ca_1a.pem | 19 +++ .../io/netty/handler/ssl/tm_test_ca_1b.pem | 19 +++ .../io/netty/handler/ssl/tm_test_ca_2.pem | 19 +++ .../io/netty/handler/ssl/tm_test_eec_1.pem | 19 +++ .../io/netty/handler/ssl/tm_test_eec_2.pem | 19 +++ .../io/netty/handler/ssl/tm_test_eec_3.pem | 19 +++ 13 files changed, 359 insertions(+), 85 deletions(-) create mode 100644 handler/src/test/java/io/netty/handler/ssl/SslContextTrustManagerTest.java create mode 100644 handler/src/test/resources/io/netty/handler/ssl/tm_test_ca_1a.pem create mode 100644 handler/src/test/resources/io/netty/handler/ssl/tm_test_ca_1b.pem create mode 100644 handler/src/test/resources/io/netty/handler/ssl/tm_test_ca_2.pem create mode 100644 handler/src/test/resources/io/netty/handler/ssl/tm_test_eec_1.pem create mode 100644 handler/src/test/resources/io/netty/handler/ssl/tm_test_eec_2.pem create mode 100644 handler/src/test/resources/io/netty/handler/ssl/tm_test_eec_3.pem diff --git a/handler/src/main/java/io/netty/handler/ssl/JdkSslClientContext.java b/handler/src/main/java/io/netty/handler/ssl/JdkSslClientContext.java index 8172ce0d02..ed9e9a0a89 100644 --- a/handler/src/main/java/io/netty/handler/ssl/JdkSslClientContext.java +++ b/handler/src/main/java/io/netty/handler/ssl/JdkSslClientContext.java @@ -171,11 +171,12 @@ public final class JdkSslClientContext extends JdkSslContext { /** * Creates a new instance. - * @param trustCertChainFile an X.509 certificate chain file in PEM format. + * @param trustCertCollectionFile an X.509 certificate collection file in PEM format. * {@code null} to use the system default * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s * that verifies the certificates sent from servers. - * {@code null} to use the default or the results of parsing {@code trustCertChainFile} + * {@code null} to use the default or the results of parsing + * {@code trustCertCollectionFile} * @param keyCertChainFile an X.509 certificate chain file in PEM format. * This provides the public key for mutual authentication. * {@code null} to use the system default @@ -200,21 +201,22 @@ public final class JdkSslClientContext extends JdkSslContext { * @deprecated use {@link SslContextBuilder} */ @Deprecated - public JdkSslClientContext(File trustCertChainFile, TrustManagerFactory trustManagerFactory, + public JdkSslClientContext(File trustCertCollectionFile, TrustManagerFactory trustManagerFactory, File keyCertChainFile, File keyFile, String keyPassword, KeyManagerFactory keyManagerFactory, Iterable ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn, long sessionCacheSize, long sessionTimeout) throws SSLException { - this(trustCertChainFile, trustManagerFactory, keyCertChainFile, keyFile, keyPassword, keyManagerFactory, + this(trustCertCollectionFile, trustManagerFactory, keyCertChainFile, keyFile, keyPassword, keyManagerFactory, ciphers, cipherFilter, toNegotiator(apn, false), sessionCacheSize, sessionTimeout); } /** * Creates a new instance. - * @param trustCertChainFile an X.509 certificate chain file in PEM format. + * @param trustCertCollectionFile an X.509 certificate collection file in PEM format. * {@code null} to use the system default * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s * that verifies the certificates sent from servers. - * {@code null} to use the default or the results of parsing {@code trustCertChainFile} + * {@code null} to use the default or the results of parsing + * {@code trustCertCollectionFile} * @param keyCertChainFile an X.509 certificate chain file in PEM format. * This provides the public key for mutual authentication. * {@code null} to use the system default @@ -239,13 +241,13 @@ public final class JdkSslClientContext extends JdkSslContext { * @deprecated use {@link SslContextBuilder} */ @Deprecated - public JdkSslClientContext(File trustCertChainFile, TrustManagerFactory trustManagerFactory, + public JdkSslClientContext(File trustCertCollectionFile, TrustManagerFactory trustManagerFactory, File keyCertChainFile, File keyFile, String keyPassword, KeyManagerFactory keyManagerFactory, Iterable ciphers, CipherSuiteFilter cipherFilter, JdkApplicationProtocolNegotiator apn, long sessionCacheSize, long sessionTimeout) throws SSLException { super(ciphers, cipherFilter, apn, ClientAuth.NONE); try { - ctx = newSSLContext(toX509Certificates(trustCertChainFile), trustManagerFactory, + ctx = newSSLContext(toX509Certificates(trustCertCollectionFile), trustManagerFactory, toX509Certificates(keyCertChainFile), toPrivateKey(keyFile, keyPassword), keyPassword, keyManagerFactory, sessionCacheSize, sessionTimeout); } catch (Exception e) { @@ -256,22 +258,22 @@ public final class JdkSslClientContext extends JdkSslContext { } } - JdkSslClientContext(X509Certificate[] trustCertChain, TrustManagerFactory trustManagerFactory, + JdkSslClientContext(X509Certificate[] trustCertCollection, TrustManagerFactory trustManagerFactory, X509Certificate[] keyCertChain, PrivateKey key, String keyPassword, KeyManagerFactory keyManagerFactory, Iterable ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn, long sessionCacheSize, long sessionTimeout) throws SSLException { super(ciphers, cipherFilter, toNegotiator(apn, false), ClientAuth.NONE); - ctx = newSSLContext(trustCertChain, trustManagerFactory, keyCertChain, key, keyPassword, + ctx = newSSLContext(trustCertCollection, trustManagerFactory, keyCertChain, key, keyPassword, keyManagerFactory, sessionCacheSize, sessionTimeout); } - private static SSLContext newSSLContext(X509Certificate[] trustCertChain, TrustManagerFactory trustManagerFactory, - X509Certificate[] keyCertChain, PrivateKey key, String keyPassword, - KeyManagerFactory keyManagerFactory, long sessionCacheSize, - long sessionTimeout) throws SSLException { + private static SSLContext newSSLContext(X509Certificate[] trustCertCollection, + TrustManagerFactory trustManagerFactory, X509Certificate[] keyCertChain, + PrivateKey key, String keyPassword, KeyManagerFactory keyManagerFactory, + long sessionCacheSize, long sessionTimeout) throws SSLException { try { - if (trustCertChain != null) { - trustManagerFactory = buildTrustManagerFactory(trustCertChain, trustManagerFactory); + if (trustCertCollection != null) { + trustManagerFactory = buildTrustManagerFactory(trustCertCollection, trustManagerFactory); } if (keyCertChain != null) { keyManagerFactory = buildKeyManagerFactory(keyCertChain, key, keyPassword, keyManagerFactory); diff --git a/handler/src/main/java/io/netty/handler/ssl/JdkSslServerContext.java b/handler/src/main/java/io/netty/handler/ssl/JdkSslServerContext.java index 849f1ecd36..c80665cb15 100644 --- a/handler/src/main/java/io/netty/handler/ssl/JdkSslServerContext.java +++ b/handler/src/main/java/io/netty/handler/ssl/JdkSslServerContext.java @@ -142,12 +142,13 @@ public final class JdkSslServerContext extends JdkSslContext { /** * Creates a new instance. - * @param trustCertChainFile an X.509 certificate chain file in PEM format. - * This provides the certificate chains used for mutual authentication. + * @param trustCertCollectionFile an X.509 certificate collection file in PEM format. + * This provides the certificate collection used for mutual authentication. * {@code null} to use the system default * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s * that verifies the certificates sent from clients. - * {@code null} to use the default or the results of parsing {@code trustCertChainFile}. + * {@code null} to use the default or the results of parsing + * {@code trustCertCollectionFile}. * @param keyCertChainFile an X.509 certificate chain file in PEM format * @param keyFile a PKCS#8 private key file in PEM format * @param keyPassword the password of the {@code keyFile}. @@ -168,22 +169,23 @@ public final class JdkSslServerContext extends JdkSslContext { * @deprecated use {@link SslContextBuilder} */ @Deprecated - public JdkSslServerContext(File trustCertChainFile, TrustManagerFactory trustManagerFactory, + public JdkSslServerContext(File trustCertCollectionFile, TrustManagerFactory trustManagerFactory, File keyCertChainFile, File keyFile, String keyPassword, KeyManagerFactory keyManagerFactory, Iterable ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn, long sessionCacheSize, long sessionTimeout) throws SSLException { - this(trustCertChainFile, trustManagerFactory, keyCertChainFile, keyFile, keyPassword, keyManagerFactory, + this(trustCertCollectionFile, trustManagerFactory, keyCertChainFile, keyFile, keyPassword, keyManagerFactory, ciphers, cipherFilter, toNegotiator(apn, true), sessionCacheSize, sessionTimeout); } /** * Creates a new instance. - * @param trustCertChainFile an X.509 certificate chain file in PEM format. - * This provides the certificate chains used for mutual authentication. + * @param trustCertCollectionFile an X.509 certificate collection file in PEM format. + * This provides the certificate collection used for mutual authentication. * {@code null} to use the system default * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s * that verifies the certificates sent from clients. - * {@code null} to use the default or the results of parsing {@code trustCertChainFile} + * {@code null} to use the default or the results of parsing + * {@code trustCertCollectionFile} * @param keyCertChainFile an X.509 certificate chain file in PEM format * @param keyFile a PKCS#8 private key file in PEM format * @param keyPassword the password of the {@code keyFile}. @@ -204,13 +206,13 @@ public final class JdkSslServerContext extends JdkSslContext { * @deprecated use {@link SslContextBuilder} */ @Deprecated - public JdkSslServerContext(File trustCertChainFile, TrustManagerFactory trustManagerFactory, + public JdkSslServerContext(File trustCertCollectionFile, TrustManagerFactory trustManagerFactory, File keyCertChainFile, File keyFile, String keyPassword, KeyManagerFactory keyManagerFactory, Iterable ciphers, CipherSuiteFilter cipherFilter, JdkApplicationProtocolNegotiator apn, long sessionCacheSize, long sessionTimeout) throws SSLException { super(ciphers, cipherFilter, apn, ClientAuth.NONE); try { - ctx = newSSLContext(toX509Certificates(trustCertChainFile), trustManagerFactory, + ctx = newSSLContext(toX509Certificates(trustCertCollectionFile), trustManagerFactory, toX509Certificates(keyCertChainFile), toPrivateKey(keyFile, keyPassword), keyPassword, keyManagerFactory, sessionCacheSize, sessionTimeout); } catch (Exception e) { @@ -221,27 +223,28 @@ public final class JdkSslServerContext extends JdkSslContext { } } - JdkSslServerContext(X509Certificate[] trustCertChain, TrustManagerFactory trustManagerFactory, + JdkSslServerContext(X509Certificate[] trustCertCollection, TrustManagerFactory trustManagerFactory, X509Certificate[] keyCertChain, PrivateKey key, String keyPassword, KeyManagerFactory keyManagerFactory, Iterable ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn, long sessionCacheSize, long sessionTimeout, ClientAuth clientAuth) throws SSLException { super(ciphers, cipherFilter, toNegotiator(apn, true), clientAuth); - ctx = newSSLContext(trustCertChain, trustManagerFactory, keyCertChain, key, + ctx = newSSLContext(trustCertCollection, trustManagerFactory, keyCertChain, key, keyPassword, keyManagerFactory, sessionCacheSize, sessionTimeout); } - private static SSLContext newSSLContext(X509Certificate[] trustCertChain, TrustManagerFactory trustManagerFactory, - X509Certificate[] keyCertChain, PrivateKey key, String keyPassword, - KeyManagerFactory keyManagerFactory, long sessionCacheSize, long sessionTimeout) + private static SSLContext newSSLContext(X509Certificate[] trustCertCollection, + TrustManagerFactory trustManagerFactory, X509Certificate[] keyCertChain, + PrivateKey key, String keyPassword, KeyManagerFactory keyManagerFactory, + long sessionCacheSize, long sessionTimeout) throws SSLException { if (key == null && keyManagerFactory == null) { throw new NullPointerException("key, keyManagerFactory"); } try { - if (trustCertChain != null) { - trustManagerFactory = buildTrustManagerFactory(trustCertChain, trustManagerFactory); + if (trustCertCollection != null) { + trustManagerFactory = buildTrustManagerFactory(trustCertCollection, trustManagerFactory); } if (key != null) { keyManagerFactory = buildKeyManagerFactory(keyCertChain, key, keyPassword, keyManagerFactory); diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslClientContext.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslClientContext.java index 23f47f00af..335dfb1f60 100644 --- a/handler/src/main/java/io/netty/handler/ssl/OpenSslClientContext.java +++ b/handler/src/main/java/io/netty/handler/ssl/OpenSslClientContext.java @@ -136,11 +136,12 @@ public final class OpenSslClientContext extends OpenSslContext { /** * Creates a new instance. - * @param trustCertChainFile an X.509 certificate chain file in PEM format. + * @param trustCertCollectionFile an X.509 certificate collection file in PEM format. * {@code null} to use the system default * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s * that verifies the certificates sent from servers. - * {@code null} to use the default or the results of parsing {@code trustCertChainFile} + * {@code null} to use the default or the results of parsing + * {@code trustCertCollectionFile} * @param keyCertChainFile an X.509 certificate chain file in PEM format. * This provides the public key for mutual authentication. * {@code null} to use the system default @@ -165,19 +166,19 @@ public final class OpenSslClientContext extends OpenSslContext { * @deprecated use {@link SslContextBuilder} */ @Deprecated - public OpenSslClientContext(File trustCertChainFile, TrustManagerFactory trustManagerFactory, + public OpenSslClientContext(File trustCertCollectionFile, TrustManagerFactory trustManagerFactory, File keyCertChainFile, File keyFile, String keyPassword, KeyManagerFactory keyManagerFactory, Iterable ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn, long sessionCacheSize, long sessionTimeout) throws SSLException { - this(toX509CertificatesInternal(trustCertChainFile), trustManagerFactory, + this(toX509CertificatesInternal(trustCertCollectionFile), trustManagerFactory, toX509CertificatesInternal(keyCertChainFile), toPrivateKeyInternal(keyFile, keyPassword), keyPassword, keyManagerFactory, ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout); } @SuppressWarnings("deprecation") - OpenSslClientContext(X509Certificate[] trustCertChain, TrustManagerFactory trustManagerFactory, + OpenSslClientContext(X509Certificate[] trustCertCollection, TrustManagerFactory trustManagerFactory, X509Certificate[] keyCertChain, PrivateKey key, String keyPassword, KeyManagerFactory keyManagerFactory, Iterable ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn, @@ -236,8 +237,8 @@ public final class OpenSslClientContext extends OpenSslContext { SSLContext.setVerify(ctx, SSL.SSL_VERIFY_NONE, VERIFY_DEPTH); try { - if (trustCertChain != null) { - trustManagerFactory = buildTrustManagerFactory(trustCertChain, trustManagerFactory); + if (trustCertCollection != null) { + trustManagerFactory = buildTrustManagerFactory(trustCertCollection, trustManagerFactory); } else if (trustManagerFactory == null) { trustManagerFactory = TrustManagerFactory.getInstance( TrustManagerFactory.getDefaultAlgorithm()); diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslServerContext.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslServerContext.java index 0e82ec2760..156843eb63 100644 --- a/handler/src/main/java/io/netty/handler/ssl/OpenSslServerContext.java +++ b/handler/src/main/java/io/netty/handler/ssl/OpenSslServerContext.java @@ -195,12 +195,13 @@ public final class OpenSslServerContext extends OpenSslContext { /** * Creates a new instance. * - * @param trustCertChainFile an X.509 certificate chain file in PEM format. - * This provides the certificate chains used for mutual authentication. + * @param trustCertCollectionFile an X.509 certificate collection file in PEM format. + * This provides the certificate collection used for mutual authentication. * {@code null} to use the system default * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s * that verifies the certificates sent from clients. - * {@code null} to use the default or the results of parsing {@code trustCertChainFile}. + * {@code null} to use the default or the results of parsing + * {@code trustCertCollectionFile}. * @param keyCertChainFile an X.509 certificate chain file in PEM format * @param keyFile a PKCS#8 private key file in PEM format * @param keyPassword the password of the {@code keyFile}. @@ -222,11 +223,11 @@ public final class OpenSslServerContext extends OpenSslContext { */ @Deprecated public OpenSslServerContext( - File trustCertChainFile, TrustManagerFactory trustManagerFactory, + File trustCertCollectionFile, TrustManagerFactory trustManagerFactory, File keyCertChainFile, File keyFile, String keyPassword, KeyManagerFactory keyManagerFactory, Iterable ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig config, long sessionCacheSize, long sessionTimeout) throws SSLException { - this(trustCertChainFile, trustManagerFactory, keyCertChainFile, keyFile, keyPassword, keyManagerFactory, + this(trustCertCollectionFile, trustManagerFactory, keyCertChainFile, keyFile, keyPassword, keyManagerFactory, ciphers, cipherFilter, toNegotiator(config), sessionCacheSize, sessionTimeout); } @@ -286,12 +287,13 @@ public final class OpenSslServerContext extends OpenSslContext { * Creates a new instance. * * - * @param trustCertChainFile an X.509 certificate chain file in PEM format. - * This provides the certificate chains used for mutual authentication. + * @param trustCertCollectionFile an X.509 certificate collection file in PEM format. + * This provides the certificate collection used for mutual authentication. * {@code null} to use the system default * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s * that verifies the certificates sent from clients. - * {@code null} to use the default or the results of parsing {@code trustCertChainFile}. + * {@code null} to use the default or the results of parsing + * {@code trustCertCollectionFile}. * @param keyCertChainFile an X.509 certificate chain file in PEM format * @param keyFile a PKCS#8 private key file in PEM format * @param keyPassword the password of the {@code keyFile}. @@ -313,28 +315,28 @@ public final class OpenSslServerContext extends OpenSslContext { */ @Deprecated public OpenSslServerContext( - File trustCertChainFile, TrustManagerFactory trustManagerFactory, + File trustCertCollectionFile, TrustManagerFactory trustManagerFactory, File keyCertChainFile, File keyFile, String keyPassword, KeyManagerFactory keyManagerFactory, Iterable ciphers, CipherSuiteFilter cipherFilter, OpenSslApplicationProtocolNegotiator apn, long sessionCacheSize, long sessionTimeout) throws SSLException { - this(toX509CertificatesInternal(trustCertChainFile), trustManagerFactory, + this(toX509CertificatesInternal(trustCertCollectionFile), trustManagerFactory, toX509CertificatesInternal(keyCertChainFile), toPrivateKeyInternal(keyFile, keyPassword), keyPassword, keyManagerFactory, ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, ClientAuth.NONE); } OpenSslServerContext( - X509Certificate[] trustCertChain, TrustManagerFactory trustManagerFactory, + X509Certificate[] trustCertCollection, TrustManagerFactory trustManagerFactory, X509Certificate[] keyCertChain, PrivateKey key, String keyPassword, KeyManagerFactory keyManagerFactory, Iterable ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn, long sessionCacheSize, long sessionTimeout, ClientAuth clientAuth) throws SSLException { - this(trustCertChain, trustManagerFactory, keyCertChain, key, keyPassword, keyManagerFactory, ciphers, + this(trustCertCollection, trustManagerFactory, keyCertChain, key, keyPassword, keyManagerFactory, ciphers, cipherFilter, toNegotiator(apn), sessionCacheSize, sessionTimeout, clientAuth); } @SuppressWarnings("deprecation") private OpenSslServerContext( - X509Certificate[] trustCertChain, TrustManagerFactory trustManagerFactory, + X509Certificate[] trustCertCollection, TrustManagerFactory trustManagerFactory, X509Certificate[] keyCertChain, PrivateKey key, String keyPassword, KeyManagerFactory keyManagerFactory, Iterable ciphers, CipherSuiteFilter cipherFilter, OpenSslApplicationProtocolNegotiator apn, long sessionCacheSize, long sessionTimeout, ClientAuth clientAuth) throws SSLException { @@ -402,8 +404,8 @@ public final class OpenSslServerContext extends OpenSslContext { } } try { - if (trustCertChain != null) { - trustManagerFactory = buildTrustManagerFactory(trustCertChain, trustManagerFactory); + if (trustCertCollection != null) { + trustManagerFactory = buildTrustManagerFactory(trustCertCollection, trustManagerFactory); } else if (trustManagerFactory == null) { // Mimic the way SSLContext.getInstance(KeyManager[], null, null) works trustManagerFactory = TrustManagerFactory.getInstance( diff --git a/handler/src/main/java/io/netty/handler/ssl/SslContext.java b/handler/src/main/java/io/netty/handler/ssl/SslContext.java index ab40c9082f..5a3920d890 100644 --- a/handler/src/main/java/io/netty/handler/ssl/SslContext.java +++ b/handler/src/main/java/io/netty/handler/ssl/SslContext.java @@ -39,7 +39,7 @@ import javax.net.ssl.SSLException; import javax.net.ssl.SSLSessionContext; import javax.net.ssl.TrustManager; import javax.net.ssl.TrustManagerFactory; -import javax.security.auth.x500.X500Principal; + import java.io.File; import java.io.IOException; import java.io.InputStream; @@ -338,12 +338,13 @@ public abstract class SslContext { * Creates a new server-side {@link SslContext}. * @param provider the {@link SslContext} implementation to use. * {@code null} to use the current default one. - * @param trustCertChainFile an X.509 certificate chain file in PEM format. - * This provides the certificate chains used for mutual authentication. + * @param trustCertCollectionFile an X.509 certificate collection file in PEM format. + * This provides the certificate collection used for mutual authentication. * {@code null} to use the system default * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s * that verifies the certificates sent from clients. - * {@code null} to use the default or the results of parsing {@code trustCertChainFile}. + * {@code null} to use the default or the results of parsing + * {@code trustCertCollectionFile}. * This parameter is ignored if {@code provider} is not {@link SslProvider#JDK}. * @param keyCertChainFile an X.509 certificate chain file in PEM format * @param keyFile a PKCS#8 private key file in PEM format @@ -369,12 +370,12 @@ public abstract class SslContext { @Deprecated public static SslContext newServerContext( SslProvider provider, - File trustCertChainFile, TrustManagerFactory trustManagerFactory, + File trustCertCollectionFile, TrustManagerFactory trustManagerFactory, File keyCertChainFile, File keyFile, String keyPassword, KeyManagerFactory keyManagerFactory, Iterable ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn, long sessionCacheSize, long sessionTimeout) throws SSLException { try { - return newServerContextInternal(provider, toX509Certificates(trustCertChainFile), trustManagerFactory, + return newServerContextInternal(provider, toX509Certificates(trustCertCollectionFile), trustManagerFactory, toX509Certificates(keyCertChainFile), toPrivateKey(keyFile, keyPassword), keyPassword, keyManagerFactory, ciphers, cipherFilter, apn, @@ -389,7 +390,7 @@ public abstract class SslContext { static SslContext newServerContextInternal( SslProvider provider, - X509Certificate[] trustCertChain, TrustManagerFactory trustManagerFactory, + X509Certificate[] trustCertCollection, TrustManagerFactory trustManagerFactory, X509Certificate[] keyCertChain, PrivateKey key, String keyPassword, KeyManagerFactory keyManagerFactory, Iterable ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn, long sessionCacheSize, long sessionTimeout, @@ -402,12 +403,12 @@ public abstract class SslContext { switch (provider) { case JDK: return new JdkSslServerContext( - trustCertChain, trustManagerFactory, keyCertChain, key, keyPassword, + trustCertCollection, trustManagerFactory, keyCertChain, key, keyPassword, keyManagerFactory, ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, clientAuth); case OPENSSL: return new OpenSslServerContext( - trustCertChain, trustManagerFactory, keyCertChain, key, keyPassword, + trustCertCollection, trustManagerFactory, keyCertChain, key, keyPassword, keyManagerFactory, ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, clientAuth); default: @@ -673,11 +674,12 @@ public abstract class SslContext { * Creates a new client-side {@link SslContext}. * @param provider the {@link SslContext} implementation to use. * {@code null} to use the current default one. - * @param trustCertChainFile an X.509 certificate chain file in PEM format. + * @param trustCertCollectionFile an X.509 certificate collection file in PEM format. * {@code null} to use the system default * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s * that verifies the certificates sent from servers. - * {@code null} to use the default or the results of parsing {@code trustCertChainFile}. + * {@code null} to use the default or the results of parsing + * {@code trustCertCollectionFile}. * This parameter is ignored if {@code provider} is not {@link SslProvider#JDK}. * @param keyCertChainFile an X.509 certificate chain file in PEM format. * This provides the public key for mutual authentication. @@ -708,12 +710,12 @@ public abstract class SslContext { @Deprecated public static SslContext newClientContext( SslProvider provider, - File trustCertChainFile, TrustManagerFactory trustManagerFactory, + File trustCertCollectionFile, TrustManagerFactory trustManagerFactory, File keyCertChainFile, File keyFile, String keyPassword, KeyManagerFactory keyManagerFactory, Iterable ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn, long sessionCacheSize, long sessionTimeout) throws SSLException { try { - return newClientContextInternal(provider, toX509Certificates(trustCertChainFile), trustManagerFactory, + return newClientContextInternal(provider, toX509Certificates(trustCertCollectionFile), trustManagerFactory, toX509Certificates(keyCertChainFile), toPrivateKey(keyFile, keyPassword), keyPassword, keyManagerFactory, ciphers, cipherFilter, apn, @@ -993,14 +995,16 @@ public abstract class SslContext { } static TrustManagerFactory buildTrustManagerFactory( - X509Certificate[] certChain, TrustManagerFactory trustManagerFactory) + X509Certificate[] certCollection, TrustManagerFactory trustManagerFactory) throws NoSuchAlgorithmException, CertificateException, KeyStoreException, IOException { KeyStore ks = KeyStore.getInstance("JKS"); ks.load(null, null); - for (X509Certificate cert: certChain) { - X500Principal principal = cert.getSubjectX500Principal(); - ks.setCertificateEntry(principal.getName("RFC2253"), cert); + int i = 1; + for (X509Certificate cert: certCollection) { + String alias = Integer.toString(i); + ks.setCertificateEntry(alias, cert); + i++; } // Set up trust manager factory to use our key store. diff --git a/handler/src/main/java/io/netty/handler/ssl/SslContextBuilder.java b/handler/src/main/java/io/netty/handler/ssl/SslContextBuilder.java index 074f64c9fa..969bea199c 100644 --- a/handler/src/main/java/io/netty/handler/ssl/SslContextBuilder.java +++ b/handler/src/main/java/io/netty/handler/ssl/SslContextBuilder.java @@ -125,7 +125,7 @@ public final class SslContextBuilder { private final boolean forServer; private SslProvider provider; - private X509Certificate[] trustCertChain; + private X509Certificate[] trustCertCollection; private TrustManagerFactory trustManagerFactory; private X509Certificate[] keyCertChain; private PrivateKey key; @@ -152,23 +152,24 @@ public final class SslContextBuilder { /** * Trusted certificates for verifying the remote endpoint's certificate. The file should - * contain an X.509 certificate chain in PEM format. {@code null} uses the system default. + * contain an X.509 certificate collection in PEM format. {@code null} uses the system default. */ - public SslContextBuilder trustManager(File trustCertChainFile) { + public SslContextBuilder trustManager(File trustCertCollectionFile) { try { - return trustManager(SslContext.toX509Certificates(trustCertChainFile)); + return trustManager(SslContext.toX509Certificates(trustCertCollectionFile)); } catch (Exception e) { - throw new IllegalArgumentException("File does not contain valid certificates: " + trustCertChainFile, e); + throw new IllegalArgumentException("File does not contain valid certificates: " + + trustCertCollectionFile, e); } } /** * Trusted certificates for verifying the remote endpoint's certificate. The input stream should - * contain an X.509 certificate chain in PEM format. {@code null} uses the system default. + * contain an X.509 certificate collection in PEM format. {@code null} uses the system default. */ - public SslContextBuilder trustManager(InputStream trustCertChainInputStream) { + public SslContextBuilder trustManager(InputStream trustCertCollectionInputStream) { try { - return trustManager(SslContext.toX509Certificates(trustCertChainInputStream)); + return trustManager(SslContext.toX509Certificates(trustCertCollectionInputStream)); } catch (Exception e) { throw new IllegalArgumentException("Input stream does not contain valid certificates.", e); } @@ -177,8 +178,8 @@ public final class SslContextBuilder { /** * Trusted certificates for verifying the remote endpoint's certificate, {@code null} uses the system default. */ - public SslContextBuilder trustManager(X509Certificate... trustCertChain) { - this.trustCertChain = trustCertChain != null ? trustCertChain.clone() : null; + public SslContextBuilder trustManager(X509Certificate... trustCertCollection) { + this.trustCertCollection = trustCertCollection != null ? trustCertCollection.clone() : null; trustManagerFactory = null; return this; } @@ -189,7 +190,7 @@ public final class SslContextBuilder { * you must use {@link #trustManager(File)}. {@code null} uses the system default. */ public SslContextBuilder trustManager(TrustManagerFactory trustManagerFactory) { - trustCertChain = null; + trustCertCollection = null; this.trustManagerFactory = trustManagerFactory; return this; } @@ -387,11 +388,11 @@ public final class SslContextBuilder { */ public SslContext build() throws SSLException { if (forServer) { - return SslContext.newServerContextInternal(provider, trustCertChain, + return SslContext.newServerContextInternal(provider, trustCertCollection, trustManagerFactory, keyCertChain, key, keyPassword, keyManagerFactory, ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, clientAuth); } else { - return SslContext.newClientContextInternal(provider, trustCertChain, + return SslContext.newClientContextInternal(provider, trustCertCollection, trustManagerFactory, keyCertChain, key, keyPassword, keyManagerFactory, ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout); } diff --git a/handler/src/test/java/io/netty/handler/ssl/SslContextTrustManagerTest.java b/handler/src/test/java/io/netty/handler/ssl/SslContextTrustManagerTest.java new file mode 100644 index 0000000000..97b90f2e90 --- /dev/null +++ b/handler/src/test/java/io/netty/handler/ssl/SslContextTrustManagerTest.java @@ -0,0 +1,147 @@ +/* + * Copyright 2016 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; + +import static org.junit.Assert.fail; +import static org.junit.Assert.assertNotNull; + +import java.io.InputStream; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.util.Arrays; + +import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactory; +import javax.net.ssl.X509TrustManager; + +import org.junit.Test; + +public class SslContextTrustManagerTest { + @Test + public void testUsingAllCAs() throws Exception { + runTests(new String[] { "tm_test_ca_1a.pem", "tm_test_ca_1b.pem", + "tm_test_ca_2.pem" }, new String[] { "tm_test_eec_1.pem", + "tm_test_eec_2.pem", "tm_test_eec_3.pem" }, new boolean[] { + true, true, true }); + } + + @Test + public void testUsingAllCAsWithDuplicates() throws Exception { + runTests(new String[] { "tm_test_ca_1a.pem", "tm_test_ca_1b.pem", + "tm_test_ca_2.pem", "tm_test_ca_2.pem" }, + new String[] { "tm_test_eec_1.pem", "tm_test_eec_2.pem", + "tm_test_eec_3.pem" }, + new boolean[] { true, true, true }); + } + + @Test + public void testUsingCAsOneAandB() throws Exception { + runTests(new String[] { "tm_test_ca_1a.pem", "tm_test_ca_1b.pem", }, + new String[] { "tm_test_eec_1.pem", "tm_test_eec_2.pem", + "tm_test_eec_3.pem" }, new boolean[] { true, true, + false }); + } + + @Test + public void testUsingCAsOneAandTwo() throws Exception { + runTests(new String[] { "tm_test_ca_1a.pem", "tm_test_ca_2.pem" }, + new String[] { "tm_test_eec_1.pem", "tm_test_eec_2.pem", + "tm_test_eec_3.pem" }, new boolean[] { true, false, + true }); + } + + /** + * + * @param caResources + * an array of paths to CA Certificates in PEM format to load + * from the classpath (relative to this class). + * @param eecResources + * an array of paths to Server Certificates in PEM format in to + * load from the classpath (relative to this class). + * @param expectations + * an array of expecting results for each EEC Server Certificate + * (the array is expected to have the same length the previous + * argument, and be arrange in matching order: true means + * expected to be valid, false otherwise. + */ + private static void runTests(String[] caResources, String[] eecResources, + boolean[] expectations) throws Exception { + X509TrustManager tm = getTrustManager(caResources); + + X509Certificate[] eecCerts = loadCertCollection(eecResources); + + for (int i = 0; i < eecResources.length; i++) { + X509Certificate eecCert = eecCerts[i]; + assertNotNull("Cannot use cert " + eecResources[i], eecCert); + try { + tm.checkServerTrusted(new X509Certificate[] { eecCert }, "RSA"); + if (!expectations[i]) { + fail(String.format( + "Certificate %s was expected not to be valid when using CAs %s, but its " + + "verification passed.", eecResources[i], + Arrays.asList(caResources))); + } + } catch (CertificateException e) { + if (expectations[i]) { + fail(String.format( + "Certificate %s was expected to be valid when using CAs %s, but its " + + "verification failed.", eecResources[i], + Arrays.asList(caResources))); + } + } + } + } + + private static X509TrustManager getTrustManager(String[] resourceNames) + throws Exception { + X509Certificate[] certCollection = loadCertCollection(resourceNames); + TrustManagerFactory tmf = SslContext.buildTrustManagerFactory( + certCollection, null); + + for (TrustManager tm : tmf.getTrustManagers()) { + if (tm instanceof X509TrustManager) { + return (X509TrustManager) tm; + } + } + + throw new Exception( + "Unable to find any X509TrustManager from this factory."); + } + + private static X509Certificate[] loadCertCollection(String[] resourceNames) + throws Exception { + CertificateFactory certFactory = CertificateFactory + .getInstance("X.509"); + + X509Certificate[] certCollection = new X509Certificate[resourceNames.length]; + for (int i = 0; i < resourceNames.length; i++) { + String resourceName = resourceNames[i]; + InputStream is = null; + try { + is = SslContextTest.class.getResourceAsStream(resourceName); + assertNotNull("Cannot find " + resourceName, is); + certCollection[i] = (X509Certificate) certFactory + .generateCertificate(is); + } finally { + if (is != null) { + is.close(); + } + } + } + return certCollection; + } +} diff --git a/handler/src/test/resources/io/netty/handler/ssl/tm_test_ca_1a.pem b/handler/src/test/resources/io/netty/handler/ssl/tm_test_ca_1a.pem new file mode 100644 index 0000000000..120859eda5 --- /dev/null +++ b/handler/src/test/resources/io/netty/handler/ssl/tm_test_ca_1a.pem @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIC/TCCAeWgAwIBAgIBATANBgkqhkiG9w0BAQsFADAXMRUwEwYDVQQDEwxuZXR0 +eS50ZXN0LjEwIBcNMTYwMzIyMTIwMDAwWhgPMjExNjAzMjIxMjAwMDBaMBcxFTAT +BgNVBAMTDG5ldHR5LnRlc3QuMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBALWMMCP4QWYWJNt+fNqpwLNM9/LkJlS3NtzJl1chvnyHpxt8OFSD8/cYSl6z +MrbgRYyGNuaL3lsKIL5p2ZnUYzcR61niAhjuMXQgM6ZkptlIsgK6426OTALOSN6l +HukItWDDL/om0Mnc8zMuLL/kIpfnzYOKMseUf/1R1MftzlNSSAMPQ7Rn8So/3nUG +j42NywEInoONv89UZ4L+xPpyJwrp0k/u19ckwhFWdudw7l2lVo6s5aBJW9CK8v/f +uUxC75eUYiQ57suKhXCy1Vf8T4vVDiEjKxa3whD1QxlxRxZNYdHJA6tEQIhiWjCC +RiDZZcaAcCCD0evE/0l5V9nnRc8CAwEAAaNSMFAwDwYDVR0TAQH/BAUwAwEB/zAd +BgNVHQ4EFgQUvdqINGhE1D1xZi9Q8NyR+G+5bLwwCwYDVR0PBAQDAgEGMBEGCWCG +SAGG+EIBAQQEAwIABzANBgkqhkiG9w0BAQsFAAOCAQEAR8gHn7MJp6cNwMR6qF3e +jU3tAzCshZVM03NyoHvMpcHsILlR0g/q2KTjcgHzpMMo5PrUGf3oR6ad4JFr5els +kstgbCe4Vv/XzEC6faTEuhLolHGMyzr3Pd6k/wJSsMktF7Ob+YjsyZbgQbyhXqJV +UDQDDncIwxl5rdsRwfiltLUOle4702b4hSCb/1NsDsvsuZQVfeAHHzT1aS8XDSwK +bHOgrDgQGhVR6rBTH9WhcRgFY9rKQ4vVjhoNbwWweQvHmQSO8xYNUhtQnxVOeB7B +NzBM+kx5nw7oIqPCYT0hBINNqeoac9Bidfl4UoTB5YjsQFse4BNuBDPFowAXq5ZB +fg== +-----END CERTIFICATE----- diff --git a/handler/src/test/resources/io/netty/handler/ssl/tm_test_ca_1b.pem b/handler/src/test/resources/io/netty/handler/ssl/tm_test_ca_1b.pem new file mode 100644 index 0000000000..df75823fc9 --- /dev/null +++ b/handler/src/test/resources/io/netty/handler/ssl/tm_test_ca_1b.pem @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIC/TCCAeWgAwIBAgIBATANBgkqhkiG9w0BAQsFADAXMRUwEwYDVQQDEwxuZXR0 +eS50ZXN0LjEwIBcNMTYwMzIyMTMwMDAwWhgPMjExNjAzMjIxMzAwMDBaMBcxFTAT +BgNVBAMTDG5ldHR5LnRlc3QuMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBANEUVJUwvWr+qyS28W2EMiDq5frQwforMED7Q8wMiMod+LFxy7y04p12zYWW +35iqC3RaQUQ31DOknAxc7H8vfr0vdl87BIsxc27Ud9h+Do0ggktCaz9Te8/q2Yxo +4TQ8QEFJ8x37zPB05LVqF4djim4GE/yaj0WFMuaRaZLUFvGbHTL7ilC2l6p9SuYx +y40cCucP5nNAXGNhnVYsJCPa/LkyIDLGbkvMMARorkbr7zfaYI2D1YfedwmCOEo1 +CkfBm2qL9/+ig/8VFrTRPlYzUWHsyPvCzfL9F/69NxRCdVk7XCyMEgmf/ztyy/7k +3iZeBhQ0z+RXiNLqBkK3RbaMD7ECAwEAAaNSMFAwDwYDVR0TAQH/BAUwAwEB/zAd +BgNVHQ4EFgQU2vr0yImPHyJv84PXeoSJYbI12uEwCwYDVR0PBAQDAgEGMBEGCWCG +SAGG+EIBAQQEAwIABzANBgkqhkiG9w0BAQsFAAOCAQEAT8mmZi/4dzozqa76tgxM +8ZQgw2C+WgetC81CKqIN3F3tFtu2KEsaAsXEpOVvDR278bLk+r3H3d47Or0xn053 +grk6kdI4C9IPHP7IDaNmAskZ5u9Hrl25P1fxMKG6hXwrk2Je7gD8aNP5IkOSKulo +e9b3XSW53WdtHZ+b98LKVMO0lRLQsiG1EmNrL0kJwMXuPxq5s0Ljqz/L19iWGupk +kybRWPcmjHnWIOnnYTwFswI/h79/afvwW5xUP4HgcU/nKrNDWveE7lSYq66zcvpt +rBCESrr3gvETNTJKCPN4u41EOJKGGgoN4U9fBopU4DfzIrcwZ5a4eFLsAFEqAB23 +3A== +-----END CERTIFICATE----- diff --git a/handler/src/test/resources/io/netty/handler/ssl/tm_test_ca_2.pem b/handler/src/test/resources/io/netty/handler/ssl/tm_test_ca_2.pem new file mode 100644 index 0000000000..1d96bfc7fe --- /dev/null +++ b/handler/src/test/resources/io/netty/handler/ssl/tm_test_ca_2.pem @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIC/TCCAeWgAwIBAgIBATANBgkqhkiG9w0BAQUFADAXMRUwEwYDVQQDEwxuZXR0 +eS50ZXN0LjIwIBcNMTYwMzIyMTIwMDAwWhgPMjExNjAzMjIxMjAwMDBaMBcxFTAT +BgNVBAMTDG5ldHR5LnRlc3QuMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBAMFTCqEUaMvZPwV8PFHgjpcqlrVfIadY+B2DAsYBQp6HirRv2STYdBue9bHS +Ya8n6J99Qcp0jct692MeOh9BhWoX7wOvi8Tckiu+LAMo7vBHAyUSamJ5qKyNvZNW +3Uwrng1LFwOo6uhY6N6vqyv5CIoDGv+afOlnZOS7484ZYvmYEPejbIPLZpj7IP8Z +c2xmi7TOj781uO2rwUzZgqGSEKsYZNMhVp7yZrsJ3el9T2+2Dma1aYt2w/grOW1t +pzxWvXqjkrjbNjJamAxyiy3qyQ2iDhpFYz8ONqSxqN/QRE72q2N8e+QtajceCFz7 +lpMWRqr7Z6Fdh5zUS7yJrCksJh8CAwEAAaNSMFAwDwYDVR0TAQH/BAUwAwEB/zAd +BgNVHQ4EFgQUnk0/s/aeR4sjFcubiyB/QMWryj8wCwYDVR0PBAQDAgEGMBEGCWCG +SAGG+EIBAQQEAwIABzANBgkqhkiG9w0BAQUFAAOCAQEAWu+RyHkL3lNl8dLlVuDa +A/Vakxf/xbd8+qFEIox2nLvSYZ3OkLzE+vUip/KP0JyQmmmzaz3sx5eZXx33gw9Z +rRYW3I0/c2QPjT5xNYnITUoX5z17FKd71lMr/bz8uhaF9Do+ZV84HgORwtmOCwNg +bOIIVtHO6Ht3V2RmLcQgUV4dK3neNJHa75/Wi3OkJNEZqbzcJX2r69BqupoLte8j +FxqkLBmwUruuCVl5gUFoXsxT3+qgWMxNweLSxEmbqkQ54g8W+06PTHMM/BpbsApv +Ce5mKeC8lHvbV3CxaOYp8w5xJPJbEt/vK6w8jrN47Tz6LaQcimDMdJVVM2H5zubG +RA== +-----END CERTIFICATE----- diff --git a/handler/src/test/resources/io/netty/handler/ssl/tm_test_eec_1.pem b/handler/src/test/resources/io/netty/handler/ssl/tm_test_eec_1.pem new file mode 100644 index 0000000000..e90e20549f --- /dev/null +++ b/handler/src/test/resources/io/netty/handler/ssl/tm_test_eec_1.pem @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDADCCAeigAwIBAgIBAjANBgkqhkiG9w0BAQUFADAXMRUwEwYDVQQDEwxuZXR0 +eS50ZXN0LjEwIBcNMTYwMzIyMTQwMDAwWhgPMjExNjAzMjIxMjAwMDBaMB0xGzAZ +BgNVBAMTEm5ldHR5LnRlc3Quc2VydmVyMTCCASIwDQYJKoZIhvcNAQEBBQADggEP +ADCCAQoCggEBALEytHncQ4iJ0d3nbLcRhe3wWmHzeqr9JKvAMSnIGw2Oc+nUK3FP +xMjdYnY3CSw6BYjK5zJsSF2UWU/jycqc5caQTEXVUQJDjQENScHHsWB+jEevd1i7 +HDmd4Ykw/bqRRRP/I6npukpwJkPuqJ7LAsDfA7FuHJY15ZlhDod5+1zleWv2tdDK +fRCvODi8ehujyNqBqNeRL2YF4wt4yqviFbDNy5+JreyfzPvv1iujSprN5JJCRJ1C +7AABrHYYMQXuEYb10t9dS908Zg2B3sDUa969F1RnU86bCppwK1otQr/RO2hUqqdq +IItb9FHRkeko81OvUiM6nvLzzJLBOInyAzMCAwEAAaNPME0wDAYDVR0TAQH/BAIw +ADAdBgNVHQ4EFgQUt5uJ55JYS1Qw2YE5OWOhgv6RxUAwCwYDVR0PBAQDAgXgMBEG +CWCGSAGG+EIBAQQEAwIGQDANBgkqhkiG9w0BAQUFAAOCAQEAUS9HzI9VXyZiaGM6 +RwpUEDgUhbAeI7i7xsdJgqlbvKrTQQy+MKIbxDgsyoz2buqwdX7ekvykTmo0pltS +ASr36gTTW4dwRtiecn/HutrnyuJIckbvMZzld5xIdNERqLHnoiRAopVhe1Fc5UFd +YGEOd+685X2fuc9PMy3G8JjQAOftYOx21JaaNumyVVLcyvciGK0Ptwh/q+6hf4+h +XUHHtIzjnPAM9vkcCmHttVbl3uvare7TfeAoU82NODz0sUaOrIwG8dQbmEdrafHa +JHXti1wv+9ZEEiYKcecvnB3q4e0MT3atf3qedw4B9ZkzoniHEOhFpZgQg6UVA7/f +ga0mCg== +-----END CERTIFICATE----- diff --git a/handler/src/test/resources/io/netty/handler/ssl/tm_test_eec_2.pem b/handler/src/test/resources/io/netty/handler/ssl/tm_test_eec_2.pem new file mode 100644 index 0000000000..898a6e092d --- /dev/null +++ b/handler/src/test/resources/io/netty/handler/ssl/tm_test_eec_2.pem @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDADCCAeigAwIBAgIBAjANBgkqhkiG9w0BAQUFADAXMRUwEwYDVQQDEwxuZXR0 +eS50ZXN0LjEwIBcNMTYwMzIyMTQwMDAwWhgPMjExNjAzMjIxMzAwMDBaMB0xGzAZ +BgNVBAMTEm5ldHR5LnRlc3Quc2VydmVyMjCCASIwDQYJKoZIhvcNAQEBBQADggEP +ADCCAQoCggEBAMFf61lsJ5Tpcg6ux5lbZhPEzvLi117aZ42figORTeZg0fMX8a3W +XfRUHldTYD6CugTIpgheZDzsYfwrSLyK5jMyQl332rCoozj2dXdi+HY/JQ5gw8DY +odeQCjCWS3V6HpHTu8tqgNquqjygSLQHSsh+oCVUa/5IWA1N+zZY5/XARnyajwS0 +8Nrgok9kd//jR7hIwHm40YThrTawRetooDK/MuFxJb6FX6UPwZ5/9g2UZMUaKzIa +hrGfjAQmRxzkRyACbVqYv+wjBMSCq2SqYZ2Fq3nKeW+dvpPeFfHGOyF/F8kIqtpa +BRawXPHKaUoQYn0PDU+RRfZjfkWTQuz/OMcCAwEAAaNPME0wDAYDVR0TAQH/BAIw +ADAdBgNVHQ4EFgQUIUVnoWei3itUqTyFxPczCYsvW4EwCwYDVR0PBAQDAgXgMBEG +CWCGSAGG+EIBAQQEAwIGQDANBgkqhkiG9w0BAQUFAAOCAQEAfK+YlGqBVExATkGF +1ZIcJZtvaiX8rGH8mwqj1wPvKjPRCHvNpPTDLNGhHrFu/0sJlZQDz6hDn0NpJpD8 +TffF+jqmBfvGQW1MEd+jyfp5IXHwR0ZejJepQIeGYuMwyrlZXUKnXvQR2QDkLyx+ +rxmO58XWLNoFUkM4guts3Jb7oAgfCbzYnmBELMVhI8v+SQhuZamvL6S5Wdb18O9i +/N/zH/KDwJmIVtWo7D8UOAMeq69s9zYZLKkqwt8o+DSXth0YPZcNcU8IouDzEJ14 +C35My7Ll7vFehgetXq9D7cMYltx2VPKKYOeT5ZzI580ZvtryT8yCTBj4GoSvAzb6 +RHwFRw== +-----END CERTIFICATE----- diff --git a/handler/src/test/resources/io/netty/handler/ssl/tm_test_eec_3.pem b/handler/src/test/resources/io/netty/handler/ssl/tm_test_eec_3.pem new file mode 100644 index 0000000000..82fa9c9f53 --- /dev/null +++ b/handler/src/test/resources/io/netty/handler/ssl/tm_test_eec_3.pem @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDADCCAeigAwIBAgIBAjANBgkqhkiG9w0BAQUFADAXMRUwEwYDVQQDEwxuZXR0 +eS50ZXN0LjIwIBcNMTYwMzIyMTUwMDAwWhgPMjExNjAzMjIxMjAwMDBaMB0xGzAZ +BgNVBAMTEm5ldHR5LnRlc3Quc2VydmVyMzCCASIwDQYJKoZIhvcNAQEBBQADggEP +ADCCAQoCggEBALGdif7vCqwoWg001wmw2X3HnF/9cjZGTY6BWiex3cIarO+aby6L +QObv7lXzzh3r7bJc1JquaawKUek6CIt2mNM+KLAIscScNUOCYg4T1XOD0rh3Qrin +V8Q+hY8InSrUqN4cuX95YOdJoOddw3mDXs376fcNBU10raP4L7k7EsyvnQqIKyNP +ysU9PpDoDLPCMBEGB8cDASv1bkopvvH9u5sic1OHtTLVllsbGNnG6Y9B+1ysG1UO +iJFAX+teigPXKVokJ1+a8dt1CkzDd+iTK1j6PrY+TXc4XOhP/cSnbxwq6JDzkkSb +3pMTJK8ypi7DQNkDbPx73A8qbjRT32gJz4ECAwEAAaNPME0wDAYDVR0TAQH/BAIw +ADAdBgNVHQ4EFgQUCIQ1MChHCo6/1mI6B7S6QPPvEZcwCwYDVR0PBAQDAgXgMBEG +CWCGSAGG+EIBAQQEAwIGQDANBgkqhkiG9w0BAQUFAAOCAQEAZas05SOIsNFmKUYY +kyR1ctlgaA7OZwSzeRPh6vZJ4YaT2lVhNPUeO84tf3LqKE8B827FzWH9mcO/2zeJ +6PTR+QYls/wg8VR881V0Xb5KVNGfwTYpmfhH9+JSzKvKiEtlOoHyvYBMdUon7LJL +ojvlragwXm4QA246345+md5C8PEyQYQf/AoZVZWeLL/BRXZ2ZjsuIT+LzpMIXuTW +AKoH7IlFbKQ5tccQDGCzZb6V1txRDFlKZ/5bvFQZqo12n0MeJy2WPjrmeRm2NC+9 +imP9oR9GIGNyGKTT1h1qjnaZZwK24cx/82eb63qQKUx80pD4DYW9EDU6/tULz5gs +Kw0iig== +-----END CERTIFICATE-----