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 9ee97791bd..1b19dc653d 100644 --- a/handler/src/main/java/io/netty/handler/ssl/OpenSslClientContext.java +++ b/handler/src/main/java/io/netty/handler/ssl/OpenSslClientContext.java @@ -21,6 +21,7 @@ import java.io.File; import java.security.KeyStore; import java.security.PrivateKey; import java.security.cert.X509Certificate; +import java.util.Map; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLException; @@ -184,10 +185,11 @@ public final class OpenSslClientContext extends OpenSslContext { X509Certificate[] keyCertChain, PrivateKey key, String keyPassword, KeyManagerFactory keyManagerFactory, Iterable ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn, String[] protocols, - long sessionCacheSize, long sessionTimeout, boolean enableOcsp, String keyStore) + long sessionCacheSize, long sessionTimeout, boolean enableOcsp, String keyStore, + Map.Entry, Object>... options) throws SSLException { super(ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, SSL.SSL_MODE_CLIENT, keyCertChain, - ClientAuth.NONE, protocols, false, enableOcsp); + ClientAuth.NONE, protocols, false, enableOcsp, options); boolean success = false; try { OpenSslKeyMaterialProvider.validateKeyMaterialSupported(keyCertChain, key, keyPassword); diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslContext.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslContext.java index 78cd7cba17..c3273fdcb2 100644 --- a/handler/src/main/java/io/netty/handler/ssl/OpenSslContext.java +++ b/handler/src/main/java/io/netty/handler/ssl/OpenSslContext.java @@ -18,6 +18,7 @@ package io.netty.handler.ssl; import io.netty.buffer.ByteBufAllocator; import java.security.cert.Certificate; +import java.util.Map; import javax.net.ssl.SSLEngine; import javax.net.ssl.SSLException; @@ -29,19 +30,20 @@ import javax.net.ssl.SSLException; public abstract class OpenSslContext extends ReferenceCountedOpenSslContext { OpenSslContext(Iterable ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apnCfg, long sessionCacheSize, long sessionTimeout, int mode, Certificate[] keyCertChain, - ClientAuth clientAuth, String[] protocols, boolean startTls, boolean enableOcsp) + ClientAuth clientAuth, String[] protocols, boolean startTls, boolean enableOcsp, + Map.Entry, Object>... options) throws SSLException { - super(ciphers, cipherFilter, apnCfg, sessionCacheSize, sessionTimeout, mode, keyCertChain, - clientAuth, protocols, startTls, enableOcsp, false); + super(ciphers, cipherFilter, toNegotiator(apnCfg), sessionCacheSize, sessionTimeout, mode, keyCertChain, + clientAuth, protocols, startTls, enableOcsp, false, options); } OpenSslContext(Iterable ciphers, CipherSuiteFilter cipherFilter, OpenSslApplicationProtocolNegotiator apn, long sessionCacheSize, long sessionTimeout, int mode, Certificate[] keyCertChain, ClientAuth clientAuth, String[] protocols, boolean startTls, - boolean enableOcsp) throws SSLException { + boolean enableOcsp, Map.Entry, Object>... options) throws SSLException { super(ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, mode, keyCertChain, clientAuth, protocols, - startTls, enableOcsp, false); + startTls, enableOcsp, false, options); } @Override diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslContextOption.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslContextOption.java new file mode 100644 index 0000000000..5cfd7da3d0 --- /dev/null +++ b/handler/src/main/java/io/netty/handler/ssl/OpenSslContextOption.java @@ -0,0 +1,52 @@ +/* + * Copyright 2021 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: + * + * https://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; + +/** + * {@link SslContextOption}s that are specific to the {@link SslProvider#OPENSSL} / {@link SslProvider#OPENSSL_REFCNT}. + * + * @param the type of the value. + */ +public final class OpenSslContextOption extends SslContextOption { + + private OpenSslContextOption(String name) { + super(name); + } + + /** + * If enabled heavy-operations may be offloaded from the {@link io.netty.channel.EventLoop} if possible. + */ + public static final OpenSslContextOption USE_TASKS = + new OpenSslContextOption("USE_TASKS"); + /** + * If enabled TLS false start will be enabled if supported. + * When TLS false start is enabled the flow of {@link SslHandshakeCompletionEvent}s may be different compared when, + * not enabled. + * + * This is currently only supported when {@code BoringSSL} and ALPN is used. + */ + public static final OpenSslContextOption TLS_FALSE_START = + new OpenSslContextOption("TLS_FALSE_START"); + + /** + * Set the {@link OpenSslPrivateKeyMethod} to use. This allows to offload private-key operations + * if needed. + * + * This is currently only supported when {@code BoringSSL} is used. + */ + public static final OpenSslContextOption PRIVATE_KEY_METHOD = + new OpenSslContextOption("PRIVATE_KEY_METHOD"); +} 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 e0ae6130c8..2ab132b9e4 100644 --- a/handler/src/main/java/io/netty/handler/ssl/OpenSslServerContext.java +++ b/handler/src/main/java/io/netty/handler/ssl/OpenSslServerContext.java @@ -21,6 +21,7 @@ import java.io.File; import java.security.KeyStore; import java.security.PrivateKey; import java.security.cert.X509Certificate; +import java.util.Map; import javax.net.ssl.KeyManager; import javax.net.ssl.KeyManagerFactory; @@ -330,10 +331,11 @@ public final class OpenSslServerContext extends OpenSslContext { X509Certificate[] keyCertChain, PrivateKey key, String keyPassword, KeyManagerFactory keyManagerFactory, Iterable ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn, long sessionCacheSize, long sessionTimeout, ClientAuth clientAuth, String[] protocols, boolean startTls, - boolean enableOcsp, String keyStore) throws SSLException { + boolean enableOcsp, String keyStore, Map.Entry, Object>... options) + throws SSLException { this(trustCertCollection, trustManagerFactory, keyCertChain, key, keyPassword, keyManagerFactory, ciphers, cipherFilter, toNegotiator(apn), sessionCacheSize, sessionTimeout, clientAuth, protocols, startTls, - enableOcsp, keyStore); + enableOcsp, keyStore, options); } @SuppressWarnings("deprecation") @@ -342,9 +344,10 @@ public final class OpenSslServerContext extends OpenSslContext { X509Certificate[] keyCertChain, PrivateKey key, String keyPassword, KeyManagerFactory keyManagerFactory, Iterable ciphers, CipherSuiteFilter cipherFilter, OpenSslApplicationProtocolNegotiator apn, long sessionCacheSize, long sessionTimeout, ClientAuth clientAuth, String[] protocols, boolean startTls, - boolean enableOcsp, String keyStore) throws SSLException { + boolean enableOcsp, String keyStore, Map.Entry, Object>... options) + throws SSLException { super(ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, SSL.SSL_MODE_SERVER, keyCertChain, - clientAuth, protocols, startTls, enableOcsp); + clientAuth, protocols, startTls, enableOcsp, options); // Create a new SSL_CTX and configure it. boolean success = false; diff --git a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslClientContext.java b/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslClientContext.java index 3a050cfd06..ad00fb560b 100644 --- a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslClientContext.java +++ b/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslClientContext.java @@ -18,8 +18,6 @@ package io.netty.handler.ssl; import io.netty.internal.tcnative.CertificateCallback; import io.netty.util.internal.SuppressJava6Requirement; import io.netty.util.internal.SystemPropertyUtil; -import io.netty.util.internal.logging.InternalLogger; -import io.netty.util.internal.logging.InternalLoggerFactory; import io.netty.internal.tcnative.SSL; import io.netty.internal.tcnative.SSLContext; @@ -31,6 +29,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.LinkedHashSet; +import java.util.Map; import java.util.Set; import javax.net.ssl.KeyManagerFactory; @@ -65,9 +64,10 @@ public final class ReferenceCountedOpenSslClientContext extends ReferenceCounted KeyManagerFactory keyManagerFactory, Iterable ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn, String[] protocols, long sessionCacheSize, long sessionTimeout, - boolean enableOcsp, String keyStore) throws SSLException { - super(ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, SSL.SSL_MODE_CLIENT, keyCertChain, - ClientAuth.NONE, protocols, false, enableOcsp, true); + boolean enableOcsp, String keyStore, + Map.Entry, Object>... options) throws SSLException { + super(ciphers, cipherFilter, toNegotiator(apn), sessionCacheSize, sessionTimeout, SSL.SSL_MODE_CLIENT, + keyCertChain, ClientAuth.NONE, protocols, false, enableOcsp, true, options); boolean success = false; try { sessionContext = newSessionContext(this, ctx, engineMap, trustCertCollection, trustManagerFactory, diff --git a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslContext.java b/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslContext.java index 7f631deba1..14d1865e9a 100644 --- a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslContext.java +++ b/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslContext.java @@ -179,19 +179,14 @@ public abstract class ReferenceCountedOpenSslContext extends SslContext implemen DH_KEY_LENGTH = dhLen; } - ReferenceCountedOpenSslContext(Iterable ciphers, CipherSuiteFilter cipherFilter, - ApplicationProtocolConfig apnCfg, long sessionCacheSize, long sessionTimeout, - int mode, Certificate[] keyCertChain, ClientAuth clientAuth, String[] protocols, - boolean startTls, boolean enableOcsp, boolean leakDetection) throws SSLException { - this(ciphers, cipherFilter, toNegotiator(apnCfg), sessionCacheSize, sessionTimeout, mode, keyCertChain, - clientAuth, protocols, startTls, enableOcsp, leakDetection); - } + final boolean tlsFalseStart; ReferenceCountedOpenSslContext(Iterable ciphers, CipherSuiteFilter cipherFilter, OpenSslApplicationProtocolNegotiator apn, long sessionCacheSize, long sessionTimeout, int mode, Certificate[] keyCertChain, ClientAuth clientAuth, String[] protocols, boolean startTls, boolean enableOcsp, - boolean leakDetection) throws SSLException { + boolean leakDetection, Map.Entry, Object>... ctxOptions) + throws SSLException { super(startTls); OpenSsl.ensureAvailability(); @@ -203,6 +198,29 @@ public abstract class ReferenceCountedOpenSslContext extends SslContext implemen if (mode != SSL.SSL_MODE_SERVER && mode != SSL.SSL_MODE_CLIENT) { throw new IllegalArgumentException("mode most be either SSL.SSL_MODE_SERVER or SSL.SSL_MODE_CLIENT"); } + + boolean tlsFalseStart = false; + boolean useTasks = USE_TASKS; + OpenSslPrivateKeyMethod privateKeyMethod = null; + + if (ctxOptions != null) { + for (Map.Entry, Object> ctxOpt : ctxOptions) { + SslContextOption option = ctxOpt.getKey(); + + if (option == OpenSslContextOption.TLS_FALSE_START) { + tlsFalseStart = (Boolean) ctxOpt.getValue(); + } else if (option == OpenSslContextOption.USE_TASKS) { + useTasks = (Boolean) ctxOpt.getValue(); + } else if (option == OpenSslContextOption.PRIVATE_KEY_METHOD) { + privateKeyMethod = (OpenSslPrivateKeyMethod) ctxOpt.getValue(); + } else { + logger.debug("Skipping unsupported " + SslContextOption.class.getSimpleName() + + ": " + ctxOpt.getKey()); + } + } + } + this.tlsFalseStart = tlsFalseStart; + leak = leakDetection ? leakDetector.track(this) : null; this.mode = mode; this.clientAuth = isServer() ? checkNotNull(clientAuth, "clientAuth") : ClientAuth.NONE; @@ -335,7 +353,10 @@ public abstract class ReferenceCountedOpenSslContext extends SslContext implemen SSLContext.enableOcsp(ctx, isClient()); } - SSLContext.setUseTasks(ctx, USE_TASKS); + SSLContext.setUseTasks(ctx, useTasks); + if (privateKeyMethod != null) { + SSLContext.setPrivateKeyMethod(ctx, new PrivateKeyMethod(engineMap, privateKeyMethod)); + } success = true; } finally { if (!success) { @@ -514,8 +535,11 @@ public abstract class ReferenceCountedOpenSslContext extends SslContext implemen * * This method is currently only supported when {@code BoringSSL} is used. * - * @param method method to use. + * @param method method to use. + * @deprecated use {@link SslContextBuilder#option(SslContextOption, Object)} with + * {@link OpenSslContextOption#PRIVATE_KEY_METHOD}. */ + @Deprecated @UnstableApi public final void setPrivateKeyMethod(OpenSslPrivateKeyMethod method) { ObjectUtil.checkNotNull(method, "method"); @@ -528,6 +552,11 @@ public abstract class ReferenceCountedOpenSslContext extends SslContext implemen } } + /** + * @deprecated use {@link SslContextBuilder#option(SslContextOption, Object)} with + * {@link OpenSslContextOption#USE_TASKS}. + */ + @Deprecated public final void setUseTasks(boolean useTasks) { Lock writerLock = ctxLock.writeLock(); writerLock.lock(); diff --git a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslEngine.java b/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslEngine.java index 7f0c269e23..7dd28d6de1 100644 --- a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslEngine.java +++ b/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslEngine.java @@ -357,10 +357,16 @@ public class ReferenceCountedOpenSslEngine extends SSLEngine implements Referenc SSL.enableOcsp(ssl); } - if (!jdkCompatibilityMode) { - SSL.setMode(ssl, SSL.getMode(ssl) | SSL.SSL_MODE_ENABLE_PARTIAL_WRITE); + int mode = SSL.getMode(ssl); + if (context.tlsFalseStart) { + mode |= SSL.SSL_MODE_ENABLE_FALSE_START; } + if (!jdkCompatibilityMode) { + mode |= SSL.SSL_MODE_ENABLE_PARTIAL_WRITE; + } + SSL.setMode(ssl, mode); + // setMode may impact the overhead. calculateMaxWrapOverhead(); } catch (Throwable cause) { diff --git a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslServerContext.java b/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslServerContext.java index 33d0e7e9b4..c75307f3a2 100644 --- a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslServerContext.java +++ b/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslServerContext.java @@ -30,6 +30,7 @@ import io.netty.util.internal.logging.InternalLoggerFactory; import java.security.KeyStore; import java.security.PrivateKey; import java.security.cert.X509Certificate; +import java.util.Map; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLException; import javax.net.ssl.TrustManagerFactory; @@ -60,10 +61,11 @@ public final class ReferenceCountedOpenSslServerContext extends ReferenceCounted X509Certificate[] keyCertChain, PrivateKey key, String keyPassword, KeyManagerFactory keyManagerFactory, Iterable ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn, long sessionCacheSize, long sessionTimeout, ClientAuth clientAuth, String[] protocols, boolean startTls, - boolean enableOcsp, String keyStore) throws SSLException { + boolean enableOcsp, String keyStore, Map.Entry, Object>... options) + throws SSLException { this(trustCertCollection, trustManagerFactory, keyCertChain, key, keyPassword, keyManagerFactory, ciphers, cipherFilter, toNegotiator(apn), sessionCacheSize, sessionTimeout, clientAuth, protocols, startTls, - enableOcsp, keyStore); + enableOcsp, keyStore, options); } ReferenceCountedOpenSslServerContext( @@ -71,9 +73,10 @@ public final class ReferenceCountedOpenSslServerContext extends ReferenceCounted X509Certificate[] keyCertChain, PrivateKey key, String keyPassword, KeyManagerFactory keyManagerFactory, Iterable ciphers, CipherSuiteFilter cipherFilter, OpenSslApplicationProtocolNegotiator apn, long sessionCacheSize, long sessionTimeout, ClientAuth clientAuth, String[] protocols, boolean startTls, - boolean enableOcsp, String keyStore) throws SSLException { + boolean enableOcsp, String keyStore, Map.Entry, Object>... options) + throws SSLException { super(ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, SSL.SSL_MODE_SERVER, keyCertChain, - clientAuth, protocols, startTls, enableOcsp, true); + clientAuth, protocols, startTls, enableOcsp, true, options); // Create a new SSL_CTX and configure it. boolean success = false; try { 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 445f4424fd..ab03a91fef 100644 --- a/handler/src/main/java/io/netty/handler/ssl/SslContext.java +++ b/handler/src/main/java/io/netty/handler/ssl/SslContext.java @@ -62,6 +62,7 @@ import java.security.cert.X509Certificate; import java.security.spec.InvalidKeySpecException; import java.security.spec.PKCS8EncodedKeySpec; import java.util.List; +import java.util.Map; import java.util.concurrent.Executor; /** @@ -451,7 +452,8 @@ public abstract class SslContext { X509Certificate[] keyCertChain, PrivateKey key, String keyPassword, KeyManagerFactory keyManagerFactory, Iterable ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn, long sessionCacheSize, long sessionTimeout, ClientAuth clientAuth, String[] protocols, boolean startTls, - boolean enableOcsp, String keyStoreType) throws SSLException { + boolean enableOcsp, String keyStoreType, Map.Entry, Object>... ctxOptions) + throws SSLException { if (provider == null) { provider = defaultServerProvider(); @@ -471,13 +473,13 @@ public abstract class SslContext { return new OpenSslServerContext( trustCertCollection, trustManagerFactory, keyCertChain, key, keyPassword, keyManagerFactory, ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, - clientAuth, protocols, startTls, enableOcsp, keyStoreType); + clientAuth, protocols, startTls, enableOcsp, keyStoreType, ctxOptions); case OPENSSL_REFCNT: verifyNullSslContextProvider(provider, sslContextProvider); return new ReferenceCountedOpenSslServerContext( trustCertCollection, trustManagerFactory, keyCertChain, key, keyPassword, keyManagerFactory, ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, - clientAuth, protocols, startTls, enableOcsp, keyStoreType); + clientAuth, protocols, startTls, enableOcsp, keyStoreType, ctxOptions); default: throw new Error(provider.toString()); } @@ -809,7 +811,8 @@ public abstract class SslContext { X509Certificate[] trustCert, TrustManagerFactory trustManagerFactory, X509Certificate[] keyCertChain, PrivateKey key, String keyPassword, KeyManagerFactory keyManagerFactory, Iterable ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn, String[] protocols, - long sessionCacheSize, long sessionTimeout, boolean enableOcsp, String keyStoreType) throws SSLException { + long sessionCacheSize, long sessionTimeout, boolean enableOcsp, String keyStoreType, + Map.Entry, Object>... options) throws SSLException { if (provider == null) { provider = defaultClientProvider(); } @@ -827,13 +830,13 @@ public abstract class SslContext { return new OpenSslClientContext( trustCert, trustManagerFactory, keyCertChain, key, keyPassword, keyManagerFactory, ciphers, cipherFilter, apn, protocols, sessionCacheSize, sessionTimeout, - enableOcsp, keyStoreType); + enableOcsp, keyStoreType, options); case OPENSSL_REFCNT: verifyNullSslContextProvider(provider, sslContextProvider); return new ReferenceCountedOpenSslClientContext( trustCert, trustManagerFactory, keyCertChain, key, keyPassword, keyManagerFactory, ciphers, cipherFilter, apn, protocols, sessionCacheSize, sessionTimeout, - enableOcsp, keyStoreType); + enableOcsp, keyStoreType, options); default: throw new Error(provider.toString()); } 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 9bef8bd4fd..3c30ee56e4 100644 --- a/handler/src/main/java/io/netty/handler/ssl/SslContextBuilder.java +++ b/handler/src/main/java/io/netty/handler/ssl/SslContextBuilder.java @@ -33,7 +33,9 @@ import java.security.PrivateKey; import java.security.Provider; import java.security.cert.X509Certificate; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; import static io.netty.util.internal.EmptyArrays.EMPTY_STRINGS; import static io.netty.util.internal.EmptyArrays.EMPTY_X509_CERTIFICATES; @@ -43,6 +45,8 @@ import static io.netty.util.internal.ObjectUtil.checkNotNull; * Builder for configuring a new SslContext for creation. */ public final class SslContextBuilder { + @SuppressWarnings("rawtypes") + private static final Map.Entry[] EMPTY_ENTRIES = new Map.Entry[0]; /** * Creates a builder for new client-side {@link SslContext}. @@ -201,11 +205,24 @@ public final class SslContextBuilder { private boolean startTls; private boolean enableOcsp; private String keyStoreType = KeyStore.getDefaultType(); + private final Map, Object> options = new HashMap, Object>(); private SslContextBuilder(boolean forServer) { this.forServer = forServer; } + /** + * Configure a {@link SslContextOption}. + */ + public SslContextBuilder option(SslContextOption option, T value) { + if (value == null) { + options.remove(option); + } else { + options.put(option, value); + } + return this; + } + /** * The {@link SslContext} implementation to use. {@code null} uses the default one. */ @@ -592,11 +609,12 @@ public final class SslContextBuilder { return SslContext.newServerContextInternal(provider, sslContextProvider, trustCertCollection, trustManagerFactory, keyCertChain, key, keyPassword, keyManagerFactory, ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, clientAuth, protocols, startTls, - enableOcsp, keyStoreType); + enableOcsp, keyStoreType, toArray(options.entrySet(), EMPTY_ENTRIES)); } else { return SslContext.newClientContextInternal(provider, sslContextProvider, trustCertCollection, trustManagerFactory, keyCertChain, key, keyPassword, keyManagerFactory, - ciphers, cipherFilter, apn, protocols, sessionCacheSize, sessionTimeout, enableOcsp, keyStoreType); + ciphers, cipherFilter, apn, protocols, sessionCacheSize, sessionTimeout, enableOcsp, keyStoreType, + toArray(options.entrySet(), EMPTY_ENTRIES)); } } diff --git a/handler/src/main/java/io/netty/handler/ssl/SslContextOption.java b/handler/src/main/java/io/netty/handler/ssl/SslContextOption.java new file mode 100644 index 0000000000..36491d5086 --- /dev/null +++ b/handler/src/main/java/io/netty/handler/ssl/SslContextOption.java @@ -0,0 +1,86 @@ +/* + * Copyright 2021 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: + * + * https://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 io.netty.util.AbstractConstant; +import io.netty.util.ConstantPool; +import io.netty.util.internal.ObjectUtil; + + +/** + * A {@link SslContextOption} allows to configure a {@link SslContext} in a type-safe + * way. Which {@link SslContextOption} is supported depends on the actual implementation + * of {@link SslContext} and may depend on the nature of the SSL implementation it belongs + * to. + * + * @param the type of the value which is valid for the {@link SslContextOption} + */ +public class SslContextOption extends AbstractConstant> { + + private static final ConstantPool> pool = new ConstantPool>() { + @Override + protected SslContextOption newConstant(int id, String name) { + return new SslContextOption(id, name); + } + }; + + /** + * Returns the {@link SslContextOption} of the specified name. + */ + @SuppressWarnings("unchecked") + public static SslContextOption valueOf(String name) { + return (SslContextOption) pool.valueOf(name); + } + + /** + * Shortcut of {@link #valueOf(String) valueOf(firstNameComponent.getName() + "#" + secondNameComponent)}. + */ + @SuppressWarnings("unchecked") + public static SslContextOption valueOf(Class firstNameComponent, String secondNameComponent) { + return (SslContextOption) pool.valueOf(firstNameComponent, secondNameComponent); + } + + /** + * Returns {@code true} if a {@link SslContextOption} exists for the given {@code name}. + */ + public static boolean exists(String name) { + return pool.exists(name); + } + + /** + * Creates a new {@link SslContextOption} with the specified unique {@code name}. + */ + private SslContextOption(int id, String name) { + super(id, name); + } + + /** + * Should be used by sub-classes. + * + * @param name the name of the option + */ + protected SslContextOption(String name) { + this(pool.nextId(), name); + } + + /** + * Validate the value which is set for the {@link SslContextOption}. Sub-classes + * may override this for special checks. + */ + public void validate(T value) { + ObjectUtil.checkNotNull(value, "value"); + } +} diff --git a/handler/src/test/java/io/netty/handler/ssl/ConscryptOpenSslEngineInteropTest.java b/handler/src/test/java/io/netty/handler/ssl/ConscryptOpenSslEngineInteropTest.java index f9e7df4c54..3fbaf9d53c 100644 --- a/handler/src/test/java/io/netty/handler/ssl/ConscryptOpenSslEngineInteropTest.java +++ b/handler/src/test/java/io/netty/handler/ssl/ConscryptOpenSslEngineInteropTest.java @@ -155,6 +155,7 @@ public class ConscryptOpenSslEngineInteropTest extends ConscryptSslEngineTest { return Java8SslTestUtils.wrapSSLEngineForTesting(engine); } + @SuppressWarnings("deprecation") @Override protected SslContext wrapContext(SslContext context) { if (context instanceof OpenSslContext) { diff --git a/handler/src/test/java/io/netty/handler/ssl/JdkOpenSslEngineInteroptTest.java b/handler/src/test/java/io/netty/handler/ssl/JdkOpenSslEngineInteroptTest.java index db6609f07a..f32df94370 100644 --- a/handler/src/test/java/io/netty/handler/ssl/JdkOpenSslEngineInteroptTest.java +++ b/handler/src/test/java/io/netty/handler/ssl/JdkOpenSslEngineInteroptTest.java @@ -162,6 +162,7 @@ public class JdkOpenSslEngineInteroptTest extends SSLEngineTest { return Java8SslTestUtils.wrapSSLEngineForTesting(engine); } + @SuppressWarnings("deprecation") @Override protected SslContext wrapContext(SslContext context) { if (context instanceof OpenSslContext) { diff --git a/handler/src/test/java/io/netty/handler/ssl/OpenSslConscryptSslEngineInteropTest.java b/handler/src/test/java/io/netty/handler/ssl/OpenSslConscryptSslEngineInteropTest.java index 0ad9b57e75..9588b6b90c 100644 --- a/handler/src/test/java/io/netty/handler/ssl/OpenSslConscryptSslEngineInteropTest.java +++ b/handler/src/test/java/io/netty/handler/ssl/OpenSslConscryptSslEngineInteropTest.java @@ -147,6 +147,7 @@ public class OpenSslConscryptSslEngineInteropTest extends ConscryptSslEngineTest return Java8SslTestUtils.wrapSSLEngineForTesting(engine); } + @SuppressWarnings("deprecation") @Override protected SslContext wrapContext(SslContext context) { if (context instanceof OpenSslContext) { diff --git a/handler/src/test/java/io/netty/handler/ssl/OpenSslEngineTest.java b/handler/src/test/java/io/netty/handler/ssl/OpenSslEngineTest.java index 25235dd7e2..9207c044d5 100644 --- a/handler/src/test/java/io/netty/handler/ssl/OpenSslEngineTest.java +++ b/handler/src/test/java/io/netty/handler/ssl/OpenSslEngineTest.java @@ -1414,6 +1414,7 @@ public class OpenSslEngineTest extends SSLEngineTest { return (ReferenceCountedOpenSslEngine) engine; } + @SuppressWarnings("deprecation") @Override protected SslContext wrapContext(SslContext context) { if (context instanceof OpenSslContext) { diff --git a/handler/src/test/java/io/netty/handler/ssl/OpenSslJdkSslEngineInteroptTest.java b/handler/src/test/java/io/netty/handler/ssl/OpenSslJdkSslEngineInteroptTest.java index 7477cee484..261b95ee88 100644 --- a/handler/src/test/java/io/netty/handler/ssl/OpenSslJdkSslEngineInteroptTest.java +++ b/handler/src/test/java/io/netty/handler/ssl/OpenSslJdkSslEngineInteroptTest.java @@ -148,6 +148,7 @@ public class OpenSslJdkSslEngineInteroptTest extends SSLEngineTest { return Java8SslTestUtils.wrapSSLEngineForTesting(engine); } + @SuppressWarnings("deprecation") @Override protected SslContext wrapContext(SslContext context) { if (context instanceof OpenSslContext) { diff --git a/handler/src/test/java/io/netty/handler/ssl/OpenSslPrivateKeyMethodTest.java b/handler/src/test/java/io/netty/handler/ssl/OpenSslPrivateKeyMethodTest.java index 01f2c8312c..5c4505a7a9 100644 --- a/handler/src/test/java/io/netty/handler/ssl/OpenSslPrivateKeyMethodTest.java +++ b/handler/src/test/java/io/netty/handler/ssl/OpenSslPrivateKeyMethodTest.java @@ -151,15 +151,13 @@ public class OpenSslPrivateKeyMethodTest { final KeyManagerFactory kmf = OpenSslX509KeyManagerFactory.newKeyless(CERT.cert()); - final SslContext sslServerContext = SslContextBuilder.forServer(kmf) + return SslContextBuilder.forServer(kmf) .sslProvider(SslProvider.OPENSSL) .ciphers(ciphers) // As this is not a TLSv1.3 cipher we should ensure we talk something else. .protocols(SslUtils.PROTOCOL_TLS_V1_2) + .option(OpenSslContextOption.PRIVATE_KEY_METHOD, method) .build(); - - ((OpenSslContext) sslServerContext).setPrivateKeyMethod(method); - return sslServerContext; } private SslContext buildClientContext() throws Exception { diff --git a/handler/src/test/java/io/netty/handler/ssl/ReferenceCountedOpenSslEngineTest.java b/handler/src/test/java/io/netty/handler/ssl/ReferenceCountedOpenSslEngineTest.java index ec28959644..b7a51b2ffe 100644 --- a/handler/src/test/java/io/netty/handler/ssl/ReferenceCountedOpenSslEngineTest.java +++ b/handler/src/test/java/io/netty/handler/ssl/ReferenceCountedOpenSslEngineTest.java @@ -73,6 +73,7 @@ public class ReferenceCountedOpenSslEngineTest extends OpenSslEngineTest { clientSslCtx.newEngine(null); } + @SuppressWarnings("deprecation") @Override protected SslContext wrapContext(SslContext context) { if (context instanceof ReferenceCountedOpenSslContext) {