diff --git a/handler/src/main/java/io/netty/handler/ssl/GroupsConverter.java b/handler/src/main/java/io/netty/handler/ssl/GroupsConverter.java new file mode 100644 index 00000000000..28b332998c3 --- /dev/null +++ b/handler/src/main/java/io/netty/handler/ssl/GroupsConverter.java @@ -0,0 +1,50 @@ +/* + * 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 java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +/** + * Convert java naming to OpenSSL naming if possible and if not return the original name. + */ +final class GroupsConverter { + + private static final Map mappings; + + static { + // See https://tools.ietf.org/search/rfc4492#appendix-A and https://www.java.com/en/configure_crypto.html + Map map = new HashMap(); + map.put("secp224r1", "P-224"); + map.put("prime256v1", "P-256"); + map.put("secp256r1", "P-256"); + map.put("secp384r1", "P-384"); + map.put("secp521r1", "P-521"); + map.put("x25519", "X25519"); + mappings = Collections.unmodifiableMap(map); + } + + static String toOpenSsl(String key) { + String mapping = mappings.get(key); + if (mapping == null) { + return key; + } + return mapping; + } + + private GroupsConverter() { } +} diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSsl.java b/handler/src/main/java/io/netty/handler/ssl/OpenSsl.java index d6fd1814ce1..acf4eb65e63 100644 --- a/handler/src/main/java/io/netty/handler/ssl/OpenSsl.java +++ b/handler/src/main/java/io/netty/handler/ssl/OpenSsl.java @@ -38,6 +38,7 @@ import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.LinkedHashSet; @@ -67,6 +68,12 @@ public final class OpenSsl { static final Set SUPPORTED_PROTOCOLS_SET; static final String[] EXTRA_SUPPORTED_TLS_1_3_CIPHERS; static final String EXTRA_SUPPORTED_TLS_1_3_CIPHERS_STRING; + static final String[] NAMED_GROUPS; + + // Use default that is supported in java 11 and earlier and also in OpenSSL / BoringSSL. + // See https://github.com/netty/netty-tcnative/issues/567 + // See https://www.java.com/en/configure_crypto.html for ordering + private static final String[] DEFAULT_NAMED_GROUPS = { "x25519", "secp256r1", "secp384r1", "secp521r1" }; // self-signed certificate for netty.io and the matching private-key private static final String CERT = "-----BEGIN CERTIFICATE-----\n" + @@ -181,6 +188,11 @@ public final class OpenSsl { boolean supportsKeyManagerFactory = false; boolean useKeyManagerFactory = false; boolean tlsv13Supported = false; + String[] namedGroups = DEFAULT_NAMED_GROUPS; + String[] defaultConvertedNamedGroups = new String[namedGroups.length]; + for (int i = 0; i < namedGroups.length; i++) { + defaultConvertedNamedGroups[i] = GroupsConverter.toOpenSsl(namedGroups[i]); + } IS_BORINGSSL = "BoringSSL".equals(versionString()); if (IS_BORINGSSL) { @@ -313,12 +325,51 @@ public final class OpenSsl { SSL.freePrivateKey(key); } } + + String groups = SystemPropertyUtil.get("jdk.tls.namedGroups", null); + if (groups != null) { + String[] nGroups = groups.split(","); + Set supportedNamedGroups = new LinkedHashSet(nGroups.length); + Set supportedConvertedNamedGroups = new LinkedHashSet(nGroups.length); + + Set unsupportedNamedGroups = new LinkedHashSet(); + for (String namedGroup : nGroups) { + String converted = GroupsConverter.toOpenSsl(namedGroup); + if (SSLContext.setCurvesList(sslCtx, converted)) { + supportedConvertedNamedGroups.add(converted); + supportedNamedGroups.add(namedGroup); + } else { + unsupportedNamedGroups.add(namedGroup); + } + } + + if (supportedNamedGroups.isEmpty()) { + namedGroups = defaultConvertedNamedGroups; + logger.info("All configured namedGroups are not supported: {}. Use default: {}.", + Arrays.toString(unsupportedNamedGroups.toArray(EmptyArrays.EMPTY_STRINGS)), + Arrays.toString(DEFAULT_NAMED_GROUPS)); + } else { + String[] groupArray = supportedNamedGroups.toArray(EmptyArrays.EMPTY_STRINGS); + if (unsupportedNamedGroups.isEmpty()) { + logger.info("Using configured namedGroups -D 'jdk.tls.namedGroup': {} ", + Arrays.toString(groupArray)); + } else { + logger.info("Using supported configured namedGroups: {}. Unsupported namedGroups: {}. ", + Arrays.toString(groupArray), + Arrays.toString(unsupportedNamedGroups.toArray(EmptyArrays.EMPTY_STRINGS))); + } + namedGroups = supportedConvertedNamedGroups.toArray(EmptyArrays.EMPTY_STRINGS); + } + } else { + namedGroups = defaultConvertedNamedGroups; + } } finally { SSLContext.free(sslCtx); } } catch (Exception e) { logger.warn("Failed to get the list of available OpenSSL cipher suites.", e); } + NAMED_GROUPS = namedGroups; AVAILABLE_OPENSSL_CIPHER_SUITES = Collections.unmodifiableSet(availableOpenSslCipherSuites); final Set availableJavaCipherSuites = new LinkedHashSet( AVAILABLE_OPENSSL_CIPHER_SUITES.size() * 2); @@ -399,6 +450,7 @@ public final class OpenSsl { IS_BORINGSSL = false; EXTRA_SUPPORTED_TLS_1_3_CIPHERS = EmptyArrays.EMPTY_STRINGS; EXTRA_SUPPORTED_TLS_1_3_CIPHERS_STRING = StringUtil.EMPTY_STRING; + NAMED_GROUPS = DEFAULT_NAMED_GROUPS; } } 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 3b1b40037dd..82124bfbc3e 100644 --- a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslContext.java +++ b/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslContext.java @@ -117,6 +117,7 @@ public abstract class ReferenceCountedOpenSslContext extends SslContext implemen // https://mail.openjdk.java.net/pipermail/security-dev/2021-March/024758.html static final boolean CLIENT_ENABLE_SESSION_CACHE = SystemPropertyUtil.getBoolean("io.netty.handler.ssl.openssl.sessionCacheClient", false); + /** * The OpenSSL SSL_CTX object. * @@ -384,6 +385,8 @@ public ApplicationProtocolConfig.SelectedListenerFailureBehavior selectedListene if (asyncPrivateKeyMethod != null) { SSLContext.setPrivateKeyMethod(ctx, new AsyncPrivateKeyMethod(engineMap, asyncPrivateKeyMethod)); } + // Set the curves. + SSLContext.setCurvesList(ctx, OpenSsl.NAMED_GROUPS); success = true; } finally { if (!success) { diff --git a/pom.xml b/pom.xml index 4eaa1bd265a..a696f9472bc 100644 --- a/pom.xml +++ b/pom.xml @@ -508,7 +508,7 @@ fedora,suse,arch netty-tcnative - 2.0.41.Final + 2.0.42.Final ${os.detected.classifier} org.conscrypt conscrypt-openjdk-uber