Skip to content

Commit

Permalink
SslContext to support TLS/SSL protocols
Browse files Browse the repository at this point in the history
Motivation:
SslContext and SslContextBuilder do not support a way to specify the desired TLS protocols. This currently requires that the user extracts the SSLEngine once a context is built and manually call SSLEngine#setEnabledProtocols(String[]). Something this critical should be supported at the SslContext level.

Modifications:
- SslContextBuilder should accept a list of protocols to configure for each SslEngine

Result:
SslContext consistently sets the supported TLS/SSL protocols.
  • Loading branch information
Scottmitch committed Mar 8, 2017
1 parent e18c85b commit a230428
Show file tree
Hide file tree
Showing 13 changed files with 123 additions and 62 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -248,16 +248,17 @@ public JdkSslClientContext(File trustCertCollectionFile, TrustManagerFactory tru
trustCertCollectionFile), trustManagerFactory,
toX509CertificatesInternal(keyCertChainFile), toPrivateKeyInternal(keyFile, keyPassword),
keyPassword, keyManagerFactory, sessionCacheSize, sessionTimeout), true,
ciphers, cipherFilter, apn, ClientAuth.NONE, false);
ciphers, cipherFilter, apn, ClientAuth.NONE, null, false);
}

JdkSslClientContext(X509Certificate[] trustCertCollection, TrustManagerFactory trustManagerFactory,
X509Certificate[] keyCertChain, PrivateKey key, String keyPassword,
KeyManagerFactory keyManagerFactory, Iterable<String> ciphers, CipherSuiteFilter cipherFilter,
ApplicationProtocolConfig apn, long sessionCacheSize, long sessionTimeout) throws SSLException {
ApplicationProtocolConfig apn, String[] protocols, long sessionCacheSize, long sessionTimeout)
throws SSLException {
super(newSSLContext(trustCertCollection, trustManagerFactory, keyCertChain, key, keyPassword,
keyManagerFactory, sessionCacheSize, sessionTimeout), true,
ciphers, cipherFilter, toNegotiator(apn, false), ClientAuth.NONE, false);
ciphers, cipherFilter, toNegotiator(apn, false), ClientAuth.NONE, protocols, false);
}

private static SSLContext newSSLContext(X509Certificate[] trustCertCollection,
Expand Down
18 changes: 10 additions & 8 deletions handler/src/main/java/io/netty/handler/ssl/JdkSslContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ public class JdkSslContext extends SslContext {
private static final InternalLogger logger = InternalLoggerFactory.getInstance(JdkSslContext.class);

static final String PROTOCOL = "TLS";
static final String[] PROTOCOLS;
static final String[] DEFAULT_PROTOCOLS;
static final List<String> DEFAULT_CIPHERS;
static final Set<String> SUPPORTED_CIPHERS;

Expand Down Expand Up @@ -80,9 +80,9 @@ public class JdkSslContext extends SslContext {
"TLSv1.2", "TLSv1.1", "TLSv1");

if (!protocols.isEmpty()) {
PROTOCOLS = protocols.toArray(new String[protocols.size()]);
DEFAULT_PROTOCOLS = protocols.toArray(new String[protocols.size()]);
} else {
PROTOCOLS = engine.getEnabledProtocols();
DEFAULT_PROTOCOLS = engine.getEnabledProtocols();
}

// Choose the sensible default list of cipher suites.
Expand Down Expand Up @@ -120,7 +120,7 @@ public class JdkSslContext extends SslContext {
DEFAULT_CIPHERS = Collections.unmodifiableList(ciphers);

if (logger.isDebugEnabled()) {
logger.debug("Default protocols (JDK): {} ", Arrays.asList(PROTOCOLS));
logger.debug("Default protocols (JDK): {} ", Arrays.asList(DEFAULT_PROTOCOLS));
logger.debug("Default cipher suites (JDK): {}", DEFAULT_CIPHERS);
}
}
Expand All @@ -133,6 +133,7 @@ private static void addIfSupported(Set<String> supported, List<String> enabled,
}
}

private final String[] protocols;
private final String[] cipherSuites;
private final List<String> unmodifiableCipherSuites;
private final JdkApplicationProtocolNegotiator apn;
Expand All @@ -150,7 +151,7 @@ private static void addIfSupported(Set<String> supported, List<String> enabled,
public JdkSslContext(SSLContext sslContext, boolean isClient,
ClientAuth clientAuth) {
this(sslContext, isClient, null, IdentityCipherSuiteFilter.INSTANCE,
JdkDefaultApplicationProtocolNegotiator.INSTANCE, clientAuth, false);
JdkDefaultApplicationProtocolNegotiator.INSTANCE, clientAuth, null, false);
}

/**
Expand All @@ -166,16 +167,17 @@ public JdkSslContext(SSLContext sslContext, boolean isClient,
public JdkSslContext(SSLContext sslContext, boolean isClient, Iterable<String> ciphers,
CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn,
ClientAuth clientAuth) {
this(sslContext, isClient, ciphers, cipherFilter, toNegotiator(apn, !isClient), clientAuth, false);
this(sslContext, isClient, ciphers, cipherFilter, toNegotiator(apn, !isClient), clientAuth, null, false);
}

JdkSslContext(SSLContext sslContext, boolean isClient, Iterable<String> ciphers, CipherSuiteFilter cipherFilter,
JdkApplicationProtocolNegotiator apn, ClientAuth clientAuth, boolean startTls) {
JdkApplicationProtocolNegotiator apn, ClientAuth clientAuth, String[] protocols, boolean startTls) {
super(startTls);
this.apn = checkNotNull(apn, "apn");
this.clientAuth = checkNotNull(clientAuth, "clientAuth");
cipherSuites = checkNotNull(cipherFilter, "cipherFilter").filterCipherSuites(
ciphers, DEFAULT_CIPHERS, SUPPORTED_CIPHERS);
this.protocols = protocols == null ? DEFAULT_PROTOCOLS : protocols;
unmodifiableCipherSuites = Collections.unmodifiableList(Arrays.asList(cipherSuites));
this.sslContext = checkNotNull(sslContext, "sslContext");
this.isClient = isClient;
Expand Down Expand Up @@ -232,7 +234,7 @@ public final SSLEngine newEngine(ByteBufAllocator alloc, String peerHost, int pe

private SSLEngine configureAndWrapEngine(SSLEngine engine) {
engine.setEnabledCipherSuites(cipherSuites);
engine.setEnabledProtocols(PROTOCOLS);
engine.setEnabledProtocols(protocols);
engine.setUseClientMode(isClient());
if (isServer()) {
switch (clientAuth) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -215,17 +215,17 @@ public JdkSslServerContext(File trustCertCollectionFile, TrustManagerFactory tru
super(newSSLContext(toX509CertificatesInternal(trustCertCollectionFile), trustManagerFactory,
toX509CertificatesInternal(keyCertChainFile), toPrivateKeyInternal(keyFile, keyPassword),
keyPassword, keyManagerFactory, sessionCacheSize, sessionTimeout), false,
ciphers, cipherFilter, apn, ClientAuth.NONE, false);
ciphers, cipherFilter, apn, ClientAuth.NONE, null, false);
}

JdkSslServerContext(X509Certificate[] trustCertCollection, TrustManagerFactory trustManagerFactory,
X509Certificate[] keyCertChain, PrivateKey key, String keyPassword,
KeyManagerFactory keyManagerFactory, Iterable<String> ciphers, CipherSuiteFilter cipherFilter,
ApplicationProtocolConfig apn, long sessionCacheSize, long sessionTimeout,
ClientAuth clientAuth, boolean startTls) throws SSLException {
ClientAuth clientAuth, String[] protocols, boolean startTls) throws SSLException {
super(newSSLContext(trustCertCollection, trustManagerFactory, keyCertChain, key,
keyPassword, keyManagerFactory, sessionCacheSize, sessionTimeout), false,
ciphers, cipherFilter, toNegotiator(apn, true), clientAuth, startTls);
ciphers, cipherFilter, toNegotiator(apn, true), clientAuth, protocols, startTls);
}

private static SSLContext newSSLContext(X509Certificate[] trustCertCollection,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -175,17 +175,17 @@ public OpenSslClientContext(File trustCertCollectionFile, TrustManagerFactory tr
throws SSLException {
this(toX509CertificatesInternal(trustCertCollectionFile), trustManagerFactory,
toX509CertificatesInternal(keyCertChainFile), toPrivateKeyInternal(keyFile, keyPassword),
keyPassword, keyManagerFactory, ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout);
keyPassword, keyManagerFactory, ciphers, cipherFilter, apn, null, sessionCacheSize, sessionTimeout);
}

OpenSslClientContext(X509Certificate[] trustCertCollection, TrustManagerFactory trustManagerFactory,
X509Certificate[] keyCertChain, PrivateKey key, String keyPassword,
KeyManagerFactory keyManagerFactory, Iterable<String> ciphers,
CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn,
CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn, String[] protocols,
long sessionCacheSize, long sessionTimeout)
throws SSLException {
super(ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, SSL.SSL_MODE_CLIENT, keyCertChain,
ClientAuth.NONE, false);
ClientAuth.NONE, protocols, false);
boolean success = false;
try {
sessionContext = newSessionContext(this, ctx, engineMap, trustCertCollection, trustManagerFactory,
Expand Down
10 changes: 5 additions & 5 deletions handler/src/main/java/io/netty/handler/ssl/OpenSslContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,18 +29,18 @@
public abstract class OpenSslContext extends ReferenceCountedOpenSslContext {
OpenSslContext(Iterable<String> ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apnCfg,
long sessionCacheSize, long sessionTimeout, int mode, Certificate[] keyCertChain,
ClientAuth clientAuth, boolean startTls)
ClientAuth clientAuth, String[] protocols, boolean startTls)
throws SSLException {
super(ciphers, cipherFilter, apnCfg, sessionCacheSize, sessionTimeout, mode, keyCertChain,
clientAuth, startTls, false);
clientAuth, protocols, startTls, false);
}

OpenSslContext(Iterable<String> ciphers, CipherSuiteFilter cipherFilter,
OpenSslApplicationProtocolNegotiator apn, long sessionCacheSize,
long sessionTimeout, int mode, Certificate[] keyCertChain,
ClientAuth clientAuth, boolean startTls) throws SSLException {
super(ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, mode, keyCertChain, clientAuth, startTls,
false);
ClientAuth clientAuth, String[] protocols, boolean startTls) throws SSLException {
super(ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, mode, keyCertChain, clientAuth, protocols,
startTls, false);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -323,26 +323,28 @@ public OpenSslServerContext(
this(toX509CertificatesInternal(trustCertCollectionFile), trustManagerFactory,
toX509CertificatesInternal(keyCertChainFile), toPrivateKeyInternal(keyFile, keyPassword),
keyPassword, keyManagerFactory, ciphers, cipherFilter,
apn, sessionCacheSize, sessionTimeout, ClientAuth.NONE, false);
apn, sessionCacheSize, sessionTimeout, ClientAuth.NONE, null, false);
}

OpenSslServerContext(
X509Certificate[] trustCertCollection, TrustManagerFactory trustManagerFactory,
X509Certificate[] keyCertChain, PrivateKey key, String keyPassword, KeyManagerFactory keyManagerFactory,
Iterable<String> ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn,
long sessionCacheSize, long sessionTimeout, ClientAuth clientAuth, boolean startTls) throws SSLException {
long sessionCacheSize, long sessionTimeout, ClientAuth clientAuth, String[] protocols, boolean startTls)
throws SSLException {
this(trustCertCollection, trustManagerFactory, keyCertChain, key, keyPassword, keyManagerFactory, ciphers,
cipherFilter, toNegotiator(apn), sessionCacheSize, sessionTimeout, clientAuth, startTls);
cipherFilter, toNegotiator(apn), sessionCacheSize, sessionTimeout, clientAuth, protocols, startTls);
}

@SuppressWarnings("deprecation")
private OpenSslServerContext(
X509Certificate[] trustCertCollection, TrustManagerFactory trustManagerFactory,
X509Certificate[] keyCertChain, PrivateKey key, String keyPassword, KeyManagerFactory keyManagerFactory,
Iterable<String> ciphers, CipherSuiteFilter cipherFilter, OpenSslApplicationProtocolNegotiator apn,
long sessionCacheSize, long sessionTimeout, ClientAuth clientAuth, boolean startTls) throws SSLException {
long sessionCacheSize, long sessionTimeout, ClientAuth clientAuth, String[] protocols, boolean startTls)
throws SSLException {
super(ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, SSL.SSL_MODE_SERVER, keyCertChain,
clientAuth, startTls);
clientAuth, protocols, startTls);
// Create a new SSL_CTX and configure it.
boolean success = false;
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,10 @@ public final class ReferenceCountedOpenSslClientContext extends ReferenceCounted
X509Certificate[] keyCertChain, PrivateKey key, String keyPassword,
KeyManagerFactory keyManagerFactory, Iterable<String> ciphers,
CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn,
long sessionCacheSize, long sessionTimeout)
String[] protocols, long sessionCacheSize, long sessionTimeout)
throws SSLException {
super(ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, SSL.SSL_MODE_CLIENT, keyCertChain,
ClientAuth.NONE, false, true);
ClientAuth.NONE, protocols, false, true);
boolean success = false;
try {
sessionContext = newSessionContext(this, ctx, engineMap, trustCertCollection, trustManagerFactory,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ protected void deallocate() {

final Certificate[] keyCertChain;
final ClientAuth clientAuth;
final String[] protocols;
final OpenSslEngineMap engineMap = new DefaultOpenSslEngineMap();
private volatile boolean rejectRemoteInitiatedRenegotiation;
private volatile int bioNonApplicationBufferSize = DEFAULT_BIO_NON_APPLICATION_BUFFER_SIZE;
Expand Down Expand Up @@ -211,16 +212,17 @@ public String run() {

ReferenceCountedOpenSslContext(Iterable<String> ciphers, CipherSuiteFilter cipherFilter,
ApplicationProtocolConfig apnCfg, long sessionCacheSize, long sessionTimeout,
int mode, Certificate[] keyCertChain, ClientAuth clientAuth, boolean startTls,
boolean leakDetection) throws SSLException {
int mode, Certificate[] keyCertChain, ClientAuth clientAuth, String[] protocols,
boolean startTls, boolean leakDetection) throws SSLException {
this(ciphers, cipherFilter, toNegotiator(apnCfg), sessionCacheSize, sessionTimeout, mode, keyCertChain,
clientAuth, startTls, leakDetection);
clientAuth, protocols, startTls, leakDetection);
}

ReferenceCountedOpenSslContext(Iterable<String> ciphers, CipherSuiteFilter cipherFilter,
OpenSslApplicationProtocolNegotiator apn, long sessionCacheSize,
long sessionTimeout, int mode, Certificate[] keyCertChain,
ClientAuth clientAuth, boolean startTls, boolean leakDetection) throws SSLException {
ClientAuth clientAuth, String[] protocols, boolean startTls, boolean leakDetection)
throws SSLException {
super(startTls);

OpenSsl.ensureAvailability();
Expand All @@ -231,6 +233,7 @@ public String run() {
leak = leakDetection ? leakDetector.track(this) : null;
this.mode = mode;
this.clientAuth = isServer() ? checkNotNull(clientAuth, "clientAuth") : ClientAuth.NONE;
this.protocols = protocols;

if (mode == SSL.SSL_MODE_SERVER) {
rejectRemoteInitiatedRenegotiation =
Expand Down Expand Up @@ -305,19 +308,19 @@ public String run() {
List<String> nextProtoList = apn.protocols();
/* Set next protocols for next protocol negotiation extension, if specified */
if (!nextProtoList.isEmpty()) {
String[] protocols = nextProtoList.toArray(new String[nextProtoList.size()]);
String[] appProtocols = nextProtoList.toArray(new String[nextProtoList.size()]);
int selectorBehavior = opensslSelectorFailureBehavior(apn.selectorFailureBehavior());

switch (apn.protocol()) {
case NPN:
SSLContext.setNpnProtos(ctx, protocols, selectorBehavior);
SSLContext.setNpnProtos(ctx, appProtocols, selectorBehavior);
break;
case ALPN:
SSLContext.setAlpnProtos(ctx, protocols, selectorBehavior);
SSLContext.setAlpnProtos(ctx, appProtocols, selectorBehavior);
break;
case NPN_AND_ALPN:
SSLContext.setNpnProtos(ctx, protocols, selectorBehavior);
SSLContext.setAlpnProtos(ctx, protocols, selectorBehavior);
SSLContext.setNpnProtos(ctx, appProtocols, selectorBehavior);
SSLContext.setAlpnProtos(ctx, appProtocols, selectorBehavior);
break;
default:
throw new Error();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,10 @@ protected void deallocate() {
// needed JNI methods.
setClientAuth(clientMode ? ClientAuth.NONE : context.clientAuth);

if (context.protocols != null) {
setEnabledProtocols(context.protocols);
}

// Use SNI if peerHost was specified
// See https://github.com/netty/netty/issues/4746
if (clientMode && peerHost != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,18 +49,20 @@ public final class ReferenceCountedOpenSslServerContext extends ReferenceCounted
X509Certificate[] trustCertCollection, TrustManagerFactory trustManagerFactory,
X509Certificate[] keyCertChain, PrivateKey key, String keyPassword, KeyManagerFactory keyManagerFactory,
Iterable<String> ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn,
long sessionCacheSize, long sessionTimeout, ClientAuth clientAuth, boolean startTls) throws SSLException {
long sessionCacheSize, long sessionTimeout, ClientAuth clientAuth, String[] protocols, boolean startTls)
throws SSLException {
this(trustCertCollection, trustManagerFactory, keyCertChain, key, keyPassword, keyManagerFactory, ciphers,
cipherFilter, toNegotiator(apn), sessionCacheSize, sessionTimeout, clientAuth, startTls);
cipherFilter, toNegotiator(apn), sessionCacheSize, sessionTimeout, clientAuth, protocols, startTls);
}

private ReferenceCountedOpenSslServerContext(
X509Certificate[] trustCertCollection, TrustManagerFactory trustManagerFactory,
X509Certificate[] keyCertChain, PrivateKey key, String keyPassword, KeyManagerFactory keyManagerFactory,
Iterable<String> ciphers, CipherSuiteFilter cipherFilter, OpenSslApplicationProtocolNegotiator apn,
long sessionCacheSize, long sessionTimeout, ClientAuth clientAuth, boolean startTls) throws SSLException {
long sessionCacheSize, long sessionTimeout, ClientAuth clientAuth, String[] protocols, boolean startTls)
throws SSLException {
super(ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, SSL.SSL_MODE_SERVER, keyCertChain,
clientAuth, startTls, true);
clientAuth, protocols, startTls, true);
// Create a new SSL_CTX and configure it.
boolean success = false;
try {
Expand Down
Loading

0 comments on commit a230428

Please sign in to comment.