diff --git a/common/src/main/java/org/conscrypt/NativeSsl.java b/common/src/main/java/org/conscrypt/NativeSsl.java
index 7fe7c49d7..31976fbc4 100644
--- a/common/src/main/java/org/conscrypt/NativeSsl.java
+++ b/common/src/main/java/org/conscrypt/NativeSsl.java
@@ -396,14 +396,14 @@ void initialize(String hostname, OpenSSLKey channelIdPrivateKey) throws IOExcept
NativeCrypto.SSL_set1_groups(ssl, this, toBoringSslGroups(paramsNamedGroups));
} else {
// 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:
+ int[] parsedNamedGroups = getParsedTlsNamedGroupsPropertyOrNull();
+ if (parsedNamedGroups == null) {
+ // The jdk.tls.namedGroups property has not been set or is empty. We have to 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);
+ NativeCrypto.SSL_set1_groups(ssl, this, parsedNamedGroups);
}
}
@@ -798,4 +798,46 @@ void close() {
}
}
}
+
+ /**
+ * Returns the parsed value of the "jdk.tls.namedGroups" property.
+ *
+ *
Is null if the property is not set or empty.
+ */
+ static synchronized int[] getParsedTlsNamedGroupsPropertyOrNull() {
+ try {
+ parseTlsNamedGroupsProperty();
+ } catch (IllegalArgumentException e) {
+ // This may happen if the user set the property to an invalid value.
+ // Since the last time the property was parsed successfully. We ignore it
+ // and return the previously parsed value.
+ }
+ return parsedTlsNamedGroupsProperty;
+ }
+
+ private static int[] parsedTlsNamedGroupsProperty = null;
+ private static String unparsedTlsNamedGroupsProperty = "";
+
+ /**
+ * Parses the "jdk.tls.namedGroups" property and stores the result in {@code
+ * parsedTlsNamedGroupsProperty}.
+ *
+ *
May throw an {@link IllegalArgumentException} if the property contains invalid values.
+ */
+ static synchronized void parseTlsNamedGroupsProperty() {
+ String property = System.getProperty("jdk.tls.namedGroups");
+ if (property == null || property.isEmpty()) {
+ parsedTlsNamedGroupsProperty = null;
+ unparsedTlsNamedGroupsProperty = "";
+ } else {
+ if (!property.equals(unparsedTlsNamedGroupsProperty)) {
+ unparsedTlsNamedGroupsProperty = property;
+ parsedTlsNamedGroupsProperty = parseNamedGroupsProperty(property);
+ }
+ }
+ }
+
+ static {
+ parseTlsNamedGroupsProperty();
+ }
}
diff --git a/common/src/main/java/org/conscrypt/OpenSSLRSAPrivateCrtKey.java b/common/src/main/java/org/conscrypt/OpenSSLRSAPrivateCrtKey.java
index ac5e5fd07..2a4f818e1 100644
--- a/common/src/main/java/org/conscrypt/OpenSSLRSAPrivateCrtKey.java
+++ b/common/src/main/java/org/conscrypt/OpenSSLRSAPrivateCrtKey.java
@@ -217,26 +217,26 @@ public boolean equals(Object o) {
RSAPrivateCrtKey other = (RSAPrivateCrtKey) o;
if (getOpenSSLKey().isHardwareBacked()) {
- return getModulus().equals(other.getModulus())
- && publicExponent.equals(other.getPublicExponent());
+ return equalsBigInteger(getModulus(), other.getModulus())
+ && equalsBigInteger(publicExponent, other.getPublicExponent());
} else {
- return getModulus().equals(other.getModulus())
- && publicExponent.equals(other.getPublicExponent())
- && getPrivateExponent().equals(other.getPrivateExponent())
- && primeP.equals(other.getPrimeP()) && primeQ.equals(other.getPrimeQ())
- && primeExponentP.equals(other.getPrimeExponentP())
- && primeExponentQ.equals(other.getPrimeExponentQ())
- && crtCoefficient.equals(other.getCrtCoefficient());
+ return equalsBigInteger(getModulus(), other.getModulus())
+ && equalsBigInteger(publicExponent, other.getPublicExponent())
+ && equalsBigInteger(getPrivateExponent(), other.getPrivateExponent())
+ && equalsBigInteger(primeP, other.getPrimeP()) && equalsBigInteger(primeQ, other.getPrimeQ())
+ && equalsBigInteger(primeExponentP, other.getPrimeExponentP())
+ && equalsBigInteger(primeExponentQ, other.getPrimeExponentQ())
+ && equalsBigInteger(crtCoefficient, other.getCrtCoefficient());
}
} else if (o instanceof RSAPrivateKey) {
ensureReadParams();
RSAPrivateKey other = (RSAPrivateKey) o;
if (getOpenSSLKey().isHardwareBacked()) {
- return getModulus().equals(other.getModulus());
+ return equalsBigInteger(getModulus(), other.getModulus());
} else {
- return getModulus().equals(other.getModulus())
- && getPrivateExponent().equals(other.getPrivateExponent());
+ return equalsBigInteger(getModulus(), other.getModulus())
+ && equalsBigInteger(getPrivateExponent(), other.getPrivateExponent());
}
}
diff --git a/common/src/main/java/org/conscrypt/OpenSSLRSAPrivateKey.java b/common/src/main/java/org/conscrypt/OpenSSLRSAPrivateKey.java
index 505e1886b..b123cdddf 100644
--- a/common/src/main/java/org/conscrypt/OpenSSLRSAPrivateKey.java
+++ b/common/src/main/java/org/conscrypt/OpenSSLRSAPrivateKey.java
@@ -22,6 +22,7 @@
import java.io.ObjectOutputStream;
import java.math.BigInteger;
import java.security.InvalidKeyException;
+import java.security.MessageDigest;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.interfaces.RSAKey;
@@ -203,6 +204,10 @@ public final String getAlgorithm() {
return "RSA";
}
+ boolean equalsBigInteger(BigInteger a, BigInteger b) {
+ return MessageDigest.isEqual(a.toByteArray(), b.toByteArray());
+ }
+
@Override
public boolean equals(Object o) {
if (o == this) {
@@ -218,8 +223,8 @@ public boolean equals(Object o) {
ensureReadParams();
RSAPrivateKey other = (RSAPrivateKey) o;
- return modulus.equals(other.getModulus())
- && privateExponent.equals(other.getPrivateExponent());
+ return equalsBigInteger(modulus, other.getModulus())
+ && equalsBigInteger(privateExponent, other.getPrivateExponent());
}
return false;
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 a68160742..2bcb67c9a 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
@@ -1319,26 +1319,56 @@ public void handshake_namedGroupsDontIntersect_throwsException() throws Exceptio
}
@Test
- public void handshake_namedGroupsProperty_failsIfAllValuesAreInvalid() throws Exception {
+ public void setNamedGroupsProperty_invalidValue_isIgnored() throws Exception {
+ // Set the property to a valid value.
+ System.setProperty("jdk.tls.namedGroups", "MLKEM1024");
+
+ {
+ 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();
+ assertEquals("MLKEM1024", getCurveName(client));
+ assertEquals("MLKEM1024", getCurveName(server));
+ client.close();
+ server.close();
+ context.close();
+ }
+
+ // Now, set the property to an invalid value.
System.setProperty("jdk.tls.namedGroups", "invalid,invalid2");
- 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;
- });
- assertThrows(ExecutionException.class, s::get);
- assertThrows(ExecutionException.class, c::get);
- client.close();
- server.close();
- context.close();
+ {
+ 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();
+ assertEquals("MLKEM1024", getCurveName(client));
+ assertEquals("MLKEM1024", getCurveName(server));
+ client.close();
+ server.close();
+ context.close();
+ }
}
@Test
diff --git a/openjdk/src/test/java/org/conscrypt/ConscryptAndroidSuite.java b/openjdk/src/test/java/org/conscrypt/ConscryptAndroidSuite.java
index 6f99aef83..51a3a6698 100644
--- a/openjdk/src/test/java/org/conscrypt/ConscryptAndroidSuite.java
+++ b/openjdk/src/test/java/org/conscrypt/ConscryptAndroidSuite.java
@@ -56,7 +56,14 @@
import org.conscrypt.javax.net.ssl.KeyManagerFactoryTest;
import org.conscrypt.javax.net.ssl.KeyStoreBuilderParametersTest;
import org.conscrypt.javax.net.ssl.SNIHostNameTest;
+import org.conscrypt.javax.net.ssl.SSLContextTest;
+import org.conscrypt.javax.net.ssl.SSLEngineTest;
+import org.conscrypt.javax.net.ssl.SSLEngineVersionCompatibilityTest;
import org.conscrypt.javax.net.ssl.SSLParametersTest;
+import org.conscrypt.javax.net.ssl.SSLServerSocketTest;
+import org.conscrypt.javax.net.ssl.SSLSessionContextTest;
+import org.conscrypt.javax.net.ssl.SSLSessionTest;
+import org.conscrypt.javax.net.ssl.SSLSocketTest;
import org.conscrypt.javax.net.ssl.X509KeyManagerTest;
import org.conscrypt.metrics.CipherSuiteTest;
import org.conscrypt.metrics.OptionalMethodTest;
@@ -150,7 +157,14 @@
ProtocolTest.class,
ScryptTest.class,
SNIHostNameTest.class,
+ SSLContextTest.class,
+ SSLEngineTest.class,
+ SSLEngineVersionCompatibilityTest.class,
SSLParametersTest.class,
+ SSLServerSocketTest.class,
+ SSLSessionContextTest.class,
+ SSLSessionTest.class,
+ SSLSocketTest.class,
VeryBasicHttpServerTest.class,
X509KeyManagerTest.class,
})
diff --git a/openjdk/src/test/java/org/conscrypt/ConscryptAndroidWithoutTlsSuite.java b/openjdk/src/test/java/org/conscrypt/ConscryptAndroidWithoutTlsSuite.java
new file mode 100644
index 000000000..2f76dde5e
--- /dev/null
+++ b/openjdk/src/test/java/org/conscrypt/ConscryptAndroidWithoutTlsSuite.java
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed 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
+ *
+ * http://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 org.conscrypt;
+
+import static org.conscrypt.TestUtils.getConscryptProvider;
+
+import org.conscrypt.ct.SerializationTest;
+import org.conscrypt.ct.VerifierTest;
+import org.conscrypt.java.security.AlgorithmParameterGeneratorTestDH;
+import org.conscrypt.java.security.AlgorithmParameterGeneratorTestDSA;
+import org.conscrypt.java.security.AlgorithmParametersPSSTest;
+import org.conscrypt.java.security.AlgorithmParametersTestAES;
+import org.conscrypt.java.security.AlgorithmParametersTestDES;
+import org.conscrypt.java.security.AlgorithmParametersTestDESede;
+import org.conscrypt.java.security.AlgorithmParametersTestDH;
+import org.conscrypt.java.security.AlgorithmParametersTestDSA;
+import org.conscrypt.java.security.AlgorithmParametersTestEC;
+import org.conscrypt.java.security.AlgorithmParametersTestGCM;
+import org.conscrypt.java.security.AlgorithmParametersTestOAEP;
+import org.conscrypt.java.security.KeyFactoryTestDH;
+import org.conscrypt.java.security.KeyFactoryTestDSA;
+import org.conscrypt.java.security.KeyFactoryTestEC;
+import org.conscrypt.java.security.KeyFactoryTestRSACrt;
+import org.conscrypt.java.security.KeyPairGeneratorTest;
+import org.conscrypt.java.security.KeyPairGeneratorTestDH;
+import org.conscrypt.java.security.KeyPairGeneratorTestDSA;
+import org.conscrypt.java.security.KeyPairGeneratorTestRSA;
+import org.conscrypt.java.security.KeyPairGeneratorTestXDH;
+import org.conscrypt.java.security.MessageDigestTest;
+import org.conscrypt.java.security.SignatureTest;
+import org.conscrypt.java.security.cert.CertificateFactoryTest;
+import org.conscrypt.java.security.cert.X509CRLTest;
+import org.conscrypt.java.security.cert.X509CertificateTest;
+import org.conscrypt.javax.crypto.AeadCipherTest;
+import org.conscrypt.javax.crypto.CipherBasicsTest;
+import org.conscrypt.javax.crypto.ECDHKeyAgreementTest;
+import org.conscrypt.javax.crypto.KeyGeneratorTest;
+import org.conscrypt.javax.crypto.ScryptTest;
+import org.conscrypt.javax.crypto.XDHKeyAgreementTest;
+import org.conscrypt.javax.crypto.XdhKeyFactoryTest;
+import org.conscrypt.javax.crypto.XdhKeyTest;
+import org.conscrypt.javax.net.ssl.KeyManagerFactoryTest;
+import org.conscrypt.javax.net.ssl.KeyStoreBuilderParametersTest;
+import org.conscrypt.javax.net.ssl.SNIHostNameTest;
+import org.conscrypt.javax.net.ssl.SSLParametersTest;
+import org.conscrypt.javax.net.ssl.X509KeyManagerTest;
+import org.conscrypt.metrics.CipherSuiteTest;
+import org.conscrypt.metrics.OptionalMethodTest;
+import org.conscrypt.metrics.ProtocolTest;
+import org.junit.BeforeClass;
+import org.junit.runner.RunWith;
+import org.junit.runners.Suite;
+
+import java.security.Provider;
+import java.security.Security;
+
+import tests.util.ServiceTester;
+
+@RunWith(Suite.class)
+@Suite.SuiteClasses({
+ // org.conscrypt tests
+ AddressUtilsTest.class,
+ ApplicationProtocolSelectorAdapterTest.class,
+ ArrayUtilsTest.class,
+ CertPinManagerTest.class,
+ ChainStrengthAnalyzerTest.class,
+ DuckTypedHpkeSpiTest.class,
+ EdDsaTest.class,
+ ExposedByteArrayOutputStreamTest.class,
+ FileClientSessionCacheTest.class,
+ HostnameVerifierTest.class,
+ HpkeContextTest.class,
+ HpkeContextRecipientTest.class,
+ HpkeContextSenderTest.class,
+ HpkeSuiteTest.class,
+ HpkeTestVectorsTest.class,
+ KeySpecUtilTest.class,
+ MlDsaTest.class,
+ NativeCryptoArgTest.class,
+ NativeCryptoTest.class,
+ NativeSslTest.class,
+ NativeRefTest.class,
+ NativeSslSessionTest.class,
+ OpenSSLKeyTest.class,
+ OpenSSLX509CertificateTest.class,
+ SSLUtilsTest.class,
+ SlhDsaTest.class,
+ TestSessionBuilderTest.class,
+ TrustManagerImplTest.class,
+ X25519Test.class,
+ XwingTest.class,
+ // org.conscrypt.ct tests
+ VerifierTest.class,
+ SerializationTest.class,
+ // java.security tests
+ CertificateFactoryTest.class,
+ X509CertificateTest.class,
+ X509CRLTest.class,
+ AlgorithmParameterGeneratorTestDH.class,
+ AlgorithmParameterGeneratorTestDSA.class,
+ AlgorithmParametersPSSTest.class,
+ AlgorithmParametersTestAES.class,
+ AlgorithmParametersTestDES.class,
+ AlgorithmParametersTestDESede.class,
+ AlgorithmParametersTestDH.class,
+ AlgorithmParametersTestDSA.class,
+ AlgorithmParametersTestEC.class,
+ AlgorithmParametersTestGCM.class,
+ AlgorithmParametersTestOAEP.class,
+ BufferUtilsTest.class,
+ CipherSuiteTest.class,
+ KeyFactoryTestDH.class,
+ KeyFactoryTestDSA.class,
+ KeyFactoryTestEC.class,
+ KeyFactoryTestRSACrt.class,
+ KeyPairGeneratorTest.class,
+ KeyPairGeneratorTestDH.class,
+ KeyPairGeneratorTestDSA.class,
+ KeyPairGeneratorTestRSA.class,
+ KeyPairGeneratorTestXDH.class,
+ MessageDigestTest.class,
+ SignatureTest.class,
+ // javax.crypto tests
+ AeadCipherTest.class,
+ CipherBasicsTest.class,
+ MacTest.class,
+ ECDHKeyAgreementTest.class,
+ KeyGeneratorTest.class,
+ XDHKeyAgreementTest.class,
+ XdhKeyFactoryTest.class,
+ XdhKeyTest.class,
+ // javax.net.ssl tests
+ KeyManagerFactoryTest.class,
+ KeyStoreBuilderParametersTest.class,
+ OptionalMethodTest.class,
+ ProtocolTest.class,
+ ScryptTest.class,
+ SNIHostNameTest.class,
+ SSLParametersTest.class,
+ VeryBasicHttpServerTest.class,
+ X509KeyManagerTest.class,
+})
+public class ConscryptAndroidWithoutTlsSuite {
+ @BeforeClass
+ public static void setupStatic() throws Exception {
+ Provider conscryptProvider = getConscryptProvider();
+ Security.insertProviderAt(conscryptProvider, 1);
+ ServiceTester.setProviders(new Provider[] {conscryptProvider});
+ }
+}
diff --git a/openjdk/src/test/java/org/conscrypt/NativeSslTest.java b/openjdk/src/test/java/org/conscrypt/NativeSslTest.java
index 70aaa3356..2d22fb4bd 100644
--- a/openjdk/src/test/java/org/conscrypt/NativeSslTest.java
+++ b/openjdk/src/test/java/org/conscrypt/NativeSslTest.java
@@ -17,6 +17,7 @@
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertThrows;
+import static org.junit.Assert.assertNull;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -101,4 +102,38 @@ public void parseNamedGroupsProperty_throwsIfNoKnownGroupsFound() {
assertThrows(IllegalArgumentException.class,
() -> NativeSsl.parseNamedGroupsProperty("Unknown,Unknown2"));
}
+
+ @Test
+ public void parseTlsNamedGroupsProperty_works() throws Exception {
+ String savedProperty = System.getProperty("jdk.tls.namedGroups");
+
+ // Valid values.
+ System.setProperty("jdk.tls.namedGroups", "P-384,X25519");
+ NativeSsl.parseTlsNamedGroupsProperty();
+ assertArrayEquals(new int[] {NativeConstants.NID_secp384r1, NativeConstants.NID_X25519},
+ NativeSsl.getParsedTlsNamedGroupsPropertyOrNull());
+
+ // Property not set.
+ System.clearProperty("jdk.tls.namedGroups");
+ NativeSsl.parseTlsNamedGroupsProperty();
+ assertNull(NativeSsl.getParsedTlsNamedGroupsPropertyOrNull());
+
+ // Empty property.
+ System.setProperty("jdk.tls.namedGroups", "");
+ NativeSsl.parseTlsNamedGroupsProperty();
+ assertNull(NativeSsl.getParsedTlsNamedGroupsPropertyOrNull());
+
+ // Invalid values.
+ System.setProperty("jdk.tls.namedGroups", "invalid,invalid2");
+ assertThrows(IllegalArgumentException.class, () -> NativeSsl.parseTlsNamedGroupsProperty());
+
+ // Restore the property to its original value, to make sure that the test does not
+ // have any side effects on other tests when setting the property.
+ if (savedProperty == null) {
+ System.clearProperty("jdk.tls.namedGroups");
+ } else {
+ System.setProperty("jdk.tls.namedGroups", savedProperty);
+ }
+ NativeSsl.parseTlsNamedGroupsProperty();
+ }
}