Allow to use custom TrustManagerFactory for JdkSslServerContent and OpenSslServerContext

Motivation:

When using client auth it is sometimes needed to use a custom TrustManagerFactory.

Modifications:

Allow to pass in TrustManagerFactory

Result:

It's now possible to use custom TrustManagerFactories for JdkSslServerContext and OpenSslServerContext
This commit is contained in:
Norman Maurer 2014-10-22 11:18:00 +02:00 committed by Norman Maurer
parent 16f69985d4
commit a86a2f6478
2 changed files with 52 additions and 22 deletions

View File

@ -67,7 +67,8 @@ public final class OpenSslServerContext extends OpenSslContext {
* {@code null} if it's not password-protected. * {@code null} if it's not password-protected.
*/ */
public OpenSslServerContext(File certChainFile, File keyFile, String keyPassword) throws SSLException { public OpenSslServerContext(File certChainFile, File keyFile, String keyPassword) throws SSLException {
this(certChainFile, keyFile, keyPassword, null, OpenSslDefaultApplicationProtocolNegotiator.INSTANCE, 0, 0); this(certChainFile, keyFile, keyPassword, null, null,
OpenSslDefaultApplicationProtocolNegotiator.INSTANCE, 0, 0);
} }
/** /**
@ -89,7 +90,8 @@ public final class OpenSslServerContext extends OpenSslContext {
File certChainFile, File keyFile, String keyPassword, File certChainFile, File keyFile, String keyPassword,
Iterable<String> ciphers, ApplicationProtocolConfig apn, Iterable<String> ciphers, ApplicationProtocolConfig apn,
long sessionCacheSize, long sessionTimeout) throws SSLException { long sessionCacheSize, long sessionTimeout) throws SSLException {
this(certChainFile, keyFile, keyPassword, ciphers, toNegotiator(apn, false), sessionCacheSize, sessionTimeout); this(certChainFile, keyFile, keyPassword, null, ciphers,
toNegotiator(apn, false), sessionCacheSize, sessionTimeout);
} }
/** /**
@ -117,7 +119,7 @@ public final class OpenSslServerContext extends OpenSslContext {
Iterable<String> ciphers, Iterable<String> nextProtocols, Iterable<String> ciphers, Iterable<String> nextProtocols,
long sessionCacheSize, long sessionTimeout) throws SSLException { long sessionCacheSize, long sessionTimeout) throws SSLException {
this(certChainFile, keyFile, keyPassword, ciphers, this(certChainFile, keyFile, keyPassword, ciphers,
toApplicationProtocolConfig(nextProtocols), sessionCacheSize, sessionTimeout); toApplicationProtocolConfig(nextProtocols), sessionCacheSize, sessionTimeout);
} }
/** /**
@ -136,12 +138,12 @@ public final class OpenSslServerContext extends OpenSslContext {
* {@code 0} to use the default value. * {@code 0} to use the default value.
*/ */
public OpenSslServerContext( public OpenSslServerContext(
File certChainFile, File keyFile, String keyPassword, File certChainFile, File keyFile, String keyPassword, TrustManagerFactory trustManagerFactory,
Iterable<String> ciphers, OpenSslApplicationProtocolNegotiator apn, Iterable<String> ciphers, OpenSslApplicationProtocolNegotiator apn,
long sessionCacheSize, long sessionTimeout) throws SSLException { long sessionCacheSize, long sessionTimeout) throws SSLException {
super(ciphers, apn, sessionCacheSize, sessionTimeout, SSL.SSL_MODE_SERVER); super(ciphers, apn, sessionCacheSize, sessionTimeout, SSL.SSL_MODE_SERVER);
OpenSsl.ensureAvailability(); OpenSsl.ensureAvailability();
checkNotNull(certChainFile, "certChainFile"); checkNotNull(certChainFile, "certChainFile");
if (!certChainFile.isFile()) { if (!certChainFile.isFile()) {
@ -218,11 +220,16 @@ public final class OpenSslServerContext extends OpenSslContext {
ks.setKeyEntry("key", key, keyPasswordChars, certChain.toArray(new Certificate[certChain.size()])); ks.setKeyEntry("key", key, keyPasswordChars, certChain.toArray(new Certificate[certChain.size()]));
// This mimics the behavior of using SSLContext.init(...); if (trustManagerFactory == null) {
TrustManagerFactory factory = TrustManagerFactory.getInstance( // Mimic the way SSLContext.getInstance(KeyManager[], null, null) works
TrustManagerFactory.getDefaultAlgorithm()); trustManagerFactory = TrustManagerFactory.getInstance(
factory.init((KeyStore) null); TrustManagerFactory.getDefaultAlgorithm());
final X509TrustManager manager = chooseTrustManager(factory.getTrustManagers()); trustManagerFactory.init((KeyStore) null);
} else {
trustManagerFactory.init(ks);
}
final X509TrustManager manager = chooseTrustManager(trustManagerFactory.getTrustManagers());
SSLContext.setCertVerifyCallback(ctx, new CertificateVerifier() { SSLContext.setCertVerifyCallback(ctx, new CertificateVerifier() {
@Override @Override
public boolean verify(long ssl, byte[][] chain, String auth) { public boolean verify(long ssl, byte[][] chain, String auth) {

View File

@ -16,9 +16,7 @@
package io.netty.handler.ssl; package io.netty.handler.ssl;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator; import io.netty.buffer.ByteBufAllocator;
import io.netty.buffer.ByteBufInputStream;
import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline; import io.netty.channel.ChannelPipeline;
import io.netty.handler.ssl.ApplicationProtocolConfig.Protocol; import io.netty.handler.ssl.ApplicationProtocolConfig.Protocol;
@ -38,17 +36,13 @@ 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.TrustManagerFactory; import javax.net.ssl.TrustManagerFactory;
import javax.security.auth.x500.X500Principal;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.security.InvalidAlgorithmParameterException; import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException; import java.security.InvalidKeyException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException; import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory; import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.spec.InvalidKeySpecException; import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.PKCS8EncodedKeySpec;
import java.util.List; import java.util.List;
@ -246,10 +240,42 @@ public abstract class SslContext {
File certChainFile, File keyFile, String keyPassword, File certChainFile, File keyFile, String keyPassword,
Iterable<String> ciphers, Iterable<String> nextProtocols, Iterable<String> ciphers, Iterable<String> nextProtocols,
long sessionCacheSize, long sessionTimeout) throws SSLException { long sessionCacheSize, long sessionTimeout) throws SSLException {
return newServerContext(provider, certChainFile, keyFile, keyPassword,
ciphers, IdentityCipherSuiteFilter.INSTANCE,
toApplicationProtocolConfig(nextProtocols), sessionCacheSize, sessionTimeout);
}
/**
* Creates a new server-side {@link SslContext}.
*
* @param provider the {@link SslContext} implementation to use.
* {@code null} to use the current default one.
* @param certChainFile 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}.
* {@code null} if it's not password-protected.
* @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link javax.net.ssl.TrustManager}s
* that verifies the certificates sent from servers.
* {@code null} to use the default.
* @param ciphers the cipher suites to enable, in the order of preference.
* {@code null} to use the default cipher suites.
* @param nextProtocols the application layer protocols to accept, in the order of preference.
* {@code null} to disable TLS NPN/ALPN extension.
* @param sessionCacheSize the size of the cache used for storing SSL session objects.
* {@code 0} to use the default value.
* @param sessionTimeout the timeout for the cached SSL session objects, in seconds.
* {@code 0} to use the default value.
* @return a new server-side {@link SslContext}
*/
public static SslContext newServerContext(
SslProvider provider,
File certChainFile, File keyFile, String keyPassword, TrustManagerFactory trustManagerFactory,
Iterable<String> ciphers, Iterable<String> nextProtocols,
long sessionCacheSize, long sessionTimeout) throws SSLException {
return newServerContext( return newServerContext(
provider, certChainFile, keyFile, keyPassword, provider, null, trustManagerFactory, certChainFile, keyFile, keyPassword,
ciphers, IdentityCipherSuiteFilter.INSTANCE, null, ciphers, IdentityCipherSuiteFilter.INSTANCE,
toApplicationProtocolConfig(nextProtocols), sessionCacheSize, sessionTimeout); toApplicationProtocolConfig(nextProtocols), sessionCacheSize, sessionTimeout);
} }
@ -329,9 +355,6 @@ public abstract class SslContext {
trustCertChainFile, trustManagerFactory, keyCertChainFile, keyFile, keyPassword, trustCertChainFile, trustManagerFactory, keyCertChainFile, keyFile, keyPassword,
keyManagerFactory, ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout); keyManagerFactory, ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout);
case OPENSSL: case OPENSSL:
if (trustCertChainFile != null) {
throw new UnsupportedOperationException("OpenSSL provider does not support mutual authentication");
}
return new OpenSslServerContext( return new OpenSslServerContext(
keyCertChainFile, keyFile, keyPassword, keyCertChainFile, keyFile, keyPassword,
ciphers, apn, sessionCacheSize, sessionTimeout); ciphers, apn, sessionCacheSize, sessionTimeout);