From 8e3a02f252f43a8ce68c5002d849ec78219cbcbc Mon Sep 17 00:00:00 2001 From: juergw Date: Mon, 15 Dec 2025 09:47:16 +0000 Subject: [PATCH 1/6] Add support for SSLParameters setNamedGroups and getNamedGroups. These methods were added in Java 20, but Conscrypt didn't support them yet. --- .../src/main/java/org/conscrypt/Platform.java | 7 + .../org/conscrypt/ConscryptEngineSocket.java | 2 +- .../ConscryptFileDescriptorSocket.java | 2 +- .../main/java/org/conscrypt/NativeSsl.java | 68 +++++++ .../java/org/conscrypt/OpenSSLSocketImpl.java | 3 + .../java/org/conscrypt/SSLParametersImpl.java | 17 ++ .../javax/net/ssl/SSLSocketTest.java | 185 +++++++++++++++++- .../java/org/conscrypt/Java9PlatformUtil.java | 36 +++- 8 files changed, 311 insertions(+), 9 deletions(-) diff --git a/android/src/main/java/org/conscrypt/Platform.java b/android/src/main/java/org/conscrypt/Platform.java index c4e447a49..83c29dd1b 100644 --- a/android/src/main/java/org/conscrypt/Platform.java +++ b/android/src/main/java/org/conscrypt/Platform.java @@ -254,6 +254,10 @@ private static void setSSLParametersOnImpl(SSLParameters params, SSLParametersIm Method m_getUseCipherSuitesOrder = params.getClass().getMethod("getUseCipherSuitesOrder"); impl.setUseCipherSuitesOrder((boolean) m_getUseCipherSuitesOrder.invoke(params)); + + Method getNamedGroupsMethod = params.getClass().getMethod("getNamedGroups"); + impl.setNamedGroups( + (String[]) getNamedGroupsMethod.invoke(params)); } public static void setSSLParameters( @@ -323,6 +327,9 @@ private static void getSSLParametersFromImpl(SSLParameters params, SSLParameters Method m_setUseCipherSuitesOrder = params.getClass().getMethod("setUseCipherSuitesOrder", boolean.class); m_setUseCipherSuitesOrder.invoke(params, impl.getUseCipherSuitesOrder()); + + Method setNamedGroupsMethod = params.getClass().getMethod("setNamedGroups", String[].class); + setNamedGroupsMethod.invoke(params, (Object[]) impl.getNamedGroups()); } public static void getSSLParameters( diff --git a/common/src/main/java/org/conscrypt/ConscryptEngineSocket.java b/common/src/main/java/org/conscrypt/ConscryptEngineSocket.java index fdd434d7c..42f602366 100644 --- a/common/src/main/java/org/conscrypt/ConscryptEngineSocket.java +++ b/common/src/main/java/org/conscrypt/ConscryptEngineSocket.java @@ -432,7 +432,7 @@ public final void setEnabledProtocols(String[] protocols) { } @Override - final String getCurveNameForTesting() { + public String getCurveNameForTesting() { return engine.getCurveNameForTesting(); } diff --git a/common/src/main/java/org/conscrypt/ConscryptFileDescriptorSocket.java b/common/src/main/java/org/conscrypt/ConscryptFileDescriptorSocket.java index 62f30bea1..af0a34323 100644 --- a/common/src/main/java/org/conscrypt/ConscryptFileDescriptorSocket.java +++ b/common/src/main/java/org/conscrypt/ConscryptFileDescriptorSocket.java @@ -761,7 +761,7 @@ public final void setEnabledProtocols(String[] protocols) { } @Override - final String getCurveNameForTesting() { + public String getCurveNameForTesting() { return ssl.getCurveNameForTesting(); } diff --git a/common/src/main/java/org/conscrypt/NativeSsl.java b/common/src/main/java/org/conscrypt/NativeSsl.java index 762314d5a..8fef37061 100644 --- a/common/src/main/java/org/conscrypt/NativeSsl.java +++ b/common/src/main/java/org/conscrypt/NativeSsl.java @@ -277,6 +277,61 @@ String getRequestedServerName() { byte[] getTlsChannelId() throws SSLException { return NativeCrypto.SSL_get_tls_channel_id(ssl, this); } + + + // Converts a Java "named group" to the corresponding BoringSSL curve name. + private static int toBoringSslCurve(String javaNamedGroup) { + if (javaNamedGroup.equals("X25519") || javaNamedGroup.equals("x25519")) { + return NativeConstants.NID_X25519; + } + if (javaNamedGroup.equals("P-256") || javaNamedGroup.equals("secp256r1")) { + return NativeConstants.NID_X9_62_prime256v1; + } + if (javaNamedGroup.equals("P-384") || javaNamedGroup.equals("secp384r1")) { + return NativeConstants.NID_secp384r1; + } + if (javaNamedGroup.equals("P-521") || javaNamedGroup.equals("secp521r1")) { + return NativeConstants.NID_secp521r1; + } + if (javaNamedGroup.equals("X25519MLKEM768")) { + return NativeConstants.NID_X25519MLKEM768; + } + if (javaNamedGroup.equals("X25519Kyber768Draft00")) { + return NativeConstants.NID_X25519Kyber768Draft00; + } + if (javaNamedGroup.equals("MLKEM1024")) { + return NativeConstants.NID_ML_KEM_1024; + } + return -1; // Unknown curve. + } + + // Default curves to use if namedGroups is null. + // Same curves as StandardNames.ELLIPTIC_CURVES_DEFAULT + private static final int[] DEFAULT_GROUPS = + new int[] { + NativeConstants.NID_X25519, + NativeConstants.NID_X9_62_prime256v1, + NativeConstants.NID_secp384r1 + }; + + /** + * Converts a list of java named groups to an array of groups that can be passed to BoringSSL. + * + *

Unknown curves are ignored. + */ + public static int[] toBoringSslGroups(String[] javaNamedGroups) { + int[] outputGroups = new int[javaNamedGroups.length]; + int i = 0; + for (String javaNamedGroup : javaNamedGroups) { + int group = toBoringSslCurve(javaNamedGroup); + if (group > 0) { + outputGroups[i] = group; + } + i++; + } + return outputGroups; + } + void initialize(String hostname, OpenSSLKey channelIdPrivateKey) throws IOException { boolean enableSessionCreation = parameters.getEnableSessionCreation(); @@ -320,6 +375,19 @@ void initialize(String hostname, OpenSSLKey channelIdPrivateKey) throws IOExcept ssl, this, parameters.enabledCipherSuites, parameters.enabledProtocols); } + String[] paramsNamedGroups = parameters.getNamedGroups(); + // - If the named groups are null, we use the default groups. + // - If the named groups are not null, it overrides the default groups. + // - Unknown curves are ignored. + // See: https://docs.oracle.com/en/java/javase/25/docs/api/java.base/javax/net/ssl/SSLParameters.html#getNamedGroups() + if (paramsNamedGroups == null) { + // Use the default curves. + NativeCrypto.SSL_set1_groups(ssl, this, DEFAULT_GROUPS); + } else { + NativeCrypto.SSL_set1_groups( + ssl, this, toBoringSslGroups(paramsNamedGroups)); + } + if (parameters.applicationProtocols.length > 0) { NativeCrypto.setApplicationProtocols(ssl, this, isClient(), parameters.applicationProtocols); } diff --git a/common/src/main/java/org/conscrypt/OpenSSLSocketImpl.java b/common/src/main/java/org/conscrypt/OpenSSLSocketImpl.java index 5aabdc358..2fed76c19 100644 --- a/common/src/main/java/org/conscrypt/OpenSSLSocketImpl.java +++ b/common/src/main/java/org/conscrypt/OpenSSLSocketImpl.java @@ -151,4 +151,7 @@ public final byte[] getAlpnSelectedProtocol() { public final void setAlpnProtocols(byte[] protocols) { setApplicationProtocols(SSLUtils.decodeProtocols(protocols == null ? EmptyArray.BYTE : protocols)); } + + @Override + public abstract String getCurveNameForTesting(); } diff --git a/common/src/main/java/org/conscrypt/SSLParametersImpl.java b/common/src/main/java/org/conscrypt/SSLParametersImpl.java index f2056f2bd..f78b8691b 100644 --- a/common/src/main/java/org/conscrypt/SSLParametersImpl.java +++ b/common/src/main/java/org/conscrypt/SSLParametersImpl.java @@ -82,6 +82,8 @@ final class SSLParametersImpl implements Cloneable { // cannot be customized, so for simplicity this field never contains any TLS 1.3 suites. String[] enabledCipherSuites; + String[] namedGroups; + // if the peer with this parameters tuned to work in client mode private boolean client_mode = true; // if the peer with this parameters tuned to require client authentication @@ -363,6 +365,21 @@ void setEnabledProtocols(String[] protocols) { enabledProtocols = NativeCrypto.checkEnabledProtocols(filteredProtocols).clone(); } + void setNamedGroups(String[] namedGroups) { + if (namedGroups == null) { + this.namedGroups = null; + return; + } + this.namedGroups = namedGroups.clone(); + } + + String[] getNamedGroups() { + if (namedGroups == null) { + return null; + } + return this.namedGroups.clone(); + } + /* * Sets the list of ALPN protocols. */ diff --git a/common/src/test/java/org/conscrypt/javax/net/ssl/SSLSocketTest.java b/common/src/test/java/org/conscrypt/javax/net/ssl/SSLSocketTest.java index 083a10a9e..d03b676e1 100644 --- a/common/src/test/java/org/conscrypt/javax/net/ssl/SSLSocketTest.java +++ b/common/src/test/java/org/conscrypt/javax/net/ssl/SSLSocketTest.java @@ -93,6 +93,10 @@ public class SSLSocketTest { private final ExecutorService executor = Executors.newCachedThreadPool(t -> new Thread(threadGroup, t)); + String getCurveName(SSLSocket socket) { + return ((OpenSSLSocketImpl) socket).getCurveNameForTesting(); + } + /** * Returns the named groups, or null if the method is not available (older versions of * Java/Android). @@ -812,19 +816,21 @@ public void setSSLParameters_invalidCipherSuite_throwsIllegalArgumentException() } @Test - public void setAndGetSSLParameters_withSetNamedGroups_isIgnored() throws Exception { + public void setAndGetSSLParameters_withSetNamedGroups_works() throws Exception { SSLSocketFactory sf = (SSLSocketFactory) SSLSocketFactory.getDefault(); try (SSLSocket ssl = (SSLSocket) sf.createSocket()) { SSLParameters parameters = new SSLParameters( new String[] {"TLS_AES_128_GCM_SHA256"}, new String[] {"TLSv1.3"}); + + assertArrayEquals(null, getNamedGroupsOrNull(ssl.getSSLParameters())); + + // values passed to setNamedGroups are not validated, any strings work. setNamedGroups(parameters, new String[] {"foo", "bar"}); ssl.setSSLParameters(parameters); SSLParameters sslParameters = ssl.getSSLParameters(); - // getNamedGroups currently returns null because setNamedGroups is not supported. - // This is allowed, see: - // https://docs.oracle.com/en/java/javase/24/docs/api/java.base/javax/net/ssl/SSLParameters.html#getNamedGroups() - assertArrayEquals(null, getNamedGroupsOrNull(sslParameters)); + + assertArrayEquals(new String[] {"foo", "bar"}, getNamedGroupsOrNull(sslParameters)); } } @@ -911,6 +917,175 @@ public void test_SSLSocket_ClientHello_cipherSuites() throws Exception { getSSLSocketFactoriesToTest()); } + @Test + public void handshake_noNamedGroups_usesX25519() throws Exception { + TestSSLContext context = TestSSLContext.create(); + final SSLSocket client = (SSLSocket) context.clientContext.getSocketFactory().createSocket( + context.host, context.port); + final SSLSocket server = (SSLSocket) context.serverSocket.accept(); + Future s = runAsync(() -> { + server.startHandshake(); + return null; + }); + Future c = runAsync(() -> { + client.startHandshake(); + return null; + }); + s.get(); + c.get(); + // By default, BoringSSL uses X25519, P-256, and P-384, in this order. + // So X25519 gets priority. + assertEquals("X25519", getCurveName(client)); + assertEquals("X25519", getCurveName(server)); + client.close(); + server.close(); + context.close(); + } + + @Test + public void handshake_p256IsSupportedByDefault() throws Exception { + TestSSLContext context = TestSSLContext.create(); + final SSLSocket client = (SSLSocket) context.clientContext.getSocketFactory().createSocket( + context.host, context.port); + final SSLSocket server = (SSLSocket) context.serverSocket.accept(); + Future s = runAsync(() -> { + server.startHandshake(); + return null; + }); + Future c = runAsync(() -> { + SSLParameters parameters = client.getSSLParameters(); + setNamedGroups(parameters, new String[] {"P-256"}); + client.setSSLParameters(parameters); + client.startHandshake(); + return null; + }); + s.get(); + c.get(); + // By default, BoringSSL uses X25519, P-256, and P-384. If the client + // requests P-256, it will be chosen. + assertEquals("P-256", getCurveName(client)); + assertEquals("P-256", getCurveName(server)); + client.close(); + server.close(); + context.close(); + } + + @Test + public void handshake_p384IsSupportedByDefault() throws Exception { + TestSSLContext context = TestSSLContext.create(); + final SSLSocket client = (SSLSocket) context.clientContext.getSocketFactory().createSocket( + context.host, context.port); + final SSLSocket server = (SSLSocket) context.serverSocket.accept(); + Future s = runAsync(() -> { + SSLParameters parameters = server.getSSLParameters(); + // secp384r1 is an alias for P-384. + setNamedGroups(parameters, new String[] {"secp384r1"}); + server.setSSLParameters(parameters); + server.startHandshake(); + return null; + }); + Future c = runAsync(() -> { + client.startHandshake(); + return null; + }); + s.get(); + c.get(); + // By default, BoringSSL uses X25519, P-256, and P-384. If the server only supports P-384, + // it will be chosen. + assertEquals("P-384", getCurveName(client)); + assertEquals("P-384", getCurveName(server)); + client.close(); + server.close(); + context.close(); + } + + @Test + public void handshake_setsNamedGroups_usesFirstServerNamedGroupThatClientSupports() throws Exception { + TestSSLContext context = TestSSLContext.create(); + final SSLSocket client = (SSLSocket) context.clientContext.getSocketFactory().createSocket( + context.host, context.port); + final SSLSocket server = (SSLSocket) context.serverSocket.accept(); + Future s = runAsync(() -> { + SSLParameters parameters = server.getSSLParameters(); + setNamedGroups(parameters, new String[] {"P-384", "X25519"}); + server.setSSLParameters(parameters); + server.startHandshake(); + return null; + }); + Future c = runAsync(() -> { + SSLParameters parameters = client.getSSLParameters(); + setNamedGroups(parameters, new String[] {"P-521", "X25519", "P-384"}); + client.setSSLParameters(parameters); + client.startHandshake(); + return null; + }); + s.get(); + c.get(); + assertEquals("P-384", getCurveName(client)); + assertEquals("P-384", getCurveName(server)); + client.close(); + server.close(); + context.close(); + } + + @Test + public void handshake_withX25519MLKEM768_works() throws Exception { + TestSSLContext context = TestSSLContext.create(); + final SSLSocket client = (SSLSocket) context.clientContext.getSocketFactory().createSocket( + context.host, context.port); + final SSLSocket server = (SSLSocket) context.serverSocket.accept(); + Future s = runAsync(() -> { + SSLParameters parameters = server.getSSLParameters(); + setNamedGroups(parameters, new String[] {"X25519MLKEM768"}); + server.setSSLParameters(parameters); + server.startHandshake(); + return null; + }); + Future c = runAsync(() -> { + SSLParameters parameters = client.getSSLParameters(); + setNamedGroups(parameters, new String[] {"X25519MLKEM768"}); + client.setSSLParameters(parameters); + client.startHandshake(); + return null; + }); + s.get(); + c.get(); + assertEquals("X25519MLKEM768", getCurveName(client)); + assertEquals("X25519MLKEM768", getCurveName(server)); + client.close(); + server.close(); + context.close(); + } + + @Test + public void handshake_namedGroupsDontIntersect_throwsException() throws Exception { + TestSSLContext context = TestSSLContext.create(); + final SSLSocket client = (SSLSocket) context.clientContext.getSocketFactory().createSocket( + context.host, context.port); + final SSLSocket server = (SSLSocket) context.serverSocket.accept(); + Future s = runAsync(() -> { + SSLParameters parameters = server.getSSLParameters(); + setNamedGroups(parameters, new String[] {"X25519", "P-384"}); + server.setSSLParameters(parameters); + server.startHandshake(); + return null; + }); + Future c = runAsync(() -> { + SSLParameters parameters = client.getSSLParameters(); + setNamedGroups(parameters, new String[] {"P-256", "P-521"}); + client.setSSLParameters(parameters); + client.startHandshake(); + return null; + }); + ExecutionException serverException = assertThrows(ExecutionException.class, s::get); + assertTrue(serverException.getCause() instanceof SSLHandshakeException); + ExecutionException clientException = assertThrows(ExecutionException.class, c::get); + assertTrue(clientException.getCause() instanceof SSLHandshakeException); + client.close(); + server.close(); + context.close(); + } + @Test public void test_SSLSocket_ClientHello_supportedCurves() throws Exception { ForEachRunner.runNamed(sslSocketFactory -> { diff --git a/openjdk/src/main/java/org/conscrypt/Java9PlatformUtil.java b/openjdk/src/main/java/org/conscrypt/Java9PlatformUtil.java index 6e3fae650..79ee4943e 100644 --- a/openjdk/src/main/java/org/conscrypt/Java9PlatformUtil.java +++ b/openjdk/src/main/java/org/conscrypt/Java9PlatformUtil.java @@ -47,14 +47,28 @@ final class Java9PlatformUtil { static void setSSLParameters( SSLParameters src, SSLParametersImpl dest, AbstractConscryptSocket socket) { Java8PlatformUtil.setSSLParameters(src, dest, socket); - + try{ + Method getNamedGroupsMethod = src.getClass().getMethod("getNamedGroups"); + dest.setNamedGroups( + (String[]) getNamedGroupsMethod.invoke(src)); + } catch (ReflectiveOperationException | SecurityException e) { + // Ignored. getNamedGroups was added in Java 20. + } dest.setApplicationProtocols(getApplicationProtocols(src)); } static void getSSLParameters( SSLParameters dest, SSLParametersImpl src, AbstractConscryptSocket socket) { Java8PlatformUtil.getSSLParameters(dest, src, socket); - + try{ + String[] namedGroups = src.getNamedGroups(); + Method setNamedGroupsMethod = dest.getClass().getMethod( + "setNamedGroups", String[].class); + setNamedGroupsMethod.invoke( + dest, (Object) namedGroups); + } catch (ReflectiveOperationException | SecurityException e) { + // Ignored. setNamedGroups was added in Java 20. + } setApplicationProtocols(dest, src.getApplicationProtocols()); } @@ -62,6 +76,14 @@ static void setSSLParameters( SSLParameters src, SSLParametersImpl dest, ConscryptEngine engine) { Java8PlatformUtil.setSSLParameters(src, dest, engine); + try{ + Method getNamedGroupsMethod = src.getClass().getMethod("getNamedGroups"); + dest.setNamedGroups( + (String[]) getNamedGroupsMethod.invoke(src)); + } catch (ReflectiveOperationException | SecurityException e) { + // Ignored. getNamedGroups was added in Java 20. + } + dest.setApplicationProtocols(getApplicationProtocols(src)); } @@ -69,6 +91,16 @@ static void getSSLParameters( SSLParameters dest, SSLParametersImpl src, ConscryptEngine engine) { Java8PlatformUtil.getSSLParameters(dest, src, engine); + try{ + String[] namedGroups = src.getNamedGroups(); + Method setNamedGroupsMethod = dest.getClass().getMethod( + "setNamedGroups", String[].class); + setNamedGroupsMethod.invoke( + dest, (Object) namedGroups); + } catch (ReflectiveOperationException | SecurityException e) { + // Ignored. setNamedGroups was added in Java 20. + } + setApplicationProtocols(dest, src.getApplicationProtocols()); } From 747acab7d3d44b998774012571afd120eadb615c Mon Sep 17 00:00:00 2001 From: juergw Date: Mon, 15 Dec 2025 10:43:53 +0000 Subject: [PATCH 2/6] Fix format. --- .../src/main/java/org/conscrypt/Platform.java | 5 +-- .../main/java/org/conscrypt/NativeSsl.java | 40 ++++++++----------- .../java/org/conscrypt/OpenSSLSocketImpl.java | 5 +-- .../javax/net/ssl/SSLSocketTest.java | 3 +- .../java/org/conscrypt/Java9PlatformUtil.java | 28 ++++++------- 5 files changed, 35 insertions(+), 46 deletions(-) diff --git a/android/src/main/java/org/conscrypt/Platform.java b/android/src/main/java/org/conscrypt/Platform.java index 83c29dd1b..1bdf9ccc5 100644 --- a/android/src/main/java/org/conscrypt/Platform.java +++ b/android/src/main/java/org/conscrypt/Platform.java @@ -254,10 +254,9 @@ private static void setSSLParametersOnImpl(SSLParameters params, SSLParametersIm Method m_getUseCipherSuitesOrder = params.getClass().getMethod("getUseCipherSuitesOrder"); impl.setUseCipherSuitesOrder((boolean) m_getUseCipherSuitesOrder.invoke(params)); - + Method getNamedGroupsMethod = params.getClass().getMethod("getNamedGroups"); - impl.setNamedGroups( - (String[]) getNamedGroupsMethod.invoke(params)); + impl.setNamedGroups((String[]) getNamedGroupsMethod.invoke(params)); } public static void setSSLParameters( diff --git a/common/src/main/java/org/conscrypt/NativeSsl.java b/common/src/main/java/org/conscrypt/NativeSsl.java index 8fef37061..748cade8c 100644 --- a/common/src/main/java/org/conscrypt/NativeSsl.java +++ b/common/src/main/java/org/conscrypt/NativeSsl.java @@ -277,10 +277,9 @@ String getRequestedServerName() { byte[] getTlsChannelId() throws SSLException { return NativeCrypto.SSL_get_tls_channel_id(ssl, this); } - - // Converts a Java "named group" to the corresponding BoringSSL curve name. - private static int toBoringSslCurve(String javaNamedGroup) { + // Converts a Java "named group" to the corresponding BoringSSL group NID, or -1. + private static int toBoringSslGroupNid(String javaNamedGroup) { if (javaNamedGroup.equals("X25519") || javaNamedGroup.equals("x25519")) { return NativeConstants.NID_X25519; } @@ -302,28 +301,24 @@ private static int toBoringSslCurve(String javaNamedGroup) { if (javaNamedGroup.equals("MLKEM1024")) { return NativeConstants.NID_ML_KEM_1024; } - return -1; // Unknown curve. + return -1; // Unknown curve. } - // Default curves to use if namedGroups is null. - // Same curves as StandardNames.ELLIPTIC_CURVES_DEFAULT - private static final int[] DEFAULT_GROUPS = - new int[] { - NativeConstants.NID_X25519, - NativeConstants.NID_X9_62_prime256v1, - NativeConstants.NID_secp384r1 - }; + // Default curves to use if namedGroups is null. + // Same curves as StandardNames.ELLIPTIC_CURVES_DEFAULT + private static final int[] DEFAULT_GROUPS = new int[] {NativeConstants.NID_X25519, + NativeConstants.NID_X9_62_prime256v1, NativeConstants.NID_secp384r1}; - /** - * Converts a list of java named groups to an array of groups that can be passed to BoringSSL. - * - *

Unknown curves are ignored. - */ - public static int[] toBoringSslGroups(String[] javaNamedGroups) { + /** + * Converts a list of java named groups to an array of groups that can be passed to BoringSSL. + * + *

Unknown curves are ignored. + */ + public static int[] toBoringSslGroups(String[] javaNamedGroups) { int[] outputGroups = new int[javaNamedGroups.length]; int i = 0; for (String javaNamedGroup : javaNamedGroups) { - int group = toBoringSslCurve(javaNamedGroup); + int group = toBoringSslGroupNid(javaNamedGroup); if (group > 0) { outputGroups[i] = group; } @@ -332,7 +327,6 @@ public static int[] toBoringSslGroups(String[] javaNamedGroups) { return outputGroups; } - void initialize(String hostname, OpenSSLKey channelIdPrivateKey) throws IOException { boolean enableSessionCreation = parameters.getEnableSessionCreation(); if (!enableSessionCreation) { @@ -379,13 +373,13 @@ void initialize(String hostname, OpenSSLKey channelIdPrivateKey) throws IOExcept // - If the named groups are null, we use the default groups. // - If the named groups are not null, it overrides the default groups. // - Unknown curves are ignored. - // See: https://docs.oracle.com/en/java/javase/25/docs/api/java.base/javax/net/ssl/SSLParameters.html#getNamedGroups() + // See: + // https://docs.oracle.com/en/java/javase/25/docs/api/java.base/javax/net/ssl/SSLParameters.html#getNamedGroups() if (paramsNamedGroups == null) { // Use the default curves. NativeCrypto.SSL_set1_groups(ssl, this, DEFAULT_GROUPS); } else { - NativeCrypto.SSL_set1_groups( - ssl, this, toBoringSslGroups(paramsNamedGroups)); + NativeCrypto.SSL_set1_groups(ssl, this, toBoringSslGroups(paramsNamedGroups)); } if (parameters.applicationProtocols.length > 0) { diff --git a/common/src/main/java/org/conscrypt/OpenSSLSocketImpl.java b/common/src/main/java/org/conscrypt/OpenSSLSocketImpl.java index 2fed76c19..f0c2571e1 100644 --- a/common/src/main/java/org/conscrypt/OpenSSLSocketImpl.java +++ b/common/src/main/java/org/conscrypt/OpenSSLSocketImpl.java @@ -151,7 +151,6 @@ public final byte[] getAlpnSelectedProtocol() { public final void setAlpnProtocols(byte[] protocols) { setApplicationProtocols(SSLUtils.decodeProtocols(protocols == null ? EmptyArray.BYTE : protocols)); } - - @Override - public abstract String getCurveNameForTesting(); + + @Override public abstract String getCurveNameForTesting(); } diff --git a/common/src/test/java/org/conscrypt/javax/net/ssl/SSLSocketTest.java b/common/src/test/java/org/conscrypt/javax/net/ssl/SSLSocketTest.java index d03b676e1..ea41df2a0 100644 --- a/common/src/test/java/org/conscrypt/javax/net/ssl/SSLSocketTest.java +++ b/common/src/test/java/org/conscrypt/javax/net/ssl/SSLSocketTest.java @@ -1000,7 +1000,8 @@ public void handshake_p384IsSupportedByDefault() throws Exception { } @Test - public void handshake_setsNamedGroups_usesFirstServerNamedGroupThatClientSupports() throws Exception { + public void handshake_setsNamedGroups_usesFirstServerNamedGroupThatClientSupports() + throws Exception { TestSSLContext context = TestSSLContext.create(); final SSLSocket client = (SSLSocket) context.clientContext.getSocketFactory().createSocket( context.host, context.port); diff --git a/openjdk/src/main/java/org/conscrypt/Java9PlatformUtil.java b/openjdk/src/main/java/org/conscrypt/Java9PlatformUtil.java index 79ee4943e..63756701e 100644 --- a/openjdk/src/main/java/org/conscrypt/Java9PlatformUtil.java +++ b/openjdk/src/main/java/org/conscrypt/Java9PlatformUtil.java @@ -47,10 +47,9 @@ final class Java9PlatformUtil { static void setSSLParameters( SSLParameters src, SSLParametersImpl dest, AbstractConscryptSocket socket) { Java8PlatformUtil.setSSLParameters(src, dest, socket); - try{ + try { Method getNamedGroupsMethod = src.getClass().getMethod("getNamedGroups"); - dest.setNamedGroups( - (String[]) getNamedGroupsMethod.invoke(src)); + dest.setNamedGroups((String[]) getNamedGroupsMethod.invoke(src)); } catch (ReflectiveOperationException | SecurityException e) { // Ignored. getNamedGroups was added in Java 20. } @@ -60,12 +59,11 @@ static void setSSLParameters( static void getSSLParameters( SSLParameters dest, SSLParametersImpl src, AbstractConscryptSocket socket) { Java8PlatformUtil.getSSLParameters(dest, src, socket); - try{ + try { String[] namedGroups = src.getNamedGroups(); - Method setNamedGroupsMethod = dest.getClass().getMethod( - "setNamedGroups", String[].class); - setNamedGroupsMethod.invoke( - dest, (Object) namedGroups); + Method setNamedGroupsMethod = + dest.getClass().getMethod("setNamedGroups", String[].class); + setNamedGroupsMethod.invoke(dest, (Object) namedGroups); } catch (ReflectiveOperationException | SecurityException e) { // Ignored. setNamedGroups was added in Java 20. } @@ -76,10 +74,9 @@ static void setSSLParameters( SSLParameters src, SSLParametersImpl dest, ConscryptEngine engine) { Java8PlatformUtil.setSSLParameters(src, dest, engine); - try{ + try { Method getNamedGroupsMethod = src.getClass().getMethod("getNamedGroups"); - dest.setNamedGroups( - (String[]) getNamedGroupsMethod.invoke(src)); + dest.setNamedGroups((String[]) getNamedGroupsMethod.invoke(src)); } catch (ReflectiveOperationException | SecurityException e) { // Ignored. getNamedGroups was added in Java 20. } @@ -91,12 +88,11 @@ static void getSSLParameters( SSLParameters dest, SSLParametersImpl src, ConscryptEngine engine) { Java8PlatformUtil.getSSLParameters(dest, src, engine); - try{ + try { String[] namedGroups = src.getNamedGroups(); - Method setNamedGroupsMethod = dest.getClass().getMethod( - "setNamedGroups", String[].class); - setNamedGroupsMethod.invoke( - dest, (Object) namedGroups); + Method setNamedGroupsMethod = + dest.getClass().getMethod("setNamedGroups", String[].class); + setNamedGroupsMethod.invoke(dest, (Object) namedGroups); } catch (ReflectiveOperationException | SecurityException e) { // Ignored. setNamedGroups was added in Java 20. } From eeeae6985430f20657d5c5f9d3cf5d185e9dc58d Mon Sep 17 00:00:00 2001 From: juergw Date: Mon, 15 Dec 2025 12:43:24 +0000 Subject: [PATCH 3/6] Add missing import. --- .../test/java/org/conscrypt/javax/net/ssl/SSLSocketTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/common/src/test/java/org/conscrypt/javax/net/ssl/SSLSocketTest.java b/common/src/test/java/org/conscrypt/javax/net/ssl/SSLSocketTest.java index ea41df2a0..baa1ffb79 100644 --- a/common/src/test/java/org/conscrypt/javax/net/ssl/SSLSocketTest.java +++ b/common/src/test/java/org/conscrypt/javax/net/ssl/SSLSocketTest.java @@ -27,6 +27,7 @@ import static java.nio.charset.StandardCharsets.UTF_8; +import org.conscrypt.OpenSSLSocketImpl; import org.conscrypt.TestUtils; import org.conscrypt.java.security.StandardNames; import org.conscrypt.java.security.TestKeyStore; @@ -42,7 +43,6 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; - import java.io.EOFException; import java.io.IOException; import java.io.InputStream; @@ -61,6 +61,7 @@ import java.util.HashSet; import java.util.List; import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; From 40753c98b18f62171fc1b3383c3b88de7c957131 Mon Sep 17 00:00:00 2001 From: juergw Date: Mon, 15 Dec 2025 12:47:16 +0000 Subject: [PATCH 4/6] Fix format. --- .../src/test/java/org/conscrypt/javax/net/ssl/SSLSocketTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/common/src/test/java/org/conscrypt/javax/net/ssl/SSLSocketTest.java b/common/src/test/java/org/conscrypt/javax/net/ssl/SSLSocketTest.java index baa1ffb79..4ca4fcc7b 100644 --- a/common/src/test/java/org/conscrypt/javax/net/ssl/SSLSocketTest.java +++ b/common/src/test/java/org/conscrypt/javax/net/ssl/SSLSocketTest.java @@ -43,6 +43,7 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; + import java.io.EOFException; import java.io.IOException; import java.io.InputStream; From 146c615d141ea4d5cc24652fd060d212463cf312 Mon Sep 17 00:00:00 2001 From: juergw Date: Mon, 15 Dec 2025 13:32:15 +0000 Subject: [PATCH 5/6] Add missing changes to platform platform. --- .../src/main/java/org/conscrypt/Platform.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/platform/src/main/java/org/conscrypt/Platform.java b/platform/src/main/java/org/conscrypt/Platform.java index e98ece7c3..a34be6da9 100644 --- a/platform/src/main/java/org/conscrypt/Platform.java +++ b/platform/src/main/java/org/conscrypt/Platform.java @@ -166,6 +166,10 @@ static void setSSLParameters( SSLParameters params, SSLParametersImpl impl, AbstractConscryptSocket socket) { impl.setEndpointIdentificationAlgorithm(params.getEndpointIdentificationAlgorithm()); impl.setUseCipherSuitesOrder(params.getUseCipherSuitesOrder()); + + Method getNamedGroupsMethod = params.getClass().getMethod("getNamedGroups"); + impl.setNamedGroups((String[]) getNamedGroupsMethod.invoke(params)); + List serverNames = params.getServerNames(); if (serverNames != null) { for (SNIServerName serverName : serverNames) { @@ -182,6 +186,10 @@ static void getSSLParameters( SSLParameters params, SSLParametersImpl impl, AbstractConscryptSocket socket) { params.setEndpointIdentificationAlgorithm(impl.getEndpointIdentificationAlgorithm()); params.setUseCipherSuitesOrder(impl.getUseCipherSuitesOrder()); + + Method setNamedGroupsMethod = params.getClass().getMethod("setNamedGroups", String[].class); + setNamedGroupsMethod.invoke(params, (Object[]) impl.getNamedGroups()); + if (impl.getUseSni() && AddressUtils.isValidSniHostname(socket.getHostname())) { params.setServerNames(Collections.singletonList( new SNIHostName(socket.getHostname()))); @@ -193,6 +201,10 @@ static void setSSLParameters( SSLParameters params, SSLParametersImpl impl, ConscryptEngine engine) { impl.setEndpointIdentificationAlgorithm(params.getEndpointIdentificationAlgorithm()); impl.setUseCipherSuitesOrder(params.getUseCipherSuitesOrder()); + + Method getNamedGroupsMethod = params.getClass().getMethod("getNamedGroups"); + impl.setNamedGroups((String[]) getNamedGroupsMethod.invoke(params)); + List serverNames = params.getServerNames(); if (serverNames != null) { for (SNIServerName serverName : serverNames) { @@ -209,6 +221,10 @@ static void getSSLParameters( SSLParameters params, SSLParametersImpl impl, ConscryptEngine engine) { params.setEndpointIdentificationAlgorithm(impl.getEndpointIdentificationAlgorithm()); params.setUseCipherSuitesOrder(impl.getUseCipherSuitesOrder()); + + Method setNamedGroupsMethod = params.getClass().getMethod("setNamedGroups", String[].class); + setNamedGroupsMethod.invoke(params, (Object[]) impl.getNamedGroups()); + if (impl.getUseSni() && AddressUtils.isValidSniHostname(engine.getHostname())) { params.setServerNames(Collections.singletonList( new SNIHostName(engine.getHostname()))); From f37c271cc6ed522d05c7d404b92adadf0157c84a Mon Sep 17 00:00:00 2001 From: juergw Date: Mon, 15 Dec 2025 14:49:28 +0000 Subject: [PATCH 6/6] Do not ignore failed set/get named group. --- .../src/main/java/org/conscrypt/Java9PlatformUtil.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/openjdk/src/main/java/org/conscrypt/Java9PlatformUtil.java b/openjdk/src/main/java/org/conscrypt/Java9PlatformUtil.java index 63756701e..fca6c175b 100644 --- a/openjdk/src/main/java/org/conscrypt/Java9PlatformUtil.java +++ b/openjdk/src/main/java/org/conscrypt/Java9PlatformUtil.java @@ -51,7 +51,7 @@ static void setSSLParameters( Method getNamedGroupsMethod = src.getClass().getMethod("getNamedGroups"); dest.setNamedGroups((String[]) getNamedGroupsMethod.invoke(src)); } catch (ReflectiveOperationException | SecurityException e) { - // Ignored. getNamedGroups was added in Java 20. + throw new RuntimeException("SSLParameters.getNamedGroups failed.", e); } dest.setApplicationProtocols(getApplicationProtocols(src)); } @@ -65,7 +65,7 @@ static void getSSLParameters( dest.getClass().getMethod("setNamedGroups", String[].class); setNamedGroupsMethod.invoke(dest, (Object) namedGroups); } catch (ReflectiveOperationException | SecurityException e) { - // Ignored. setNamedGroups was added in Java 20. + throw new RuntimeException("SSLParameters.setNamedGroups failed.", e); } setApplicationProtocols(dest, src.getApplicationProtocols()); } @@ -78,7 +78,7 @@ static void setSSLParameters( Method getNamedGroupsMethod = src.getClass().getMethod("getNamedGroups"); dest.setNamedGroups((String[]) getNamedGroupsMethod.invoke(src)); } catch (ReflectiveOperationException | SecurityException e) { - // Ignored. getNamedGroups was added in Java 20. + throw new RuntimeException("SSLParameters.getNamedGroups failed.", e); } dest.setApplicationProtocols(getApplicationProtocols(src)); @@ -94,7 +94,7 @@ static void getSSLParameters( dest.getClass().getMethod("setNamedGroups", String[].class); setNamedGroupsMethod.invoke(dest, (Object) namedGroups); } catch (ReflectiveOperationException | SecurityException e) { - // Ignored. setNamedGroups was added in Java 20. + throw new RuntimeException("SSLParameters.setNamedGroups failed.", e); } setApplicationProtocols(dest, src.getApplicationProtocols());