Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions android/src/main/java/org/conscrypt/Platform.java
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +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));
}

public static void setSSLParameters(
Expand Down Expand Up @@ -323,6 +326,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(
Expand Down
25 changes: 18 additions & 7 deletions common/src/main/java/org/conscrypt/NativeSsl.java
Original file line number Diff line number Diff line change
Expand Up @@ -386,14 +386,25 @@ void initialize(String hostname, OpenSSLKey channelIdPrivateKey) throws IOExcept
ssl, this, parameters.enabledCipherSuites, parameters.enabledProtocols);
}

String namedGroupsProperty = System.getProperty("jdk.tls.namedGroups");
if (namedGroupsProperty == null || namedGroupsProperty.isEmpty()) {
// If the property is not set or empty, use the default named groups. See:
// https://docs.oracle.com/javase/8/docs/technotes/guides/security/jsse/JSSERefGuide.html
setDefaultNamedGroups(ssl, this);
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) {
NativeCrypto.SSL_set1_groups(ssl, this, toBoringSslGroups(paramsNamedGroups));
} else {
int[] groups = parseNamedGroupsProperty(namedGroupsProperty);
NativeCrypto.SSL_set1_groups(ssl, this, groups);
// Use default named group.
String namedGroupsProperty = System.getProperty("jdk.tls.namedGroups");
if (namedGroupsProperty == null || namedGroupsProperty.isEmpty()) {
// If the property is not set or empty, use the default named groups. See:
// https://docs.oracle.com/javase/8/docs/technotes/guides/security/jsse/JSSERefGuide.html
setDefaultNamedGroups(ssl, this);
} else {
int[] groups = parseNamedGroupsProperty(namedGroupsProperty);
NativeCrypto.SSL_set1_groups(ssl, this, groups);
}
}

if (parameters.applicationProtocols.length > 0) {
Expand Down
17 changes: 17 additions & 0 deletions common/src/main/java/org/conscrypt/SSLParametersImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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.
*/
Expand Down
200 changes: 195 additions & 5 deletions common/src/test/java/org/conscrypt/javax/net/ssl/SSLSocketTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -833,20 +833,32 @@ public void setSSLParameters_invalidCipherSuite_throwsIllegalArgumentException()
}
}

boolean sslParametersSupportsNamedGroups() throws SecurityException {
try {
Method unused = SSLParameters.class.getMethod("getNamedGroups");
return true;
} catch (NoSuchMethodException e) {
return false;
}
}

@Test
public void setAndGetSSLParameters_withSetNamedGroups_isIgnored() throws Exception {
public void setAndGetSSLParameters_withSetNamedGroups_worksIfSupported() 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()));

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));
if (sslParametersSupportsNamedGroups()) {
assertArrayEquals(new String[] {"foo", "bar"}, getNamedGroupsOrNull(sslParameters));
} else {
assertArrayEquals(null, getNamedGroupsOrNull(sslParameters));
}
}
}

Expand Down Expand Up @@ -984,6 +996,184 @@ public void handshake_namedGroupsProperty_usesFirstKnownEntry() throws Exception
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<Void> s = runAsync(() -> {
server.startHandshake();
return null;
});
Future<Void> 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 (sslParametersSupportsNamedGroups()) {
// If the client requests P-256, it will be chosen.
assertEquals("P-256", getCurveName(client));
assertEquals("P-256", getCurveName(server));
} else {
// Otherwise, X25519 gets priority.
assertEquals("X25519", getCurveName(client));
assertEquals("X25519", 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<Void> 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<Void> c = runAsync(() -> {
client.startHandshake();
return null;
});
s.get();
c.get();
// By default, BoringSSL uses X25519, P-256, and P-384.
if (sslParametersSupportsNamedGroups()) {
// If the client requests P-384, it will be chosen.
assertEquals("P-384", getCurveName(client));
assertEquals("P-384", getCurveName(server));
} else {
// Otherwise, X25519 gets priority.
assertEquals("X25519", getCurveName(client));
assertEquals("X25519", 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<Void> s = runAsync(() -> {
SSLParameters parameters = server.getSSLParameters();
setNamedGroups(parameters, new String[] {"P-384", "X25519"});
server.setSSLParameters(parameters);
server.startHandshake();
return null;
});
Future<Void> 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();
if (sslParametersSupportsNamedGroups()) {
// P-384 is the first named group in the server's list that both support.
assertEquals("P-384", getCurveName(client));
assertEquals("P-384", getCurveName(server));
} else {
// The defaults are used, and X25519 gets priority.
assertEquals("X25519", getCurveName(client));
assertEquals("X25519", 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<Void> s = runAsync(() -> {
SSLParameters parameters = server.getSSLParameters();
setNamedGroups(parameters, new String[] {"X25519MLKEM768"});
server.setSSLParameters(parameters);
server.startHandshake();
return null;
});
Future<Void> c = runAsync(() -> {
SSLParameters parameters = client.getSSLParameters();
setNamedGroups(parameters, new String[] {"X25519MLKEM768"});
client.setSSLParameters(parameters);
client.startHandshake();
return null;
});
s.get();
c.get();
if (sslParametersSupportsNamedGroups()) {
assertEquals("X25519MLKEM768", getCurveName(client));
assertEquals("X25519MLKEM768", getCurveName(server));
} else {
// The defaults are used, and X25519 gets priority.
assertEquals("X25519", getCurveName(client));
assertEquals("X25519", 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<Void> s = runAsync(() -> {
SSLParameters parameters = server.getSSLParameters();
setNamedGroups(parameters, new String[] {"X25519", "P-384"});
server.setSSLParameters(parameters);
server.startHandshake();
return null;
});
Future<Void> c = runAsync(() -> {
SSLParameters parameters = client.getSSLParameters();
setNamedGroups(parameters, new String[] {"P-256", "P-521"});
client.setSSLParameters(parameters);
client.startHandshake();
return null;
});
if (sslParametersSupportsNamedGroups()) {
ExecutionException serverException = assertThrows(ExecutionException.class, s::get);
assertTrue(serverException.getCause() instanceof SSLHandshakeException);
ExecutionException clientException = assertThrows(ExecutionException.class, c::get);
assertTrue(clientException.getCause() instanceof SSLHandshakeException);
} else {
s.get();
c.get();
// The defaults are used, and X25519 gets priority.
assertEquals("X25519", getCurveName(client));
assertEquals("X25519", getCurveName(server));
}
client.close();
server.close();
context.close();
}

@Test
public void handshake_namedGroupsProperty_failsIfAllValuesAreInvalid() throws Exception {
System.setProperty("jdk.tls.namedGroups", "invalid,invalid2");
Expand Down
32 changes: 30 additions & 2 deletions openjdk/src/main/java/org/conscrypt/Java9PlatformUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -47,28 +47,56 @@ 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) {
// Method is not available. Ignore.
}
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) {
// Method is not available. Ignore.
}
setApplicationProtocols(dest, src.getApplicationProtocols());
}

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) {
// Method is not available. Ignore.
}

dest.setApplicationProtocols(getApplicationProtocols(src));
}

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) {
// Method is not available. Ignore.
}

setApplicationProtocols(dest, src.getApplicationProtocols());
}

Expand Down
Loading
Loading