From 61cf687009f06a551d4fe24c4418bd832c4bd6ea Mon Sep 17 00:00:00 2001 From: Miguel Aranda Date: Thu, 22 Jan 2026 22:55:55 +0000 Subject: [PATCH] Project import generated by Copybara. PiperOrigin-RevId: 859786913 --- .clang-format | 5 +- PREUPLOAD.cfg | 3 - android/lint.xml | 6 + .../ConscryptNetworkSecurityPolicy.java | 45 + .../java/org/conscrypt/ConscryptStatsLog.java | 26 + .../src/main/java/org/conscrypt/Platform.java | 257 +- common/src/jni/main/cpp/conscrypt/jniutil.cc | 89 +- .../jni/main/cpp/conscrypt/native_crypto.cc | 442 ++- .../src/jni/main/include/conscrypt/jniutil.h | 17 +- .../conscrypt/AbstractConscryptEngine.java | 18 +- .../conscrypt/AbstractConscryptSocket.java | 19 +- .../main/java/org/conscrypt/ArrayUtils.java | 7 +- .../main/java/org/conscrypt/BufferUtils.java | 27 +- .../java/org/conscrypt/CertBlocklist.java | 4 +- .../org/conscrypt/CertBlocklistEntry.java | 37 + .../main/java/org/conscrypt/Conscrypt.java | 95 +- .../ConscryptFileDescriptorSocket.java | 76 +- .../conscrypt/ConscryptX509TrustManager.java | 63 + .../org/conscrypt/DomainEncryptionMode.java | 19 + .../main/java/org/conscrypt/EchOptions.java | 36 + .../src/main/java/org/conscrypt/HpkeImpl.java | 43 +- .../org/conscrypt/Java8EngineWrapper.java | 8 +- .../main/java/org/conscrypt/NativeCrypto.java | 984 ++++-- .../main/java/org/conscrypt/NativeSsl.java | 75 +- .../org/conscrypt/NetworkSecurityPolicy.java | 34 + .../java/org/conscrypt/OpenSSLAeadCipher.java | 80 +- .../org/conscrypt/OpenSSLContextImpl.java | 15 +- .../java/org/conscrypt/OpenSSLProvider.java | 225 +- .../java/org/conscrypt/OpenSSLSocketImpl.java | 36 +- .../conscrypt/OpenSSLX25519PrivateKey.java | 23 +- .../org/conscrypt/OpenSSLX25519PublicKey.java | 16 +- .../org/conscrypt/OpenSSLX509CRLEntry.java | 38 +- .../org/conscrypt/OpenSslXwingKeyFactory.java | 51 +- .../org/conscrypt/OpenSslXwingPrivateKey.java | 45 +- .../org/conscrypt/OpenSslXwingPublicKey.java | 46 +- .../java/org/conscrypt/SSLParametersImpl.java | 169 +- .../org/conscrypt/ScryptSecretKeyFactory.java | 22 +- .../java/org/conscrypt/TrustManagerImpl.java | 175 +- .../main/java/org/conscrypt/XdhKeySpec.java | 25 +- .../org/conscrypt/ct/CertificateEntry.java | 33 +- .../conscrypt/ct/CertificateTransparency.java | 26 +- .../main/java/org/conscrypt/ct/LogInfo.java | 63 +- .../org/conscrypt/ct/PolicyCompliance.java | 4 +- .../ct/SignedCertificateTimestamp.java | 43 +- ...ificateTransparencyVerificationReason.java | 7 +- .../conscrypt/metrics/ConscryptStatsLog.java | 32 +- .../org/conscrypt/metrics/NoopStatsLog.java | 10 +- .../java/org/conscrypt/metrics/StatsLog.java | 10 +- .../org/conscrypt/metrics/StatsLogImpl.java | 157 +- .../java/org/conscrypt/ArrayUtilsTest.java | 36 +- .../org/conscrypt/HostnameVerifierTest.java | 712 +++-- .../src/test/java/org/conscrypt/MacTest.java | 266 +- .../org/conscrypt/NativeCryptoArgTest.java | 130 +- .../test/java/org/conscrypt/XwingTest.java | 165 +- .../org/conscrypt/ct/SerializationTest.java | 177 +- .../java/org/conscrypt/ct/VerifierTest.java | 27 +- .../security/AlgorithmParametersTestAES.java | 50 +- .../AlgorithmParametersTestDESede.java | 49 +- .../security/AlgorithmParametersTestEC.java | 66 +- .../security/AlgorithmParametersTestGCM.java | 84 +- .../security/AlgorithmParametersTestOAEP.java | 237 +- .../java/security/KeyFactoryTestEC.java | 66 +- .../java/security/KeyFactoryTestRSA.java | 26 +- .../java/security/KeyPairGeneratorTest.java | 211 +- .../java/security/MessageDigestTest.java | 283 +- .../java/security/SignatureTest.java | 2832 +++++++++-------- .../security/cert/CertificateFactoryTest.java | 193 +- .../java/security/cert/X509CRLTest.java | 120 +- .../security/cert/X509CertificateTest.java | 230 +- .../conscrypt/javax/crypto/CipherTest.java | 2168 +++++++------ .../javax/crypto/ECDHKeyAgreementTest.java | 111 +- .../javax/crypto/KeyGeneratorTest.java | 75 +- .../javax/crypto/XDHKeyAgreementTest.java | 66 +- .../javax/crypto/XdhKeyFactoryTest.java | 41 +- .../conscrypt/javax/crypto/XdhKeyTest.java | 44 +- .../javax/net/ssl/KeyManagerFactoryTest.java | 73 +- .../javax/net/ssl/SSLEngineTest.java | 412 +-- constants/src/gen/cpp/generate_constants.cc | 133 - fix_format.py | 79 + .../src/main/java/libcore/util/NonNull.java | 47 - .../src/main/java/libcore/util/Nullable.java | 47 - openjdk/build.gradle | 10 +- .../ConscryptNetworkSecurityPolicy.java | 45 + .../src/main/java/org/conscrypt/Platform.java | 154 +- platform/src/main/ct_log_store.fbs | 38 + .../java/org/conscrypt/AndroidHpkeSpi.java | 50 +- .../java/org/conscrypt/CertBlocklistImpl.java | 283 +- .../ConscryptNetworkSecurityPolicy.java | 102 + platform/src/main/java/org/conscrypt/Hex.java | 47 +- .../src/main/java/org/conscrypt/Platform.java | 193 +- .../java/org/conscrypt/ct/LogStoreImpl.java | 182 +- .../java/org/conscrypt/ct/PolicyImpl.java | 48 +- .../org/conscrypt/AndroidHpkeSpiTest.java | 15 +- .../java/org/conscrypt/CertBlocklistTest.java | 56 +- .../test/java/org/conscrypt/SpakeTest.java | 9 +- .../org/conscrypt/TlsDeprecationTest.java | 39 +- .../org/conscrypt/ct/LogStoreImplTest.java | 274 +- .../java/org/conscrypt/ct/PolicyImplTest.java | 119 +- .../main/java/org/conscrypt/TestUtils.java | 139 +- .../java/security/StandardNames.java | 155 +- .../org/conscrypt/testing/OpaqueProvider.java | 618 ++-- 101 files changed, 8530 insertions(+), 7088 deletions(-) delete mode 100644 PREUPLOAD.cfg create mode 100644 android/src/main/java/org/conscrypt/ConscryptNetworkSecurityPolicy.java create mode 100644 android/src/main/java/org/conscrypt/ConscryptStatsLog.java create mode 100644 common/src/main/java/org/conscrypt/CertBlocklistEntry.java create mode 100644 common/src/main/java/org/conscrypt/ConscryptX509TrustManager.java create mode 100644 common/src/main/java/org/conscrypt/DomainEncryptionMode.java create mode 100644 common/src/main/java/org/conscrypt/EchOptions.java create mode 100644 common/src/main/java/org/conscrypt/NetworkSecurityPolicy.java delete mode 100644 constants/src/gen/cpp/generate_constants.cc create mode 100755 fix_format.py delete mode 100644 libcore-stub/src/main/java/libcore/util/NonNull.java delete mode 100644 libcore-stub/src/main/java/libcore/util/Nullable.java create mode 100644 openjdk/src/main/java/org/conscrypt/ConscryptNetworkSecurityPolicy.java create mode 100644 platform/src/main/ct_log_store.fbs create mode 100644 platform/src/main/java/org/conscrypt/ConscryptNetworkSecurityPolicy.java diff --git a/.clang-format b/.clang-format index c05d06f80..ad30c81a3 100644 --- a/.clang-format +++ b/.clang-format @@ -1,18 +1,21 @@ --- Language: Cpp -BasedOnStyle: Google +BasedOnStyle: Google AccessModifierOffset: -4 AllowShortFunctionsOnASingleLine: Empty ColumnLimit: 100 IndentWidth: 4 ContinuationIndentWidth: 8 TypenameMacros: ['STACK_OF'] +AlignEscapedNewlines: Left +AlignAfterOpenBracket: Align --- Language: Java BasedOnStyle: Google ColumnLimit: 100 IndentWidth: 4 ContinuationIndentWidth: 8 +AlignAfterOpenBracket: Align JavaImportGroups: - android - androidx diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg deleted file mode 100644 index 4c8d13794..000000000 --- a/PREUPLOAD.cfg +++ /dev/null @@ -1,3 +0,0 @@ -[Builtin Hooks] -commit_msg_test_field = true -clang_format = true diff --git a/android/lint.xml b/android/lint.xml index 5d43d7ff6..8ad971986 100644 --- a/android/lint.xml +++ b/android/lint.xml @@ -28,4 +28,10 @@ + + + + + + diff --git a/android/src/main/java/org/conscrypt/ConscryptNetworkSecurityPolicy.java b/android/src/main/java/org/conscrypt/ConscryptNetworkSecurityPolicy.java new file mode 100644 index 000000000..4f5f0e6ad --- /dev/null +++ b/android/src/main/java/org/conscrypt/ConscryptNetworkSecurityPolicy.java @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2025 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 org.conscrypt.metrics.CertificateTransparencyVerificationReason; + +/** + * A default NetworkSecurityPolicy for unbundled Android. + */ +@Internal +public class ConscryptNetworkSecurityPolicy implements NetworkSecurityPolicy { + public static ConscryptNetworkSecurityPolicy getDefault() { + return new ConscryptNetworkSecurityPolicy(); + } + + @Override + public boolean isCertificateTransparencyVerificationRequired(String hostname) { + return false; + } + + @Override + public CertificateTransparencyVerificationReason getCertificateTransparencyVerificationReason( + String hostname) { + return CertificateTransparencyVerificationReason.UNKNOWN; + } + + @Override + public DomainEncryptionMode getDomainEncryptionMode(String hostname) { + return DomainEncryptionMode.UNKNOWN; + } +} diff --git a/android/src/main/java/org/conscrypt/ConscryptStatsLog.java b/android/src/main/java/org/conscrypt/ConscryptStatsLog.java new file mode 100644 index 000000000..19ab61631 --- /dev/null +++ b/android/src/main/java/org/conscrypt/ConscryptStatsLog.java @@ -0,0 +1,26 @@ +/* + * Copyright 2020 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; + +/** + * Stub class for logging statistics events. + */ +public class ConscryptStatsLog { + public static final int TLS_HANDSHAKE_REPORTED = 0; + + public static void write(int code, boolean arg1, int arg2, int arg3, int arg4) {} +} diff --git a/android/src/main/java/org/conscrypt/Platform.java b/android/src/main/java/org/conscrypt/Platform.java index 65fc084ad..681842ff5 100644 --- a/android/src/main/java/org/conscrypt/Platform.java +++ b/android/src/main/java/org/conscrypt/Platform.java @@ -59,11 +59,13 @@ import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.function.Supplier; import javax.net.ssl.SNIHostName; import javax.net.ssl.SNIMatcher; import javax.net.ssl.SNIServerName; import javax.net.ssl.SSLEngine; +import javax.net.ssl.SSLException; import javax.net.ssl.SSLParameters; import javax.net.ssl.SSLSession; import javax.net.ssl.SSLSocketFactory; @@ -82,13 +84,14 @@ final public class Platform { private static boolean FILTERED_TLS_V1 = true; private static Method m_getCurveName; + static { NativeCrypto.setTlsV1DeprecationStatus(DEPRECATED_TLS_V1, ENABLED_TLS_V1); try { m_getCurveName = ECParameterSpec.class.getDeclaredMethod("getCurveName"); m_getCurveName.setAccessible(true); } catch (Exception ignored) { - //Ignored + // Ignored } } @@ -146,7 +149,7 @@ public static void setCurveName(ECParameterSpec spec, String curveName) { Method setCurveName = spec.getClass().getDeclaredMethod("setCurveName", String.class); setCurveName.invoke(spec, curveName); } catch (Exception ignored) { - //Ignored + // Ignored } } @@ -212,15 +215,16 @@ public static void setSocketWriteTimeout(Socket s, long timeoutMillis) throws So return; } - Method m_setsockoptTimeval = instance_os.getClass().getMethod("setsockoptTimeval", - FileDescriptor.class, int.class, int.class, c_structTimeval); + Method m_setsockoptTimeval = + instance_os.getClass().getMethod("setsockoptTimeval", FileDescriptor.class, + int.class, int.class, c_structTimeval); if (m_setsockoptTimeval == null) { Log.w(TAG, "setsockoptTimeval == null; not setting socket write timeout"); return; } m_setsockoptTimeval.invoke(instance_os, fd, f_SOL_SOCKET.get(null), - f_SO_SNDTIMEO.get(null), timeval); + f_SO_SNDTIMEO.get(null), timeval); } catch (Exception e) { // We don't want to spam the logcat since this isn't a fatal error, but we want to know // why this might be happening. @@ -257,13 +261,14 @@ private static void setSSLParametersOnImpl(SSLParameters params, SSLParametersIm try { Method getNamedGroupsMethod = params.getClass().getMethod("getNamedGroups"); impl.setNamedGroups((String[]) getNamedGroupsMethod.invoke(params)); - } catch (NoSuchMethodException | IllegalArgumentException e) { + } catch (NoSuchMethodException | IllegalArgumentException | IllegalAccessException + | InvocationTargetException e) { // Do nothing. } } - public static void setSSLParameters( - SSLParameters params, SSLParametersImpl impl, AbstractConscryptSocket socket) { + public static void setSSLParameters(SSLParameters params, SSLParametersImpl impl, + AbstractConscryptSocket socket) { try { setSSLParametersOnImpl(params, impl); @@ -274,16 +279,16 @@ public static void setSSLParameters( } } } catch (NoSuchMethodException ignored) { - //Ignored + // Ignored } catch (IllegalAccessException ignored) { - //Ignored + // Ignored } catch (InvocationTargetException e) { throw new RuntimeException(e.getCause()); } } - public static void setSSLParameters( - SSLParameters params, SSLParametersImpl impl, ConscryptEngine engine) { + public static void setSSLParameters(SSLParameters params, SSLParametersImpl impl, + ConscryptEngine engine) { try { setSSLParametersOnImpl(params, impl); @@ -294,9 +299,9 @@ public static void setSSLParameters( } } } catch (NoSuchMethodException ignored) { - //Ignored + // Ignored } catch (IllegalAccessException ignored) { - //Ignored + // Ignored } catch (InvocationTargetException e) { throw new RuntimeException(e.getCause()); } @@ -323,8 +328,8 @@ private static void getSSLParametersFromImpl(SSLParameters params, SSLParameters throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { Method m_setEndpointIdentificationAlgorithm = params.getClass().getMethod("setEndpointIdentificationAlgorithm", String.class); - m_setEndpointIdentificationAlgorithm.invoke( - params, impl.getEndpointIdentificationAlgorithm()); + m_setEndpointIdentificationAlgorithm.invoke(params, + impl.getEndpointIdentificationAlgorithm()); Method m_setUseCipherSuitesOrder = params.getClass().getMethod("setUseCipherSuitesOrder", boolean.class); @@ -334,13 +339,14 @@ private static void getSSLParametersFromImpl(SSLParameters params, SSLParameters Method setNamedGroupsMethod = params.getClass().getMethod("setNamedGroups", String[].class); setNamedGroupsMethod.invoke(params, (Object) impl.getNamedGroups()); - } catch (NoSuchMethodException | IllegalArgumentException e) { + } catch (NoSuchMethodException | IllegalArgumentException | IllegalAccessException + | InvocationTargetException e) { // Do nothing. } } - public static void getSSLParameters( - SSLParameters params, SSLParametersImpl impl, AbstractConscryptSocket socket) { + public static void getSSLParameters(SSLParameters params, SSLParametersImpl impl, + AbstractConscryptSocket socket) { try { getSSLParametersFromImpl(params, impl); @@ -348,28 +354,28 @@ public static void getSSLParameters( setParametersSniHostname(params, impl, socket); } } catch (NoSuchMethodException ignored) { - //Ignored + // Ignored } catch (IllegalAccessException ignored) { - //Ignored + // Ignored } catch (InvocationTargetException e) { throw new RuntimeException(e.getCause()); } } @TargetApi(24) - private static void setParametersSniHostname( - SSLParameters params, SSLParametersImpl impl, AbstractConscryptSocket socket) + private static void setParametersSniHostname(SSLParameters params, SSLParametersImpl impl, + AbstractConscryptSocket socket) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { if (impl.getUseSni() && AddressUtils.isValidSniHostname(socket.getHostname())) { Method m_setServerNames = params.getClass().getMethod("setServerNames", List.class); m_setServerNames.invoke(params, - Collections.singletonList( - new SNIHostName(socket.getHostname()))); + Collections.singletonList( + new SNIHostName(socket.getHostname()))); } } - public static void getSSLParameters( - SSLParameters params, SSLParametersImpl impl, ConscryptEngine engine) { + public static void getSSLParameters(SSLParameters params, SSLParametersImpl impl, + ConscryptEngine engine) { try { getSSLParametersFromImpl(params, impl); @@ -377,23 +383,23 @@ public static void getSSLParameters( setParametersSniHostname(params, impl, engine); } } catch (NoSuchMethodException ignored) { - //Ignored + // Ignored } catch (IllegalAccessException ignored) { - //Ignored + // Ignored } catch (InvocationTargetException e) { throw new RuntimeException(e.getCause()); } } @TargetApi(24) - private static void setParametersSniHostname( - SSLParameters params, SSLParametersImpl impl, ConscryptEngine engine) + private static void setParametersSniHostname(SSLParameters params, SSLParametersImpl impl, + ConscryptEngine engine) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { if (impl.getUseSni() && AddressUtils.isValidSniHostname(engine.getHostname())) { Method m_setServerNames = params.getClass().getMethod("setServerNames", List.class); m_setServerNames.invoke(params, - Collections.singletonList( - new SNIHostName(engine.getHostname()))); + Collections.singletonList( + new SNIHostName(engine.getHostname()))); } } @@ -405,14 +411,14 @@ private static Class getClass(String... klasses) { try { return Class.forName(klass); } catch (Exception ignored) { - //Ignored + // Ignored } } return null; } - public static void setEndpointIdentificationAlgorithm( - SSLParameters params, String endpointIdentificationAlgorithm) { + public static void setEndpointIdentificationAlgorithm(SSLParameters params, + String endpointIdentificationAlgorithm) { // TODO: implement this for unbundled } @@ -426,21 +432,22 @@ public static String getEndpointIdentificationAlgorithm(SSLParameters params) { * Socket, SSLEngine, or String (legacy Android). */ private static boolean checkTrusted(String methodName, X509TrustManager tm, - X509Certificate[] chain, String authType, Class argumentClass, - Object argumentInstance) throws CertificateException { + X509Certificate[] chain, String authType, + Class argumentClass, Object argumentInstance) + throws CertificateException { // Use duck-typing to try and call the hostname-aware method if available. try { - Method method = tm.getClass().getMethod( - methodName, X509Certificate[].class, String.class, argumentClass); + Method method = tm.getClass().getMethod(methodName, X509Certificate[].class, + String.class, argumentClass); method.invoke(tm, chain, authType, argumentInstance); return true; } catch (NoSuchMethodException ignored) { - //Ignored + // Ignored } catch (IllegalAccessException ignored) { - //Ignored + // Ignored } catch (InvocationTargetException e) { if (e.getCause() instanceof CertificateException) { - throw(CertificateException) e.getCause(); + throw (CertificateException) e.getCause(); } throw new RuntimeException(e.getCause()); } @@ -449,40 +456,44 @@ private static boolean checkTrusted(String methodName, X509TrustManager tm, @SuppressLint("NewApi") // AbstractConscryptSocket defines getHandshakeSession() public static void checkClientTrusted(X509TrustManager tm, X509Certificate[] chain, - String authType, AbstractConscryptSocket socket) throws CertificateException { + String authType, AbstractConscryptSocket socket) + throws CertificateException { if (!checkTrusted("checkClientTrusted", tm, chain, authType, Socket.class, socket) - && !checkTrusted("checkClientTrusted", tm, chain, authType, String.class, - socket.getHandshakeSession().getPeerHost())) { + && !checkTrusted("checkClientTrusted", tm, chain, authType, String.class, + socket.getHandshakeSession().getPeerHost())) { tm.checkClientTrusted(chain, authType); } } @SuppressLint("NewApi") // AbstractConscryptSocket defines getHandshakeSession() public static void checkServerTrusted(X509TrustManager tm, X509Certificate[] chain, - String authType, AbstractConscryptSocket socket) throws CertificateException { + String authType, AbstractConscryptSocket socket) + throws CertificateException { if (!checkTrusted("checkServerTrusted", tm, chain, authType, Socket.class, socket) - && !checkTrusted("checkServerTrusted", tm, chain, authType, String.class, - socket.getHandshakeSession().getPeerHost())) { + && !checkTrusted("checkServerTrusted", tm, chain, authType, String.class, + socket.getHandshakeSession().getPeerHost())) { tm.checkServerTrusted(chain, authType); } } @SuppressLint("NewApi") // AbstractConscryptSocket defines getHandshakeSession() public static void checkClientTrusted(X509TrustManager tm, X509Certificate[] chain, - String authType, ConscryptEngine engine) throws CertificateException { + String authType, ConscryptEngine engine) + throws CertificateException { if (!checkTrusted("checkClientTrusted", tm, chain, authType, SSLEngine.class, engine) - && !checkTrusted("checkClientTrusted", tm, chain, authType, String.class, - engine.getHandshakeSession().getPeerHost())) { + && !checkTrusted("checkClientTrusted", tm, chain, authType, String.class, + engine.getHandshakeSession().getPeerHost())) { tm.checkClientTrusted(chain, authType); } } @SuppressLint("NewApi") // AbstractConscryptSocket defines getHandshakeSession() public static void checkServerTrusted(X509TrustManager tm, X509Certificate[] chain, - String authType, ConscryptEngine engine) throws CertificateException { + String authType, ConscryptEngine engine) + throws CertificateException { if (!checkTrusted("checkServerTrusted", tm, chain, authType, SSLEngine.class, engine) - && !checkTrusted("checkServerTrusted", tm, chain, authType, String.class, - engine.getHandshakeSession().getPeerHost())) { + && !checkTrusted("checkServerTrusted", tm, chain, authType, String.class, + engine.getHandshakeSession().getPeerHost())) { tm.checkServerTrusted(chain, authType); } } @@ -506,7 +517,8 @@ static ConscryptEngineSocket createEngineSocket(SSLParametersImpl sslParameters) } static ConscryptEngineSocket createEngineSocket(String hostname, int port, - SSLParametersImpl sslParameters) throws IOException { + SSLParametersImpl sslParameters) + throws IOException { if (Build.VERSION.SDK_INT >= 24) { return new Java8EngineSocket(hostname, port, sslParameters); } @@ -514,7 +526,8 @@ static ConscryptEngineSocket createEngineSocket(String hostname, int port, } static ConscryptEngineSocket createEngineSocket(InetAddress address, int port, - SSLParametersImpl sslParameters) throws IOException { + SSLParametersImpl sslParameters) + throws IOException { if (Build.VERSION.SDK_INT >= 24) { return new Java8EngineSocket(address, port, sslParameters); } @@ -522,7 +535,8 @@ static ConscryptEngineSocket createEngineSocket(InetAddress address, int port, } static ConscryptEngineSocket createEngineSocket(String hostname, int port, - InetAddress clientAddress, int clientPort, SSLParametersImpl sslParameters) + InetAddress clientAddress, int clientPort, + SSLParametersImpl sslParameters) throws IOException { if (Build.VERSION.SDK_INT >= 24) { return new Java8EngineSocket(hostname, port, clientAddress, clientPort, sslParameters); @@ -531,7 +545,8 @@ static ConscryptEngineSocket createEngineSocket(String hostname, int port, } static ConscryptEngineSocket createEngineSocket(InetAddress address, int port, - InetAddress clientAddress, int clientPort, SSLParametersImpl sslParameters) + InetAddress clientAddress, int clientPort, + SSLParametersImpl sslParameters) throws IOException { if (Build.VERSION.SDK_INT >= 24) { return new Java8EngineSocket(address, port, clientAddress, clientPort, sslParameters); @@ -540,7 +555,9 @@ static ConscryptEngineSocket createEngineSocket(InetAddress address, int port, } static ConscryptEngineSocket createEngineSocket(Socket socket, String hostname, int port, - boolean autoClose, SSLParametersImpl sslParameters) throws IOException { + boolean autoClose, + SSLParametersImpl sslParameters) + throws IOException { if (Build.VERSION.SDK_INT >= 24) { return new Java8EngineSocket(socket, hostname, port, autoClose, sslParameters); } @@ -556,7 +573,8 @@ static ConscryptFileDescriptorSocket createFileDescriptorSocket(SSLParametersImp } static ConscryptFileDescriptorSocket createFileDescriptorSocket(String hostname, int port, - SSLParametersImpl sslParameters) throws IOException { + SSLParametersImpl sslParameters) + throws IOException { if (Build.VERSION.SDK_INT >= 24) { return new Java8FileDescriptorSocket(hostname, port, sslParameters); } @@ -564,7 +582,8 @@ static ConscryptFileDescriptorSocket createFileDescriptorSocket(String hostname, } static ConscryptFileDescriptorSocket createFileDescriptorSocket(InetAddress address, int port, - SSLParametersImpl sslParameters) throws IOException { + SSLParametersImpl sslParameters) + throws IOException { if (Build.VERSION.SDK_INT >= 24) { return new Java8FileDescriptorSocket(address, port, sslParameters); } @@ -572,29 +591,35 @@ static ConscryptFileDescriptorSocket createFileDescriptorSocket(InetAddress addr } static ConscryptFileDescriptorSocket createFileDescriptorSocket(String hostname, int port, - InetAddress clientAddress, int clientPort, SSLParametersImpl sslParameters) + InetAddress clientAddress, + int clientPort, + SSLParametersImpl sslParameters) throws IOException { if (Build.VERSION.SDK_INT >= 24) { - return new Java8FileDescriptorSocket( - hostname, port, clientAddress, clientPort, sslParameters); + return new Java8FileDescriptorSocket(hostname, port, clientAddress, clientPort, + sslParameters); } - return new ConscryptFileDescriptorSocket( - hostname, port, clientAddress, clientPort, sslParameters); + return new ConscryptFileDescriptorSocket(hostname, port, clientAddress, clientPort, + sslParameters); } static ConscryptFileDescriptorSocket createFileDescriptorSocket(InetAddress address, int port, - InetAddress clientAddress, int clientPort, SSLParametersImpl sslParameters) + InetAddress clientAddress, + int clientPort, + SSLParametersImpl sslParameters) throws IOException { if (Build.VERSION.SDK_INT >= 24) { - return new Java8FileDescriptorSocket( - address, port, clientAddress, clientPort, sslParameters); + return new Java8FileDescriptorSocket(address, port, clientAddress, clientPort, + sslParameters); } - return new ConscryptFileDescriptorSocket( - address, port, clientAddress, clientPort, sslParameters); + return new ConscryptFileDescriptorSocket(address, port, clientAddress, clientPort, + sslParameters); } static ConscryptFileDescriptorSocket createFileDescriptorSocket(Socket socket, String hostname, - int port, boolean autoClose, SSLParametersImpl sslParameters) throws IOException { + int port, boolean autoClose, + SSLParametersImpl sslParameters) + throws IOException { if (Build.VERSION.SDK_INT >= 24) { return new Java8FileDescriptorSocket(socket, hostname, port, autoClose, sslParameters); } @@ -639,8 +664,8 @@ public static GCMParameters fromGCMParameterSpec(AlgorithmParameterSpec params) } catch (IllegalAccessException e) { throw new RuntimeException("GCMParameterSpec lacks expected methods", e); } catch (InvocationTargetException e) { - throw new RuntimeException( - "Could not fetch GCM parameters", e.getTargetException()); + throw new RuntimeException("Could not fetch GCM parameters", + e.getTargetException()); } } return null; @@ -685,7 +710,7 @@ public static AlgorithmParameterSpec toGCMParameterSpec(int tagLenInBits, byte[] Constructor constructor = gcmSpecClass.getConstructor(int.class, byte[].class); return (AlgorithmParameterSpec) constructor.newInstance(tagLenInBits, iv); } catch (NoSuchMethodException | InstantiationException | IllegalAccessException - | IllegalArgumentException e) { + | IllegalArgumentException e) { logStackTraceSnippet("Can't find GCMParameterSpec class", e); } catch (InvocationTargetException e) { logStackTraceSnippet("Can't find GCMParameterSpec class", e.getCause()); @@ -741,13 +766,13 @@ public static String oidToAlgorithmName(String oid) { } catch (InvocationTargetException e) { Throwable cause = e.getCause(); if (cause instanceof RuntimeException) { - throw(RuntimeException) cause; + throw (RuntimeException) cause; } else if (cause instanceof Error) { - throw(Error) cause; + throw (Error) cause; } throw new RuntimeException(e); } catch (Exception ignored) { - //Ignored + // Ignored } // Newer OpenJDK style @@ -763,13 +788,13 @@ public static String oidToAlgorithmName(String oid) { } catch (InvocationTargetException e) { Throwable cause = e.getCause(); if (cause instanceof RuntimeException) { - throw(RuntimeException) cause; + throw (RuntimeException) cause; } else if (cause instanceof Error) { - throw(Error) cause; + throw (Error) cause; } throw new RuntimeException(e); } catch (Exception ignored) { - //Ignored + // Ignored } return oid; @@ -808,9 +833,9 @@ public static String getOriginalHostNameFromInetAddress(InetAddress addr) { } catch (ClassNotFoundException ignore) { // passthrough and return addr.getHostAddress() } catch (IllegalAccessException ignore) { - //Ignored + // Ignored } catch (NoSuchMethodException ignore) { - //Ignored + // Ignored } } return addr.getHostAddress(); @@ -828,7 +853,7 @@ public static String getHostStringFromInetSocketAddress(InetSocketAddress addr) } catch (InvocationTargetException e) { throw new RuntimeException(e); } catch (Exception ignored) { - //Ignored + // Ignored } } return null; @@ -839,59 +864,8 @@ static boolean supportsX509ExtendedTrustManager() { return Build.VERSION.SDK_INT > 23; } - /** - * Check if SCT verification is required for a given hostname. - * - * SCT Verification is enabled using {@code Security} properties. - * The "conscrypt.ct.enable" property must be true, as well as a per domain property. - * The reverse notation of the domain name, prefixed with "conscrypt.ct.enforce." - * is used as the property name. - * Basic globbing is also supported. - * - * For example, for the domain foo.bar.com, the following properties will be - * looked up, in order of precedence. - * - conscrypt.ct.enforce.com.bar.foo - * - conscrypt.ct.enforce.com.bar.* - * - conscrypt.ct.enforce.com.* - * - conscrypt.ct.enforce.* - */ - public static boolean isCTVerificationRequired(String hostname) { - if (hostname == null) { - return false; - } - // TODO: Use the platform version on platforms that support it - - String property = Security.getProperty("conscrypt.ct.enable"); - if (property == null || !Boolean.parseBoolean(property)) { - return false; - } - - List parts = Arrays.asList(hostname.split("\\.")); - Collections.reverse(parts); - - boolean enable = false; - String propertyName = "conscrypt.ct.enforce"; - // The loop keeps going on even once we've found a match - // This allows for finer grained settings on subdomains - for (String part : parts) { - property = Security.getProperty(propertyName + ".*"); - if (property != null) { - enable = Boolean.parseBoolean(property); - } - - propertyName = propertyName + "." + part; - } - - property = Security.getProperty(propertyName); - if (property != null) { - enable = Boolean.parseBoolean(property); - } - return enable; - } - - public static CertificateTransparencyVerificationReason reasonCTVerificationRequired( - String hostname) { - return CertificateTransparencyVerificationReason.UNKNOWN; + static SSLException wrapInvalidEchDataException(SSLException e) { + return e; } static boolean supportsConscryptCertStore() { @@ -920,7 +894,8 @@ static CertBlocklist newDefaultBlocklist() { return null; } - static CertificateTransparency newDefaultCertificateTransparency() { + static CertificateTransparency newDefaultCertificateTransparency( + Supplier policySupplier) { return null; } @@ -932,8 +907,8 @@ static boolean serverNamePermitted(SSLParametersImpl parameters, String serverNa } @TargetApi(24) - private static boolean serverNamePermittedInternal( - SSLParametersImpl parameters, String serverName) { + private static boolean serverNamePermittedInternal(SSLParametersImpl parameters, + String serverName) { Collection sniMatchers = parameters.getSNIMatchers(); if (sniMatchers == null || sniMatchers.isEmpty()) { return true; diff --git a/common/src/jni/main/cpp/conscrypt/jniutil.cc b/common/src/jni/main/cpp/conscrypt/jniutil.cc index 96385df2a..ae24377e5 100644 --- a/common/src/jni/main/cpp/conscrypt/jniutil.cc +++ b/common/src/jni/main/cpp/conscrypt/jniutil.cc @@ -14,17 +14,17 @@ * limitations under the License. */ -#include - #include +#include #include -#include #include +#include + namespace conscrypt { namespace jniutil { -JavaVM *gJavaVM; +JavaVM* gJavaVM; jclass cryptoUpcallsClass; jclass openSslInputStreamClass; jclass nativeRefClass; @@ -84,10 +84,10 @@ void init(JavaVM* vm, JNIEnv* env) { bufferClass = findClass(env, "java/nio/Buffer"); fileDescriptorClass = findClass(env, "java/io/FileDescriptor"); - cryptoUpcallsClass = getGlobalRefToClass( - env, TO_STRING(JNI_JARJAR_PREFIX) "org/conscrypt/CryptoUpcalls"); - nativeRefClass = getGlobalRefToClass( - env, TO_STRING(JNI_JARJAR_PREFIX) "org/conscrypt/NativeRef"); + cryptoUpcallsClass = + getGlobalRefToClass(env, TO_STRING(JNI_JARJAR_PREFIX) "org/conscrypt/CryptoUpcalls"); + nativeRefClass = + getGlobalRefToClass(env, TO_STRING(JNI_JARJAR_PREFIX) "org/conscrypt/NativeRef"); nativeRefHpkeCtxClass = getGlobalRefToClass( env, TO_STRING(JNI_JARJAR_PREFIX) "org/conscrypt/NativeRef$EVP_HPKE_CTX"); openSslInputStreamClass = getGlobalRefToClass( @@ -106,46 +106,43 @@ void init(JavaVM* vm, JNIEnv* env) { inputStream_readMethod = getMethodRef(env, inputStreamClass, "read", "([B)I"); integer_valueOfMethod = env->GetStaticMethodID(integerClass, "valueOf", "(I)Ljava/lang/Integer;"); - openSslInputStream_readLineMethod = - getMethodRef(env, openSslInputStreamClass, "gets", "([B)I"); + openSslInputStream_readLineMethod = getMethodRef(env, openSslInputStreamClass, "gets", "([B)I"); outputStream_writeMethod = getMethodRef(env, outputStreamClass, "write", "([B)V"); outputStream_flushMethod = getMethodRef(env, outputStreamClass, "flush", "()V"); buffer_positionMethod = getMethodRef(env, bufferClass, "position", "()I"); buffer_limitMethod = getMethodRef(env, bufferClass, "limit", "()I"); buffer_isDirectMethod = getMethodRef(env, bufferClass, "isDirect", "()Z"); - sslHandshakeCallbacks_verifyCertificateChain = - getMethodRef(env, sslHandshakeCallbacksClass, "verifyCertificateChain", "([[BLjava/lang/String;)V"); + sslHandshakeCallbacks_verifyCertificateChain = getMethodRef( + env, sslHandshakeCallbacksClass, "verifyCertificateChain", "([[BLjava/lang/String;)V"); sslHandshakeCallbacks_onSSLStateChange = - getMethodRef(env, sslHandshakeCallbacksClass, "onSSLStateChange", "(II)V"); - sslHandshakeCallbacks_clientCertificateRequested = - getMethodRef(env, sslHandshakeCallbacksClass, "clientCertificateRequested", "([B[I[[B)V"); + getMethodRef(env, sslHandshakeCallbacksClass, "onSSLStateChange", "(II)V"); + sslHandshakeCallbacks_clientCertificateRequested = getMethodRef( + env, sslHandshakeCallbacksClass, "clientCertificateRequested", "([B[I[[B)V"); sslHandshakeCallbacks_serverCertificateRequested = - getMethodRef(env, sslHandshakeCallbacksClass, "serverCertificateRequested", "()V"); - sslHandshakeCallbacks_clientPSKKeyRequested = - getMethodRef(env, sslHandshakeCallbacksClass, "clientPSKKeyRequested", "(Ljava/lang/String;[B[B)I"); + getMethodRef(env, sslHandshakeCallbacksClass, "serverCertificateRequested", "()V"); + sslHandshakeCallbacks_clientPSKKeyRequested = getMethodRef( + env, sslHandshakeCallbacksClass, "clientPSKKeyRequested", "(Ljava/lang/String;[B[B)I"); sslHandshakeCallbacks_serverPSKKeyRequested = - getMethodRef(env, sslHandshakeCallbacksClass, "serverPSKKeyRequested", "(Ljava/lang/String;Ljava/lang/String;[B)I"); + getMethodRef(env, sslHandshakeCallbacksClass, "serverPSKKeyRequested", + "(Ljava/lang/String;Ljava/lang/String;[B)I"); sslHandshakeCallbacks_onNewSessionEstablished = - getMethodRef(env, sslHandshakeCallbacksClass, "onNewSessionEstablished", "(J)V"); + getMethodRef(env, sslHandshakeCallbacksClass, "onNewSessionEstablished", "(J)V"); sslHandshakeCallbacks_serverSessionRequested = - getMethodRef(env, sslHandshakeCallbacksClass, "serverSessionRequested", "([B)J"); + getMethodRef(env, sslHandshakeCallbacksClass, "serverSessionRequested", "([B)J"); sslHandshakeCallbacks_selectApplicationProtocol = - getMethodRef(env, sslHandshakeCallbacksClass, "selectApplicationProtocol", "([B)I"); - cryptoUpcallsClass_rawSignMethod = env->GetStaticMethodID(cryptoUpcallsClass, - "ecSignDigestWithPrivateKey", - "(Ljava/security/PrivateKey;[B)[B"); + getMethodRef(env, sslHandshakeCallbacksClass, "selectApplicationProtocol", "([B)I"); + cryptoUpcallsClass_rawSignMethod = env->GetStaticMethodID( + cryptoUpcallsClass, "ecSignDigestWithPrivateKey", "(Ljava/security/PrivateKey;[B)[B"); if (cryptoUpcallsClass_rawSignMethod == nullptr) { env->FatalError("Could not find ecSignDigestWithPrivateKey"); } - cryptoUpcallsClass_rsaSignMethod = env->GetStaticMethodID(cryptoUpcallsClass, - "rsaSignDigestWithPrivateKey", - "(Ljava/security/PrivateKey;I[B)[B"); + cryptoUpcallsClass_rsaSignMethod = env->GetStaticMethodID( + cryptoUpcallsClass, "rsaSignDigestWithPrivateKey", "(Ljava/security/PrivateKey;I[B)[B"); if (cryptoUpcallsClass_rsaSignMethod == nullptr) { env->FatalError("Could not find rsaSignDigestWithPrivateKey"); } - cryptoUpcallsClass_rsaDecryptMethod = env->GetStaticMethodID(cryptoUpcallsClass, - "rsaDecryptWithPrivateKey", - "(Ljava/security/PrivateKey;I[B)[B"); + cryptoUpcallsClass_rsaDecryptMethod = env->GetStaticMethodID( + cryptoUpcallsClass, "rsaDecryptWithPrivateKey", "(Ljava/security/PrivateKey;I[B)[B"); if (cryptoUpcallsClass_rsaDecryptMethod == nullptr) { env->FatalError("Could not find rsaDecryptWithPrivateKey"); } @@ -257,14 +254,13 @@ int throwInvalidKeyException(JNIEnv* env, const char* message) { int throwIllegalArgumentException(JNIEnv* env, const char* message) { JNI_TRACE("throwIllegalArgumentException %s", message); - return conscrypt::jniutil::throwException( - env, "java/lang/IllegalArgumentException", message); + return conscrypt::jniutil::throwException(env, "java/lang/IllegalArgumentException", message); } int throwIllegalBlockSizeException(JNIEnv* env, const char* message) { JNI_TRACE("throwIllegalBlockSizeException %s", message); - return conscrypt::jniutil::throwException( - env, "javax/crypto/IllegalBlockSizeException", message); + return conscrypt::jniutil::throwException(env, "javax/crypto/IllegalBlockSizeException", + message); } int throwIllegalStateException(JNIEnv* env, const char* message) { @@ -274,14 +270,13 @@ int throwIllegalStateException(JNIEnv* env, const char* message) { int throwShortBufferException(JNIEnv* env, const char* message) { JNI_TRACE("throwShortBufferException %s", message); - return conscrypt::jniutil::throwException( - env, "javax/crypto/ShortBufferException", message); + return conscrypt::jniutil::throwException(env, "javax/crypto/ShortBufferException", message); } int throwNoSuchAlgorithmException(JNIEnv* env, const char* message) { JNI_TRACE("throwUnknownAlgorithmException %s", message); - return conscrypt::jniutil::throwException( - env, "java/security/NoSuchAlgorithmException", message); + return conscrypt::jniutil::throwException(env, "java/security/NoSuchAlgorithmException", + message); } int throwIOException(JNIEnv* env, const char* message) { @@ -291,8 +286,8 @@ int throwIOException(JNIEnv* env, const char* message) { int throwCertificateException(JNIEnv* env, const char* message) { JNI_TRACE("throwCertificateException %s", message); - return conscrypt::jniutil::throwException( - env, "java/security/cert/CertificateException", message); + return conscrypt::jniutil::throwException(env, "java/security/cert/CertificateException", + message); } int throwParsingException(JNIEnv* env, const char* message) { @@ -333,9 +328,9 @@ int throwForCipherError(JNIEnv* env, int reason, const char* message, case CIPHER_R_WRONG_FINAL_BLOCK_LENGTH: return throwIllegalBlockSizeException(env, message); break; - // TODO(davidben): Remove these ifdefs after - // https://boringssl-review.googlesource.com/c/boringssl/+/35565 has - // rolled out to relevant BoringSSL copies. + // TODO(davidben): Remove these ifdefs after + // https://boringssl-review.googlesource.com/c/boringssl/+/35565 has + // rolled out to relevant BoringSSL copies. #if defined(CIPHER_R_BAD_KEY_LENGTH) case CIPHER_R_BAD_KEY_LENGTH: #endif @@ -503,8 +498,7 @@ int throwSocketTimeoutException(JNIEnv* env, const char* message) { int throwSSLHandshakeExceptionStr(JNIEnv* env, const char* message) { JNI_TRACE("throwSSLExceptionStr %s", message); - return conscrypt::jniutil::throwException( - env, "javax/net/ssl/SSLHandshakeException", message); + return conscrypt::jniutil::throwException(env, "javax/net/ssl/SSLHandshakeException", message); } int throwSSLExceptionStr(JNIEnv* env, const char* message) { @@ -514,8 +508,7 @@ int throwSSLExceptionStr(JNIEnv* env, const char* message) { int throwSSLProtocolExceptionStr(JNIEnv* env, const char* message) { JNI_TRACE("throwSSLProtocolExceptionStr %s", message); - return conscrypt::jniutil::throwException( - env, "javax/net/ssl/SSLProtocolException", message); + return conscrypt::jniutil::throwException(env, "javax/net/ssl/SSLProtocolException", message); } int throwSSLExceptionWithSslErrors(JNIEnv* env, SSL* ssl, int sslErrorCode, const char* message, diff --git a/common/src/jni/main/cpp/conscrypt/native_crypto.cc b/common/src/jni/main/cpp/conscrypt/native_crypto.cc index b99815873..7ede18d2b 100644 --- a/common/src/jni/main/cpp/conscrypt/native_crypto.cc +++ b/common/src/jni/main/cpp/conscrypt/native_crypto.cc @@ -58,6 +58,8 @@ #include #include +#include "jni.h" + using conscrypt::AppData; using conscrypt::BioInputStream; using conscrypt::BioOutputStream; @@ -216,7 +218,7 @@ static bool arrayToBignum(JNIEnv* env, jbyteArray source, BIGNUM** dest) { } static bssl::UniquePtr arrayToBignum(JNIEnv* env, jbyteArray source) { - BIGNUM *bn = nullptr; + BIGNUM* bn = nullptr; if (!arrayToBignum(env, source, &bn)) { return nullptr; } @@ -501,7 +503,7 @@ static long bio_stream_ctrl(BIO* b, int cmd, long, void*) { } } -static const BIO_METHOD *stream_bio_method() { +static const BIO_METHOD* stream_bio_method() { static const BIO_METHOD* stream_method = []() -> const BIO_METHOD* { BIO_METHOD* method = BIO_meth_new(0, nullptr); if (!method || !BIO_meth_set_write(method, bio_stream_write) || @@ -543,8 +545,7 @@ static jbyteArray ecSignDigestWithPrivateKey(JNIEnv* env, jobject privateKey, co return reinterpret_cast(env->CallStaticObjectMethod( conscrypt::jniutil::cryptoUpcallsClass, - conscrypt::jniutil::cryptoUpcallsClass_rawSignMethod, - privateKey, messageArray.get())); + conscrypt::jniutil::cryptoUpcallsClass_rawSignMethod, privateKey, messageArray.get())); } static jbyteArray rsaSignDigestWithPrivateKey(JNIEnv* env, jobject privateKey, jint padding, @@ -571,10 +572,9 @@ static jbyteArray rsaSignDigestWithPrivateKey(JNIEnv* env, jobject privateKey, j } return reinterpret_cast( - env->CallStaticObjectMethod( - conscrypt::jniutil::cryptoUpcallsClass, - conscrypt::jniutil::cryptoUpcallsClass_rsaSignMethod, - privateKey, padding, messageArray.get())); + env->CallStaticObjectMethod(conscrypt::jniutil::cryptoUpcallsClass, + conscrypt::jniutil::cryptoUpcallsClass_rsaSignMethod, + privateKey, padding, messageArray.get())); } // rsaDecryptWithPrivateKey uses privateKey to decrypt |ciphertext_len| bytes @@ -605,10 +605,9 @@ static jbyteArray rsaDecryptWithPrivateKey(JNIEnv* env, jobject privateKey, jint } return reinterpret_cast( - env->CallStaticObjectMethod( - conscrypt::jniutil::cryptoUpcallsClass, - conscrypt::jniutil::cryptoUpcallsClass_rsaDecryptMethod, - privateKey, padding, ciphertextArray.get())); + env->CallStaticObjectMethod(conscrypt::jniutil::cryptoUpcallsClass, + conscrypt::jniutil::cryptoUpcallsClass_rsaDecryptMethod, + privateKey, padding, ciphertextArray.get())); } // ********************************************* @@ -639,22 +638,14 @@ struct KeyExData { // ExDataDup is called when one of the RSA or EC_KEY objects is duplicated. We // don't support this and it should never happen. -int ExDataDup(CRYPTO_EX_DATA* /* to */, - const CRYPTO_EX_DATA* /* from */, - void** /* from_d */, - int /* index */, - long /* argl */ /* NOLINT(runtime/int) */, - void* /* argp */) { - return 0; +int ExDataDup(CRYPTO_EX_DATA* /* to */, const CRYPTO_EX_DATA* /* from */, void** /* from_d */, + int /* index */, long /* argl */ /* NOLINT(runtime/int) */, void* /* argp */) { + return 0; } // ExDataFree is called when one of the RSA or EC_KEY objects is freed. -void ExDataFree(void* /* parent */, - void* ptr, - CRYPTO_EX_DATA* /* ad */, - int /* index */, - long /* argl */ /* NOLINT(runtime/int) */, - void* /* argp */) { +void ExDataFree(void* /* parent */, void* ptr, CRYPTO_EX_DATA* /* ad */, int /* index */, + long /* argl */ /* NOLINT(runtime/int) */, void* /* argp */) { // Ensure the global JNI reference created with this wrapper is // properly destroyed with it. KeyExData* ex_data = reinterpret_cast(ptr); @@ -787,8 +778,8 @@ int EcdsaMethodSign(const uint8_t* digest, size_t digest_len, uint8_t* sig, unsi // Sign message with it through JNI. ScopedLocalRef signature( - env, ecSignDigestWithPrivateKey(env, private_key, - reinterpret_cast(digest), digest_len)); + env, ecSignDigestWithPrivateKey(env, private_key, reinterpret_cast(digest), + digest_len)); if (signature.get() == nullptr) { CONSCRYPT_LOG_ERROR("Could not sign message in EcdsaMethodDoSign!"); return 0; @@ -1584,8 +1575,8 @@ static jbyteArray NativeCrypto_EVP_PKEY_get_private_seed(JNIEnv* env, jclass, jo return seedArray.release(); } -static jbyteArray NativeCrypto_EVP_raw_X25519_private_key( - JNIEnv* env, jclass cls, jbyteArray keyJavaBytes) { +static jbyteArray NativeCrypto_EVP_raw_X25519_private_key(JNIEnv* env, jclass cls, + jbyteArray keyJavaBytes) { CHECK_ERROR_QUEUE_ON_RETURN; JNI_TRACE("NativeCrypto_EVP_raw_X25519_private_key(%p)", keyJavaBytes); @@ -1614,8 +1605,8 @@ static jbyteArray NativeCrypto_EVP_raw_X25519_private_key( return nullptr; } - if (EVP_PKEY_get_raw_private_key( - pkey.get(), reinterpret_cast(bytes.get()), &key_length) == 0) { + if (EVP_PKEY_get_raw_private_key(pkey.get(), reinterpret_cast(bytes.get()), + &key_length) == 0) { conscrypt::jniutil::throwExceptionFromBoringSSLError(env, "EVP_PKEY_get_raw_private_key"); return nullptr; } @@ -1885,8 +1876,8 @@ static jint RSA_crypt_operation(RSACryptOperation operation, const char* caller, operation(static_cast(flen), reinterpret_cast(from.get()), reinterpret_cast(to.get()), rsa.get(), padding); if (resultSize == -1) { - conscrypt::jniutil::throwExceptionFromBoringSSLError(env, caller, - conscrypt::jniutil::throwBadPaddingException); + conscrypt::jniutil::throwExceptionFromBoringSSLError( + env, caller, conscrypt::jniutil::throwBadPaddingException); JNI_TRACE("%s => threw error", caller); return -1; } @@ -2052,8 +2043,9 @@ static jobjectArray NativeCrypto_get_RSA_private_params(JNIEnv* env, jclass, job } static void NativeCrypto_chacha20_encrypt_decrypt(JNIEnv* env, jclass, jbyteArray inBytes, - jint inOffset, jbyteArray outBytes, jint outOffset, jint length, jbyteArray keyBytes, - jbyteArray nonceBytes, jint blockCounter) { + jint inOffset, jbyteArray outBytes, + jint outOffset, jint length, jbyteArray keyBytes, + jbyteArray nonceBytes, jint blockCounter) { CHECK_ERROR_QUEUE_ON_RETURN; JNI_TRACE("chacha20_encrypt_decrypt"); ScopedByteArrayRO in(env, inBytes); @@ -2077,13 +2069,10 @@ static void NativeCrypto_chacha20_encrypt_decrypt(JNIEnv* env, jclass, jbyteArra return; } - CRYPTO_chacha_20( - reinterpret_cast(out.get()) + outOffset, - reinterpret_cast(in.get()) + inOffset, - length, - reinterpret_cast(key.get()), - reinterpret_cast(nonce.get()), - blockCounter); + CRYPTO_chacha_20(reinterpret_cast(out.get()) + outOffset, + reinterpret_cast(in.get()) + inOffset, length, + reinterpret_cast(key.get()), + reinterpret_cast(nonce.get()), blockCounter); } static jlong NativeCrypto_EC_GROUP_new_by_curve_name(JNIEnv* env, jclass, jstring curveNameJava) { @@ -2170,7 +2159,8 @@ static jlong NativeCrypto_EC_GROUP_new_arbitrary(JNIEnv* env, jclass, jbyteArray return 0; } - if (!EC_POINT_set_affine_coordinates_GFp(group.get(), generator.get(), x.get(), y.get(), ctx.get())) { + if (!EC_POINT_set_affine_coordinates_GFp(group.get(), generator.get(), x.get(), y.get(), + ctx.get())) { JNI_TRACE("EC_POINT_set_affine_coordinates_GFp => error"); conscrypt::jniutil::throwExceptionFromBoringSSLError(env, "EC_POINT_set_affine_coordinates_GFp"); @@ -2705,16 +2695,16 @@ static jint NativeCrypto_ECDH_compute_key(JNIEnv* env, jclass, jbyteArray outArr bssl::UniquePtr pubkey(EVP_PKEY_get1_EC_KEY(pubPkey)); if (pubkey.get() == nullptr) { JNI_TRACE("ECDH_compute_key(%p) => can't get public key", pubPkey); - conscrypt::jniutil::throwExceptionFromBoringSSLError(env, "EVP_PKEY_get1_EC_KEY public", - conscrypt::jniutil::throwInvalidKeyException); + conscrypt::jniutil::throwExceptionFromBoringSSLError( + env, "EVP_PKEY_get1_EC_KEY public", conscrypt::jniutil::throwInvalidKeyException); return -1; } const EC_POINT* pubkeyPoint = EC_KEY_get0_public_key(pubkey.get()); if (pubkeyPoint == nullptr) { JNI_TRACE("ECDH_compute_key(%p) => can't get public key point", pubPkey); - conscrypt::jniutil::throwExceptionFromBoringSSLError(env, "EVP_PKEY_get1_EC_KEY public", - conscrypt::jniutil::throwInvalidKeyException); + conscrypt::jniutil::throwExceptionFromBoringSSLError( + env, "EVP_PKEY_get1_EC_KEY public", conscrypt::jniutil::throwInvalidKeyException); return -1; } @@ -2726,8 +2716,8 @@ static jint NativeCrypto_ECDH_compute_key(JNIEnv* env, jclass, jbyteArray outArr bssl::UniquePtr privkey(EVP_PKEY_get1_EC_KEY(privPkey)); if (privkey.get() == nullptr) { - conscrypt::jniutil::throwExceptionFromBoringSSLError(env, "EVP_PKEY_get1_EC_KEY private", - conscrypt::jniutil::throwInvalidKeyException); + conscrypt::jniutil::throwExceptionFromBoringSSLError( + env, "EVP_PKEY_get1_EC_KEY private", conscrypt::jniutil::throwInvalidKeyException); return -1; } @@ -2736,8 +2726,8 @@ static jint NativeCrypto_ECDH_compute_key(JNIEnv* env, jclass, jbyteArray outArr privkey.get(), nullptr /* No KDF */); if (outputLength == -1) { JNI_TRACE("ECDH_compute_key(%p) => outputLength = -1", pubPkey); - conscrypt::jniutil::throwExceptionFromBoringSSLError(env, "ECDH_compute_key", - conscrypt::jniutil::throwInvalidKeyException); + conscrypt::jniutil::throwExceptionFromBoringSSLError( + env, "ECDH_compute_key", conscrypt::jniutil::throwInvalidKeyException); return -1; } @@ -3105,13 +3095,14 @@ static jint NativeCrypto_SLHDSA_SHA2_128S_verify(JNIEnv* env, jclass, jbyteArray } static jboolean NativeCrypto_X25519(JNIEnv* env, jclass, jbyteArray outArray, - jbyteArray privkeyArray, jbyteArray pubkeyArray) { + jbyteArray privkeyArray, jbyteArray pubkeyArray) { CHECK_ERROR_QUEUE_ON_RETURN; JNI_TRACE("X25519(%p, %p, %p)", outArray, privkeyArray, pubkeyArray); ScopedByteArrayRW out(env, outArray); if (out.get() == nullptr) { - JNI_TRACE("X25519(%p, %p, %p) can't get output buffer", outArray, privkeyArray, pubkeyArray); + JNI_TRACE("X25519(%p, %p, %p) can't get output buffer", outArray, privkeyArray, + pubkeyArray); return JNI_FALSE; } @@ -3131,8 +3122,8 @@ static jboolean NativeCrypto_X25519(JNIEnv* env, jclass, jbyteArray outArray, reinterpret_cast(privkey.get()), reinterpret_cast(pubkey.get())) != 1) { JNI_TRACE("X25519(%p) => failure", outArray); - conscrypt::jniutil::throwExceptionFromBoringSSLError(env, "X25519", - conscrypt::jniutil::throwInvalidKeyException); + conscrypt::jniutil::throwExceptionFromBoringSSLError( + env, "X25519", conscrypt::jniutil::throwInvalidKeyException); return JNI_FALSE; } @@ -3140,28 +3131,34 @@ static jboolean NativeCrypto_X25519(JNIEnv* env, jclass, jbyteArray outArray, return JNI_TRUE; } -static void NativeCrypto_X25519_keypair(JNIEnv* env, jclass, jbyteArray outPublicArray, jbyteArray outPrivateArray) { +static void NativeCrypto_X25519_keypair(JNIEnv* env, jclass, jbyteArray outPublicArray, + jbyteArray outPrivateArray) { CHECK_ERROR_QUEUE_ON_RETURN; JNI_TRACE("X25519_keypair(%p, %p)", outPublicArray, outPrivateArray); ScopedByteArrayRW outPublic(env, outPublicArray); if (outPublic.get() == nullptr) { - JNI_TRACE("X25519_keypair(%p, %p) can't get output public key buffer", outPublicArray, outPrivateArray); + JNI_TRACE("X25519_keypair(%p, %p) can't get output public key buffer", outPublicArray, + outPrivateArray); return; } ScopedByteArrayRW outPrivate(env, outPrivateArray); if (outPrivate.get() == nullptr) { - JNI_TRACE("X25519_keypair(%p, %p) can't get output private key buffer", outPublicArray, outPrivateArray); + JNI_TRACE("X25519_keypair(%p, %p) can't get output private key buffer", outPublicArray, + outPrivateArray); return; } - if (outPublic.size() != X25519_PUBLIC_VALUE_LEN || outPrivate.size() != X25519_PRIVATE_KEY_LEN) { - conscrypt::jniutil::throwException(env, "java/lang/IllegalArgumentException", "Output key array length != 32"); + if (outPublic.size() != X25519_PUBLIC_VALUE_LEN || + outPrivate.size() != X25519_PRIVATE_KEY_LEN) { + conscrypt::jniutil::throwException(env, "java/lang/IllegalArgumentException", + "Output key array length != 32"); return; } - X25519_keypair(reinterpret_cast(outPublic.get()), reinterpret_cast(outPrivate.get())); + X25519_keypair(reinterpret_cast(outPublic.get()), + reinterpret_cast(outPrivate.get())); JNI_TRACE("X25519_keypair(%p, %p) => success", outPublicArray, outPrivateArray); } @@ -3605,14 +3602,14 @@ static void NativeCrypto_EVP_DigestSignUpdate(JNIEnv* env, jclass, jobject evpMd jint inLength) { CHECK_ERROR_QUEUE_ON_RETURN; evpUpdate(env, evpMdCtxRef, inJavaBytes, inOffset, inLength, "EVP_DigestSignUpdate", - EVP_DigestSignUpdate); + EVP_DigestSignUpdate); } static void NativeCrypto_EVP_DigestSignUpdateDirect(JNIEnv* env, jclass, jobject evpMdCtxRef, - jlong inPtr, jint inLength) { + jlong inPtr, jint inLength) { CHECK_ERROR_QUEUE_ON_RETURN; evpUpdate(env, evpMdCtxRef, inPtr, inLength, "EVP_DigestSignUpdateDirect", - EVP_DigestSignUpdate); + EVP_DigestSignUpdate); } static void NativeCrypto_EVP_DigestVerifyUpdate(JNIEnv* env, jclass, jobject evpMdCtxRef, @@ -4261,8 +4258,8 @@ static jint NativeCrypto_EVP_CipherFinal_ex(JNIEnv* env, jclass, jobject ctxRef, int outl; if (!EVP_CipherFinal_ex(ctx, out + outOffset, &outl)) { - conscrypt::jniutil::throwExceptionFromBoringSSLError(env, "EVP_CipherFinal_ex", - conscrypt::jniutil::throwBadPaddingException); + conscrypt::jniutil::throwExceptionFromBoringSSLError( + env, "EVP_CipherFinal_ex", conscrypt::jniutil::throwBadPaddingException); JNI_TRACE("ctx=%p EVP_CipherFinal_ex => threw error", ctx); return 0; } @@ -4458,9 +4455,10 @@ typedef int (*evp_aead_ctx_op_func)(const EVP_AEAD_CTX* ctx, uint8_t* out, size_ size_t ad_len); static jint evp_aead_ctx_op_common(JNIEnv* env, jlong evpAeadRef, jbyteArray keyArray, jint tagLen, - uint8_t* outBuf, jbyteArray nonceArray, - const uint8_t* inBuf, jbyteArray aadArray, - evp_aead_ctx_op_func realFunc, jobject inBuffer, jobject outBuffer, jint outRange, jint inRange) { + uint8_t* outBuf, jbyteArray nonceArray, const uint8_t* inBuf, + jbyteArray aadArray, evp_aead_ctx_op_func realFunc, + jobject inBuffer, jobject outBuffer, jint outRange, + jint inRange) { const EVP_AEAD* evpAead = reinterpret_cast(evpAeadRef); ScopedByteArrayRO keyBytes(env, keyArray); @@ -4491,26 +4489,22 @@ static jint evp_aead_ctx_op_common(JNIEnv* env, jlong evpAeadRef, jbyteArray key static_cast(tagLen), nullptr)) { conscrypt::jniutil::throwExceptionFromBoringSSLError(env, "failure initializing AEAD context"); - JNI_TRACE( - "evp_aead_ctx_op(%p, %p, %d, %p, %p, %p, %p) => fail EVP_AEAD_CTX_init", - evpAead, keyArray, tagLen, outBuffer, nonceArray, inBuffer, - aadArray); + JNI_TRACE("evp_aead_ctx_op(%p, %p, %d, %p, %p, %p, %p) => fail EVP_AEAD_CTX_init", evpAead, + keyArray, tagLen, outBuffer, nonceArray, inBuffer, aadArray); return 0; } const uint8_t* nonceTmp = reinterpret_cast(nonceBytes.get()); size_t actualOutLength; - if (!realFunc(aeadCtx.get(), outBuf, &actualOutLength, outRange, - nonceTmp, nonceBytes.size(), inBuf, static_cast(inRange), - aad_chars, aad_chars_size)) { + if (!realFunc(aeadCtx.get(), outBuf, &actualOutLength, outRange, nonceTmp, nonceBytes.size(), + inBuf, static_cast(inRange), aad_chars, aad_chars_size)) { conscrypt::jniutil::throwExceptionFromBoringSSLError(env, "evp_aead_ctx_op"); return 0; } - JNI_TRACE("evp_aead_ctx_op(%p, %p, %d, %p, %p, %p, %p) => success outlength=%zd", - evpAead, keyArray, tagLen, outBuffer, nonceArray, inBuffer, - aadArray, actualOutLength); + JNI_TRACE("evp_aead_ctx_op(%p, %p, %d, %p, %p, %p, %p) => success outlength=%zd", evpAead, + keyArray, tagLen, outBuffer, nonceArray, inBuffer, aadArray, actualOutLength); return static_cast(actualOutLength); } @@ -4522,7 +4516,6 @@ static jint evp_aead_ctx_op(JNIEnv* env, jlong evpAeadRef, jbyteArray keyArray, JNI_TRACE("evp_aead_ctx_op(%p, %p, %d, %p, %d, %p, %p, %d, %d, %p)", evpAead, keyArray, tagLen, outArray, outOffset, nonceArray, inArray, inOffset, inLength, aadArray); - ScopedByteArrayRW outBytes(env, outArray); if (outBytes.get() == nullptr) { return 0; @@ -4554,18 +4547,17 @@ static jint evp_aead_ctx_op(JNIEnv* env, jlong evpAeadRef, jbyteArray keyArray, uint8_t* outTmp = reinterpret_cast(outBytes.get()); const uint8_t* inTmp = reinterpret_cast(inBytes.get()); - return evp_aead_ctx_op_common(env, evpAeadRef, keyArray, tagLen, outTmp + outOffset, nonceArray, inTmp + inOffset, - aadArray, realFunc, inArray, outArray, outBytes.size() - outOffset, inLength); + return evp_aead_ctx_op_common(env, evpAeadRef, keyArray, tagLen, outTmp + outOffset, nonceArray, + inTmp + inOffset, aadArray, realFunc, inArray, outArray, + outBytes.size() - outOffset, inLength); } static jint evp_aead_ctx_op_buf(JNIEnv* env, jlong evpAeadRef, jbyteArray keyArray, jint tagLen, - jobject outBuffer, jbyteArray nonceArray, - jobject inBuffer, jbyteArray aadArray, - evp_aead_ctx_op_func realFunc) { - + jobject outBuffer, jbyteArray nonceArray, jobject inBuffer, + jbyteArray aadArray, evp_aead_ctx_op_func realFunc) { const EVP_AEAD* evpAead = reinterpret_cast(evpAeadRef); - JNI_TRACE("evp_aead_ctx_op(%p, %p, %d, %p, %p, %p, %p)", evpAead, keyArray, tagLen, - outBuffer, nonceArray, inBuffer, aadArray); + JNI_TRACE("evp_aead_ctx_op(%p, %p, %d, %p, %p, %p, %p)", evpAead, keyArray, tagLen, outBuffer, + nonceArray, inBuffer, aadArray); if (!conscrypt::jniutil::isDirectByteBufferInstance(env, inBuffer)) { conscrypt::jniutil::throwException(env, "java/lang/IllegalArgumentException", @@ -4584,19 +4576,19 @@ static jint evp_aead_ctx_op_buf(JNIEnv* env, jlong evpAeadRef, jbyteArray keyArr jint in_position; inBuf = (uint8_t*)(env->GetDirectBufferAddress(inBuffer)); - // limit is the index of the first element that should not be read or written - in_limit = env->CallIntMethod(inBuffer,conscrypt::jniutil::buffer_limitMethod); + // limit is the index of the first element that should not be read or written + in_limit = env->CallIntMethod(inBuffer, conscrypt::jniutil::buffer_limitMethod); // position is the index of the next element to be read or written - in_position = env->CallIntMethod(inBuffer,conscrypt::jniutil::buffer_positionMethod); + in_position = env->CallIntMethod(inBuffer, conscrypt::jniutil::buffer_positionMethod); uint8_t* outBuf; jint out_limit; jint out_position; outBuf = (uint8_t*)(env->GetDirectBufferAddress(outBuffer)); // limit is the index of the first element that should not be read or written - out_limit = env->CallIntMethod(outBuffer,conscrypt::jniutil::buffer_limitMethod); + out_limit = env->CallIntMethod(outBuffer, conscrypt::jniutil::buffer_limitMethod); // position is the index of the next element to be read or written - out_position = env->CallIntMethod(outBuffer,conscrypt::jniutil::buffer_positionMethod); + out_position = env->CallIntMethod(outBuffer, conscrypt::jniutil::buffer_positionMethod); // Shifting over of ByteBuffer address to start at true position inBuf += in_position; @@ -4606,9 +4598,9 @@ static jint evp_aead_ctx_op_buf(JNIEnv* env, jlong evpAeadRef, jbyteArray keyArr uint8_t* outBufEnd = outBuf + out_limit - out_position; uint8_t* inBufEnd = inBuf + inSize; std::unique_ptr inCopy; - if (outBufEnd >= inBuf && inBufEnd >= outBuf) { // We have an overlap - inCopy.reset((new(std::nothrow) uint8_t[inSize])); - if (inCopy.get() == nullptr) { + if (outBufEnd >= inBuf && inBufEnd >= outBuf) { // We have an overlap + inCopy.reset((new (std::nothrow) uint8_t[inSize])); + if (inCopy.get() == nullptr) { conscrypt::jniutil::throwOutOfMemory(env, "Unable to allocate new buffer for overlap"); return 0; } @@ -4616,8 +4608,9 @@ static jint evp_aead_ctx_op_buf(JNIEnv* env, jlong evpAeadRef, jbyteArray keyArr inBuf = inCopy.get(); } - return evp_aead_ctx_op_common(env, evpAeadRef, keyArray, tagLen, outBuf, nonceArray, inBuf, aadArray, realFunc, - inBuffer, outBuffer, out_limit-out_position, in_limit-in_position); + return evp_aead_ctx_op_common(env, evpAeadRef, keyArray, tagLen, outBuf, nonceArray, inBuf, + aadArray, realFunc, inBuffer, outBuffer, out_limit - out_position, + in_limit - in_position); } static jint NativeCrypto_EVP_AEAD_CTX_seal(JNIEnv* env, jclass, jlong evpAeadRef, @@ -4641,19 +4634,21 @@ static jint NativeCrypto_EVP_AEAD_CTX_open(JNIEnv* env, jclass, jlong evpAeadRef } static jint NativeCrypto_EVP_AEAD_CTX_seal_buf(JNIEnv* env, jclass, jlong evpAeadRef, - jbyteArray keyArray, jint tagLen, jobject outBuffer, - jbyteArray nonceArray, jobject inBuffer, jbyteArray aadArray) { + jbyteArray keyArray, jint tagLen, jobject outBuffer, + jbyteArray nonceArray, jobject inBuffer, + jbyteArray aadArray) { CHECK_ERROR_QUEUE_ON_RETURN; - return evp_aead_ctx_op_buf(env, evpAeadRef, keyArray, tagLen, outBuffer, nonceArray, - inBuffer, aadArray, EVP_AEAD_CTX_seal); + return evp_aead_ctx_op_buf(env, evpAeadRef, keyArray, tagLen, outBuffer, nonceArray, inBuffer, + aadArray, EVP_AEAD_CTX_seal); } static jint NativeCrypto_EVP_AEAD_CTX_open_buf(JNIEnv* env, jclass, jlong evpAeadRef, - jbyteArray keyArray, jint tagLen, jobject outBuffer, - jbyteArray nonceArray, jobject inBuffer, jbyteArray aadArray) { + jbyteArray keyArray, jint tagLen, jobject outBuffer, + jbyteArray nonceArray, jobject inBuffer, + jbyteArray aadArray) { CHECK_ERROR_QUEUE_ON_RETURN; - return evp_aead_ctx_op_buf(env, evpAeadRef, keyArray, tagLen, outBuffer, nonceArray, - inBuffer, aadArray, EVP_AEAD_CTX_open); + return evp_aead_ctx_op_buf(env, evpAeadRef, keyArray, tagLen, outBuffer, nonceArray, inBuffer, + aadArray, EVP_AEAD_CTX_open); } static jbyteArray NativeCrypto_EVP_HPKE_CTX_export(JNIEnv* env, jclass, jobject hpkeCtxRef, @@ -4689,7 +4684,8 @@ static jbyteArray NativeCrypto_EVP_HPKE_CTX_export(JNIEnv* env, jclass, jobject return {}; } - ScopedLocalRef exportedArray(env, env->NewByteArray(static_cast(exportedLen))); + ScopedLocalRef exportedArray(env, + env->NewByteArray(static_cast(exportedLen))); if (exportedArray.get() == nullptr) { return {}; } @@ -4760,7 +4756,8 @@ static jbyteArray NativeCrypto_EVP_HPKE_CTX_open(JNIEnv* env, jclass, jobject re } plaintext.resize(plaintextLen); - ScopedLocalRef plaintextArray(env, env->NewByteArray(static_cast(plaintextLen))); + ScopedLocalRef plaintextArray(env, + env->NewByteArray(static_cast(plaintextLen))); if (plaintextArray.get() == nullptr) { return {}; } @@ -4816,7 +4813,8 @@ static jbyteArray NativeCrypto_EVP_HPKE_CTX_seal(JNIEnv* env, jclass, jobject se return {}; } - ScopedLocalRef ciphertextArray(env, env->NewByteArray(static_cast(encryptedLen))); + ScopedLocalRef ciphertextArray(env, + env->NewByteArray(static_cast(encryptedLen))); if (ciphertextArray.get() == nullptr) { return {}; } @@ -4865,12 +4863,9 @@ const EVP_HPKE_KEM* getHpkeKem(JNIEnv* env, jint kemValue) { } } -static jobject NativeCrypto_EVP_HPKE_CTX_setup_base_mode_recipient(JNIEnv* env, jclass, - jint kemValue,jint kdfValue, - jint aeadValue, - jbyteArray privateKeyArray, - jbyteArray encArray, - jbyteArray infoArray) { +static jobject NativeCrypto_EVP_HPKE_CTX_setup_base_mode_recipient( + JNIEnv* env, jclass, jint kemValue, jint kdfValue, jint aeadValue, + jbyteArray privateKeyArray, jbyteArray encArray, jbyteArray infoArray) { CHECK_ERROR_QUEUE_ON_RETURN; JNI_TRACE("EVP_HPKE_CTX_setup_recipient(%d, %d, %d, %p, %p, %p)", kemValue, kdfValue, aeadValue, privateKeyArray, encArray, infoArray); @@ -4935,14 +4930,14 @@ static jobject NativeCrypto_EVP_HPKE_CTX_setup_base_mode_recipient(JNIEnv* env, } ScopedLocalRef ctxObject( - env, env->NewObject(conscrypt::jniutil::nativeRefHpkeCtxClass, - conscrypt::jniutil::nativeRefHpkeCtxClass_constructor, - reinterpret_cast(ctx.release()))); + env, env->NewObject(conscrypt::jniutil::nativeRefHpkeCtxClass, + conscrypt::jniutil::nativeRefHpkeCtxClass_constructor, + reinterpret_cast(ctx.release()))); return ctxObject.release(); } static jobjectArray NativeCrypto_EVP_HPKE_CTX_setup_base_mode_sender(JNIEnv* env, jclass, - jint kemValue,jint kdfValue, + jint kemValue, jint kdfValue, jint aeadValue, jbyteArray publicKeyArray, jbyteArray infoArray) { @@ -4986,22 +4981,24 @@ static jobjectArray NativeCrypto_EVP_HPKE_CTX_setup_base_mode_sender(JNIEnv* env bssl::UniquePtr ctx(EVP_HPKE_CTX_new()); - if (!EVP_HPKE_CTX_setup_sender(/* ctx= */ ctx.get(), - /* out_enc= */ encapsulatedSharedSecret, - /* out_enc_len= */ &encapsulatedSharedSecretLen, - /* max_enc= */ EVP_HPKE_MAX_ENC_LENGTH, - /* kem= */ kem, - /* kdf= */ kdf, - /* aead= */ aead, - /* peer_public_key= */ reinterpret_cast(peer_public_key.get()), - /* peer_public_key_len= */ peer_public_key.size(), - /* info= */ info, - /* info_len= */ infoLen)) { + if (!EVP_HPKE_CTX_setup_sender( + /* ctx= */ ctx.get(), + /* out_enc= */ encapsulatedSharedSecret, + /* out_enc_len= */ &encapsulatedSharedSecretLen, + /* max_enc= */ EVP_HPKE_MAX_ENC_LENGTH, + /* kem= */ kem, + /* kdf= */ kdf, + /* aead= */ aead, + /* peer_public_key= */ reinterpret_cast(peer_public_key.get()), + /* peer_public_key_len= */ peer_public_key.size(), + /* info= */ info, + /* info_len= */ infoLen)) { conscrypt::jniutil::throwExceptionFromBoringSSLError(env, "EVP_HPKE_CTX_setup_sender"); return {}; } - ScopedLocalRef encArray(env, env->NewByteArray(static_cast(encapsulatedSharedSecretLen))); + ScopedLocalRef encArray( + env, env->NewByteArray(static_cast(encapsulatedSharedSecretLen))); if (encArray.get() == nullptr) { return {}; } @@ -5009,15 +5006,16 @@ static jobjectArray NativeCrypto_EVP_HPKE_CTX_setup_base_mode_sender(JNIEnv* env if (encBytes.get() == nullptr) { return {}; } - memcpy(encBytes.get(), reinterpret_cast(encapsulatedSharedSecret), encapsulatedSharedSecretLen); + memcpy(encBytes.get(), reinterpret_cast(encapsulatedSharedSecret), + encapsulatedSharedSecretLen); ScopedLocalRef result( env, env->NewObjectArray(2, conscrypt::jniutil::objectClass, nullptr)); ScopedLocalRef ctxObject( - env, env->NewObject(conscrypt::jniutil::nativeRefHpkeCtxClass, - conscrypt::jniutil::nativeRefHpkeCtxClass_constructor, - reinterpret_cast(ctx.release()))); + env, env->NewObject(conscrypt::jniutil::nativeRefHpkeCtxClass, + conscrypt::jniutil::nativeRefHpkeCtxClass_constructor, + reinterpret_cast(ctx.release()))); env->SetObjectArrayElement(result.get(), 0, ctxObject.release()); env->SetObjectArrayElement(result.get(), 1, encArray.release()); @@ -5071,25 +5069,26 @@ static jobjectArray NativeCrypto_EVP_HPKE_CTX_setup_base_mode_sender_with_seed_f bssl::UniquePtr ctx(EVP_HPKE_CTX_new()); if (!EVP_HPKE_CTX_setup_sender_with_seed_for_testing( - /* ctx= */ ctx.get(), - /* out_enc= */ encapsulatedSharedSecret, - /* out_enc_len= */ &encapsulatedSharedSecretLen, - /* max_enc= */ EVP_HPKE_MAX_ENC_LENGTH, - /* kem= */ kem, - /* kdf= */ kdf, - /* aead= */ aead, - /* peer_public_key= */ reinterpret_cast(peer_public_key.get()), - /* peer_public_key_len= */ peer_public_key.size(), - /* info= */ info, - /* info_len= */ infoLen, - /* seed= */ reinterpret_cast(seed.get()), - /* seed_len= */ seed.size())) { + /* ctx= */ ctx.get(), + /* out_enc= */ encapsulatedSharedSecret, + /* out_enc_len= */ &encapsulatedSharedSecretLen, + /* max_enc= */ EVP_HPKE_MAX_ENC_LENGTH, + /* kem= */ kem, + /* kdf= */ kdf, + /* aead= */ aead, + /* peer_public_key= */ reinterpret_cast(peer_public_key.get()), + /* peer_public_key_len= */ peer_public_key.size(), + /* info= */ info, + /* info_len= */ infoLen, + /* seed= */ reinterpret_cast(seed.get()), + /* seed_len= */ seed.size())) { conscrypt::jniutil::throwExceptionFromBoringSSLError( env, "EVP_HPKE_CTX_setup_sender_with_seed_for_testing"); return {}; } - ScopedLocalRef encArray(env, env->NewByteArray(static_cast(encapsulatedSharedSecretLen))); + ScopedLocalRef encArray( + env, env->NewByteArray(static_cast(encapsulatedSharedSecretLen))); if (encArray.get() == nullptr) { return {}; } @@ -5097,15 +5096,16 @@ static jobjectArray NativeCrypto_EVP_HPKE_CTX_setup_base_mode_sender_with_seed_f if (encBytes.get() == nullptr) { return {}; } - memcpy(encBytes.get(), reinterpret_cast(encapsulatedSharedSecret), encapsulatedSharedSecretLen); + memcpy(encBytes.get(), reinterpret_cast(encapsulatedSharedSecret), + encapsulatedSharedSecretLen); ScopedLocalRef result( env, env->NewObjectArray(2, conscrypt::jniutil::objectClass, nullptr)); ScopedLocalRef ctxObject( - env, env->NewObject(conscrypt::jniutil::nativeRefHpkeCtxClass, - conscrypt::jniutil::nativeRefHpkeCtxClass_constructor, - reinterpret_cast(ctx.release()))); + env, env->NewObject(conscrypt::jniutil::nativeRefHpkeCtxClass, + conscrypt::jniutil::nativeRefHpkeCtxClass_constructor, + reinterpret_cast(ctx.release()))); env->SetObjectArrayElement(result.get(), 0, ctxObject.release()); env->SetObjectArrayElement(result.get(), 1, encArray.release()); @@ -5150,21 +5150,21 @@ static void NativeCrypto_CMAC_Init(JNIEnv* env, jclass, jobject cmacCtxRef, jbyt const uint8_t* keyPtr = reinterpret_cast(keyBytes.get()); - const EVP_CIPHER *cipher; - switch(keyBytes.size()) { - case 16: - cipher = EVP_aes_128_cbc(); - break; - case 24: - cipher = EVP_aes_192_cbc(); - break; - case 32: - cipher = EVP_aes_256_cbc(); - break; - default: - conscrypt::jniutil::throwException(env, "java/lang/IllegalArgumentException", - "CMAC_Init: Unsupported key length"); - return; + const EVP_CIPHER* cipher; + switch (keyBytes.size()) { + case 16: + cipher = EVP_aes_128_cbc(); + break; + case 24: + cipher = EVP_aes_192_cbc(); + break; + case 32: + cipher = EVP_aes_256_cbc(); + break; + default: + conscrypt::jniutil::throwException(env, "java/lang/IllegalArgumentException", + "CMAC_Init: Unsupported key length"); + return; } if (!CMAC_Init(cmacCtx, keyPtr, keyBytes.size(), cipher, nullptr)) { @@ -5468,7 +5468,7 @@ static jlong NativeCrypto_create_BIO_InputStream(JNIEnv* env, jclass, jobject st return 0; } - const BIO_METHOD *method = stream_bio_method(); + const BIO_METHOD* method = stream_bio_method(); if (!method) { return 0; } @@ -5492,7 +5492,7 @@ static jlong NativeCrypto_create_BIO_OutputStream(JNIEnv* env, jclass, jobject s return 0; } - const BIO_METHOD *method = stream_bio_method(); + const BIO_METHOD* method = stream_bio_method(); if (!method) { return 0; } @@ -5569,7 +5569,7 @@ static jobject GENERAL_NAME_to_jobject(JNIEnv* env, GENERAL_NAME* gen) { // Converting ASCII to UTF-16 is the identity function. jchars.push_back(data[i]); } - JNI_TRACE("GENERAL_NAME_to_jobject(%p)=> Email/DNS/URI \"%.*s\"", gen, (int) len, data); + JNI_TRACE("GENERAL_NAME_to_jobject(%p)=> Email/DNS/URI \"%.*s\"", gen, (int)len, data); return env->NewString(jchars.data(), jchars.size()); } case GEN_DIRNAME: @@ -5647,7 +5647,8 @@ static jobjectArray NativeCrypto_get_X509_GENERAL_NAME_stack(JNIEnv* env, jclass // TODO(https://github.com/google/conscrypt/issues/916): Handle errors, remove // |ERR_clear_error|, and throw CertificateParsingException. if (gn_stack == nullptr) { - JNI_TRACE("get_X509_GENERAL_NAME_stack(%p, %d) => null (no extension or error)", x509, type); + JNI_TRACE("get_X509_GENERAL_NAME_stack(%p, %d) => null (no extension or error)", x509, + type); ERR_clear_error(); return nullptr; } @@ -6582,12 +6583,9 @@ static void NativeCrypto_ASN1_TIME_to_Calendar(JNIEnv* env, jclass, jlong asn1Ti int year, mon, mday, hour, min, sec; const char* data = reinterpret_cast(ASN1_STRING_get0_data(gen.get())); - if (!decimal_to_integer(data, 4, &year) || - !decimal_to_integer(data + 4, 2, &mon) || - !decimal_to_integer(data + 6, 2, &mday) || - !decimal_to_integer(data + 8, 2, &hour) || - !decimal_to_integer(data + 10, 2, &min) || - !decimal_to_integer(data + 12, 2, &sec)) { + if (!decimal_to_integer(data, 4, &year) || !decimal_to_integer(data + 4, 2, &mon) || + !decimal_to_integer(data + 6, 2, &mday) || !decimal_to_integer(data + 8, 2, &hour) || + !decimal_to_integer(data + 10, 2, &min) || !decimal_to_integer(data + 12, 2, &sec)) { conscrypt::jniutil::throwParsingException(env, "Invalid date format"); return; } @@ -7175,8 +7173,8 @@ static jlongArray NativeCrypto_d2i_PKCS7_bio(JNIEnv* env, jclass, jlong bioRef, uint8_t* data; size_t len; if (!BIO_read_asn1(bio, &data, &len, 256 * 1024 * 1024 /* max length, 256MB for sanity */)) { - conscrypt::jniutil::throwExceptionFromBoringSSLError(env, "Error reading PKCS#7 data", - conscrypt::jniutil::throwParsingException); + conscrypt::jniutil::throwExceptionFromBoringSSLError( + env, "Error reading PKCS#7 data", conscrypt::jniutil::throwParsingException); JNI_TRACE("d2i_PKCS7_bio(%p, %d) => error reading BIO", bio, which); return nullptr; } @@ -7188,8 +7186,8 @@ static jlongArray NativeCrypto_d2i_PKCS7_bio(JNIEnv* env, jclass, jlong bioRef, if (which == PKCS7_CERTS) { bssl::UniquePtr outCerts(sk_X509_new_null()); if (!PKCS7_get_certificates(outCerts.get(), &cbs)) { - conscrypt::jniutil::throwExceptionFromBoringSSLError(env, - "PKCS7_get_certificates", conscrypt::jniutil::throwParsingException); + conscrypt::jniutil::throwExceptionFromBoringSSLError( + env, "PKCS7_get_certificates", conscrypt::jniutil::throwParsingException); JNI_TRACE("d2i_PKCS7_bio(%p, %d) => error reading certs", bio, which); return nullptr; } @@ -7198,8 +7196,8 @@ static jlongArray NativeCrypto_d2i_PKCS7_bio(JNIEnv* env, jclass, jlong bioRef, } else if (which == PKCS7_CRLS) { bssl::UniquePtr outCRLs(sk_X509_CRL_new_null()); if (!PKCS7_get_CRLs(outCRLs.get(), &cbs)) { - conscrypt::jniutil::throwExceptionFromBoringSSLError(env, "PKCS7_get_CRLs", - conscrypt::jniutil::throwParsingException); + conscrypt::jniutil::throwExceptionFromBoringSSLError( + env, "PKCS7_get_CRLs", conscrypt::jniutil::throwParsingException); JNI_TRACE("d2i_PKCS7_bio(%p, %d) => error reading CRLs", bio, which); return nullptr; } @@ -7224,8 +7222,8 @@ static jlongArray NativeCrypto_ASN1_seq_unpack_X509_bio(JNIEnv* env, jclass, jlo uint8_t* data; size_t len; if (!BIO_read_asn1(bio, &data, &len, 256 * 1024 * 1024 /* max length, 256MB for sanity */)) { - conscrypt::jniutil::throwExceptionFromBoringSSLError(env, "Error reading X.509 data", - conscrypt::jniutil::throwParsingException); + conscrypt::jniutil::throwExceptionFromBoringSSLError( + env, "Error reading X.509 data", conscrypt::jniutil::throwParsingException); JNI_TRACE("ASN1_seq_unpack_X509_bio(%p) => error reading BIO", bio); return nullptr; } @@ -7875,8 +7873,9 @@ static int sslSelect(JNIEnv* env, int type, jobject fdObject, AppData* appData, break; } - if (WSAEventSelect(fd.get(), events[1], (type == SSL_ERROR_WANT_READ ? FD_READ : FD_WRITE) | - FD_CLOSE) == SOCKET_ERROR) { + if (WSAEventSelect(fd.get(), events[1], + (type == SSL_ERROR_WANT_READ ? FD_READ : FD_WRITE) | FD_CLOSE) == + SOCKET_ERROR) { JNI_TRACE("sslSelect failure in WSAEventSelect: %d", WSAGetLastError()); break; } @@ -8101,7 +8100,7 @@ static void info_callback(const SSL* ssl, int type, int value) { JNI_TRACE("ssl=%p info_callback calling onSSLStateChange", ssl); env->CallVoidMethod(sslHandshakeCallbacks, - conscrypt::jniutil::sslHandshakeCallbacks_onSSLStateChange, type, value); + conscrypt::jniutil::sslHandshakeCallbacks_onSSLStateChange, type, value); if (env->ExceptionCheck()) { JNI_TRACE("ssl=%p info_callback exception", ssl); @@ -8422,8 +8421,7 @@ static SSL_SESSION* server_session_requested_callback(SSL* ssl, const uint8_t* i return ssl_session_ptr; } -static jint NativeCrypto_EVP_has_aes_hardware(JNIEnv* env, jclass) { - CHECK_ERROR_QUEUE_ON_RETURN; +static jint NativeCrypto_EVP_has_aes_hardware(CRITICAL_JNI_PARAMS) { int ret = 0; ret = EVP_has_aes_hardware(); JNI_TRACE("EVP_has_aes_hardware => %d", ret); @@ -9113,8 +9111,8 @@ static jbyteArray NativeCrypto_SSL_export_keying_material(JNIEnv* env, jclass, j int ret; if (context == nullptr) { ret = SSL_export_keying_material(ssl, out.get(), num_bytes, - reinterpret_cast(labelBytes.get()), labelBytes.size(), - nullptr, 0, 0); + reinterpret_cast(labelBytes.get()), + labelBytes.size(), nullptr, 0, 0); } else { ScopedByteArrayRO contextBytes(env, context); if (contextBytes.get() == nullptr) { @@ -9128,8 +9126,8 @@ static jbyteArray NativeCrypto_SSL_export_keying_material(JNIEnv* env, jclass, j contextBytes.size(), 1); } if (!ret) { - conscrypt::jniutil::throwExceptionFromBoringSSLError(env, "SSL_export_keying_material", - conscrypt::jniutil::throwSSLExceptionStr); + conscrypt::jniutil::throwExceptionFromBoringSSLError( + env, "SSL_export_keying_material", conscrypt::jniutil::throwSSLExceptionStr); JNI_TRACE("ssl=%p NativeCrypto_SSL_export_keying_material => exception", ssl); return nullptr; } @@ -9491,8 +9489,7 @@ static jstring NativeCrypto_SSL_get_servername(JNIEnv* env, jclass, jlong ssl_ad * which should take precedence. */ static int selectApplicationProtocol(SSL* ssl, unsigned char** out, unsigned char* outLength, - const unsigned char* primary, - const unsigned int primaryLength, + const unsigned char* primary, const unsigned int primaryLength, const unsigned char* secondary, const unsigned int secondaryLength) { JNI_TRACE("primary=%p, length=%d", primary, primaryLength); @@ -9518,9 +9515,8 @@ static int selectApplicationProtocol(SSL* ssl, unsigned char** out, unsigned cha * Calls out to an application-provided selector to choose the ALPN protocol. */ static int selectApplicationProtocol(SSL* ssl, JNIEnv* env, jobject sslHandshakeCallbacks, - unsigned char** out, - unsigned char* outLen, const unsigned char* in, - const unsigned int inLen) { + unsigned char** out, unsigned char* outLen, + const unsigned char* in, const unsigned int inLen) { // Copy the input array. ScopedLocalRef protocols(env, env->NewByteArray(static_cast(inLen))); if (protocols.get() == nullptr) { @@ -9580,10 +9576,10 @@ static int alpn_select_callback(SSL* ssl, const unsigned char** out, unsigned ch const_cast(out), outLen, in, inLen); } - return selectApplicationProtocol(ssl, const_cast(out), outLen, - reinterpret_cast(appData->applicationProtocolsData), - static_cast(appData->applicationProtocolsLength), - in, inLen); + return selectApplicationProtocol( + ssl, const_cast(out), outLen, + reinterpret_cast(appData->applicationProtocolsData), + static_cast(appData->applicationProtocolsLength), in, inLen); } static jbyteArray NativeCrypto_getApplicationProtocol(JNIEnv* env, jclass, jlong ssl_address, @@ -10065,7 +10061,9 @@ static int sslRead(JNIEnv* env, SSL* ssl, jobject fdObject, jobject shc, char* b } // Everything else is basically an error. - default: { return THROW_SSLEXCEPTION; } + default: { + return THROW_SSLEXCEPTION; + } } } @@ -10342,7 +10340,9 @@ static int sslWrite(JNIEnv* env, SSL* ssl, jobject fdObject, jobject shc, const } // Everything else is basically an error. - default: { return THROW_SSLEXCEPTION; } + default: { + return THROW_SSLEXCEPTION; + } } } JNI_TRACE("ssl=%p sslWrite => count=%d", ssl, count); @@ -10715,9 +10715,8 @@ static jlong NativeCrypto_SSL_get_timeout(JNIEnv* env, jclass, jlong ssl_address return result; } -static jint NativeCrypto_SSL_get_signature_algorithm_key_type(JNIEnv* env, jclass, - jint signatureAlg) { - CHECK_ERROR_QUEUE_ON_RETURN; +static jint NativeCrypto_SSL_get_signature_algorithm_key_type( + CRITICAL_JNI_PARAMS_COMMA jint signatureAlg) { return SSL_get_signature_algorithm_key_type(signatureAlg); } @@ -11190,7 +11189,7 @@ static jint NativeCrypto_SSL_get_error(JNIEnv* env, jclass, jlong ssl_address, return SSL_get_error(ssl, ret); } -static void NativeCrypto_SSL_clear_error(JNIEnv*, jclass) { +static void NativeCrypto_SSL_clear_error(CRITICAL_JNI_PARAMS) { ERR_clear_error(); } @@ -11733,8 +11732,9 @@ static jboolean NativeCrypto_usesBoringSsl_FIPS_mode() { * Scrypt support */ -static jbyteArray NativeCrypto_Scrypt_generate_key(JNIEnv* env, jclass, jbyteArray password, jbyteArray salt, - jint n, jint r, jint p, jint key_len) { +static jbyteArray NativeCrypto_Scrypt_generate_key(JNIEnv* env, jclass, jbyteArray password, + jbyteArray salt, jint n, jint r, jint p, + jint key_len) { CHECK_ERROR_QUEUE_ON_RETURN; JNI_TRACE("Scrypt_generate_key(%p, %p, %d, %d, %d, %d)", password, salt, n, r, p, key_len); @@ -11761,10 +11761,10 @@ static jbyteArray NativeCrypto_Scrypt_generate_key(JNIEnv* env, jclass, jbyteArr ScopedByteArrayRO password_bytes(env, password); ScopedByteArrayRO salt_bytes(env, salt); - int result = EVP_PBE_scrypt(reinterpret_cast(password_bytes.get()), password_bytes.size(), - reinterpret_cast(salt_bytes.get()), salt_bytes.size(), - n, r, p, memory_limit, - reinterpret_cast(out_key.get()), key_len); + int result = EVP_PBE_scrypt( + reinterpret_cast(password_bytes.get()), password_bytes.size(), + reinterpret_cast(salt_bytes.get()), salt_bytes.size(), n, r, p, + memory_limit, reinterpret_cast(out_key.get()), key_len); if (result <= 0) { conscrypt::jniutil::throwExceptionFromBoringSSLError(env, "Scrypt_generate_key"); @@ -12217,12 +12217,10 @@ static jboolean NativeCrypto_SSL_CTX_ech_enable_server(JNIEnv* env, jclass, jlon // TESTING METHODS END -#define CONSCRYPT_NATIVE_METHOD(functionName, signature) \ - { \ - /* NOLINTNEXTLINE */ \ - (char*)#functionName, (char*)(signature), \ - reinterpret_cast(NativeCrypto_##functionName) \ - } +#define CONSCRYPT_NATIVE_METHOD(functionName, signature) \ + {/* NOLINTNEXTLINE */ \ + (char*)#functionName, (char*)(signature), \ + reinterpret_cast(NativeCrypto_##functionName)} #define FILE_DESCRIPTOR "Ljava/io/FileDescriptor;" #define SSL_CALLBACKS \ diff --git a/common/src/jni/main/include/conscrypt/jniutil.h b/common/src/jni/main/include/conscrypt/jniutil.h index 7ae567dbc..de69107f5 100644 --- a/common/src/jni/main/include/conscrypt/jniutil.h +++ b/common/src/jni/main/include/conscrypt/jniutil.h @@ -17,16 +17,23 @@ #ifndef CONSCRYPT_JNIUTIL_H_ #define CONSCRYPT_JNIUTIL_H_ -#include -#include - #include #include +#include #include +#include namespace conscrypt { namespace jniutil { +#ifdef __ANDROID__ +#define CRITICAL_JNI_PARAMS +#define CRITICAL_JNI_PARAMS_COMMA +#else +#define CRITICAL_JNI_PARAMS JNIEnv*, jclass +#define CRITICAL_JNI_PARAMS_COMMA JNIEnv*, jclass, +#endif + extern JavaVM* gJavaVM; extern jclass cryptoUpcallsClass; extern jclass openSslInputStreamClass; @@ -308,7 +315,7 @@ extern int throwSSLExceptionWithSslErrors(JNIEnv* env, SSL* ssl, int sslErrorCod * ensure that the error queue is empty whenever the function exits. */ class ErrorQueueChecker { - public: +public: explicit ErrorQueueChecker(JNIEnv* env) : env(env) {} ~ErrorQueueChecker() { if (ERR_peek_error() != 0) { @@ -326,7 +333,7 @@ class ErrorQueueChecker { } } - private: +private: JNIEnv* env; }; diff --git a/common/src/main/java/org/conscrypt/AbstractConscryptEngine.java b/common/src/main/java/org/conscrypt/AbstractConscryptEngine.java index 0f1354a93..6bbd260da 100644 --- a/common/src/main/java/org/conscrypt/AbstractConscryptEngine.java +++ b/common/src/main/java/org/conscrypt/AbstractConscryptEngine.java @@ -18,6 +18,7 @@ import java.nio.ByteBuffer; import java.security.PrivateKey; + import javax.net.ssl.SSLEngine; import javax.net.ssl.SSLEngineResult; import javax.net.ssl.SSLException; @@ -111,21 +112,21 @@ public final SSLSession getHandshakeSession() { @Override public abstract SSLEngineResult unwrap(final ByteBuffer src, final ByteBuffer[] dsts, - final int offset, final int length) throws SSLException; + final int offset, final int length) throws SSLException; abstract SSLEngineResult unwrap(final ByteBuffer[] srcs, final ByteBuffer[] dsts) throws SSLException; abstract SSLEngineResult unwrap(final ByteBuffer[] srcs, int srcsOffset, final int srcsLength, - final ByteBuffer[] dsts, final int dstsOffset, final int dstsLength) - throws SSLException; + final ByteBuffer[] dsts, final int dstsOffset, + final int dstsLength) throws SSLException; @Override public abstract SSLEngineResult wrap(ByteBuffer src, ByteBuffer dst) throws SSLException; @Override - public abstract SSLEngineResult wrap( - ByteBuffer[] srcs, int srcsOffset, int srcsLength, ByteBuffer dst) throws SSLException; + public abstract SSLEngineResult wrap(ByteBuffer[] srcs, int srcsOffset, int srcsLength, + ByteBuffer dst) throws SSLException; /** * This method enables session ticket support. @@ -134,6 +135,13 @@ public abstract SSLEngineResult wrap( */ abstract void setUseSessionTickets(boolean useSessionTickets); + /** + * This method sets the ECH config data to be used in the TLS handshake. + * + * @param echConfigList the ECH config data to be used in the TLS handshake + */ + abstract void setEchConfigList(byte[] echConfigList); + /** * Sets the list of ALPN protocols. * diff --git a/common/src/main/java/org/conscrypt/AbstractConscryptSocket.java b/common/src/main/java/org/conscrypt/AbstractConscryptSocket.java index d9848681d..e77e37562 100644 --- a/common/src/main/java/org/conscrypt/AbstractConscryptSocket.java +++ b/common/src/main/java/org/conscrypt/AbstractConscryptSocket.java @@ -32,6 +32,7 @@ import java.security.PrivateKey; import java.util.ArrayList; import java.util.List; + import javax.net.ssl.HandshakeCompletedEvent; import javax.net.ssl.HandshakeCompletedListener; import javax.net.ssl.SSLException; @@ -118,7 +119,7 @@ int getPort() { } AbstractConscryptSocket(InetAddress address, int port, InetAddress clientAddress, - int clientPort) throws IOException { + int clientPort) throws IOException { super(address, port, clientAddress, clientPort); this.socket = this; this.peerHostname = null; @@ -626,6 +627,13 @@ private boolean isDelegating() { */ abstract void setUseSessionTickets(boolean useSessionTickets); + /** + * This method sets the ECH config data to be used in the TLS handshake. + * + * @param echConfigList the ECH config data to be used in the TLS handshake + */ + abstract void setEchConfigList(byte[] echConfigList); + /** * Enables/disables TLS Channel ID for this server socket. * @@ -668,8 +676,7 @@ private boolean isDelegating() { * * @deprecated use {@link #getApplicationProtocol()} instead. */ - @Deprecated - abstract byte[] getAlpnSelectedProtocol(); + @Deprecated abstract byte[] getAlpnSelectedProtocol(); /** * Sets the list of ALPN protocols. This method internally converts the protocols to their @@ -678,8 +685,7 @@ private boolean isDelegating() { * @param alpnProtocols the list of ALPN protocols * @deprecated use {@link #setApplicationProtocols(String[])} instead. */ - @Deprecated - abstract void setAlpnProtocols(String[] alpnProtocols); + @Deprecated abstract void setAlpnProtocols(String[] alpnProtocols); /** * Alternate version of {@link #setAlpnProtocols(String[])} that directly sets the list of @@ -689,8 +695,7 @@ private boolean isDelegating() { * @param alpnProtocols the encoded form of the ALPN protocol list * @deprecated Use {@link #setApplicationProtocols(String[])} instead. */ - @Deprecated - abstract void setAlpnProtocols(byte[] alpnProtocols); + @Deprecated abstract void setAlpnProtocols(byte[] alpnProtocols); /** * Sets the list of ALPN protocols. diff --git a/common/src/main/java/org/conscrypt/ArrayUtils.java b/common/src/main/java/org/conscrypt/ArrayUtils.java index 113be7893..5563c5c08 100644 --- a/common/src/main/java/org/conscrypt/ArrayUtils.java +++ b/common/src/main/java/org/conscrypt/ArrayUtils.java @@ -29,17 +29,18 @@ private ArrayUtils() {} * Checks that the range described by {@code offset} and {@code count} * doesn't exceed {@code arrayLength}. */ - static void checkOffsetAndCount(int arrayLength, int offset, int count) { + + public static void checkOffsetAndCount(int arrayLength, int offset, int count) { if ((offset | count) < 0 || offset > arrayLength || arrayLength - offset < count) { throw new ArrayIndexOutOfBoundsException("length=" + arrayLength + "; regionStart=" - + offset + "; regionLength=" + count); + + offset + "; regionLength=" + count); } } @SafeVarargs @SuppressWarnings("varargs") public static T[] concatValues(T[] a1, T... values) { - return concat (a1, values); + return concat(a1, values); } public static T[] concat(T[] a1, T[] a2) { diff --git a/common/src/main/java/org/conscrypt/BufferUtils.java b/common/src/main/java/org/conscrypt/BufferUtils.java index eb0806b4c..73b115048 100644 --- a/common/src/main/java/org/conscrypt/BufferUtils.java +++ b/common/src/main/java/org/conscrypt/BufferUtils.java @@ -16,18 +16,24 @@ package org.conscrypt; -import static java.lang.Math.min; import static org.conscrypt.Preconditions.checkArgument; +import static java.lang.Math.min; + import java.nio.ByteBuffer; -final class BufferUtils { +/** + * Utility methods for dealing with arrays of ByteBuffers. + * + * @hide This class is not part of the Android public SDK API + */ +public final class BufferUtils { private BufferUtils() {} /** * Throws {@link IllegalArgumentException} if any of the buffers in the array are null. */ - static void checkNotNull(ByteBuffer[] buffers) { + public static void checkNotNull(ByteBuffer[] buffers) { for (ByteBuffer buffer : buffers) { if (buffer == null) { throw new IllegalArgumentException("Null buffer in array"); @@ -38,7 +44,7 @@ static void checkNotNull(ByteBuffer[] buffers) { /** * Returns the total number of bytes remaining in the buffer array. */ - static long remaining(ByteBuffer[] buffers) { + public static long remaining(ByteBuffer[] buffers) { long size = 0; for (ByteBuffer buffer : buffers) { size += buffer.remaining(); @@ -51,7 +57,7 @@ static long remaining(ByteBuffer[] buffers) { * * @throws IllegalArgumentException if there are fewer than {@code toConsume} bytes remaining */ - static void consume(ByteBuffer[] sourceBuffers, int toConsume) { + public static void consume(ByteBuffer[] sourceBuffers, int toConsume) { for (ByteBuffer sourceBuffer : sourceBuffers) { int amount = min(sourceBuffer.remaining(), toConsume); if (amount > 0) { @@ -71,7 +77,7 @@ static void consume(ByteBuffer[] sourceBuffers, int toConsume) { * Looks for a buffer in the buffer array which EITHER is larger than {@code minSize} AND * has no preceding non-empty buffers OR is the only non-empty buffer in the array. */ - static ByteBuffer getBufferLargerThan(ByteBuffer[] buffers, int minSize) { + public static ByteBuffer getBufferLargerThan(ByteBuffer[] buffers, int minSize) { int length = buffers.length; for (int i = 0; i < length; i++) { ByteBuffer buffer = buffers[i]; @@ -99,11 +105,12 @@ static ByteBuffer getBufferLargerThan(ByteBuffer[] buffers, int minSize) { * {@code consume()} method. * */ - static ByteBuffer copyNoConsume(ByteBuffer[] buffers, ByteBuffer destination, int maxAmount) { - checkArgument(destination.remaining() >= maxAmount, "Destination buffer too small"); - int needed = maxAmount; + public static ByteBuffer copyNoConsume(ByteBuffer[] buffers, ByteBuffer destination, + int maxAmount) { + checkArgument(destination.remaining() >= maxAmount, "Destination buffer too small"); + int needed = maxAmount; for (ByteBuffer buffer : buffers) { - int remaining = buffer.remaining(); + int remaining = buffer.remaining(); if (remaining > 0) { // If this buffer can fit completely then copy it all, otherwise temporarily // adjust its limit to fill so as to the output buffer completely diff --git a/common/src/main/java/org/conscrypt/CertBlocklist.java b/common/src/main/java/org/conscrypt/CertBlocklist.java index 024947b89..056718f02 100644 --- a/common/src/main/java/org/conscrypt/CertBlocklist.java +++ b/common/src/main/java/org/conscrypt/CertBlocklist.java @@ -16,14 +16,16 @@ package org.conscrypt; +import org.conscrypt.Internal; + import java.math.BigInteger; import java.security.PublicKey; /** * A set of certificates that are blacklisted from trust. */ +@Internal public interface CertBlocklist { - /** * Returns whether the given public key is in the blacklist. */ diff --git a/common/src/main/java/org/conscrypt/CertBlocklistEntry.java b/common/src/main/java/org/conscrypt/CertBlocklistEntry.java new file mode 100644 index 000000000..950d568d5 --- /dev/null +++ b/common/src/main/java/org/conscrypt/CertBlocklistEntry.java @@ -0,0 +1,37 @@ +/* + * Copyright 2025 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 org.conscrypt.Internal; + +/** + * An entry in the blocklist, for the purpose of reporting. + */ +@Internal +public interface CertBlocklistEntry { + enum Origin { SHA1_TEST, SHA1_BUILT_IN, SHA1_FILE, SHA256_TEST, SHA256_BUILT_IN, SHA256_FILE } + + /** + * Returns the origin of this entry. + */ + Origin getOrigin(); + + /** + * Returns the index of this entry in its blocklist. + */ + int getIndex(); +} diff --git a/common/src/main/java/org/conscrypt/Conscrypt.java b/common/src/main/java/org/conscrypt/Conscrypt.java index 90c8d6c1e..819469d27 100644 --- a/common/src/main/java/org/conscrypt/Conscrypt.java +++ b/common/src/main/java/org/conscrypt/Conscrypt.java @@ -225,8 +225,8 @@ public ProviderBuilder isTlsV1Enabled(boolean enabledTlsV1) { } public Provider build() { - return new OpenSSLProvider( - name, provideTrustManager, defaultTlsProtocol, deprecatedTlsV1, enabledTlsV1); + return new OpenSSLProvider(name, provideTrustManager, defaultTlsProtocol, + deprecatedTlsV1, enabledTlsV1); } } @@ -271,8 +271,8 @@ public static SSLContextSpi newPreferredSSLContextSpi() { public static void setClientSessionCache(SSLContext context, SSLClientSessionCache cache) { SSLSessionContext clientContext = context.getClientSessionContext(); if (!(clientContext instanceof ClientSessionContext)) { - throw new IllegalArgumentException( - "Not a conscrypt client context: " + clientContext.getClass().getName()); + throw new IllegalArgumentException("Not a conscrypt client context: " + + clientContext.getClass().getName()); } ((ClientSessionContext) clientContext).setPersistentCache(cache); } @@ -283,8 +283,8 @@ public static void setClientSessionCache(SSLContext context, SSLClientSessionCac public static void setServerSessionCache(SSLContext context, SSLServerSessionCache cache) { SSLSessionContext serverContext = context.getServerSessionContext(); if (!(serverContext instanceof ServerSessionContext)) { - throw new IllegalArgumentException( - "Not a conscrypt client context: " + serverContext.getClass().getName()); + throw new IllegalArgumentException("Not a conscrypt client context: " + + serverContext.getClass().getName()); } ((ServerSessionContext) serverContext).setPersistentCache(cache); } @@ -299,8 +299,8 @@ public static boolean isConscrypt(SSLSocketFactory factory) { private static OpenSSLSocketFactoryImpl toConscrypt(SSLSocketFactory factory) { if (!isConscrypt(factory)) { - throw new IllegalArgumentException( - "Not a conscrypt socket factory: " + factory.getClass().getName()); + throw new IllegalArgumentException("Not a conscrypt socket factory: " + + factory.getClass().getName()); } return (OpenSSLSocketFactoryImpl) factory; } @@ -332,8 +332,8 @@ public static boolean isConscrypt(SSLServerSocketFactory factory) { private static OpenSSLServerSocketFactoryImpl toConscrypt(SSLServerSocketFactory factory) { if (!isConscrypt(factory)) { - throw new IllegalArgumentException( - "Not a conscrypt server socket factory: " + factory.getClass().getName()); + throw new IllegalArgumentException("Not a conscrypt server socket factory: " + + factory.getClass().getName()); } return (OpenSSLServerSocketFactoryImpl) factory; } @@ -355,8 +355,8 @@ public static boolean isConscrypt(SSLSocket socket) { private static AbstractConscryptSocket toConscrypt(SSLSocket socket) { if (!isConscrypt(socket)) { - throw new IllegalArgumentException( - "Not a conscrypt socket: " + socket.getClass().getName()); + throw new IllegalArgumentException("Not a conscrypt socket: " + + socket.getClass().getName()); } return (AbstractConscryptSocket) socket; } @@ -400,6 +400,16 @@ public static void setUseSessionTickets(SSLSocket socket, boolean useSessionTick toConscrypt(socket).setUseSessionTickets(useSessionTickets); } + /** + * This method sets the ECH config data to be used in the TLS handshake. + * + * @param socket the socket + * @param echConfigList the ECH config data to be used in the TLS handshake + */ + public static void setEchConfigList(SSLSocket socket, byte[] echConfigList) { + toConscrypt(socket).setEchConfigList(echConfigList); + } + /** * Enables/disables TLS Channel ID for the given server-side socket. * @@ -458,8 +468,8 @@ public static String getApplicationProtocol(SSLSocket socket) { return toConscrypt(socket).getApplicationProtocol(); } if (!socket.getClass().getName().contains("conscrypt")) { - throw new IllegalArgumentException( - "Not a conscrypt socket: " + socket.getClass().getName()); + throw new IllegalArgumentException("Not a conscrypt socket: " + + socket.getClass().getName()); } return invokeConscryptMethod(socket, "getApplicationProtocol"); } @@ -471,8 +481,8 @@ public static String getApplicationProtocol(SSLSocket socket) { * @param socket the socket * @param selector the ALPN protocol selector */ - public static void setApplicationProtocolSelector( - SSLSocket socket, ApplicationProtocolSelector selector) { + public static void setApplicationProtocolSelector(SSLSocket socket, + ApplicationProtocolSelector selector) { toConscrypt(socket).setApplicationProtocolSelector(selector); } @@ -522,8 +532,8 @@ public static byte[] getTlsUnique(SSLSocket socket) { * completed or the connection has been closed. * @throws SSLException if the value could not be exported. */ - public static byte[] exportKeyingMaterial( - SSLSocket socket, String label, byte[] context, int length) throws SSLException { + public static byte[] exportKeyingMaterial(SSLSocket socket, String label, byte[] context, + int length) throws SSLException { return toConscrypt(socket).exportKeyingMaterial(label, context, length); } @@ -536,8 +546,8 @@ public static boolean isConscrypt(SSLEngine engine) { private static AbstractConscryptEngine toConscrypt(SSLEngine engine) { if (!isConscrypt(engine)) { - throw new IllegalArgumentException( - "Not a conscrypt engine: " + engine.getClass().getName()); + throw new IllegalArgumentException("Not a conscrypt engine: " + + engine.getClass().getName()); } return (AbstractConscryptEngine) engine; } @@ -664,7 +674,7 @@ public static void setChannelIdPrivateKey(SSLEngine engine, PrivateKey privateKe * @throws SSLException thrown if an SSL error occurred */ public static SSLEngineResult unwrap(SSLEngine engine, final ByteBuffer[] srcs, - final ByteBuffer[] dsts) throws SSLException { + final ByteBuffer[] dsts) throws SSLException { return toConscrypt(engine).unwrap(srcs, dsts); } @@ -682,10 +692,11 @@ public static SSLEngineResult unwrap(SSLEngine engine, final ByteBuffer[] srcs, * @throws SSLException thrown if an SSL error occurred */ public static SSLEngineResult unwrap(SSLEngine engine, final ByteBuffer[] srcs, int srcsOffset, - final int srcsLength, final ByteBuffer[] dsts, final int dstsOffset, - final int dstsLength) throws SSLException { - return toConscrypt(engine).unwrap( - srcs, srcsOffset, srcsLength, dsts, dstsOffset, dstsLength); + final int srcsLength, final ByteBuffer[] dsts, + final int dstsOffset, final int dstsLength) + throws SSLException { + return toConscrypt(engine).unwrap(srcs, srcsOffset, srcsLength, dsts, dstsOffset, + dstsLength); } /** @@ -698,6 +709,16 @@ public static void setUseSessionTickets(SSLEngine engine, boolean useSessionTick toConscrypt(engine).setUseSessionTickets(useSessionTickets); } + /** + * This method sets the ECH config data to be used in the TLS handshake. + * + * @param engine the engine + * @param echConfigList the ECH config data to be used in the TLS handshake + */ + public static void setEchConfigList(SSLEngine engine, byte[] echConfigList) { + toConscrypt(engine).setEchConfigList(echConfigList); + } + /** * Sets the application-layer protocols (ALPN) in prioritization order. * @@ -729,8 +750,8 @@ public static String[] getApplicationProtocols(SSLEngine engine) { * @param engine the engine * @param selector the ALPN protocol selector */ - public static void setApplicationProtocolSelector( - SSLEngine engine, ApplicationProtocolSelector selector) { + public static void setApplicationProtocolSelector(SSLEngine engine, + ApplicationProtocolSelector selector) { toConscrypt(engine).setApplicationProtocolSelector(selector); } @@ -746,8 +767,8 @@ public static String getApplicationProtocol(SSLEngine engine) { return toConscrypt(engine).getApplicationProtocol(); } if (!engine.getClass().getName().contains("conscrypt")) { - throw new IllegalArgumentException( - "Not a conscrypt engine: " + engine.getClass().getName()); + throw new IllegalArgumentException("Not a conscrypt engine: " + + engine.getClass().getName()); } return invokeConscryptMethod(engine, "getApplicationProtocol"); } @@ -774,8 +795,8 @@ public static byte[] getTlsUnique(SSLEngine engine) { * completed or the connection has been closed. * @throws SSLException if the value could not be exported. */ - public static byte[] exportKeyingMaterial( - SSLEngine engine, String label, byte[] context, int length) throws SSLException { + public static byte[] exportKeyingMaterial(SSLEngine engine, String label, byte[] context, + int length) throws SSLException { return toConscrypt(engine).exportKeyingMaterial(label, context, length); } @@ -789,8 +810,8 @@ public static boolean isConscrypt(TrustManager trustManager) { private static TrustManagerImpl toConscrypt(TrustManager trustManager) { if (!isConscrypt(trustManager)) { - throw new IllegalArgumentException( - "Not a Conscrypt trust manager: " + trustManager.getClass().getName()); + throw new IllegalArgumentException("Not a Conscrypt trust manager: " + + trustManager.getClass().getName()); } return (TrustManagerImpl) trustManager; } @@ -824,8 +845,8 @@ public synchronized static ConscryptHostnameVerifier getDefaultHostnameVerifier( * @throws IllegalArgumentException if the provided trust manager is not a Conscrypt trust * manager per {@link #isConscrypt(TrustManager)} */ - public static void setHostnameVerifier( - TrustManager trustManager, ConscryptHostnameVerifier verifier) { + public static void setHostnameVerifier(TrustManager trustManager, + ConscryptHostnameVerifier verifier) { toConscrypt(trustManager).setHostnameVerifier(verifier); } @@ -847,8 +868,8 @@ public static ConscryptHostnameVerifier getHostnameVerifier(TrustManager trustMa public static ConscryptHostnameVerifier wrapHostnameVerifier(final HostnameVerifier verifier) { return new ConscryptHostnameVerifier() { @Override - public boolean verify( - X509Certificate[] certificates, String hostname, SSLSession session) { + public boolean verify(X509Certificate[] certificates, String hostname, + SSLSession session) { return verifier.verify(hostname, session); } }; diff --git a/common/src/main/java/org/conscrypt/ConscryptFileDescriptorSocket.java b/common/src/main/java/org/conscrypt/ConscryptFileDescriptorSocket.java index c457a1636..85e36f187 100644 --- a/common/src/main/java/org/conscrypt/ConscryptFileDescriptorSocket.java +++ b/common/src/main/java/org/conscrypt/ConscryptFileDescriptorSocket.java @@ -62,8 +62,7 @@ * */ class ConscryptFileDescriptorSocket extends OpenSSLSocketImpl - implements NativeCrypto.SSLHandshakeCallbacks, - SSLParametersImpl.PSKCallbacks, + implements NativeCrypto.SSLHandshakeCallbacks, SSLParametersImpl.PSKCallbacks, SSLParametersImpl.AliasChooser { private static final boolean DBG_STATE = false; @@ -111,12 +110,12 @@ class ConscryptFileDescriptorSocket extends OpenSSLSocketImpl * The session object exposed externally from this class. */ private final SSLSession externalSession = - Platform.wrapSSLSession(new ExternalSession(new ExternalSession.Provider() { - @Override - public ConscryptSession provideSession() { - return ConscryptFileDescriptorSocket.this.provideSession(); - } - })); + Platform.wrapSSLSession(new ExternalSession(new ExternalSession.Provider() { + @Override + public ConscryptSession provideSession() { + return ConscryptFileDescriptorSocket.this.provideSession(); + } + })); private int writeTimeoutMilliseconds = 0; private int handshakeTimeoutMilliseconds = -1; // -1 = same as timeout; 0 = infinite @@ -148,7 +147,8 @@ public ConscryptSession provideSession() { } ConscryptFileDescriptorSocket(String hostname, int port, InetAddress clientAddress, - int clientPort, SSLParametersImpl sslParameters) throws IOException { + int clientPort, SSLParametersImpl sslParameters) + throws IOException { super(hostname, port, clientAddress, clientPort); this.sslParameters = sslParameters; this.ssl = newSsl(sslParameters, this); @@ -156,7 +156,8 @@ public ConscryptSession provideSession() { } ConscryptFileDescriptorSocket(InetAddress address, int port, InetAddress clientAddress, - int clientPort, SSLParametersImpl sslParameters) throws IOException { + int clientPort, SSLParametersImpl sslParameters) + throws IOException { super(address, port, clientAddress, clientPort); this.sslParameters = sslParameters; this.ssl = newSsl(sslParameters, this); @@ -164,7 +165,7 @@ public ConscryptSession provideSession() { } ConscryptFileDescriptorSocket(Socket socket, String hostname, int port, boolean autoClose, - SSLParametersImpl sslParameters) throws IOException { + SSLParametersImpl sslParameters) throws IOException { super(socket, hostname, port, autoClose); this.sslParameters = sslParameters; this.ssl = newSsl(sslParameters, this); @@ -172,7 +173,7 @@ public ConscryptSession provideSession() { } private static NativeSsl newSsl(SSLParametersImpl sslParameters, - ConscryptFileDescriptorSocket engine) throws SSLException { + ConscryptFileDescriptorSocket engine) throws SSLException { return NativeSsl.newInstance(sslParameters, engine, engine, engine); } @@ -306,7 +307,7 @@ public final void startHandshake() throws IOException { @Override @SuppressWarnings("unused") // used by NativeCrypto.SSLHandshakeCallbacks / client_cert_cb public final void clientCertificateRequested(byte[] keyTypeBytes, int[] signatureAlgs, - byte[][] asn1DerEncodedPrincipals) + byte[][] asn1DerEncodedPrincipals) throws CertificateEncodingException, SSLException { ssl.chooseClientCertificate(keyTypeBytes, signatureAlgs, asn1DerEncodedPrincipals); } @@ -476,9 +477,8 @@ private void waitForHandshake() throws IOException { startHandshake(); synchronized (ssl) { - while (state != STATE_READY && - state != STATE_READY_HANDSHAKE_CUT_THROUGH && - state != STATE_CLOSED) { + while (state != STATE_READY && state != STATE_READY_HANDSHAKE_CUT_THROUGH + && state != STATE_CLOSED) { try { ssl.wait(); } catch (InterruptedException e) { @@ -506,8 +506,7 @@ private class SSLInputStream extends InputStream { */ private final Object readLock = new Object(); - SSLInputStream() { - } + SSLInputStream() {} /** * Reads one byte. If there is no data in the underlying buffer, @@ -546,8 +545,8 @@ public int read(byte[] buf, int offset, int byteCount) throws IOException { } } - int ret = ssl.read( - Platform.getFileDescriptor(socket), buf, offset, byteCount, getSoTimeout()); + int ret = ssl.read(Platform.getFileDescriptor(socket), buf, offset, byteCount, + getSoTimeout()); if (ret == -1) { synchronized (ssl) { if (state == STATE_CLOSED) { @@ -590,8 +589,7 @@ private class SSLOutputStream extends OutputStream { */ private final Object writeLock = new Object(); - SSLOutputStream() { - } + SSLOutputStream() {} /** * Method acts as described in spec for superclass. @@ -629,7 +627,7 @@ public void write(byte[] buf, int offset, int byteCount) throws IOException { } ssl.write(Platform.getFileDescriptor(socket), buf, offset, byteCount, - writeTimeoutMilliseconds); + writeTimeoutMilliseconds); synchronized (ssl) { if (state == STATE_CLOSED) { @@ -687,16 +685,16 @@ private ConscryptSession provideSession() { // After handshake has started, provide active session otherwise a null session, // for code which needs to read session attributes without triggering the handshake. private ConscryptSession provideAfterHandshakeSession() { - return (state < STATE_HANDSHAKE_STARTED) - ? SSLNullSession.getNullSession() - : provideSession(); + return (state < STATE_HANDSHAKE_STARTED) ? SSLNullSession.getNullSession() + : provideSession(); } // If handshake is in progress, provide active session otherwise a null session. private ConscryptSession provideHandshakeSession() { synchronized (ssl) { - return state >= STATE_HANDSHAKE_STARTED && state < STATE_READY ? activeSession - : SSLNullSession.getNullSession(); + return state >= STATE_HANDSHAKE_STARTED && state < STATE_READY + ? activeSession + : SSLNullSession.getNullSession(); } } @@ -775,6 +773,11 @@ public final void setUseSessionTickets(boolean useSessionTickets) { sslParameters.setUseSessionTickets(useSessionTickets); } + @Override + public final void setEchConfigList(byte[] echConfigList) { + sslParameters.setEchConfigList(echConfigList); + } + /** * This method enables Server Name Indication. If the hostname is not a valid SNI hostname, * the SNI extension will be omitted from the handshake. @@ -805,7 +808,7 @@ public final void setChannelIdEnabled(boolean enabled) { if (state != STATE_NEW) { throw new IllegalStateException( "Could not enable/disable Channel ID after the initial handshake has" - + " begun."); + + " begun."); } } sslParameters.channelIdEnabled = enabled; @@ -858,7 +861,7 @@ public final void setChannelIdPrivateKey(PrivateKey privateKey) { if (state != STATE_NEW) { throw new IllegalStateException( "Could not change Channel ID private key after the initial handshake has" - + " begun."); + + " begun."); } } @@ -1133,7 +1136,8 @@ public final String getApplicationProtocol() { public final String getHandshakeApplicationProtocol() { synchronized (ssl) { return state >= STATE_HANDSHAKE_STARTED && state < STATE_READY - ? getApplicationProtocol() : null; + ? getApplicationProtocol() + : null; } } @@ -1164,7 +1168,8 @@ public final String chooseClientPSKIdentity(PSKKeyManager keyManager, String ide @Override @SuppressWarnings("deprecation") // PSKKeyManager is deprecated, but in our own package - public final SecretKey getPSKKey(PSKKeyManager keyManager, String identityHint, String identity) { + public final SecretKey getPSKKey(PSKKeyManager keyManager, String identityHint, + String identity) { return keyManager.getKey(identityHint, identity, this); } @@ -1202,8 +1207,8 @@ private void transitionTo(int newState) { if (handshakeStartedMillis != 0) { StatsLog statsLog = Platform.getStatsLog(); if (statsLog != null) { - statsLog.countTlsHandshake(true, activeSession.getProtocol(), - activeSession.getCipherSuite(), + statsLog.countTlsHandshake( + true, activeSession.getProtocol(), activeSession.getCipherSuite(), Platform.getMillisSinceBoot() - handshakeStartedMillis); } handshakeStartedMillis = 0; @@ -1215,7 +1220,8 @@ private void transitionTo(int newState) { // Handshake was in progress so must have failed. StatsLog statsLog = Platform.getStatsLog(); if (statsLog != null) { - statsLog.countTlsHandshake(false, "TLS_PROTO_FAILED", "TLS_CIPHER_FAILED", + statsLog.countTlsHandshake( + false, "TLS_PROTO_FAILED", "TLS_CIPHER_FAILED", Platform.getMillisSinceBoot() - handshakeStartedMillis); } handshakeStartedMillis = 0; diff --git a/common/src/main/java/org/conscrypt/ConscryptX509TrustManager.java b/common/src/main/java/org/conscrypt/ConscryptX509TrustManager.java new file mode 100644 index 000000000..f3586d6f9 --- /dev/null +++ b/common/src/main/java/org/conscrypt/ConscryptX509TrustManager.java @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2025 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 java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.util.List; + +/** + * Interface for TrustManager methods implemented in Conscrypt but not part of + * the standard X509TrustManager or X509ExtendedTrustManager. + * + * These methods can be called by the Android framework. Extend + * X509TrustManagerExtensions if these need to be visible to apps. + */ +@Internal +public interface ConscryptX509TrustManager { + /** + * Verifies the given certificate chain. + * + *

See {@link X509TrustManager#checkServerTrusted(X509Certificate[], String)} for a + * description of the chain and authType parameters. The final parameter, host, should be the + * hostname of the server.

+ * + * @throws CertificateException if the chain does not verify correctly. + * @return the properly ordered chain used for verification as a list of X509Certificates. + */ + public List checkServerTrusted(X509Certificate[] chain, String authType, + String hostname) throws CertificateException; + + /** + * Verifies the given certificate chain. + * + *

See {@link X509TrustManager#checkServerTrusted(X509Certificate[], String)} for a + * description of the chain and authType parameters. The final parameter, host, should be the + * hostname of the server. + * + *

ocspData and tlsSctData may be provided to verify any Signed Certificate Timestamp (SCT) + * attached to the connection. These are ASN.1 octet strings (SignedCertificateTimestampList) as + * described in RFC 6962, Section 3.3. Note that SCTs embedded in the certificate chain will + * automatically be processed. + * + * @throws CertificateException if the chain does not verify correctly. + * @return the properly ordered chain used for verification as a list of X509Certificates. + */ + public List checkServerTrusted(X509Certificate[] chain, byte[] ocspData, + byte[] tlsSctData, String authType, + String hostname) throws CertificateException; +} diff --git a/common/src/main/java/org/conscrypt/DomainEncryptionMode.java b/common/src/main/java/org/conscrypt/DomainEncryptionMode.java new file mode 100644 index 000000000..ab878a468 --- /dev/null +++ b/common/src/main/java/org/conscrypt/DomainEncryptionMode.java @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2025 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; + +@Internal enum DomainEncryptionMode { UNKNOWN, DISABLED, OPPORTUNISTIC, ENABLED, REQUIRED } diff --git a/common/src/main/java/org/conscrypt/EchOptions.java b/common/src/main/java/org/conscrypt/EchOptions.java new file mode 100644 index 000000000..3715a4819 --- /dev/null +++ b/common/src/main/java/org/conscrypt/EchOptions.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2025 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; + +@Internal +class EchOptions { + private final byte[] configList; + private final boolean enableGrease; + + EchOptions(byte[] configList, boolean enableGrease) { + this.configList = configList; + this.enableGrease = enableGrease; + } + + byte[] getConfigList() { + return configList; + } + + boolean isGreaseEnabled() { + return enableGrease; + } +} diff --git a/common/src/main/java/org/conscrypt/HpkeImpl.java b/common/src/main/java/org/conscrypt/HpkeImpl.java index ac50d1804..ff5b863be 100644 --- a/common/src/main/java/org/conscrypt/HpkeImpl.java +++ b/common/src/main/java/org/conscrypt/HpkeImpl.java @@ -50,7 +50,7 @@ public HpkeImpl(HpkeSuite hpkeSuite) { @Override public void engineInitSender(PublicKey recipientKey, byte[] info, PrivateKey senderKey, - byte[] psk, byte[] psk_id) throws InvalidKeyException { + byte[] psk, byte[] psk_id) throws InvalidKeyException { checkNotInitialised(); checkArgumentsForBaseModeOnly(senderKey, psk, psk_id); if (recipientKey == null) { @@ -65,8 +65,8 @@ public void engineInitSender(PublicKey recipientKey, byte[] info, PrivateKey sen @Override public void engineInitSenderForTesting(PublicKey recipientKey, byte[] info, - PrivateKey senderKey, byte[] psk, byte[] psk_id, byte[] sKe) - throws InvalidKeyException { + PrivateKey senderKey, byte[] psk, byte[] psk_id, + byte[] sKe) throws InvalidKeyException { checkNotInitialised(); Objects.requireNonNull(sKe); checkArgumentsForBaseModeOnly(senderKey, psk, psk_id); @@ -85,7 +85,8 @@ public void engineInitSenderForTesting(PublicKey recipientKey, byte[] info, @Override public void engineInitRecipient(byte[] encapsulated, PrivateKey recipientKey, byte[] info, - PublicKey senderKey, byte[] psk, byte[] psk_id) throws InvalidKeyException { + PublicKey senderKey, byte[] psk, byte[] psk_id) + throws InvalidKeyException { checkNotInitialised(); checkArgumentsForBaseModeOnly(senderKey, psk, psk_id); Preconditions.checkNotNull(encapsulated, "null encapsulated data"); @@ -125,8 +126,8 @@ public byte[] engineExport(int length, byte[] exporterContext) { checkInitialised(); long maxLength = hpkeSuite.getKdf().maxExportLength(); if (length < 0 || length > maxLength) { - throw new IllegalArgumentException( - "Export length must be between 0 and " + maxLength + ", but was " + length); + throw new IllegalArgumentException("Export length must be between 0 and " + maxLength + + ", but was " + length); } return NativeCrypto.EVP_HPKE_CTX_export(ctx, exporterContext, length); } @@ -182,8 +183,8 @@ private HpkeX25519Impl(HpkeSuite hpkeSuite) { @Override byte[] getRecipientPublicKeyBytes(PublicKey recipientKey) throws InvalidKeyException { if (!(recipientKey instanceof OpenSSLX25519PublicKey)) { - throw new InvalidKeyException( - "Unsupported recipient key class: " + recipientKey.getClass()); + throw new InvalidKeyException("Unsupported recipient key class: " + + recipientKey.getClass()); } return ((OpenSSLX25519PublicKey) recipientKey).getU(); } @@ -191,8 +192,8 @@ byte[] getRecipientPublicKeyBytes(PublicKey recipientKey) throws InvalidKeyExcep @Override byte[] getPrivateRecipientKeyBytes(PrivateKey recipientKey) throws InvalidKeyException { if (!(recipientKey instanceof OpenSSLX25519PrivateKey)) { - throw new InvalidKeyException( - "Unsupported recipient private key class: " + recipientKey.getClass()); + throw new InvalidKeyException("Unsupported recipient private key class: " + + recipientKey.getClass()); } return ((OpenSSLX25519PrivateKey) recipientKey).getU(); } @@ -215,13 +216,11 @@ public X25519_AES_256() { /** Implementation of X25519/HKDF_SHA256/CHACHA20_POLY1305. */ public static class X25519_CHACHA20 extends HpkeX25519Impl { public X25519_CHACHA20() { - super(new HpkeSuite( - KEM_DHKEM_X25519_HKDF_SHA256, KDF_HKDF_SHA256, AEAD_CHACHA20POLY1305)); + super(new HpkeSuite(KEM_DHKEM_X25519_HKDF_SHA256, KDF_HKDF_SHA256, + AEAD_CHACHA20POLY1305)); } } - private static final OpenSslXwingKeyFactory xwingKeyFactory = new OpenSslXwingKeyFactory(); - private static class HpkeXwingImpl extends HpkeImpl { HpkeXwingImpl(HpkeSuite hpkeSuite) { super(hpkeSuite); @@ -229,20 +228,20 @@ private static class HpkeXwingImpl extends HpkeImpl { @Override byte[] getRecipientPublicKeyBytes(PublicKey publicKey) throws InvalidKeyException { - Key translatedKey = xwingKeyFactory.engineTranslateKey(publicKey); - if (!(translatedKey instanceof OpenSslXwingPublicKey)) { - throw new IllegalStateException("Unexpected public key class"); + if (!(publicKey instanceof OpenSslXwingPublicKey)) { + throw new InvalidKeyException("Unsupported recipient key class: " + + publicKey.getClass()); } - return ((OpenSslXwingPublicKey) translatedKey).getRaw(); + return ((OpenSslXwingPublicKey) publicKey).getRaw(); } @Override byte[] getPrivateRecipientKeyBytes(PrivateKey recipientKey) throws InvalidKeyException { - Key translatedKey = xwingKeyFactory.engineTranslateKey(recipientKey); - if (!(translatedKey instanceof OpenSslXwingPrivateKey)) { - throw new IllegalStateException("Unexpected private key class"); + if (!(recipientKey instanceof OpenSslXwingPrivateKey)) { + throw new InvalidKeyException("Unsupported recipient private key class: " + + recipientKey.getClass()); } - return ((OpenSslXwingPrivateKey) translatedKey).getRaw(); + return ((OpenSslXwingPrivateKey) recipientKey).getRaw(); } } diff --git a/common/src/main/java/org/conscrypt/Java8EngineWrapper.java b/common/src/main/java/org/conscrypt/Java8EngineWrapper.java index 5cf135d4f..c6a0b7d38 100644 --- a/common/src/main/java/org/conscrypt/Java8EngineWrapper.java +++ b/common/src/main/java/org/conscrypt/Java8EngineWrapper.java @@ -22,6 +22,7 @@ import java.security.PrivateKey; import java.util.List; import java.util.function.BiFunction; + import javax.net.ssl.SSLEngine; import javax.net.ssl.SSLEngineResult; import javax.net.ssl.SSLEngineResult.HandshakeStatus; @@ -254,7 +255,7 @@ SSLEngineResult unwrap(ByteBuffer[] srcs, ByteBuffer[] dsts) throws SSLException @Override SSLEngineResult unwrap(ByteBuffer[] srcs, int srcsOffset, int srcsLength, ByteBuffer[] dsts, - int dstsOffset, int dstsLength) throws SSLException { + int dstsOffset, int dstsLength) throws SSLException { return delegate.unwrap(srcs, srcsOffset, srcsLength, dsts, dstsOffset, dstsLength); } @@ -274,6 +275,11 @@ void setUseSessionTickets(boolean useSessionTickets) { delegate.setUseSessionTickets(useSessionTickets); } + @Override + void setEchConfigList(byte[] echConfigList) { + delegate.setEchConfigList(echConfigList); + } + @Override void setApplicationProtocols(String[] protocols) { delegate.setApplicationProtocols(protocols); diff --git a/common/src/main/java/org/conscrypt/NativeCrypto.java b/common/src/main/java/org/conscrypt/NativeCrypto.java index 9269ba708..d4fe34101 100644 --- a/common/src/main/java/org/conscrypt/NativeCrypto.java +++ b/common/src/main/java/org/conscrypt/NativeCrypto.java @@ -18,6 +18,8 @@ import org.conscrypt.OpenSSLX509CertificateFactory.ParsingException; +// android-add: import dalvik.annotation.optimization.CriticalNative; +// android-add: import dalvik.annotation.optimization.FastNative; import java.io.FileDescriptor; import java.io.IOException; import java.io.OutputStream; @@ -61,6 +63,7 @@ public final class NativeCrypto { // --- OpenSSL library initialization -------------------------------------- private static final UnsatisfiedLinkError loadError; + static { UnsatisfiedLinkError error = null; try { @@ -75,8 +78,8 @@ public final class NativeCrypto { } /** - * Checks to see whether or not the native library was successfully loaded. If not, throws - * the {@link UnsatisfiedLinkError} that was encountered while attempting to load the library. + * Checks to see whether or not the native library was successfully loaded. If not, throws the + * {@link UnsatisfiedLinkError} that was encountered while attempting to load the library. */ static void checkAvailability() { if (loadError != null) { @@ -86,23 +89,32 @@ static void checkAvailability() { // --- DSA/RSA public/private key handling functions ----------------------- + // android-add: @FastNative static native long EVP_PKEY_new_RSA(byte[] n, byte[] e, byte[] d, byte[] p, byte[] q, - byte[] dmp1, byte[] dmq1, byte[] iqmp); + byte[] dmp1, byte[] dmq1, byte[] iqmp); + // android-add: @FastNative static native int EVP_PKEY_type(NativeRef.EVP_PKEY pkey); + // android-add: @FastNative static native String EVP_PKEY_print_public(NativeRef.EVP_PKEY pkeyRef); + // android-add: @FastNative static native String EVP_PKEY_print_params(NativeRef.EVP_PKEY pkeyRef); + // android-add: @FastNative static native void EVP_PKEY_free(long pkey); + // android-add: @FastNative static native int EVP_PKEY_cmp(NativeRef.EVP_PKEY pkey1, NativeRef.EVP_PKEY pkey2); + // android-add: @FastNative static native byte[] EVP_marshal_private_key(NativeRef.EVP_PKEY pkey); + // android-add: @FastNative static native long EVP_parse_private_key(byte[] data) throws ParsingException; + // android-add: @FastNative static native byte[] EVP_marshal_public_key(NativeRef.EVP_PKEY pkey); static native long EVP_PKEY_from_private_key_info(byte[] data, int[] algs) @@ -123,43 +135,58 @@ static native long EVP_PKEY_from_subject_public_key_info(byte[] data, int[] algs static native byte[] EVP_PKEY_get_private_seed(NativeRef.EVP_PKEY pkey); + // android-add: @FastNative static native byte[] EVP_raw_X25519_private_key(byte[] data) throws ParsingException, InvalidKeyException; + // android-add: @FastNative static native long EVP_parse_public_key(byte[] data) throws ParsingException; + // android-add: @FastNative static native long PEM_read_bio_PUBKEY(long bioCtx); + // android-add: @FastNative static native long PEM_read_bio_PrivateKey(long bioCtx); + // android-add: @FastNative static native long getRSAPrivateKeyWrapper(PrivateKey key, byte[] modulus); + // android-add: @FastNative static native long getECPrivateKeyWrapper(PrivateKey key, NativeRef.EC_GROUP ecGroupRef); static native long RSA_generate_key_ex(int modulusBits, byte[] publicExponent); + // android-add: @FastNative static native int RSA_size(NativeRef.EVP_PKEY pkey); - static native int RSA_private_encrypt( - int flen, byte[] from, byte[] to, NativeRef.EVP_PKEY pkey, int padding); + // android-add: @FastNative + static native int RSA_private_encrypt(int flen, byte[] from, byte[] to, NativeRef.EVP_PKEY pkey, + int padding); + // android-add: @FastNative static native int RSA_public_decrypt(int flen, byte[] from, byte[] to, NativeRef.EVP_PKEY pkey, - int padding) throws BadPaddingException, SignatureException; + int padding) + throws BadPaddingException, SignatureException; - static native int RSA_public_encrypt( - int flen, byte[] from, byte[] to, NativeRef.EVP_PKEY pkey, int padding); + // android-add: @FastNative + static native int RSA_public_encrypt(int flen, byte[] from, byte[] to, NativeRef.EVP_PKEY pkey, + int padding); + // android-add: @FastNative static native int RSA_private_decrypt(int flen, byte[] from, byte[] to, NativeRef.EVP_PKEY pkey, - int padding) throws BadPaddingException, SignatureException; + int padding) + throws BadPaddingException, SignatureException; /* * Returns array of {n, e} */ + // android-add: @FastNative static native byte[][] get_RSA_public_params(NativeRef.EVP_PKEY rsa); /* * Returns array of {n, e, d, p, q, dmp1, dmq1, iqmp} */ + // android-add: @FastNative static native byte[][] get_RSA_private_params(NativeRef.EVP_PKEY rsa); // --- ChaCha20 ----------------------- @@ -167,88 +194,122 @@ static native int RSA_private_decrypt(int flen, byte[] from, byte[] to, NativeRe /* * Returns the encrypted or decrypted version of the data. */ + // android-add: @FastNative static native void chacha20_encrypt_decrypt(byte[] in, int inOffset, byte[] out, int outOffset, - int length, byte[] key, byte[] nonce, int blockCounter); + int length, byte[] key, byte[] nonce, + int blockCounter); // --- EC functions -------------------------- - static native long EVP_PKEY_new_EC_KEY( - NativeRef.EC_GROUP groupRef, NativeRef.EC_POINT pubkeyRef, byte[] privkey); + // android-add: @FastNative + static native long EVP_PKEY_new_EC_KEY(NativeRef.EC_GROUP groupRef, + NativeRef.EC_POINT pubkeyRef, byte[] privkey); + // android-add: @FastNative static native long EC_GROUP_new_by_curve_name(String curveName); - static native long EC_GROUP_new_arbitrary( - byte[] p, byte[] a, byte[] b, byte[] x, byte[] y, byte[] order, int cofactor); + // android-add: @FastNative + static native long EC_GROUP_new_arbitrary(byte[] p, byte[] a, byte[] b, byte[] x, byte[] y, + byte[] order, int cofactor); + // android-add: @FastNative static native String EC_GROUP_get_curve_name(NativeRef.EC_GROUP groupRef); + // android-add: @FastNative static native byte[][] EC_GROUP_get_curve(NativeRef.EC_GROUP groupRef); + // android-add: @FastNative static native void EC_GROUP_clear_free(long groupRef); + // android-add: @FastNative static native long EC_GROUP_get_generator(NativeRef.EC_GROUP groupRef); + // android-add: @FastNative static native byte[] EC_GROUP_get_order(NativeRef.EC_GROUP groupRef); + // android-add: @FastNative static native int EC_GROUP_get_degree(NativeRef.EC_GROUP groupRef); + // android-add: @FastNative static native byte[] EC_GROUP_get_cofactor(NativeRef.EC_GROUP groupRef); + // android-add: @FastNative static native long EC_POINT_new(NativeRef.EC_GROUP groupRef); + // android-add: @FastNative static native void EC_POINT_clear_free(long pointRef); - static native byte[][] EC_POINT_get_affine_coordinates( - NativeRef.EC_GROUP groupRef, NativeRef.EC_POINT pointRef); + // android-add: @FastNative + static native byte[][] EC_POINT_get_affine_coordinates(NativeRef.EC_GROUP groupRef, + NativeRef.EC_POINT pointRef); - static native void EC_POINT_set_affine_coordinates( - NativeRef.EC_GROUP groupRef, NativeRef.EC_POINT pointRef, byte[] x, byte[] y); + // android-add: @FastNative + static native void EC_POINT_set_affine_coordinates(NativeRef.EC_GROUP groupRef, + NativeRef.EC_POINT pointRef, byte[] x, + byte[] y); static native long EC_KEY_generate_key(NativeRef.EC_GROUP groupRef); + // android-add: @FastNative static native long EC_KEY_get1_group(NativeRef.EVP_PKEY pkeyRef); + // android-add: @FastNative static native byte[] EC_KEY_get_private_key(NativeRef.EVP_PKEY keyRef); + // android-add: @FastNative static native long EC_KEY_get_public_key(NativeRef.EVP_PKEY keyRef); + // android-add: @FastNative static native byte[] EC_KEY_marshal_curve_name(NativeRef.EC_GROUP groupRef) throws IOException; + // android-add: @FastNative static native long EC_KEY_parse_curve_name(byte[] encoded) throws IOException; + // android-add: @FastNative static native int ECDH_compute_key(byte[] out, int outOffset, NativeRef.EVP_PKEY publicKeyRef, - NativeRef.EVP_PKEY privateKeyRef) throws InvalidKeyException, IndexOutOfBoundsException; + NativeRef.EVP_PKEY privateKeyRef) + throws InvalidKeyException, IndexOutOfBoundsException; + // android-add: @FastNative static native int ECDSA_size(NativeRef.EVP_PKEY pkey); + // android-add: @FastNative static native int ECDSA_sign(byte[] data, int dataLen, byte[] sig, NativeRef.EVP_PKEY pkey); + // android-add: @FastNative static native int ECDSA_verify(byte[] data, int dataLen, byte[] sig, NativeRef.EVP_PKEY pkey); // --- MLDSA65 -------------------------------------------------------------- + // android-add: @FastNative static native byte[] MLDSA65_public_key_from_seed(byte[] privateKeySeed); // --- MLDSA87 -------------------------------------------------------------- + // android-add: @FastNative static native byte[] MLDSA87_public_key_from_seed(byte[] privateKeySeed); // --- SLHDSA_SHA2_128S -------------------------------------------------------------- static native void SLHDSA_SHA2_128S_generate_key(byte[] outPublicKey, byte[] outPrivateKey); + // android-add: @FastNative static native byte[] SLHDSA_SHA2_128S_sign(byte[] data, int dataLen, byte[] privateKey); - static native int SLHDSA_SHA2_128S_verify( - byte[] data, int dataLen, byte[] sig, byte[] publicKey); + // android-add: @FastNative + static native int SLHDSA_SHA2_128S_verify(byte[] data, int dataLen, byte[] sig, + byte[] publicKey); // --- Curve25519 -------------- + // android-add: @FastNative static native boolean X25519(byte[] out, byte[] privateKey, byte[] publicKey) throws InvalidKeyException; + // android-add: @FastNative static native void X25519_keypair(byte[] outPublicKey, byte[] outPrivateKey); + // android-add: @FastNative static native void ED25519_keypair(byte[] outPublicKey, byte[] outPrivateKey); // --- X-Wing -------------- @@ -258,224 +319,311 @@ static native boolean X25519(byte[] out, byte[] privateKey, byte[] publicKey) // --- Message digest functions -------------- // These return const references + // android-add: @FastNative static native long EVP_get_digestbyname(String name); + // android-add: @FastNative static native int EVP_MD_size(long evp_md_const); // --- Message digest context functions -------------- + // android-add: @FastNative static native long EVP_MD_CTX_create(); + // android-add: @FastNative static native void EVP_MD_CTX_cleanup(NativeRef.EVP_MD_CTX ctx); + // android-add: @FastNative static native void EVP_MD_CTX_destroy(long ctx); - static native int EVP_MD_CTX_copy_ex( - NativeRef.EVP_MD_CTX dst_ctx, NativeRef.EVP_MD_CTX src_ctx); + // android-add: @FastNative + static native int EVP_MD_CTX_copy_ex(NativeRef.EVP_MD_CTX dst_ctx, + NativeRef.EVP_MD_CTX src_ctx); // --- Digest handling functions ------------------------------------------- + // android-add: @FastNative static native int EVP_DigestInit_ex(NativeRef.EVP_MD_CTX ctx, long evp_md); - static native void EVP_DigestUpdate( - NativeRef.EVP_MD_CTX ctx, byte[] buffer, int offset, int length); + // android-add: @FastNative + static native void EVP_DigestUpdate(NativeRef.EVP_MD_CTX ctx, byte[] buffer, int offset, + int length); + // android-add: @FastNative static native void EVP_DigestUpdateDirect(NativeRef.EVP_MD_CTX ctx, long ptr, int length); + // android-add: @FastNative static native int EVP_DigestFinal_ex(NativeRef.EVP_MD_CTX ctx, byte[] hash, int offset); // --- Signature handling functions ---------------------------------------- - static native long EVP_DigestSignInit( - NativeRef.EVP_MD_CTX ctx, long evpMdRef, NativeRef.EVP_PKEY key); + // android-add: @FastNative + static native long EVP_DigestSignInit(NativeRef.EVP_MD_CTX ctx, long evpMdRef, + NativeRef.EVP_PKEY key); - static native long EVP_DigestVerifyInit( - NativeRef.EVP_MD_CTX ctx, long evpMdRef, NativeRef.EVP_PKEY key); + // android-add: @FastNative + static native long EVP_DigestVerifyInit(NativeRef.EVP_MD_CTX ctx, long evpMdRef, + NativeRef.EVP_PKEY key); - static native void EVP_DigestSignUpdate( - NativeRef.EVP_MD_CTX ctx, byte[] buffer, int offset, int length); + // android-add: @FastNative + static native void EVP_DigestSignUpdate(NativeRef.EVP_MD_CTX ctx, byte[] buffer, int offset, + int length); + // android-add: @FastNative static native void EVP_DigestSignUpdateDirect(NativeRef.EVP_MD_CTX ctx, long ptr, int length); - static native void EVP_DigestVerifyUpdate( - NativeRef.EVP_MD_CTX ctx, byte[] buffer, int offset, int length); + // android-add: @FastNative + static native void EVP_DigestVerifyUpdate(NativeRef.EVP_MD_CTX ctx, byte[] buffer, int offset, + int length); + // android-add: @FastNative static native void EVP_DigestVerifyUpdateDirect(NativeRef.EVP_MD_CTX ctx, long ptr, int length); + // android-add: @FastNative static native byte[] EVP_DigestSignFinal(NativeRef.EVP_MD_CTX ctx); + // android-add: @FastNative static native boolean EVP_DigestVerifyFinal(NativeRef.EVP_MD_CTX ctx, byte[] signature, - int offset, int length) throws IndexOutOfBoundsException; + int offset, int length) + throws IndexOutOfBoundsException; - static native byte[] EVP_DigestSign( - NativeRef.EVP_MD_CTX ctx, byte[] buffer, int offset, int length); + // android-add: @FastNative + static native byte[] EVP_DigestSign(NativeRef.EVP_MD_CTX ctx, byte[] buffer, int offset, + int length); + // android-add: @FastNative static native boolean EVP_DigestVerify(NativeRef.EVP_MD_CTX ctx, byte[] sigBuffer, - int sigOffset, int sigLen, byte[] dataBuffer, int dataOffset, int dataLen); + int sigOffset, int sigLen, byte[] dataBuffer, + int dataOffset, int dataLen); + // android-add: @FastNative static native long EVP_PKEY_encrypt_init(NativeRef.EVP_PKEY pkey) throws InvalidKeyException; + // android-add: @FastNative static native int EVP_PKEY_encrypt(NativeRef.EVP_PKEY_CTX ctx, byte[] out, int outOffset, - byte[] input, int inOffset, int inLength) + byte[] input, int inOffset, int inLength) throws IndexOutOfBoundsException, BadPaddingException; + // android-add: @FastNative static native long EVP_PKEY_decrypt_init(NativeRef.EVP_PKEY pkey) throws InvalidKeyException; + // android-add: @FastNative static native int EVP_PKEY_decrypt(NativeRef.EVP_PKEY_CTX ctx, byte[] out, int outOffset, - byte[] input, int inOffset, int inLength) + byte[] input, int inOffset, int inLength) throws IndexOutOfBoundsException, BadPaddingException; + // android-add: @FastNative static native void EVP_PKEY_CTX_free(long pkeyCtx); + // android-add: @FastNative static native void EVP_PKEY_CTX_set_rsa_padding(long ctx, int pad) throws InvalidAlgorithmParameterException; + // android-add: @FastNative static native void EVP_PKEY_CTX_set_rsa_pss_saltlen(long ctx, int len) throws InvalidAlgorithmParameterException; + // android-add: @FastNative static native void EVP_PKEY_CTX_set_rsa_mgf1_md(long ctx, long evpMdRef) throws InvalidAlgorithmParameterException; + // android-add: @FastNative static native void EVP_PKEY_CTX_set_rsa_oaep_md(long ctx, long evpMdRef) throws InvalidAlgorithmParameterException; + // android-add: @FastNative static native void EVP_PKEY_CTX_set_rsa_oaep_label(long ctx, byte[] label) throws InvalidAlgorithmParameterException; // --- Block ciphers ------------------------------------------------------- // These return const references + // android-add: @FastNative static native long EVP_get_cipherbyname(String string); + // android-add: @FastNative static native void EVP_CipherInit_ex(NativeRef.EVP_CIPHER_CTX ctx, long evpCipher, byte[] key, - byte[] iv, boolean encrypting); + byte[] iv, boolean encrypting); + // android-add: @FastNative static native int EVP_CipherUpdate(NativeRef.EVP_CIPHER_CTX ctx, byte[] out, int outOffset, - byte[] in, int inOffset, int inLength) throws IndexOutOfBoundsException; + byte[] in, int inOffset, int inLength) + throws IndexOutOfBoundsException; + // android-add: @FastNative static native int EVP_CipherFinal_ex(NativeRef.EVP_CIPHER_CTX ctx, byte[] out, int outOffset) throws BadPaddingException, IllegalBlockSizeException; + // android-add: @FastNative static native int EVP_CIPHER_iv_length(long evpCipher); + // android-add: @FastNative static native long EVP_CIPHER_CTX_new(); + // android-add: @FastNative static native int EVP_CIPHER_CTX_block_size(NativeRef.EVP_CIPHER_CTX ctx); + // android-add: @FastNative static native int get_EVP_CIPHER_CTX_buf_len(NativeRef.EVP_CIPHER_CTX ctx); + // android-add: @FastNative static native boolean get_EVP_CIPHER_CTX_final_used(NativeRef.EVP_CIPHER_CTX ctx); - static native void EVP_CIPHER_CTX_set_padding( - NativeRef.EVP_CIPHER_CTX ctx, boolean enablePadding); + // android-add: @FastNative + static native void EVP_CIPHER_CTX_set_padding(NativeRef.EVP_CIPHER_CTX ctx, + boolean enablePadding); + // android-add: @FastNative static native void EVP_CIPHER_CTX_set_key_length(NativeRef.EVP_CIPHER_CTX ctx, int keyBitSize); + // android-add: @FastNative static native void EVP_CIPHER_CTX_free(long ctx); // --- AEAD ---------------------------------------------------------------- + // android-add: @FastNative static native long EVP_aead_aes_128_gcm(); + // android-add: @FastNative static native long EVP_aead_aes_256_gcm(); + // android-add: @FastNative static native long EVP_aead_chacha20_poly1305(); + // android-add: @FastNative static native long EVP_aead_aes_128_gcm_siv(); + // android-add: @FastNative static native long EVP_aead_aes_256_gcm_siv(); + // android-add: @FastNative static native int EVP_AEAD_max_overhead(long evpAead); + // android-add: @FastNative static native int EVP_AEAD_nonce_length(long evpAead); + // android-add: @FastNative static native int EVP_AEAD_CTX_seal(long evpAead, byte[] key, int tagLengthInBytes, byte[] out, - int outOffset, byte[] nonce, byte[] in, int inOffset, int inLength, byte[] ad) + int outOffset, byte[] nonce, byte[] in, int inOffset, + int inLength, byte[] ad) throws ShortBufferException, BadPaddingException; + // android-add: @FastNative static native int EVP_AEAD_CTX_seal_buf(long evpAead, byte[] key, int tagLengthInBytes, - ByteBuffer out, byte[] nonce, ByteBuffer input, byte[] ad) + ByteBuffer out, byte[] nonce, ByteBuffer input, + byte[] ad) throws ShortBufferException, BadPaddingException; + // android-add: @FastNative static native int EVP_AEAD_CTX_open(long evpAead, byte[] key, int tagLengthInBytes, byte[] out, - int outOffset, byte[] nonce, byte[] in, int inOffset, int inLength, byte[] ad) + int outOffset, byte[] nonce, byte[] in, int inOffset, + int inLength, byte[] ad) throws ShortBufferException, BadPaddingException; + // android-add: @FastNative static native int EVP_AEAD_CTX_open_buf(long evpAead, byte[] key, int tagLengthInBytes, - ByteBuffer out, byte[] nonce, ByteBuffer input, byte[] ad) + ByteBuffer out, byte[] nonce, ByteBuffer input, + byte[] ad) throws ShortBufferException, BadPaddingException; // --- CMAC functions ------------------------------------------------------ + // android-add: @FastNative static native long CMAC_CTX_new(); + // android-add: @FastNative static native void CMAC_CTX_free(long ctx); + // android-add: @FastNative static native void CMAC_Init(NativeRef.CMAC_CTX ctx, byte[] key); + // android-add: @FastNative static native void CMAC_Update(NativeRef.CMAC_CTX ctx, byte[] in, int inOffset, int inLength); + // android-add: @FastNative static native void CMAC_UpdateDirect(NativeRef.CMAC_CTX ctx, long inPtr, int inLength); + // android-add: @FastNative static native byte[] CMAC_Final(NativeRef.CMAC_CTX ctx); + // android-add: @FastNative static native void CMAC_Reset(NativeRef.CMAC_CTX ctx); // --- HMAC functions ------------------------------------------------------ + // android-add: @FastNative static native long HMAC_CTX_new(); + // android-add: @FastNative static native void HMAC_CTX_free(long ctx); + // android-add: @FastNative static native void HMAC_Init_ex(NativeRef.HMAC_CTX ctx, byte[] key, long evp_md); + // android-add: @FastNative static native void HMAC_Update(NativeRef.HMAC_CTX ctx, byte[] in, int inOffset, int inLength); + // android-add: @FastNative static native void HMAC_UpdateDirect(NativeRef.HMAC_CTX ctx, long inPtr, int inLength); + // android-add: @FastNative static native byte[] HMAC_Final(NativeRef.HMAC_CTX ctx); + // android-add: @FastNative static native void HMAC_Reset(NativeRef.HMAC_CTX ctx); // --- HPKE functions ------------------------------------------------------ - static native byte[] EVP_HPKE_CTX_export( - NativeRef.EVP_HPKE_CTX ctx, byte[] exporterCtx, int length); + // android-add: @FastNative + static native byte[] EVP_HPKE_CTX_export(NativeRef.EVP_HPKE_CTX ctx, byte[] exporterCtx, + int length); static native void EVP_HPKE_CTX_free(long ctx); - static native byte[] EVP_HPKE_CTX_open( - NativeRef.EVP_HPKE_CTX ctx, byte[] ciphertext, byte[] aad) throws BadPaddingException; + // android-add: @FastNative + static native byte[] EVP_HPKE_CTX_open(NativeRef.EVP_HPKE_CTX ctx, byte[] ciphertext, + byte[] aad) throws BadPaddingException; - static native byte[] EVP_HPKE_CTX_seal( - NativeRef.EVP_HPKE_CTX ctx, byte[] plaintext, byte[] aad); + // android-add: @FastNative + static native byte[] EVP_HPKE_CTX_seal(NativeRef.EVP_HPKE_CTX ctx, byte[] plaintext, + byte[] aad); - static native Object EVP_HPKE_CTX_setup_base_mode_recipient( - int kem, int kdf, int aead, byte[] privateKey, byte[] enc, byte[] info); + // android-add: @FastNative + static native Object EVP_HPKE_CTX_setup_base_mode_recipient(int kem, int kdf, int aead, + byte[] privateKey, byte[] enc, + byte[] info); - static Object EVP_HPKE_CTX_setup_base_mode_recipient( - HpkeSuite suite, byte[] privateKey, byte[] enc, byte[] info) { - return EVP_HPKE_CTX_setup_base_mode_recipient(suite.getKem().getId(), - suite.getKdf().getId(), suite.getAead().getId(), privateKey, enc, info); + static Object EVP_HPKE_CTX_setup_base_mode_recipient(HpkeSuite suite, byte[] privateKey, + byte[] enc, byte[] info) { + return EVP_HPKE_CTX_setup_base_mode_recipient( + suite.getKem().getId(), suite.getKdf().getId(), suite.getAead().getId(), privateKey, + enc, info); } - static native Object[] EVP_HPKE_CTX_setup_base_mode_sender( - int kem, int kdf, int aead, byte[] publicKey, byte[] info); + // android-add: @FastNative + static native Object[] EVP_HPKE_CTX_setup_base_mode_sender(int kem, int kdf, int aead, + byte[] publicKey, byte[] info); - static Object[] EVP_HPKE_CTX_setup_base_mode_sender( - HpkeSuite suite, byte[] publicKey, byte[] info) { + static Object[] EVP_HPKE_CTX_setup_base_mode_sender(HpkeSuite suite, byte[] publicKey, + byte[] info) { return EVP_HPKE_CTX_setup_base_mode_sender(suite.getKem().getId(), suite.getKdf().getId(), - suite.getAead().getId(), publicKey, info); + suite.getAead().getId(), publicKey, info); } + + // android-add: @FastNative static native Object[] EVP_HPKE_CTX_setup_base_mode_sender_with_seed_for_testing( int kem, int kdf, int aead, byte[] publicKey, byte[] info, byte[] seed); - static Object[] EVP_HPKE_CTX_setup_base_mode_sender_with_seed_for_testing( - HpkeSuite suite, byte[] publicKey, byte[] info, byte[] seed) { - return EVP_HPKE_CTX_setup_base_mode_sender_with_seed_for_testing(suite.getKem().getId(), - suite.getKdf().getId(), suite.getAead().getId(), publicKey, info, seed); + static Object[] EVP_HPKE_CTX_setup_base_mode_sender_with_seed_for_testing(HpkeSuite suite, + byte[] publicKey, + byte[] info, + byte[] seed) { + return EVP_HPKE_CTX_setup_base_mode_sender_with_seed_for_testing( + suite.getKem().getId(), suite.getKdf().getId(), suite.getAead().getId(), publicKey, + info, seed); } // --- RAND ---------------------------------------------------------------- + // android-add: @FastNative static native void RAND_bytes(byte[] output); // --- X509_NAME ----------------------------------------------------------- @@ -487,6 +635,7 @@ static int X509_NAME_hash(X500Principal principal) { public static int X509_NAME_hash_old(X500Principal principal) { return X509_NAME_hash(principal, "MD5"); } + private static int X509_NAME_hash(X500Principal principal, String algorithm) { try { byte[] digest = MessageDigest.getInstance(algorithm).digest(principal.getEncoded()); @@ -503,102 +652,130 @@ private static int X509_NAME_hash(X500Principal principal, String algorithm) { /** Used to request get_X509_GENERAL_NAME_stack get the "altname" field. */ static final int GN_STACK_SUBJECT_ALT_NAME = 1; - /** - * Used to request get_X509_GENERAL_NAME_stack get the issuerAlternativeName - * extension. - */ + /** Used to request get_X509_GENERAL_NAME_stack get the issuerAlternativeName extension. */ static final int GN_STACK_ISSUER_ALT_NAME = 2; - /** - * Used to request only non-critical types in get_X509*_ext_oids. - */ + /** Used to request only non-critical types in get_X509*_ext_oids. */ static final int EXTENSION_TYPE_NON_CRITICAL = 0; - /** - * Used to request only critical types in get_X509*_ext_oids. - */ + /** Used to request only critical types in get_X509*_ext_oids. */ static final int EXTENSION_TYPE_CRITICAL = 1; + // android-add: @FastNative static native long d2i_X509_bio(long bioCtx); + // android-add: @FastNative static native long d2i_X509(byte[] encoded) throws ParsingException; + // android-add: @FastNative static native long PEM_read_bio_X509(long bioCtx); + // android-add: @FastNative static native byte[] i2d_X509(long x509ctx, OpenSSLX509Certificate holder); /** Takes an X509 context not an X509_PUBKEY context. */ + // android-add: @FastNative static native byte[] i2d_X509_PUBKEY(long x509ctx, OpenSSLX509Certificate holder); + // android-add: @FastNative static native byte[] ASN1_seq_pack_X509(long[] x509CertRefs); + // android-add: @FastNative static native long[] ASN1_seq_unpack_X509_bio(long bioRef) throws ParsingException; static native void X509_free(long x509ctx, OpenSSLX509Certificate holder); + // android-add: @FastNative static native int X509_cmp(long x509ctx1, OpenSSLX509Certificate holder, long x509ctx2, - OpenSSLX509Certificate holder2); + OpenSSLX509Certificate holder2); - static native void X509_print_ex( - long bioCtx, long x509ctx, OpenSSLX509Certificate holder, long nmflag, long certflag); + // android-add: @FastNative + static native void X509_print_ex(long bioCtx, long x509ctx, OpenSSLX509Certificate holder, + long nmflag, long certflag); + // android-add: @FastNative static native byte[] X509_get_issuer_name(long x509ctx, OpenSSLX509Certificate holder); + // android-add: @FastNative static native byte[] X509_get_subject_name(long x509ctx, OpenSSLX509Certificate holder); + // android-add: @FastNative static native String get_X509_sig_alg_oid(long x509ctx, OpenSSLX509Certificate holder); + // android-add: @FastNative static native byte[] get_X509_sig_alg_parameter(long x509ctx, OpenSSLX509Certificate holder); + // android-add: @FastNative static native boolean[] get_X509_issuerUID(long x509ctx, OpenSSLX509Certificate holder); + // android-add: @FastNative static native boolean[] get_X509_subjectUID(long x509ctx, OpenSSLX509Certificate holder); + // android-add: @FastNative static native long X509_get_pubkey(long x509ctx, OpenSSLX509Certificate holder) throws NoSuchAlgorithmException, InvalidKeyException; + // android-add: @FastNative static native String get_X509_pubkey_oid(long x509ctx, OpenSSLX509Certificate holder); + // android-add: @FastNative static native byte[] X509_get_ext_oid(long x509ctx, OpenSSLX509Certificate holder, String oid); - static native String[] get_X509_ext_oids( - long x509ctx, OpenSSLX509Certificate holder, int critical); + // android-add: @FastNative + static native String[] get_X509_ext_oids(long x509ctx, OpenSSLX509Certificate holder, + int critical); + // android-add: @FastNative static native Object[][] get_X509_GENERAL_NAME_stack(long x509ctx, - OpenSSLX509Certificate holder, int type) throws CertificateParsingException; + OpenSSLX509Certificate holder, int type) + throws CertificateParsingException; + // android-add: @FastNative static native boolean[] get_X509_ex_kusage(long x509ctx, OpenSSLX509Certificate holder); + // android-add: @FastNative static native String[] get_X509_ex_xkusage(long x509ctx, OpenSSLX509Certificate holder); + // android-add: @FastNative static native int get_X509_ex_pathlen(long x509ctx, OpenSSLX509Certificate holder); + // android-add: @FastNative static native long X509_get_notBefore(long x509ctx, OpenSSLX509Certificate holder) throws ParsingException; + // android-add: @FastNative static native long X509_get_notAfter(long x509ctx, OpenSSLX509Certificate holder) throws ParsingException; + // android-add: @FastNative static native long X509_get_version(long x509ctx, OpenSSLX509Certificate holder); + // android-add: @FastNative static native byte[] X509_get_serialNumber(long x509ctx, OpenSSLX509Certificate holder); + // android-add: @FastNative static native void X509_verify(long x509ctx, OpenSSLX509Certificate holder, - NativeRef.EVP_PKEY pkeyCtx) throws BadPaddingException, IllegalBlockSizeException; + NativeRef.EVP_PKEY pkeyCtx) + throws BadPaddingException, IllegalBlockSizeException; + // android-add: @FastNative static native byte[] get_X509_tbs_cert(long x509ctx, OpenSSLX509Certificate holder); - static native byte[] get_X509_tbs_cert_without_ext( - long x509ctx, OpenSSLX509Certificate holder, String oid); + // android-add: @FastNative + static native byte[] get_X509_tbs_cert_without_ext(long x509ctx, OpenSSLX509Certificate holder, + String oid); + // android-add: @FastNative static native byte[] get_X509_signature(long x509ctx, OpenSSLX509Certificate holder); + // android-add: @FastNative static native int get_X509_ex_flags(long x509ctx, OpenSSLX509Certificate holder); // Used by Android platform TrustedCertificateStore. @SuppressWarnings("unused") - static native int X509_check_issued( - long ctx, OpenSSLX509Certificate holder, long ctx2, OpenSSLX509Certificate holder2); + // android-add: @FastNative + static native int X509_check_issued(long ctx, OpenSSLX509Certificate holder, long ctx2, + OpenSSLX509Certificate holder2); // --- PKCS7 --------------------------------------------------------------- @@ -609,110 +786,148 @@ static native int X509_check_issued( static final int PKCS7_CRLS = 2; /** Returns an array of X509 or X509_CRL pointers. */ + // android-add: @FastNative static native long[] d2i_PKCS7_bio(long bioCtx, int which) throws ParsingException; /** Returns an array of X509 or X509_CRL pointers. */ + // android-add: @FastNative static native byte[] i2d_PKCS7(long[] certs); /** Returns an array of X509 or X509_CRL pointers. */ + // android-add: @FastNative static native long[] PEM_read_bio_PKCS7(long bioCtx, int which); // --- X509_CRL ------------------------------------------------------------ + // android-add: @FastNative static native long d2i_X509_CRL_bio(long bioCtx); + // android-add: @FastNative static native long PEM_read_bio_X509_CRL(long bioCtx); + // android-add: @FastNative static native byte[] i2d_X509_CRL(long x509CrlCtx, OpenSSLX509CRL holder); + // android-add: @FastNative static native void X509_CRL_free(long x509CrlCtx, OpenSSLX509CRL holder); + // android-add: @FastNative static native void X509_CRL_print(long bioCtx, long x509CrlCtx, OpenSSLX509CRL holder); + // android-add: @FastNative static native String get_X509_CRL_sig_alg_oid(long x509CrlCtx, OpenSSLX509CRL holder); + // android-add: @FastNative static native byte[] get_X509_CRL_sig_alg_parameter(long x509CrlCtx, OpenSSLX509CRL holder); + // android-add: @FastNative static native byte[] X509_CRL_get_issuer_name(long x509CrlCtx, OpenSSLX509CRL holder); /** Returns X509_REVOKED reference that is not duplicated! */ - static native long X509_CRL_get0_by_cert( - long x509CrlCtx, OpenSSLX509CRL holder, long x509Ctx, OpenSSLX509Certificate holder2); + // android-add: @FastNative + static native long X509_CRL_get0_by_cert(long x509CrlCtx, OpenSSLX509CRL holder, long x509Ctx, + OpenSSLX509Certificate holder2); /** Returns X509_REVOKED reference that is not duplicated! */ - static native long X509_CRL_get0_by_serial( - long x509CrlCtx, OpenSSLX509CRL holder, byte[] serial); + // android-add: @FastNative + static native long X509_CRL_get0_by_serial(long x509CrlCtx, OpenSSLX509CRL holder, + byte[] serial); /** Returns an array of X509_REVOKED that are owned by the caller. */ + // android-add: @FastNative static native long[] X509_CRL_get_REVOKED(long x509CrlCtx, OpenSSLX509CRL holder); - static native String[] get_X509_CRL_ext_oids( - long x509Crlctx, OpenSSLX509CRL holder, int critical); + // android-add: @FastNative + static native String[] get_X509_CRL_ext_oids(long x509Crlctx, OpenSSLX509CRL holder, + int critical); + // android-add: @FastNative static native byte[] X509_CRL_get_ext_oid(long x509CrlCtx, OpenSSLX509CRL holder, String oid); + // android-add: @FastNative static native long X509_CRL_get_version(long x509CrlCtx, OpenSSLX509CRL holder); + // android-add: @FastNative static native long X509_CRL_get_ext(long x509CrlCtx, OpenSSLX509CRL holder, String oid); + // android-add: @FastNative static native byte[] get_X509_CRL_signature(long x509ctx, OpenSSLX509CRL holder); + // android-add: @FastNative static native void X509_CRL_verify(long x509CrlCtx, OpenSSLX509CRL holder, - NativeRef.EVP_PKEY pkeyCtx) throws BadPaddingException, SignatureException, - NoSuchAlgorithmException, InvalidKeyException, - IllegalBlockSizeException; + NativeRef.EVP_PKEY pkeyCtx) + throws BadPaddingException, SignatureException, NoSuchAlgorithmException, + InvalidKeyException, IllegalBlockSizeException; + // android-add: @FastNative static native byte[] get_X509_CRL_crl_enc(long x509CrlCtx, OpenSSLX509CRL holder); + // android-add: @FastNative static native long X509_CRL_get_lastUpdate(long x509CrlCtx, OpenSSLX509CRL holder) throws ParsingException; + // android-add: @FastNative static native long X509_CRL_get_nextUpdate(long x509CrlCtx, OpenSSLX509CRL holder) throws ParsingException; // --- X509_REVOKED -------------------------------------------------------- + // android-add: @FastNative static native long X509_REVOKED_dup(long x509RevokedCtx); + // android-add: @FastNative static native byte[] i2d_X509_REVOKED(long x509RevokedCtx, OpenSSLX509CRLEntry holder); - static native String[] get_X509_REVOKED_ext_oids( - long x509ctx, int critical, OpenSSLX509CRLEntry holder); + // android-add: @FastNative + static native String[] get_X509_REVOKED_ext_oids(long x509ctx, int critical, + OpenSSLX509CRLEntry holder); - static native byte[] X509_REVOKED_get_ext_oid( - long x509RevokedCtx, String oid, OpenSSLX509CRLEntry holder); + // android-add: @FastNative + static native byte[] X509_REVOKED_get_ext_oid(long x509RevokedCtx, String oid, + OpenSSLX509CRLEntry holder); - static native byte[] X509_REVOKED_get_serialNumber( - long x509RevokedCtx, OpenSSLX509CRLEntry holder); + // android-add: @FastNative + static native byte[] X509_REVOKED_get_serialNumber(long x509RevokedCtx, + OpenSSLX509CRLEntry holder); - static native long X509_REVOKED_get_ext( - long x509RevokedCtx, String oid, OpenSSLX509CRLEntry holder); + // android-add: @FastNative + static native long X509_REVOKED_get_ext(long x509RevokedCtx, String oid, + OpenSSLX509CRLEntry holder); /** Returns ASN1_TIME reference. */ - static native long get_X509_REVOKED_revocationDate( - long x509RevokedCtx, OpenSSLX509CRLEntry holder); + // android-add: @FastNative + static native long get_X509_REVOKED_revocationDate(long x509RevokedCtx, + OpenSSLX509CRLEntry holder); - static native void X509_REVOKED_print( - long bioRef, long x509RevokedCtx, OpenSSLX509CRLEntry holder); + // android-add: @FastNative + static native void X509_REVOKED_print(long bioRef, long x509RevokedCtx, + OpenSSLX509CRLEntry holder); + // android-add: @FastNative static native void X509_REVOKED_free(long x509RevokedCtx, OpenSSLX509CRLEntry holder); // --- X509_EXTENSION ------------------------------------------------------ + // android-add: @FastNative static native int X509_supported_extension(long x509ExtensionRef); // --- SPAKE --------------------------------------------------------------- /** - * Sets the SPAKE credential for the given SSL context using a password. - * Used for both client and server. + * Sets the SPAKE credential for the given SSL context using a password. Used for both client + * and server. */ + // android-add: @FastNative static native void SSL_CTX_set_spake_credential(byte[] context, byte[] pw_array, - byte[] id_prover_array, byte[] id_verifier_array, boolean is_client, - int handshake_limit, long ssl_ctx, AbstractSessionContext holder) throws SSLException; + byte[] id_prover_array, + byte[] id_verifier_array, boolean is_client, + int handshake_limit, long ssl_ctx, + AbstractSessionContext holder) + throws SSLException; // --- ASN1_TIME ----------------------------------------------------------- + // android-add: @FastNative static native void ASN1_TIME_to_Calendar(long asn1TimeCtx, Calendar cal) throws ParsingException; @@ -720,144 +935,151 @@ static native void ASN1_TIME_to_Calendar(long asn1TimeCtx, Calendar cal) /** * Allocates and returns an opaque reference to an object that can be used with other - * asn1_read_* functions to read the ASN.1-encoded data in val. The returned object must - * be freed after use by calling asn1_read_free. + * asn1_read_* functions to read the ASN.1-encoded data in val. The returned object must be + * freed after use by calling asn1_read_free. */ + // android-add: @FastNative static native long asn1_read_init(byte[] val) throws IOException; /** * Allocates and returns an opaque reference to an object that can be used with other - * asn1_read_* functions to read the ASN.1 sequence pointed to by cbsRef. The returned - * object must be freed after use by calling asn1_read_free. + * asn1_read_* functions to read the ASN.1 sequence pointed to by cbsRef. The returned object + * must be freed after use by calling asn1_read_free. */ + // android-add: @FastNative static native long asn1_read_sequence(long cbsRef) throws IOException; /** - * Returns whether the next object in the given reference is explicitly tagged with the - * given tag number. + * Returns whether the next object in the given reference is explicitly tagged with the given + * tag number. */ + // android-add: @FastNative static native boolean asn1_read_next_tag_is(long cbsRef, int tag) throws IOException; /** - * Allocates and returns an opaque reference to an object that can be used with - * other asn1_read_* functions to read the ASN.1 data pointed to by cbsRef. The returned - * object must be freed after use by calling asn1_read_free. + * Allocates and returns an opaque reference to an object that can be used with other + * asn1_read_* functions to read the ASN.1 data pointed to by cbsRef. The returned object must + * be freed after use by calling asn1_read_free. */ + // android-add: @FastNative static native long asn1_read_tagged(long cbsRef) throws IOException; - /** - * Returns the contents of an ASN.1 octet string from the given reference. - */ + /** Returns the contents of an ASN.1 octet string from the given reference. */ + // android-add: @FastNative static native byte[] asn1_read_octetstring(long cbsRef) throws IOException; /** - * Returns an ASN.1 integer from the given reference. If the integer doesn't fit - * in a uint64, this method will throw an IOException. + * Returns an ASN.1 integer from the given reference. If the integer doesn't fit in a uint64, + * this method will throw an IOException. */ + // android-add: @FastNative static native long asn1_read_uint64(long cbsRef) throws IOException; - /** - * Consumes an ASN.1 NULL from the given reference. - */ + /** Consumes an ASN.1 NULL from the given reference. */ + // android-add: @FastNative static native void asn1_read_null(long cbsRef) throws IOException; /** * Returns an ASN.1 OID in dotted-decimal notation (eg, "1.3.14.3.2.26" for SHA-1) from the * given reference. */ + // android-add: @FastNative static native String asn1_read_oid(long cbsRef) throws IOException; - /** - * Returns whether or not the given reference has been read completely. - */ + /** Returns whether or not the given reference has been read completely. */ + // android-add: @FastNative static native boolean asn1_read_is_empty(long cbsRef); /** - * Frees any resources associated with the given reference. After calling, the reference - * must not be used again. This may be called with a zero reference, in which case nothing - * will be done. + * Frees any resources associated with the given reference. After calling, the reference must + * not be used again. This may be called with a zero reference, in which case nothing will be + * done. */ + // android-add: @FastNative static native void asn1_read_free(long cbsRef); /** * Allocates and returns an opaque reference to an object that can be used with other - * asn1_write_* functions to write ASN.1-encoded data. The returned object must be finalized - * after use by calling either asn1_write_finish or asn1_write_cleanup, and its resources - * must be freed by calling asn1_write_free. + * asn1_write_* functions to write ASN.1-encoded data. The returned object must be finalized + * after use by calling either asn1_write_finish or asn1_write_cleanup, and its resources must + * be freed by calling asn1_write_free. */ + // android-add: @FastNative static native long asn1_write_init() throws IOException; /** * Allocates and returns an opaque reference to an object that can be used with other - * asn1_write_* functions to write an ASN.1 sequence into the given reference. The returned - * reference may only be used until the next call on the parent reference. The returned - * object must be freed after use by calling asn1_write_free. + * asn1_write_* functions to write an ASN.1 sequence into the given reference. The returned + * reference may only be used until the next call on the parent reference. The returned object + * must be freed after use by calling asn1_write_free. */ + // android-add: @FastNative static native long asn1_write_sequence(long cbbRef) throws IOException; /** * Allocates and returns an opaque reference to an object that can be used with other - * asn1_write_* functions to write a explicitly-tagged ASN.1 object with the given tag - * into the given reference. The returned reference may only be used until the next - * call on the parent reference. The returned object must be freed after use by - * calling asn1_write_free. + * asn1_write_* functions to write a explicitly-tagged ASN.1 object with the given tag into the + * given reference. The returned reference may only be used until the next call on the parent + * reference. The returned object must be freed after use by calling asn1_write_free. */ + // android-add: @FastNative static native long asn1_write_tag(long cbbRef, int tag) throws IOException; - /** - * Writes the given data into the given reference as an ASN.1-encoded octet string. - */ + /** Writes the given data into the given reference as an ASN.1-encoded octet string. */ + // android-add: @FastNative static native void asn1_write_octetstring(long cbbRef, byte[] data) throws IOException; - /** - * Writes the given value into the given reference as an ASN.1-encoded integer. - */ + /** Writes the given value into the given reference as an ASN.1-encoded integer. */ + // android-add: @FastNative static native void asn1_write_uint64(long cbbRef, long value) throws IOException; - /** - * Writes a NULL value into the given reference. - */ + /** Writes a NULL value into the given reference. */ + // android-add: @FastNative static native void asn1_write_null(long cbbRef) throws IOException; - /** - * Writes the given OID (which must be in dotted-decimal notation) into the given reference. - */ + /** Writes the given OID (which must be in dotted-decimal notation) into the given reference. */ + // android-add: @FastNative static native void asn1_write_oid(long cbbRef, String oid) throws IOException; /** * Flushes the given reference, invalidating any child references and completing their - * operations. This must be called if the child references are to be freed before - * asn1_write_finish is called on the ultimate parent. The child references must still - * be freed. + * operations. This must be called if the child references are to be freed before + * asn1_write_finish is called on the ultimate parent. The child references must still be freed. */ + // android-add: @FastNative static native void asn1_write_flush(long cbbRef) throws IOException; /** - * Completes any in-progress operations and returns the ASN.1-encoded data. Either this - * or asn1_write_cleanup must be called on any reference returned from asn1_write_init - * before it is freed. + * Completes any in-progress operations and returns the ASN.1-encoded data. Either this or + * asn1_write_cleanup must be called on any reference returned from asn1_write_init before it is + * freed. */ + // android-add: @FastNative static native byte[] asn1_write_finish(long cbbRef) throws IOException; /** - * Cleans up intermediate state in the given reference. Either this or asn1_write_finish - * must be called on any reference returned from asn1_write_init before it is freed. + * Cleans up intermediate state in the given reference. Either this or asn1_write_finish must be + * called on any reference returned from asn1_write_init before it is freed. */ + // android-add: @FastNative static native void asn1_write_cleanup(long cbbRef); /** - * Frees resources associated with the given reference. After calling, the reference - * must not be used again. This may be called with a zero reference, in which case nothing - * will be done. + * Frees resources associated with the given reference. After calling, the reference must not be + * used again. This may be called with a zero reference, in which case nothing will be done. */ + // android-add: @FastNative static native void asn1_write_free(long cbbRef); // --- BIO stream creation ------------------------------------------------- + // android-add: @FastNative static native long create_BIO_InputStream(OpenSSLBIOInputStream is, boolean isFinite); + // android-add: @FastNative static native long create_BIO_OutputStream(OutputStream os); + // android-add: @FastNative static native void BIO_free_all(long bioRef); // --- SSL handling -------------------------------------------------------- @@ -887,23 +1109,18 @@ static native void ASN1_TIME_to_Calendar(long asn1TimeCtx, Calendar cal) new HashSet(Arrays.asList(SUPPORTED_TLS_1_3_CIPHER_SUITES)); /** - * TLS_EMPTY_RENEGOTIATION_INFO_SCSV is RFC 5746's renegotiation - * indication signaling cipher suite value. It is not a real - * cipher suite. It is just an indication in the default and - * supported cipher suite lists indicates that the implementation - * supports secure renegotiation. - *

- * In the RI, its presence means that the SCSV is sent in the - * cipher suite list to indicate secure renegotiation support and - * its absense means to send an empty TLS renegotiation info + * TLS_EMPTY_RENEGOTIATION_INFO_SCSV is RFC 5746's renegotiation indication signaling cipher + * suite value. It is not a real cipher suite. It is just an indication in the default and + * supported cipher suite lists indicates that the implementation supports secure renegotiation. + * + *

In the RI, its presence means that the SCSV is sent in the cipher suite list to indicate + * secure renegotiation support and its absense means to send an empty TLS renegotiation info * extension instead. - *

- * However, OpenSSL doesn't provide an API to give this level of - * control, instead always sending the SCSV and always including - * the empty renegotiation info if TLS is used (as opposed to - * SSL). So we simply allow TLS_EMPTY_RENEGOTIATION_INFO_SCSV to - * be passed for compatibility as to provide the hint that we - * support secure renegotiation. + * + *

However, OpenSSL doesn't provide an API to give this level of control, instead always + * sending the SCSV and always including the empty renegotiation info if TLS is used (as opposed + * to SSL). So we simply allow TLS_EMPTY_RENEGOTIATION_INFO_SCSV to be passed for compatibility + * as to provide the hint that we support secure renegotiation. */ static final String TLS_EMPTY_RENEGOTIATION_INFO_SCSV = "TLS_EMPTY_RENEGOTIATION_INFO_SCSV"; @@ -923,15 +1140,14 @@ static String cipherSuiteFromJava(String javaCipherSuite) { } /** - * TLS_FALLBACK_SCSV is from - * https://tools.ietf.org/html/draft-ietf-tls-downgrade-scsv-00 - * to indicate to the server that this is a fallback protocol - * request. + * TLS_FALLBACK_SCSV is from https://tools.ietf.org/html/draft-ietf-tls-downgrade-scsv-00 to + * indicate to the server that this is a fallback protocol request. */ private static final String TLS_FALLBACK_SCSV = "TLS_FALLBACK_SCSV"; private static final boolean HAS_AES_HARDWARE; private static final String[] SUPPORTED_TLS_1_2_CIPHER_SUITES; + static { if (loadError == null) { // If loadError is not null, it means the native code was not loaded, so @@ -965,11 +1181,13 @@ static String cipherSuiteFromJava(String javaCipherSuite) { } /** - * Returns 1 if the BoringSSL believes the CPU has AES accelerated hardware - * instructions. Used to determine cipher suite ordering. + * Returns 1 if the BoringSSL believes the CPU has AES accelerated hardware instructions. Used + * to determine cipher suite ordering. */ + // android-add: @FastNative static native int EVP_has_aes_hardware(); + // android-add: @FastNative static native long SSL_CTX_new(); // IMPLEMENTATION NOTE: The default list of cipher suites is a trade-off between what we'd like @@ -991,39 +1209,40 @@ static String cipherSuiteFromJava(String javaCipherSuite) { // prevent apps from connecting to servers they were previously able to connect to. /** X.509 based cipher suites enabled by default (if requested), in preference order. */ - static final String[] DEFAULT_X509_CIPHER_SUITES = HAS_AES_HARDWARE ? - new String[] { - "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", - "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", - "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256", - "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", - "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", - "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256", - "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", - "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", - "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", - "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", - "TLS_RSA_WITH_AES_128_GCM_SHA256", - "TLS_RSA_WITH_AES_256_GCM_SHA384", - "TLS_RSA_WITH_AES_128_CBC_SHA", - "TLS_RSA_WITH_AES_256_CBC_SHA", - } : - new String[] { - "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256", - "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", - "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", - "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256", - "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", - "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", - "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", - "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", - "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", - "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", - "TLS_RSA_WITH_AES_128_GCM_SHA256", - "TLS_RSA_WITH_AES_256_GCM_SHA384", - "TLS_RSA_WITH_AES_128_CBC_SHA", - "TLS_RSA_WITH_AES_256_CBC_SHA", - }; + static final String[] DEFAULT_X509_CIPHER_SUITES = + HAS_AES_HARDWARE + ? new String[] { + "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", + "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", + "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256", + "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", + "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", + "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256", + "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", + "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", + "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", + "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", + "TLS_RSA_WITH_AES_128_GCM_SHA256", + "TLS_RSA_WITH_AES_256_GCM_SHA384", + "TLS_RSA_WITH_AES_128_CBC_SHA", + "TLS_RSA_WITH_AES_256_CBC_SHA", + } + : new String[] { + "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256", + "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", + "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", + "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256", + "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", + "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", + "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", + "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", + "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", + "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", + "TLS_RSA_WITH_AES_128_GCM_SHA256", + "TLS_RSA_WITH_AES_256_GCM_SHA384", + "TLS_RSA_WITH_AES_128_CBC_SHA", + "TLS_RSA_WITH_AES_256_CBC_SHA", + }; /** TLS-PSK cipher suites enabled by default (if requested), in preference order. */ static final String[] DEFAULT_PSK_CIPHER_SUITES = new String[] { @@ -1040,27 +1259,34 @@ static String cipherSuiteFromJava(String javaCipherSuite) { }; static String[] getSupportedCipherSuites() { - return SSLUtils.concat( - SUPPORTED_TLS_1_3_CIPHER_SUITES, SUPPORTED_TLS_1_2_CIPHER_SUITES.clone()); + return SSLUtils.concat(SUPPORTED_TLS_1_3_CIPHER_SUITES, + SUPPORTED_TLS_1_2_CIPHER_SUITES.clone()); } + // android-add: @FastNative static native void SSL_CTX_free(long ssl_ctx, AbstractSessionContext holder); - static native void SSL_CTX_set_session_id_context( - long ssl_ctx, AbstractSessionContext holder, byte[] sid_ctx); + // android-add: @FastNative + static native void SSL_CTX_set_session_id_context(long ssl_ctx, AbstractSessionContext holder, + byte[] sid_ctx); - static native long SSL_CTX_set_timeout( - long ssl_ctx, AbstractSessionContext holder, long seconds); + // android-add: @FastNative + static native long SSL_CTX_set_timeout(long ssl_ctx, AbstractSessionContext holder, + long seconds); + // android-add: @FastNative static native long SSL_new(long ssl_ctx, AbstractSessionContext holder) throws SSLException; + // android-add: @FastNative static native void SSL_enable_tls_channel_id(long ssl, NativeSsl ssl_holder) throws SSLException; + // android-add: @FastNative static native byte[] SSL_get_tls_channel_id(long ssl, NativeSsl ssl_holder) throws SSLException; - static native void SSL_set1_tls_channel_id( - long ssl, NativeSsl ssl_holder, NativeRef.EVP_PKEY pkey); + // android-add: @FastNative + static native void SSL_set1_tls_channel_id(long ssl, NativeSsl ssl_holder, + NativeRef.EVP_PKEY pkey); /** * Sets the local certificates and private key. @@ -1070,47 +1296,67 @@ static native void SSL_set1_tls_channel_id( * @param pkey a reference to the private key. * @throws SSLException if a problem occurs setting the cert/key. */ + // android-add: @FastNative static native void setLocalCertsAndPrivateKey(long ssl, NativeSsl ssl_holder, - byte[][] encodedCertificates, NativeRef.EVP_PKEY pkey) throws SSLException; + byte[][] encodedCertificates, + NativeRef.EVP_PKEY pkey) throws SSLException; + // android-add: @FastNative static native void SSL_set_client_CA_list(long ssl, NativeSsl ssl_holder, - byte[][] asn1DerEncodedX500Principals) throws SSLException; + byte[][] asn1DerEncodedX500Principals) + throws SSLException; + // android-add: @FastNative static native long SSL_set_mode(long ssl, NativeSsl ssl_holder, long mode); + // android-add: @FastNative static native long SSL_set_options(long ssl, NativeSsl ssl_holder, long options); + // android-add: @FastNative static native long SSL_clear_options(long ssl, NativeSsl ssl_holder, long options); - static native int SSL_set_protocol_versions( - long ssl, NativeSsl ssl_holder, int min_version, int max_version); + // android-add: @FastNative + static native int SSL_set_protocol_versions(long ssl, NativeSsl ssl_holder, int min_version, + int max_version); + // android-add: @FastNative static native void SSL_enable_signed_cert_timestamps(long ssl, NativeSsl ssl_holder); + // android-add: @FastNative static native byte[] SSL_get_signed_cert_timestamp_list(long ssl, NativeSsl ssl_holder); - static native void SSL_set_signed_cert_timestamp_list( - long ssl, NativeSsl ssl_holder, byte[] list); + // android-add: @FastNative + static native void SSL_set_signed_cert_timestamp_list(long ssl, NativeSsl ssl_holder, + byte[] list); + // android-add: @FastNative static native void SSL_enable_ocsp_stapling(long ssl, NativeSsl ssl_holder); + // android-add: @FastNative static native byte[] SSL_get_ocsp_response(long ssl, NativeSsl ssl_holder); + // android-add: @FastNative static native void SSL_set_ocsp_response(long ssl, NativeSsl ssl_holder, byte[] response); + // android-add: @FastNative static native byte[] SSL_get_tls_unique(long ssl, NativeSsl ssl_holder); + // android-add: @FastNative static native byte[] SSL_export_keying_material(long ssl, NativeSsl ssl_holder, byte[] label, - byte[] context, int num_bytes) throws SSLException; + byte[] context, int num_bytes) + throws SSLException; - static native void SSL_use_psk_identity_hint( - long ssl, NativeSsl ssl_holder, String identityHint) throws SSLException; + // android-add: @FastNative + static native void SSL_use_psk_identity_hint(long ssl, NativeSsl ssl_holder, + String identityHint) throws SSLException; - static native void set_SSL_psk_client_callback_enabled( - long ssl, NativeSsl ssl_holder, boolean enabled); + // android-add: @FastNative + static native void set_SSL_psk_client_callback_enabled(long ssl, NativeSsl ssl_holder, + boolean enabled); - static native void set_SSL_psk_server_callback_enabled( - long ssl, NativeSsl ssl_holder, boolean enabled); + // android-add: @FastNative + static native void set_SSL_psk_server_callback_enabled(long ssl, NativeSsl ssl_holder, + boolean enabled); public static void setTlsV1DeprecationStatus(boolean deprecated, boolean supported) { if (deprecated) { @@ -1180,6 +1426,7 @@ static String[] getSupportedProtocols() { private static class Range { public final String min; public final String max; + public Range(String min, String max) { this.min = min; this.max = max; @@ -1215,8 +1462,8 @@ private static Range getProtocolRange(String[] protocols) { static void setEnabledProtocols(long ssl, NativeSsl ssl_holder, String[] protocols) { checkEnabledProtocols(protocols); Range range = getProtocolRange(protocols); - SSL_set_protocol_versions( - ssl, ssl_holder, getProtocolConstant(range.min), getProtocolConstant(range.max)); + SSL_set_protocol_versions(ssl, ssl_holder, getProtocolConstant(range.min), + getProtocolConstant(range.max)); } private static int getProtocolConstant(String protocol) { @@ -1248,6 +1495,7 @@ static String[] checkEnabledProtocols(String[] protocols) { return protocols; } + // android-add: @FastNative static native void SSL_set_cipher_lists(long ssl, NativeSsl ssl_holder, String[] ciphers); /** @@ -1255,10 +1503,11 @@ static String[] checkEnabledProtocols(String[] protocols) { * * @return array of {@code SSL_CIPHER} references. */ + // android-add: @FastNative static native long[] SSL_get_ciphers(long ssl, NativeSsl ssl_holder); - static void setEnabledCipherSuites( - long ssl, NativeSsl ssl_holder, String[] cipherSuites, String[] protocols) { + static void setEnabledCipherSuites(long ssl, NativeSsl ssl_holder, String[] cipherSuites, + String[] protocols) { checkEnabledCipherSuites(cipherSuites); String maxProtocol = getProtocolRange(protocols).max; List opensslSuites = new ArrayList(); @@ -1271,15 +1520,15 @@ static void setEnabledCipherSuites( // problems when servers upgrade. See https://github.com/google/conscrypt/issues/574 // for more discussion. if (cipherSuite.equals(TLS_FALLBACK_SCSV) - && (maxProtocol.equals(DEPRECATED_PROTOCOL_TLSV1) - || maxProtocol.equals(DEPRECATED_PROTOCOL_TLSV1_1))) { + && (maxProtocol.equals(DEPRECATED_PROTOCOL_TLSV1) + || maxProtocol.equals(DEPRECATED_PROTOCOL_TLSV1_1))) { SSL_set_mode(ssl, ssl_holder, NativeConstants.SSL_MODE_SEND_FALLBACK_SCSV); continue; } opensslSuites.add(cipherSuiteFromJava(cipherSuite)); } - SSL_set_cipher_lists( - ssl, ssl_holder, opensslSuites.toArray(new String[opensslSuites.size()])); + SSL_set_cipher_lists(ssl, ssl_holder, + opensslSuites.toArray(new String[opensslSuites.size()])); } static String[] checkEnabledCipherSuites(String[] cipherSuites) { @@ -1292,7 +1541,7 @@ static String[] checkEnabledCipherSuites(String[] cipherSuites) { throw new IllegalArgumentException("cipherSuites[" + i + "] == null"); } if (cipherSuites[i].equals(TLS_EMPTY_RENEGOTIATION_INFO_SCSV) - || cipherSuites[i].equals(TLS_FALLBACK_SCSV)) { + || cipherSuites[i].equals(TLS_FALLBACK_SCSV)) { continue; } if (SUPPORTED_TLS_1_2_CIPHER_SUITES_SET.contains(cipherSuites[i])) { @@ -1310,106 +1559,136 @@ static String[] checkEnabledCipherSuites(String[] cipherSuites) { // TODO log warning about using backward compatability continue; } - throw new IllegalArgumentException( - "cipherSuite " + cipherSuites[i] + " is not supported."); + throw new IllegalArgumentException("cipherSuite " + cipherSuites[i] + + " is not supported."); } return cipherSuites; } + // android-add: @FastNative static native void SSL_set_accept_state(long ssl, NativeSsl ssl_holder); + // android-add: @FastNative static native void SSL_set_connect_state(long ssl, NativeSsl ssl_holder); + // android-add: @FastNative static native void SSL_set_verify(long ssl, NativeSsl ssl_holder, int mode); + // android-add: @FastNative static native void SSL_set_session(long ssl, NativeSsl ssl_holder, long sslSessionNativePointer) throws SSLException; - static native void SSL_set_session_creation_enabled( - long ssl, NativeSsl ssl_holder, boolean creationEnabled) throws SSLException; + // android-add: @FastNative + static native void SSL_set_session_creation_enabled(long ssl, NativeSsl ssl_holder, + boolean creationEnabled) + throws SSLException; + // android-add: @FastNative static native boolean SSL_session_reused(long ssl, NativeSsl ssl_holder); + // android-add: @FastNative static native void SSL_accept_renegotiations(long ssl, NativeSsl ssl_holder) throws SSLException; + // android-add: @FastNative static native void SSL_set_tlsext_host_name(long ssl, NativeSsl ssl_holder, String hostname) throws SSLException; + + // android-add: @FastNative static native String SSL_get_servername(long ssl, NativeSsl ssl_holder); static native void SSL_do_handshake(long ssl, NativeSsl ssl_holder, FileDescriptor fd, - SSLHandshakeCallbacks shc, int timeoutMillis) + SSLHandshakeCallbacks shc, int timeoutMillis) throws SSLException, SocketTimeoutException, CertificateException; + // android-add: @FastNative public static native String SSL_get_current_cipher(long ssl, NativeSsl ssl_holder); + // android-add: @FastNative + public static native String SSL_get_version(long ssl, NativeSsl ssl_holder); + public static native void SSL_set1_groups(long ssl, NativeSsl sslHolder, int[] groups); public static native String SSL_get_curve_name(long ssl, NativeSsl sslHolder); - public static native String SSL_get_version(long ssl, NativeSsl ssl_holder); - - /** - * Returns the peer certificate chain. - */ + /** Returns the peer certificate chain. */ + // android-add: @FastNative static native byte[][] SSL_get0_peer_certificates(long ssl, NativeSsl ssl_holder); /** * Reads with the native SSL_read function from the encrypted data stream + * * @return -1 if error or the end of the stream is reached. */ static native int SSL_read(long ssl, NativeSsl ssl_holder, FileDescriptor fd, - SSLHandshakeCallbacks shc, byte[] b, int off, int len, int readTimeoutMillis) - throws IOException; + SSLHandshakeCallbacks shc, byte[] b, int off, int len, + int readTimeoutMillis) throws IOException; - /** - * Writes with the native SSL_write function to the encrypted data stream. - */ + /** Writes with the native SSL_write function to the encrypted data stream. */ static native void SSL_write(long ssl, NativeSsl ssl_holder, FileDescriptor fd, - SSLHandshakeCallbacks shc, byte[] b, int off, int len, int writeTimeoutMillis) - throws IOException; + SSLHandshakeCallbacks shc, byte[] b, int off, int len, + int writeTimeoutMillis) throws IOException; + // android-add: @FastNative static native void SSL_interrupt(long ssl, NativeSsl ssl_holder); + static native void SSL_shutdown(long ssl, NativeSsl ssl_holder, FileDescriptor fd, - SSLHandshakeCallbacks shc) throws IOException; + SSLHandshakeCallbacks shc) throws IOException; + // android-add: @FastNative static native int SSL_get_shutdown(long ssl, NativeSsl ssl_holder); + // android-add: @FastNative static native void SSL_free(long ssl, NativeSsl ssl_holder); + // android-add: @FastNative static native long SSL_get_time(long ssl, NativeSsl ssl_holder); + // android-add: @FastNative static native long SSL_set_timeout(long ssl, NativeSsl ssl_holder, long millis); + // android-add: @FastNative static native long SSL_get_timeout(long ssl, NativeSsl ssl_holder); + // android-add: @FastNative static native int SSL_get_signature_algorithm_key_type(int signatureAlg); + // android-add: @FastNative static native byte[] SSL_session_id(long ssl, NativeSsl ssl_holder); + // android-add: @FastNative static native byte[] SSL_SESSION_session_id(long sslSessionNativePointer); + // android-add: @FastNative static native long SSL_SESSION_get_time(long sslSessionNativePointer); + // android-add: @FastNative static native long SSL_SESSION_get_timeout(long sslSessionNativePointer); + // android-add: @FastNative static native String SSL_SESSION_get_version(long sslSessionNativePointer); + // android-add: @FastNative static native String SSL_SESSION_cipher(long sslSessionNativePointer); + // android-add: @FastNative static native boolean SSL_SESSION_should_be_single_use(long sslSessionNativePointer); + // android-add: @FastNative static native void SSL_SESSION_up_ref(long sslSessionNativePointer); + // android-add: @FastNative static native void SSL_SESSION_free(long sslSessionNativePointer); + // android-add: @FastNative static native byte[] i2d_SSL_SESSION(long sslSessionNativePointer); + // android-add: @FastNative static native long d2i_SSL_SESSION(byte[] data) throws IOException; /** - * A collection of callbacks from the native OpenSSL code that are - * related to the SSL handshake initiated by SSL_do_handshake. + * A collection of callbacks from the native OpenSSL code that are related to the SSL handshake + * initiated by SSL_do_handshake. */ interface SSLHandshakeCallbacks { /** @@ -1417,7 +1696,6 @@ interface SSLHandshakeCallbacks { * * @param certificateChain chain of X.509 certificates in their encoded form * @param authMethod auth algorithm name - * * @throws CertificateException if the certificate is untrusted */ @SuppressWarnings("unused") @@ -1433,14 +1711,14 @@ void verifyCertificateChain(byte[][] certificateChain, String authMethod) * @param asn1DerEncodedX500Principals CAs known to the server */ @SuppressWarnings("unused") - void clientCertificateRequested( - byte[] keyTypes, int[] signatureAlgs, byte[][] asn1DerEncodedX500Principals) + void clientCertificateRequested(byte[] keyTypes, int[] signatureAlgs, + byte[][] asn1DerEncodedX500Principals) throws CertificateEncodingException, SSLException; /** - * Called when acting as a server during ClientHello processing before a decision - * to resume a session is made. This allows the selection of the correct server - * certificate based on things like Server Name Indication (SNI). + * Called when acting as a server during ClientHello processing before a decision to resume + * a session is made. This allows the selection of the correct server certificate based on + * things like Server Name Indication (SNI). * * @throws IOException if there was an error during certificate selection. */ @@ -1451,13 +1729,12 @@ void clientCertificateRequested( * exchange. * * @param identityHint PSK identity hint provided by the server or {@code null} if no hint - * provided. + * provided. * @param identity buffer to be populated with PSK identity (NULL-terminated modified UTF-8) - * by this method. This identity will be provided to the server. + * by this method. This identity will be provided to the server. * @param key buffer to be populated with key material by this method. - * * @return number of bytes this method stored in the {@code key} buffer or {@code 0} if an - * error occurred in which case the handshake will be aborted. + * error occurred in which case the handshake will be aborted. */ int clientPSKKeyRequested(String identityHint, byte[] identity, byte[] key); @@ -1465,33 +1742,30 @@ void clientCertificateRequested( * Gets the key to be used in server mode for this connection in Pre-Shared Key (PSK) key * exchange. * - * @param identityHint PSK identity hint provided by this server to the client or - * {@code null} if no hint was provided. + * @param identityHint PSK identity hint provided by this server to the client or {@code + * null} if no hint was provided. * @param identity PSK identity provided by the client. * @param key buffer to be populated with key material by this method. - * * @return number of bytes this method stored in the {@code key} buffer or {@code 0} if an - * error occurred in which case the handshake will be aborted. + * error occurred in which case the handshake will be aborted. */ int serverPSKKeyRequested(String identityHint, String identity, byte[] key); - /** - * Called when SSL state changes. This could be handshake completion. - */ + /** Called when SSL state changes. This could be handshake completion. */ @SuppressWarnings("unused") void onSSLStateChange(int type, int val); /** - * Called when a new session has been established and may be added to the session cache. - * The callee is responsible for incrementing the reference count on the returned session. + * Called when a new session has been established and may be added to the session cache. The + * callee is responsible for incrementing the reference count on the returned session. */ @SuppressWarnings("unused") void onNewSessionEstablished(long sslSessionNativePtr); /** - * Called for servers where TLS < 1.3 (TLS 1.3 uses session tickets rather than - * application session caches). + * Called for servers where TLS < 1.3 (TLS 1.3 uses session tickets rather than application + * session caches). * - *

Looks up the session by ID in the application's session cache. If a valid session - * is returned, this callback is responsible for incrementing the reference count (and any + *

Looks up the session by ID in the application's session cache. If a valid session is + * returned, this callback is responsible for incrementing the reference count (and any * required synchronization). * * @param id the ID of the session to find. @@ -1501,7 +1775,7 @@ void clientCertificateRequested( /** * Called when acting as a server, the socket has an {@link - * ApplicationProtocolSelectorAdapter} associated with it, and the application protocol + * ApplicationProtocolSelectorAdapter} associated with it, and the application protocol * needs to be selected. * * @param applicationProtocols list of application protocols in length-prefix format @@ -1510,131 +1784,146 @@ void clientCertificateRequested( @SuppressWarnings("unused") int selectApplicationProtocol(byte[] applicationProtocols); } + // android-add: @FastNative static native String SSL_CIPHER_get_kx_name(long cipherAddress); + // android-add: @FastNative static native String[] get_cipher_names(String selection); + // android-add: @FastNative public static native byte[] get_ocsp_single_extension(byte[] ocspResponse, String oid, - long x509Ref, OpenSSLX509Certificate holder, long issuerX509Ref, - OpenSSLX509Certificate holder2); + long x509Ref, + OpenSSLX509Certificate holder, + long issuerX509Ref, + OpenSSLX509Certificate holder2); /** - * Returns the starting address of the memory region referenced by the provided direct - * {@link Buffer} or {@code 0} if the provided buffer is not direct or if such access to direct - * buffers is not supported by the platform. + * Returns the starting address of the memory region referenced by the provided direct {@link + * Buffer} or {@code 0} if the provided buffer is not direct or if such access to direct buffers + * is not supported by the platform. * *

NOTE: This method ignores the buffer's current {@code position}. */ + // android-add: @FastNative static native long getDirectBufferAddress(Buffer buf); + // android-add: @FastNative static native long SSL_BIO_new(long ssl, NativeSsl ssl_holder) throws SSLException; + // android-add: @FastNative static native int SSL_get_error(long ssl, NativeSsl ssl_holder, int ret); + // android-add: @FastNative static native void SSL_clear_error(); + // android-add: @FastNative static native int SSL_pending_readable_bytes(long ssl, NativeSsl ssl_holder); + // android-add: @FastNative static native int SSL_pending_written_bytes_in_BIO(long bio); - /** - * Returns the maximum overhead, in bytes, of sealing a record with SSL. - */ + /** Returns the maximum overhead, in bytes, of sealing a record with SSL. */ + // android-add: @FastNative static native int SSL_max_seal_overhead(long ssl, NativeSsl ssl_holder); /** * Enables ALPN for this TLS endpoint and sets the list of supported ALPN protocols in * wire-format (length-prefixed 8-bit strings). */ - static native void setApplicationProtocols( - long ssl, NativeSsl ssl_holder, boolean client, byte[] protocols) throws IOException; + // android-add: @FastNative + static native void setApplicationProtocols(long ssl, NativeSsl ssl_holder, boolean client, + byte[] protocols) throws IOException; /** * Called for a server endpoint only. Enables ALPN and indicates that the {@link - * SSLHandshakeCallbacks#selectApplicationProtocol} will be called to select the - * correct protocol during a handshake. Calling this method overrides - * {@link #setApplicationProtocols(long, NativeSsl, boolean, byte[])}. + * SSLHandshakeCallbacks#selectApplicationProtocol} will be called to select the correct + * protocol during a handshake. Calling this method overrides {@link + * #setApplicationProtocols(long, NativeSsl, boolean, byte[])}. */ - static native void setHasApplicationProtocolSelector( - long ssl, NativeSsl ssl_holder, boolean hasSelector) throws IOException; + // android-add: @FastNative + static native void setHasApplicationProtocolSelector(long ssl, NativeSsl ssl_holder, + boolean hasSelector) throws IOException; /** - * Returns the selected ALPN protocol. If the server did not select a - * protocol, {@code null} will be returned. + * Returns the selected ALPN protocol. If the server did not select a protocol, {@code null} + * will be returned. */ + // android-add: @FastNative static native byte[] getApplicationProtocol(long ssl, NativeSsl ssl_holder); /** * Variant of the {@link #SSL_do_handshake} used by {@link ConscryptEngine}. This differs - * slightly from the raw BoringSSL API in that it returns the SSL error code from the - * operation, rather than the return value from {@code SSL_do_handshake}. This is done in - * order to allow to properly handle SSL errors and propagate useful exceptions. + * slightly from the raw BoringSSL API in that it returns the SSL error code from the operation, + * rather than the return value from {@code SSL_do_handshake}. This is done in order to allow to + * properly handle SSL errors and propagate useful exceptions. * * @return Returns the SSL error code for the operation when the error was {@code - * SSL_ERROR_NONE}, {@code SSL_ERROR_WANT_READ}, or {@code SSL_ERROR_WANT_WRITE}. + * SSL_ERROR_NONE}, {@code SSL_ERROR_WANT_READ}, or {@code SSL_ERROR_WANT_WRITE}. * @throws IOException when the error code is anything except those returned by this method. */ - static native int ENGINE_SSL_do_handshake( - long ssl, NativeSsl ssl_holder, SSLHandshakeCallbacks shc) throws IOException; + static native int ENGINE_SSL_do_handshake(long ssl, NativeSsl ssl_holder, + SSLHandshakeCallbacks shc) throws IOException; /** * Variant of the {@link #SSL_read} for a direct {@link java.nio.ByteBuffer} used by {@link * ConscryptEngine}. * - * @return if positive, represents the number of bytes read into the given buffer. - * Returns {@code -SSL_ERROR_WANT_READ} if more data is needed. Returns - * {@code -SSL_ERROR_WANT_WRITE} if data needs to be written out to flush the BIO. - * + * @return if positive, represents the number of bytes read into the given buffer. Returns + * {@code -SSL_ERROR_WANT_READ} if more data is needed. Returns {@code + * -SSL_ERROR_WANT_WRITE} if data needs to be written out to flush the BIO. * @throws java.io.InterruptedIOException if the read was interrupted. * @throws java.io.EOFException if the end of stream has been reached. * @throws CertificateException if the application's certificate verification callback failed. - * Only occurs during handshake processing. + * Only occurs during handshake processing. * @throws SSLException if any other error occurs. */ static native int ENGINE_SSL_read_direct(long ssl, NativeSsl ssl_holder, long address, - int length, SSLHandshakeCallbacks shc) throws IOException, CertificateException; + int length, SSLHandshakeCallbacks shc) + throws IOException, CertificateException; /** * Variant of the {@link #SSL_write} for a direct {@link java.nio.ByteBuffer} used by {@link * ConscryptEngine}. This version does not lock or and does no error pre-processing. */ static native int ENGINE_SSL_write_direct(long ssl, NativeSsl ssl_holder, long address, - int length, SSLHandshakeCallbacks shc) throws IOException; + int length, SSLHandshakeCallbacks shc) + throws IOException; /** * Writes data from the given direct {@link java.nio.ByteBuffer} to the BIO. */ static native int ENGINE_SSL_write_BIO_direct(long ssl, NativeSsl ssl_holder, long bioRef, - long pos, int length, SSLHandshakeCallbacks shc) throws IOException; + long pos, int length, SSLHandshakeCallbacks shc) + throws IOException; /** * Reads data from the given BIO into a direct {@link java.nio.ByteBuffer}. */ static native int ENGINE_SSL_read_BIO_direct(long ssl, NativeSsl ssl_holder, long bioRef, - long address, int len, SSLHandshakeCallbacks shc) throws IOException; + long address, int len, SSLHandshakeCallbacks shc) + throws IOException; /** * Forces the SSL object to process any data pending in the BIO. */ - static native void ENGINE_SSL_force_read( - long ssl, NativeSsl ssl_holder, SSLHandshakeCallbacks shc) throws IOException; + static native void ENGINE_SSL_force_read(long ssl, NativeSsl ssl_holder, + SSLHandshakeCallbacks shc) throws IOException; /** * Variant of the {@link #SSL_shutdown} used by {@link ConscryptEngine}. This version does not * lock. */ - static native void ENGINE_SSL_shutdown( - long ssl, NativeSsl ssl_holder, SSLHandshakeCallbacks shc) throws IOException; + static native void ENGINE_SSL_shutdown(long ssl, NativeSsl ssl_holder, + SSLHandshakeCallbacks shc) throws IOException; /** * Generates a key from a password and salt using Scrypt. */ - static native byte[] Scrypt_generate_key( - byte[] password, byte[] salt, int n, int r, int p, int key_len); + static native byte[] Scrypt_generate_key(byte[] password, byte[] salt, int n, int r, int p, + int key_len); - /** - * Return {@code true} if BoringSSL has been built in FIPS mode. - */ + /** Return {@code true} if BoringSSL has been built in FIPS mode. */ + // android-add: @FastNative static native boolean usesBoringSsl_FIPS_mode(); /* ECH */ @@ -1660,17 +1949,28 @@ static native boolean SSL_set1_ech_config_list(long ssl, NativeSsl ssl_holder, b static native boolean SSL_ech_accepted(long ssl, NativeSsl ssl_holder); - static native boolean SSL_CTX_ech_enable_server( - long sslCtx, AbstractSessionContext holder, byte[] key, byte[] config); + static native boolean SSL_CTX_ech_enable_server(long sslCtx, AbstractSessionContext holder, + byte[] key, byte[] config); /** * Used for testing only. */ + // android-add: @FastNative static native int BIO_read(long bioRef, byte[] buffer) throws IOException; + + // android-add: @FastNative static native void BIO_write(long bioRef, byte[] buffer, int offset, int length) throws IOException, IndexOutOfBoundsException; + + // android-add: @FastNative static native long SSL_clear_mode(long ssl, NativeSsl ssl_holder, long mode); + + // android-add: @FastNative static native long SSL_get_mode(long ssl, NativeSsl ssl_holder); + + // android-add: @FastNative static native long SSL_get_options(long ssl, NativeSsl ssl_holder); + + // android-add: @FastNative static native long SSL_get1_session(long ssl, NativeSsl ssl_holder); } diff --git a/common/src/main/java/org/conscrypt/NativeSsl.java b/common/src/main/java/org/conscrypt/NativeSsl.java index ebf915ed9..02bc62496 100644 --- a/common/src/main/java/org/conscrypt/NativeSsl.java +++ b/common/src/main/java/org/conscrypt/NativeSsl.java @@ -65,8 +65,8 @@ final class NativeSsl { private volatile long ssl; private NativeSsl(long ssl, SSLParametersImpl parameters, - SSLHandshakeCallbacks handshakeCallbacks, AliasChooser aliasChooser, - PSKCallbacks pskCallbacks) { + SSLHandshakeCallbacks handshakeCallbacks, AliasChooser aliasChooser, + PSKCallbacks pskCallbacks) { this.ssl = ssl; this.parameters = parameters; this.handshakeCallbacks = handshakeCallbacks; @@ -75,8 +75,8 @@ private NativeSsl(long ssl, SSLParametersImpl parameters, } static NativeSsl newInstance(SSLParametersImpl parameters, - SSLHandshakeCallbacks handshakeCallbacks, AliasChooser chooser, - PSKCallbacks pskCallbacks) throws SSLException { + SSLHandshakeCallbacks handshakeCallbacks, AliasChooser chooser, + PSKCallbacks pskCallbacks) throws SSLException { long ssl = parameters.getSessionContext().newSsl(); return new NativeSsl(ssl, parameters, handshakeCallbacks, chooser, pskCallbacks); } @@ -209,7 +209,7 @@ int serverPSKKeyRequested(String identityHint, String identity, byte[] key) { } void chooseClientCertificate(byte[] keyTypeBytes, int[] signatureAlgs, - byte[][] asn1DerEncodedPrincipals) + byte[][] asn1DerEncodedPrincipals) throws SSLException, CertificateEncodingException { Set keyTypesSet = SSLUtils.getSupportedClientKeyTypes(keyTypeBytes, signatureAlgs); String[] keyTypes = keyTypesSet.toArray(new String[0]); @@ -322,8 +322,8 @@ static int[] toBoringSslGroups(String[] javaNamedGroups) { } } if (i == 0) { - throw new IllegalArgumentException( - "No valid known group found in: " + Arrays.toString(javaNamedGroups)); + throw new IllegalArgumentException("No valid known group found in: " + + Arrays.toString(javaNamedGroups)); } if (i < javaNamedGroups.length) { return Arrays.copyOf(outputGroups, i); @@ -363,6 +363,7 @@ void initialize(String hostname, OpenSSLKey channelIdPrivateKey) throws IOExcept if (parameters.isCTVerificationEnabled(hostname)) { NativeCrypto.SSL_enable_signed_cert_timestamps(ssl, this); } + enableEchBasedOnPolicy(hostname); } else { NativeCrypto.SSL_set_accept_state(ssl, this); @@ -373,17 +374,17 @@ void initialize(String hostname, OpenSSLKey channelIdPrivateKey) throws IOExcept } if (parameters.getEnabledProtocols().length == 0 && parameters.isEnabledProtocolsFiltered) { - throw new SSLHandshakeException("No enabled protocols; " - + NativeCrypto.OBSOLETE_PROTOCOL_SSLV3 + ", " - + NativeCrypto.DEPRECATED_PROTOCOL_TLSV1 - + " and " + NativeCrypto.DEPRECATED_PROTOCOL_TLSV1_1 + throw new SSLHandshakeException( + "No enabled protocols; " + NativeCrypto.OBSOLETE_PROTOCOL_SSLV3 + ", " + + NativeCrypto.DEPRECATED_PROTOCOL_TLSV1 + " and " + + NativeCrypto.DEPRECATED_PROTOCOL_TLSV1_1 + " are no longer supported and were filtered from the list"); } NativeCrypto.setEnabledProtocols(ssl, this, parameters.enabledProtocols); // We only set the cipher suites if we are not using SPAKE. if (!parameters.isSpake()) { - NativeCrypto.setEnabledCipherSuites( - ssl, this, parameters.enabledCipherSuites, parameters.enabledProtocols); + NativeCrypto.setEnabledCipherSuites(ssl, this, parameters.enabledCipherSuites, + parameters.enabledProtocols); } String[] paramsNamedGroups = parameters.getNamedGroups(); @@ -408,7 +409,8 @@ void initialize(String hostname, OpenSSLKey channelIdPrivateKey) throws IOExcept } if (parameters.applicationProtocols.length > 0) { - NativeCrypto.setApplicationProtocols(ssl, this, isClient(), parameters.applicationProtocols); + NativeCrypto.setApplicationProtocols(ssl, this, isClient(), + parameters.applicationProtocols); } if (!isClient() && parameters.applicationProtocolSelector != null) { NativeCrypto.setHasApplicationProtocolSelector(ssl, this, true); @@ -520,8 +522,8 @@ int read(FileDescriptor fd, byte[] buf, int offset, int len, int timeoutMillis) if (isClosed() || fd == null || !fd.valid()) { throw new SocketException("Socket is closed"); } - return NativeCrypto - .SSL_read(ssl, this, fd, handshakeCallbacks, buf, offset, len, timeoutMillis); + return NativeCrypto.SSL_read(ssl, this, fd, handshakeCallbacks, buf, offset, len, + timeoutMillis); } finally { lock.readLock().unlock(); } @@ -535,8 +537,8 @@ void write(FileDescriptor fd, byte[] buf, int offset, int len, int timeoutMillis if (isClosed() || fd == null || !fd.valid()) { throw new SocketException("Socket is closed"); } - NativeCrypto - .SSL_write(ssl, this, fd, handshakeCallbacks, buf, offset, len, timeoutMillis); + NativeCrypto.SSL_write(ssl, this, fd, handshakeCallbacks, buf, offset, len, + timeoutMillis); } finally { lock.readLock().unlock(); } @@ -583,14 +585,35 @@ private void setTlsChannelId(OpenSSLKey channelIdPrivateKey) throws SSLException } } + private void enableEchBasedOnPolicy(String hostname) throws SSLException { + EchOptions opts = parameters.getEchOptions(hostname); + if (opts == null) { + return; + } + + byte[] configList = opts.getConfigList(); + if (configList != null) { + try { + NativeCrypto.SSL_set1_ech_config_list(ssl, this, configList); + } catch (SSLException e) { + // The platform may provide a more specialized exception type for this error. + throw Platform.wrapInvalidEchDataException(e); + } + } + + if (opts.isGreaseEnabled()) { + NativeCrypto.SSL_set_enable_ech_grease(ssl, this, /* enable= */ true); + } + } + private void setCertificateValidation() throws SSLException { // setup peer certificate verification if (!isClient()) { // needing client auth takes priority... boolean certRequested; if (parameters.getNeedClientAuth()) { - NativeCrypto.SSL_set_verify(ssl, this, SSL_VERIFY_PEER - | SSL_VERIFY_FAIL_IF_NO_PEER_CERT); + NativeCrypto.SSL_set_verify(ssl, this, + SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT); certRequested = true; // ... over just wanting it... } else if (parameters.getWantClientAuth()) { @@ -658,8 +681,8 @@ int readDirectByteBuffer(long destAddress, int destLength) throws IOException, CertificateException { lock.readLock().lock(); try { - return NativeCrypto.ENGINE_SSL_read_direct( - ssl, this, destAddress, destLength, handshakeCallbacks); + return NativeCrypto.ENGINE_SSL_read_direct(ssl, this, destAddress, destLength, + handshakeCallbacks); } finally { lock.readLock().unlock(); } @@ -668,8 +691,8 @@ int readDirectByteBuffer(long destAddress, int destLength) int writeDirectByteBuffer(long sourceAddress, int sourceLength) throws IOException { lock.readLock().lock(); try { - return NativeCrypto.ENGINE_SSL_write_direct( - ssl, this, sourceAddress, sourceLength, handshakeCallbacks); + return NativeCrypto.ENGINE_SSL_write_direct(ssl, this, sourceAddress, sourceLength, + handshakeCallbacks); } finally { lock.readLock().unlock(); } @@ -764,8 +787,8 @@ int writeDirectByteBuffer(long address, int length) throws IOException { if (isClosed()) { throw new SSLException("Connection closed"); } - return NativeCrypto.ENGINE_SSL_write_BIO_direct( - ssl, NativeSsl.this, bio, address, length, handshakeCallbacks); + return NativeCrypto.ENGINE_SSL_write_BIO_direct(ssl, NativeSsl.this, bio, address, + length, handshakeCallbacks); } finally { lock.readLock().unlock(); } diff --git a/common/src/main/java/org/conscrypt/NetworkSecurityPolicy.java b/common/src/main/java/org/conscrypt/NetworkSecurityPolicy.java new file mode 100644 index 000000000..499c5eda0 --- /dev/null +++ b/common/src/main/java/org/conscrypt/NetworkSecurityPolicy.java @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2025 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 org.conscrypt.metrics.CertificateTransparencyVerificationReason; + +/** + * A policy provided by the platform to decide on the behaviour of TrustManagerImpl. + * + * See the platform-specific implementations in PlatformNetworkSecurityPolicy. + */ +@Internal +public interface NetworkSecurityPolicy { + boolean isCertificateTransparencyVerificationRequired(String hostname); + + CertificateTransparencyVerificationReason getCertificateTransparencyVerificationReason( + String hostname); + + DomainEncryptionMode getDomainEncryptionMode(String hostname); +} diff --git a/common/src/main/java/org/conscrypt/OpenSSLAeadCipher.java b/common/src/main/java/org/conscrypt/OpenSSLAeadCipher.java index 867803af1..7ff4b3925 100644 --- a/common/src/main/java/org/conscrypt/OpenSSLAeadCipher.java +++ b/common/src/main/java/org/conscrypt/OpenSSLAeadCipher.java @@ -24,6 +24,7 @@ import java.security.SecureRandom; import java.security.spec.AlgorithmParameterSpec; import java.util.Arrays; +import java.util.logging.Logger; import javax.crypto.BadPaddingException; import javax.crypto.IllegalBlockSizeException; @@ -33,6 +34,8 @@ @Internal public abstract class OpenSSLAeadCipher extends OpenSSLCipher { + private static final Logger logger = Logger.getLogger(OpenSSLAeadCipher.class.getName()); + /** * Controls whether no-copy optimizations for direct ByteBuffers are enabled. */ @@ -97,8 +100,10 @@ private void checkInitialization() { } } - /** Constant-time array comparison. Since we are using this to compare keys, we want to - * ensure there's no opportunity for a timing attack. */ + /** + * Constant-time array comparison. Since we are using this to compare keys, we want to + * ensure there's no opportunity for a timing attack. + */ private boolean arraysAreEqual(byte[] a, byte[] b) { if (a.length != b.length) { return false; @@ -130,9 +135,8 @@ private void reset() { } @Override - void engineInitInternal(byte[] encodedKey, AlgorithmParameterSpec params, - SecureRandom random) throws InvalidKeyException, - InvalidAlgorithmParameterException { + void engineInitInternal(byte[] encodedKey, AlgorithmParameterSpec params, SecureRandom random) + throws InvalidKeyException, InvalidAlgorithmParameterException { byte[] iv; final int tagLenBits; if (params == null) { @@ -165,7 +169,7 @@ void engineInitInternal(byte[] encodedKey, AlgorithmParameterSpec params, if (iv == null && expectedIvLength != 0) { if (!encrypting) { throw new InvalidAlgorithmParameterException("IV must be specified in " + mode - + " mode"); + + " mode"); } iv = new byte[expectedIvLength]; @@ -177,14 +181,13 @@ void engineInitInternal(byte[] encodedKey, AlgorithmParameterSpec params, } else if (expectedIvLength == 0 && iv != null) { throw new InvalidAlgorithmParameterException("IV not used in " + mode + " mode"); } else if (iv != null && iv.length != expectedIvLength) { - throw new InvalidAlgorithmParameterException("Expected IV length of " - + expectedIvLength + " but was " + iv.length); + throw new InvalidAlgorithmParameterException("Expected IV length of " + expectedIvLength + + " but was " + iv.length); } if (isEncrypting() && iv != null && !allowsNonceReuse()) { - if (previousKey != null && previousIv != null - && arraysAreEqual(previousKey, encodedKey) - && arraysAreEqual(previousIv, iv)) { + if (previousKey != null && previousIv != null && arraysAreEqual(previousKey, encodedKey) + && arraysAreEqual(previousIv, iv)) { mustInitialize = true; throw new InvalidAlgorithmParameterException( "When using AEAD key and IV must not be re-used"); @@ -202,11 +205,10 @@ && arraysAreEqual(previousIv, iv)) { bufCount = 0; } - void checkSupportedTagLength(int tagLenBits) - throws InvalidAlgorithmParameterException { + void checkSupportedTagLength(int tagLenBits) throws InvalidAlgorithmParameterException { if (tagLenBits % 8 != 0) { - throw new InvalidAlgorithmParameterException( - "Tag length must be a multiple of 8; was " + tagLenBits); + throw new InvalidAlgorithmParameterException("Tag length must be a multiple of 8; was " + + tagLenBits); } } @@ -220,8 +222,8 @@ boolean allowsNonceReuse() { } @Override - protected int engineDoFinal(ByteBuffer input, ByteBuffer output) throws ShortBufferException, - IllegalBlockSizeException, BadPaddingException { + protected int engineDoFinal(ByteBuffer input, ByteBuffer output) + throws ShortBufferException, IllegalBlockSizeException, BadPaddingException { if (!ENABLE_BYTEBUFFER_OPTIMIZATIONS) { return super.engineDoFinal(input, output); } @@ -247,14 +249,13 @@ protected int engineDoFinal(ByteBuffer input, ByteBuffer output) throws ShortBuf input = inputClone; } if (!output.isDirect()) { - ByteBuffer outputClone = ByteBuffer.allocateDirect( - getOutputSizeForFinal(input.remaining())); + ByteBuffer outputClone = + ByteBuffer.allocateDirect(getOutputSizeForFinal(input.remaining())); bytesWritten = doFinalInternal(input, outputClone); output.put(outputClone); input.position(input.limit()); // API reasons - } - else { - bytesWritten = doFinalInternal(input, output); + } else { + bytesWritten = doFinalInternal(input, output); output.position(output.position() + bytesWritten); input.position(input.limit()); // API reasons } @@ -288,8 +289,8 @@ protected byte[] engineDoFinal(byte[] input, int inputOffset, int inputLen) @Override protected int engineDoFinal(byte[] input, int inputOffset, int inputLen, byte[] output, - int outputOffset) throws ShortBufferException, IllegalBlockSizeException, - BadPaddingException { + int outputOffset) + throws ShortBufferException, IllegalBlockSizeException, BadPaddingException { if (output == null) { throw new NullPointerException("output == null"); } @@ -309,8 +310,8 @@ void appendToBuf(byte[] input, int inputOffset, int inputLen) { } @Override - int updateInternal(byte[] input, int inputOffset, int inputLen, byte[] output, - int outputOffset, int maximumLen) throws ShortBufferException { + int updateInternal(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset, + int maximumLen) throws ShortBufferException { checkInitialization(); appendToBuf(input, inputOffset, inputLen); return 0; @@ -321,8 +322,8 @@ private void throwAEADBadTagExceptionIfAvailable(String message, Throwable cause throws BadPaddingException { Constructor aeadBadTagConstructor; try { - aeadBadTagConstructor = Class.forName("javax.crypto.AEADBadTagException") - .getConstructor(String.class); + aeadBadTagConstructor = + Class.forName("javax.crypto.AEADBadTagException").getConstructor(String.class); } catch (Exception ignored) { return; } @@ -336,8 +337,7 @@ private void throwAEADBadTagExceptionIfAvailable(String message, Throwable cause } catch (InstantiationException e2) { // Fall through } catch (InvocationTargetException e2) { - throw(BadPaddingException) new BadPaddingException().initCause( - e2.getTargetException()); + throw(BadPaddingException) new BadPaddingException().initCause(e2.getTargetException()); } if (badTagException != null) { throw badTagException; @@ -378,8 +378,8 @@ int doFinalInternal(ByteBuffer input, ByteBuffer output) return bytesWritten; } - int doFinalInternal(byte[] input, int inputOffset, int inputLen, - byte[] output, int outputOffset) + int doFinalInternal(byte[] input, int inputOffset, int inputLen, byte[] output, + int outputOffset) throws ShortBufferException, IllegalBlockSizeException, BadPaddingException { checkInitialization(); @@ -398,9 +398,9 @@ int doFinalInternal(byte[] input, int inputOffset, int inputLen, in = EmptyArray.BYTE; // input can be null when inputLen == 0 inOffset = inputOffset; } else if (input == output - && ((inputOffset + inputLen > outputOffset && inputOffset <= outputOffset) - || (inputOffset >= outputOffset - && outputOffset + inputLen + tagLengthInBytes > inputOffset))) { + && ((inputOffset + inputLen > outputOffset && inputOffset <= outputOffset) + || (inputOffset >= outputOffset + && outputOffset + inputLen + tagLengthInBytes > inputOffset))) { // BoringSSL requires that input and output do not overlap. To be on the safe side, // we copy the input to a new array. in = Arrays.copyOfRange(input, inputOffset, inputOffset + inputLen); @@ -416,11 +416,13 @@ int doFinalInternal(byte[] input, int inputOffset, int inputLen, final int bytesWritten; try { if (isEncrypting()) { - bytesWritten = NativeCrypto.EVP_AEAD_CTX_seal(evpAead, encodedKey, - tagLengthInBytes, output, outputOffset, iv, in, inOffset, inLen, aad); + bytesWritten = NativeCrypto.EVP_AEAD_CTX_seal(evpAead, encodedKey, tagLengthInBytes, + output, outputOffset, iv, in, + inOffset, inLen, aad); } else { - bytesWritten = NativeCrypto.EVP_AEAD_CTX_open(evpAead, encodedKey, - tagLengthInBytes, output, outputOffset, iv, in, inOffset, inLen, aad); + bytesWritten = NativeCrypto.EVP_AEAD_CTX_open(evpAead, encodedKey, tagLengthInBytes, + output, outputOffset, iv, in, + inOffset, inLen, aad); } } catch (BadPaddingException e) { throwAEADBadTagExceptionIfAvailable(e.getMessage(), e.getCause()); diff --git a/common/src/main/java/org/conscrypt/OpenSSLContextImpl.java b/common/src/main/java/org/conscrypt/OpenSSLContextImpl.java index 802506603..755d63cd8 100644 --- a/common/src/main/java/org/conscrypt/OpenSSLContextImpl.java +++ b/common/src/main/java/org/conscrypt/OpenSSLContextImpl.java @@ -67,6 +67,10 @@ public static OpenSSLContextImpl getPreferred() { serverSessionContext = new ServerSessionContext(); } + private OpenSSLContextImpl() throws GeneralSecurityException, IOException { + this(NativeCrypto.TLSV13_PROTOCOLS, true); + } + /** * Constructor for the DefaultSSLContextImpl. The unused boolean parameter is solely to * indicate that this constructor is desired. @@ -92,9 +96,10 @@ public static OpenSSLContextImpl getPreferred() { (ServerSessionContext) defaultSslContextImpl.engineGetServerSessionContext(); } - sslParameters = new SSLParametersImpl(defaultSslContextImpl.getKeyManagers(), - defaultSslContextImpl.getTrustManagers(), null, clientSessionContext, - serverSessionContext, protocols); + sslParameters = + new SSLParametersImpl(defaultSslContextImpl.getKeyManagers(), + defaultSslContextImpl.getTrustManagers(), null, + clientSessionContext, serverSessionContext, protocols); } } @@ -111,8 +116,8 @@ public static OpenSSLContextImpl getPreferred() { @Override public void engineInit(KeyManager[] kms, TrustManager[] tms, SecureRandom sr) throws KeyManagementException { - sslParameters = new SSLParametersImpl( - kms, tms, sr, clientSessionContext, serverSessionContext, protocols); + sslParameters = new SSLParametersImpl(kms, tms, sr, clientSessionContext, + serverSessionContext, protocols); } @Override diff --git a/common/src/main/java/org/conscrypt/OpenSSLProvider.java b/common/src/main/java/org/conscrypt/OpenSSLProvider.java index e3a158073..71fdc5cf0 100644 --- a/common/src/main/java/org/conscrypt/OpenSSLProvider.java +++ b/common/src/main/java/org/conscrypt/OpenSSLProvider.java @@ -52,18 +52,16 @@ public OpenSSLProvider() { @SuppressWarnings("deprecation") public OpenSSLProvider(String providerName) { this(providerName, Platform.provideTrustManagerByDefault(), "TLSv1.3", - Platform.isTlsV1Deprecated(), Platform.isTlsV1Supported()); + Platform.isTlsV1Deprecated(), Platform.isTlsV1Supported()); } - OpenSSLProvider(String providerName, boolean includeTrustManager, - String defaultTlsProtocol) { + OpenSSLProvider(String providerName, boolean includeTrustManager, String defaultTlsProtocol) { this(providerName, includeTrustManager, defaultTlsProtocol, Platform.isTlsV1Deprecated(), - Platform.isTlsV1Supported()); + Platform.isTlsV1Supported()); } - OpenSSLProvider(String providerName, boolean includeTrustManager, - String defaultTlsProtocol, boolean deprecatedTlsV1, - boolean enabledTlsV1) { + OpenSSLProvider(String providerName, boolean includeTrustManager, String defaultTlsProtocol, + boolean deprecatedTlsV1, boolean enabledTlsV1) { super(providerName, 1.0, "Android's OpenSSL-backed security provider"); // Ensure that the native library has been loaded. @@ -88,8 +86,8 @@ public OpenSSLProvider(String providerName) { defaultSSLContextSuffix = tls13SSLContextSuffix; break; default: - throw new IllegalArgumentException( - "Choice of default protocol is unsupported: " + defaultTlsProtocol); + throw new IllegalArgumentException("Choice of default protocol is unsupported: " + + defaultTlsProtocol); } // Keep SSL as an alias to TLS put("SSLContext.SSL", classOpenSSLContextImpl + defaultSSLContextSuffix); @@ -295,36 +293,30 @@ public OpenSSLProvider(String providerName) { put("Alg.Alias.Signature.SHA224/RSA", "SHA224withRSA"); put("Alg.Alias.Signature.1.2.840.113549.1.1.14", "SHA224withRSA"); put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.14", "SHA224withRSA"); - put("Alg.Alias.Signature.2.16.840.1.101.3.4.2.4with1.2.840.113549.1.1.1", - "SHA224withRSA"); - put("Alg.Alias.Signature.2.16.840.1.101.3.4.2.4with1.2.840.113549.1.1.14", - "SHA224withRSA"); + put("Alg.Alias.Signature.2.16.840.1.101.3.4.2.4with1.2.840.113549.1.1.1", "SHA224withRSA"); + put("Alg.Alias.Signature.2.16.840.1.101.3.4.2.4with1.2.840.113549.1.1.14", "SHA224withRSA"); putSignatureImplClass("SHA256withRSA", "OpenSSLSignature$SHA256RSA"); put("Alg.Alias.Signature.SHA256withRSAEncryption", "SHA256withRSA"); put("Alg.Alias.Signature.SHA256/RSA", "SHA256withRSA"); put("Alg.Alias.Signature.1.2.840.113549.1.1.11", "SHA256withRSA"); put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.11", "SHA256withRSA"); - put("Alg.Alias.Signature.2.16.840.1.101.3.4.2.1with1.2.840.113549.1.1.1", - "SHA256withRSA"); - put("Alg.Alias.Signature.2.16.840.1.101.3.4.2.1with1.2.840.113549.1.1.11", - "SHA256withRSA"); + put("Alg.Alias.Signature.2.16.840.1.101.3.4.2.1with1.2.840.113549.1.1.1", "SHA256withRSA"); + put("Alg.Alias.Signature.2.16.840.1.101.3.4.2.1with1.2.840.113549.1.1.11", "SHA256withRSA"); putSignatureImplClass("SHA384withRSA", "OpenSSLSignature$SHA384RSA"); put("Alg.Alias.Signature.SHA384withRSAEncryption", "SHA384withRSA"); put("Alg.Alias.Signature.SHA384/RSA", "SHA384withRSA"); put("Alg.Alias.Signature.1.2.840.113549.1.1.12", "SHA384withRSA"); put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.12", "SHA384withRSA"); - put("Alg.Alias.Signature.2.16.840.1.101.3.4.2.2with1.2.840.113549.1.1.1", - "SHA384withRSA"); + put("Alg.Alias.Signature.2.16.840.1.101.3.4.2.2with1.2.840.113549.1.1.1", "SHA384withRSA"); putSignatureImplClass("SHA512withRSA", "OpenSSLSignature$SHA512RSA"); put("Alg.Alias.Signature.SHA512withRSAEncryption", "SHA512withRSA"); put("Alg.Alias.Signature.SHA512/RSA", "SHA512withRSA"); put("Alg.Alias.Signature.1.2.840.113549.1.1.13", "SHA512withRSA"); put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.13", "SHA512withRSA"); - put("Alg.Alias.Signature.2.16.840.1.101.3.4.2.3with1.2.840.113549.1.1.1", - "SHA512withRSA"); + put("Alg.Alias.Signature.2.16.840.1.101.3.4.2.3with1.2.840.113549.1.1.1", "SHA512withRSA"); putRAWRSASignatureImplClass("OpenSSLSignatureRawRSA"); @@ -416,23 +408,23 @@ public OpenSSLProvider(String providerName) { put("Alg.Alias.Cipher.RSA/None/OAEPPadding", "RSA/ECB/OAEPPadding"); putRSACipherImplClass("RSA/ECB/OAEPWithSHA-1AndMGF1Padding", "OpenSSLCipherRSA$OAEP$SHA1"); put("Alg.Alias.Cipher.RSA/None/OAEPWithSHA-1AndMGF1Padding", - "RSA/ECB/OAEPWithSHA-1AndMGF1Padding"); - putRSACipherImplClass( - "RSA/ECB/OAEPWithSHA-224AndMGF1Padding", "OpenSSLCipherRSA$OAEP$SHA224"); + "RSA/ECB/OAEPWithSHA-1AndMGF1Padding"); + putRSACipherImplClass("RSA/ECB/OAEPWithSHA-224AndMGF1Padding", + "OpenSSLCipherRSA$OAEP$SHA224"); put("Alg.Alias.Cipher.RSA/None/OAEPWithSHA-224AndMGF1Padding", - "RSA/ECB/OAEPWithSHA-224AndMGF1Padding"); - putRSACipherImplClass( - "RSA/ECB/OAEPWithSHA-256AndMGF1Padding", "OpenSSLCipherRSA$OAEP$SHA256"); + "RSA/ECB/OAEPWithSHA-224AndMGF1Padding"); + putRSACipherImplClass("RSA/ECB/OAEPWithSHA-256AndMGF1Padding", + "OpenSSLCipherRSA$OAEP$SHA256"); put("Alg.Alias.Cipher.RSA/None/OAEPWithSHA-256AndMGF1Padding", - "RSA/ECB/OAEPWithSHA-256AndMGF1Padding"); - putRSACipherImplClass( - "RSA/ECB/OAEPWithSHA-384AndMGF1Padding", "OpenSSLCipherRSA$OAEP$SHA384"); + "RSA/ECB/OAEPWithSHA-256AndMGF1Padding"); + putRSACipherImplClass("RSA/ECB/OAEPWithSHA-384AndMGF1Padding", + "OpenSSLCipherRSA$OAEP$SHA384"); put("Alg.Alias.Cipher.RSA/None/OAEPWithSHA-384AndMGF1Padding", - "RSA/ECB/OAEPWithSHA-384AndMGF1Padding"); - putRSACipherImplClass( - "RSA/ECB/OAEPWithSHA-512AndMGF1Padding", "OpenSSLCipherRSA$OAEP$SHA512"); + "RSA/ECB/OAEPWithSHA-384AndMGF1Padding"); + putRSACipherImplClass("RSA/ECB/OAEPWithSHA-512AndMGF1Padding", + "OpenSSLCipherRSA$OAEP$SHA512"); put("Alg.Alias.Cipher.RSA/None/OAEPWithSHA-512AndMGF1Padding", - "RSA/ECB/OAEPWithSHA-512AndMGF1Padding"); + "RSA/ECB/OAEPWithSHA-512AndMGF1Padding"); /* * OpenSSL only supports a subset of modes, so we'll name them @@ -447,27 +439,25 @@ public OpenSSLProvider(String providerName) { * than 64 bits. We solve this confusion by making PKCS7Padding an * alias for PKCS5Padding. */ - putSymmetricCipherImplClass("AES/ECB/NoPadding", - "OpenSSLEvpCipherAES$AES$ECB$NoPadding"); + putSymmetricCipherImplClass("AES/ECB/NoPadding", "OpenSSLEvpCipherAES$AES$ECB$NoPadding"); putSymmetricCipherImplClass("AES/ECB/PKCS5Padding", - "OpenSSLEvpCipherAES$AES$ECB$PKCS5Padding"); + "OpenSSLEvpCipherAES$AES$ECB$PKCS5Padding"); put("Alg.Alias.Cipher.AES/ECB/PKCS7Padding", "AES/ECB/PKCS5Padding"); - putSymmetricCipherImplClass("AES/CBC/NoPadding", - "OpenSSLEvpCipherAES$AES$CBC$NoPadding"); + putSymmetricCipherImplClass("AES/CBC/NoPadding", "OpenSSLEvpCipherAES$AES$CBC$NoPadding"); putSymmetricCipherImplClass("AES/CBC/PKCS5Padding", - "OpenSSLEvpCipherAES$AES$CBC$PKCS5Padding"); + "OpenSSLEvpCipherAES$AES$CBC$PKCS5Padding"); put("Alg.Alias.Cipher.AES/CBC/PKCS7Padding", "AES/CBC/PKCS5Padding"); putSymmetricCipherImplClass("AES/CTR/NoPadding", "OpenSSLEvpCipherAES$AES$CTR"); - putSymmetricCipherImplClass( - "AES_128/ECB/NoPadding", "OpenSSLEvpCipherAES$AES_128$ECB$NoPadding"); - putSymmetricCipherImplClass( - "AES_128/ECB/PKCS5Padding", "OpenSSLEvpCipherAES$AES_128$ECB$PKCS5Padding"); + putSymmetricCipherImplClass("AES_128/ECB/NoPadding", + "OpenSSLEvpCipherAES$AES_128$ECB$NoPadding"); + putSymmetricCipherImplClass("AES_128/ECB/PKCS5Padding", + "OpenSSLEvpCipherAES$AES_128$ECB$PKCS5Padding"); put("Alg.Alias.Cipher.AES_128/ECB/PKCS7Padding", "AES_128/ECB/PKCS5Padding"); - putSymmetricCipherImplClass( - "AES_128/CBC/NoPadding", "OpenSSLEvpCipherAES$AES_128$CBC$NoPadding"); - putSymmetricCipherImplClass( - "AES_128/CBC/PKCS5Padding", "OpenSSLEvpCipherAES$AES_128$CBC$PKCS5Padding"); + putSymmetricCipherImplClass("AES_128/CBC/NoPadding", + "OpenSSLEvpCipherAES$AES_128$CBC$NoPadding"); + putSymmetricCipherImplClass("AES_128/CBC/PKCS5Padding", + "OpenSSLEvpCipherAES$AES_128$CBC$PKCS5Padding"); put("Alg.Alias.Cipher.AES_128/CBC/PKCS7Padding", "AES_128/CBC/PKCS5Padding"); put("Alg.Alias.Cipher.PBEWithHmacSHA1AndAES_128", "AES_128/CBC/PKCS5PADDING"); @@ -476,15 +466,15 @@ public OpenSSLProvider(String providerName) { put("Alg.Alias.Cipher.PBEWithHmacSHA384AndAES_128", "AES_128/CBC/PKCS5PADDING"); put("Alg.Alias.Cipher.PBEWithHmacSHA512AndAES_128", "AES_128/CBC/PKCS5PADDING"); - putSymmetricCipherImplClass( - "AES_256/ECB/NoPadding", "OpenSSLEvpCipherAES$AES_256$ECB$NoPadding"); - putSymmetricCipherImplClass( - "AES_256/ECB/PKCS5Padding", "OpenSSLEvpCipherAES$AES_256$ECB$PKCS5Padding"); + putSymmetricCipherImplClass("AES_256/ECB/NoPadding", + "OpenSSLEvpCipherAES$AES_256$ECB$NoPadding"); + putSymmetricCipherImplClass("AES_256/ECB/PKCS5Padding", + "OpenSSLEvpCipherAES$AES_256$ECB$PKCS5Padding"); put("Alg.Alias.Cipher.AES_256/ECB/PKCS7Padding", "AES_256/ECB/PKCS5Padding"); - putSymmetricCipherImplClass( - "AES_256/CBC/NoPadding", "OpenSSLEvpCipherAES$AES_256$CBC$NoPadding"); - putSymmetricCipherImplClass( - "AES_256/CBC/PKCS5Padding", "OpenSSLEvpCipherAES$AES_256$CBC$PKCS5Padding"); + putSymmetricCipherImplClass("AES_256/CBC/NoPadding", + "OpenSSLEvpCipherAES$AES_256$CBC$NoPadding"); + putSymmetricCipherImplClass("AES_256/CBC/PKCS5Padding", + "OpenSSLEvpCipherAES$AES_256$CBC$PKCS5Padding"); put("Alg.Alias.Cipher.AES_256/CBC/PKCS7Padding", "AES_256/CBC/PKCS5Padding"); put("Alg.Alias.Cipher.PBEWithHmacSHA1AndAES_256", "AES_256/CBC/PKCS5PADDING"); @@ -493,10 +483,9 @@ public OpenSSLProvider(String providerName) { put("Alg.Alias.Cipher.PBEWithHmacSHA384AndAES_256", "AES_256/CBC/PKCS5PADDING"); put("Alg.Alias.Cipher.PBEWithHmacSHA512AndAES_256", "AES_256/CBC/PKCS5PADDING"); - putSymmetricCipherImplClass("DESEDE/CBC/NoPadding", - "OpenSSLEvpCipherDESEDE$CBC$NoPadding"); + putSymmetricCipherImplClass("DESEDE/CBC/NoPadding", "OpenSSLEvpCipherDESEDE$CBC$NoPadding"); putSymmetricCipherImplClass("DESEDE/CBC/PKCS5Padding", - "OpenSSLEvpCipherDESEDE$CBC$PKCS5Padding"); + "OpenSSLEvpCipherDESEDE$CBC$PKCS5Padding"); put("Alg.Alias.Cipher.DESEDE/CBC/PKCS7Padding", "DESEDE/CBC/PKCS5Padding"); putSymmetricCipherImplClass("ARC4", "OpenSSLEvpCipherARC4"); @@ -510,21 +499,17 @@ public OpenSSLProvider(String providerName) { put("Alg.Alias.Cipher.2.16.840.1.101.3.4.1.6", "AES/GCM/NoPadding"); put("Alg.Alias.Cipher.2.16.840.1.101.3.4.1.26", "AES/GCM/NoPadding"); put("Alg.Alias.Cipher.2.16.840.1.101.3.4.1.46", "AES/GCM/NoPadding"); - putSymmetricCipherImplClass( - "AES_128/GCM/NoPadding", "OpenSSLAeadCipherAES$GCM$AES_128"); - putSymmetricCipherImplClass( - "AES_256/GCM/NoPadding", "OpenSSLAeadCipherAES$GCM$AES_256"); + putSymmetricCipherImplClass("AES_128/GCM/NoPadding", "OpenSSLAeadCipherAES$GCM$AES_128"); + putSymmetricCipherImplClass("AES_256/GCM/NoPadding", "OpenSSLAeadCipherAES$GCM$AES_256"); putSymmetricCipherImplClass("AES/GCM-SIV/NoPadding", "OpenSSLAeadCipherAES$GCM_SIV"); - putSymmetricCipherImplClass( - "AES_128/GCM-SIV/NoPadding", "OpenSSLAeadCipherAES$GCM_SIV$AES_128"); - putSymmetricCipherImplClass( - "AES_256/GCM-SIV/NoPadding", "OpenSSLAeadCipherAES$GCM_SIV$AES_256"); - - putSymmetricCipherImplClass("ChaCha20", - "OpenSSLCipherChaCha20"); - putSymmetricCipherImplClass("ChaCha20/Poly1305/NoPadding", - "OpenSSLAeadCipherChaCha20"); + putSymmetricCipherImplClass("AES_128/GCM-SIV/NoPadding", + "OpenSSLAeadCipherAES$GCM_SIV$AES_128"); + putSymmetricCipherImplClass("AES_256/GCM-SIV/NoPadding", + "OpenSSLAeadCipherAES$GCM_SIV$AES_256"); + + putSymmetricCipherImplClass("ChaCha20", "OpenSSLCipherChaCha20"); + putSymmetricCipherImplClass("ChaCha20/Poly1305/NoPadding", "OpenSSLAeadCipherChaCha20"); put("Alg.Alias.Cipher.ChaCha20-Poly1305", "ChaCha20/Poly1305/NoPadding"); /* === Mac === */ @@ -580,26 +565,29 @@ public OpenSSLProvider(String providerName) { put("Alg.Alias.CertificateFactory.X.509", "X509"); /* === HPKE === */ - String baseClass = classExists("android.crypto.hpke.HpkeSpi") - ? PREFIX + "AndroidHpkeSpi" - : PREFIX + "HpkeImpl"; + // BEGIN google3-changed: b/393827797 - This logic was only correct in the Android platform. + // String baseClass = classExists("android.crypto.hpke.HpkeSpi") + // ? PREFIX + "AndroidHpkeSpi" + // : PREFIX + "HpkeImpl"; + String baseClass = PREFIX + "HpkeImpl"; + // END google3-changed: b/393827797 - This logic was only correct in the Android platform. put("ConscryptHpke.DHKEM_X25519_HKDF_SHA256/HKDF_SHA256/AES_128_GCM", - baseClass + "$X25519_AES_128"); + baseClass + "$X25519_AES_128"); put("Alg.Alias.ConscryptHpke.DHKEM_X25519_HKDF_SHA256_HKDF_SHA256_AES_128_GCM", - "DHKEM_X25519_HKDF_SHA256/HKDF_SHA256/AES_128_GCM"); + "DHKEM_X25519_HKDF_SHA256/HKDF_SHA256/AES_128_GCM"); put("ConscryptHpke.DHKEM_X25519_HKDF_SHA256/HKDF_SHA256/AES_256_GCM", - baseClass + "$X25519_AES_256"); + baseClass + "$X25519_AES_256"); put("Alg.Alias.ConscryptHpke.DHKEM_X25519_HKDF_SHA256_HKDF_SHA256_AES_256_GCM", - "DHKEM_X25519_HKDF_SHA256/HKDF_SHA256/AES_256_GCM"); + "DHKEM_X25519_HKDF_SHA256/HKDF_SHA256/AES_256_GCM"); put("ConscryptHpke.DHKEM_X25519_HKDF_SHA256/HKDF_SHA256/CHACHA20POLY1305", - baseClass + "$X25519_CHACHA20"); + baseClass + "$X25519_CHACHA20"); put("Alg.Alias.ConscryptHpke.DHKEM_X25519_HKDF_SHA256_HKDF_SHA256_GhpkeCHACHA20POLY1305", - "DHKEM_X25519_HKDF_SHA256/HKDF_SHA256/CHACHA20POLY1305"); + "DHKEM_X25519_HKDF_SHA256/HKDF_SHA256/CHACHA20POLY1305"); put("ConscryptHpke.XWING/HKDF_SHA256/AES_128_GCM", baseClass + "$XwingHkdfSha256Aes128Gcm"); put("ConscryptHpke.XWING/HKDF_SHA256/AES_256_GCM", baseClass + "$XwingHkdfSha256Aes256Gcm"); put("ConscryptHpke.XWING/HKDF_SHA256/CHACHA20POLY1305", - baseClass + "$XwingHkdfSha256ChaCha20Poly1305"); + baseClass + "$XwingHkdfSha256ChaCha20Poly1305"); /* === PAKE === */ if (Platform.isPakeSupported()) { @@ -623,11 +611,8 @@ private void putMacImplClass(String algorithm, String className) { // * the key provides its key material in "RAW" encoding via Key.getEncoded. String supportedKeyClasses = PREFIX + "OpenSSLKeyHolder"; String supportedKeyFormats = "RAW"; - putImplClassWithKeyConstraints( - "Mac." + algorithm, - PREFIX + className, - supportedKeyClasses, - supportedKeyFormats); + putImplClassWithKeyConstraints("Mac." + algorithm, PREFIX + className, supportedKeyClasses, + supportedKeyFormats); } private void putSymmetricCipherImplClass(String transformation, String className) { @@ -635,11 +620,8 @@ private void putSymmetricCipherImplClass(String transformation, String className // * the key provides its key material in "RAW" encoding via Key.getEncoded. String supportedKeyClasses = null; // ignored -- filtered based on encoding format only String supportedKeyFormats = "RAW"; - putImplClassWithKeyConstraints( - "Cipher." + transformation, - PREFIX + className, - supportedKeyClasses, - supportedKeyFormats); + putImplClassWithKeyConstraints("Cipher." + transformation, PREFIX + className, + supportedKeyClasses, supportedKeyFormats); } private void putRSACipherImplClass(String transformation, String className) { @@ -647,15 +629,12 @@ private void putRSACipherImplClass(String transformation, String className) { // * the key is instance of OpenSSLRSAPrivateKey, RSAPrivateKey, OpenSSLRSAPublicKey, or // RSAPublicKey. String supportedKeyClasses = PREFIX + "OpenSSLRSAPrivateKey" - + "|" + STANDARD_RSA_PRIVATE_KEY_INTERFACE_CLASS_NAME - + "|" + PREFIX + "OpenSSLRSAPublicKey" + + "|" + STANDARD_RSA_PRIVATE_KEY_INTERFACE_CLASS_NAME + "|" + PREFIX + + "OpenSSLRSAPublicKey" + "|" + STANDARD_RSA_PUBLIC_KEY_INTERFACE_CLASS_NAME; String supportedKeyFormats = null; // ignored -- filtered based on class only - putImplClassWithKeyConstraints( - "Cipher." + transformation, - PREFIX + className, - supportedKeyClasses, - supportedKeyFormats); + putImplClassWithKeyConstraints("Cipher." + transformation, PREFIX + className, + supportedKeyClasses, supportedKeyFormats); } private void putSignatureImplClass(String algorithm, String className) { @@ -667,15 +646,12 @@ private void putSignatureImplClass(String algorithm, String className) { // transparent public keys -- it only accepts them if they provide their key material in // encoded form (see above). String supportedKeyClasses = PREFIX + "OpenSSLKeyHolder" - + "|" + STANDARD_RSA_PRIVATE_KEY_INTERFACE_CLASS_NAME - + "|" + STANDARD_EC_PRIVATE_KEY_INTERFACE_CLASS_NAME - + "|" + STANDARD_RSA_PUBLIC_KEY_INTERFACE_CLASS_NAME; + + "|" + STANDARD_RSA_PRIVATE_KEY_INTERFACE_CLASS_NAME + "|" + + STANDARD_EC_PRIVATE_KEY_INTERFACE_CLASS_NAME + "|" + + STANDARD_RSA_PUBLIC_KEY_INTERFACE_CLASS_NAME; String supportedKeyFormats = "PKCS#8|X.509"; - putImplClassWithKeyConstraints( - "Signature." + algorithm, - PREFIX + className, - supportedKeyClasses, - supportedKeyFormats); + putImplClassWithKeyConstraints("Signature." + algorithm, PREFIX + className, + supportedKeyClasses, supportedKeyFormats); } private void putRAWRSASignatureImplClass(String className) { @@ -683,15 +659,12 @@ private void putRAWRSASignatureImplClass(String className) { // * the key is instance of OpenSSLRSAPrivateKey, RSAPrivateKey, OpenSSLRSAPublicKey, or // RSAPublicKey. String supportedKeyClasses = PREFIX + "OpenSSLRSAPrivateKey" - + "|" + STANDARD_RSA_PRIVATE_KEY_INTERFACE_CLASS_NAME - + "|" + PREFIX + "OpenSSLRSAPublicKey" + + "|" + STANDARD_RSA_PRIVATE_KEY_INTERFACE_CLASS_NAME + "|" + PREFIX + + "OpenSSLRSAPublicKey" + "|" + STANDARD_RSA_PUBLIC_KEY_INTERFACE_CLASS_NAME; String supportedKeyFormats = null; // ignored -- filtered based on class only - putImplClassWithKeyConstraints( - "Signature.NONEwithRSA", - PREFIX + className, - supportedKeyClasses, - supportedKeyFormats); + putImplClassWithKeyConstraints("Signature.NONEwithRSA", PREFIX + className, + supportedKeyClasses, supportedKeyFormats); } private void putECDHKeyAgreementImplClass(String className) { @@ -702,11 +675,8 @@ private void putECDHKeyAgreementImplClass(String className) { String supportedKeyClasses = PREFIX + "OpenSSLKeyHolder" + "|" + STANDARD_EC_PRIVATE_KEY_INTERFACE_CLASS_NAME; String supportedKeyFormats = "PKCS#8"; - putImplClassWithKeyConstraints( - "KeyAgreement.ECDH", - PREFIX + className, - supportedKeyClasses, - supportedKeyFormats); + putImplClassWithKeyConstraints("KeyAgreement.ECDH", PREFIX + className, supportedKeyClasses, + supportedKeyFormats); } private void putXDHKeyAgreementImplClass(String className) { @@ -715,22 +685,19 @@ private void putXDHKeyAgreementImplClass(String className) { // * the key provides its key material in "PKCS#8" encoding via Key.getEncoded. // * the key is a transparent XEC private key (subclass of XECPrivateKey). String supportedKeyClasses = PREFIX + "OpenSSLKeyHolder" - + "|" + STANDARD_XEC_PRIVATE_KEY_INTERFACE_CLASS_NAME - + "|" + PREFIX + "OpenSSLX25519PrivateKey"; + + "|" + STANDARD_XEC_PRIVATE_KEY_INTERFACE_CLASS_NAME + "|" + PREFIX + + "OpenSSLX25519PrivateKey"; String supportedKeyFormats = "PKCS#8"; - putImplClassWithKeyConstraints( - "KeyAgreement.XDH", - PREFIX + className, - supportedKeyClasses, - supportedKeyFormats); + putImplClassWithKeyConstraints("KeyAgreement.XDH", PREFIX + className, supportedKeyClasses, + supportedKeyFormats); put("Alg.Alias.KeyAgreement.X25519", "XDH"); } private void putImplClassWithKeyConstraints(String typeAndAlgName, - String fullyQualifiedClassName, - String supportedKeyClasses, - String supportedKeyFormats) { + String fullyQualifiedClassName, + String supportedKeyClasses, + String supportedKeyFormats) { put(typeAndAlgName, fullyQualifiedClassName); if (supportedKeyClasses != null) { put(typeAndAlgName + " SupportedKeyClasses", supportedKeyClasses); diff --git a/common/src/main/java/org/conscrypt/OpenSSLSocketImpl.java b/common/src/main/java/org/conscrypt/OpenSSLSocketImpl.java index f0c2571e1..327f77e3c 100644 --- a/common/src/main/java/org/conscrypt/OpenSSLSocketImpl.java +++ b/common/src/main/java/org/conscrypt/OpenSSLSocketImpl.java @@ -22,6 +22,7 @@ import java.net.Socket; import java.net.SocketException; import java.security.PrivateKey; + import javax.net.ssl.SSLException; import javax.net.ssl.SSLSession; @@ -31,8 +32,7 @@ */ @Internal public abstract class OpenSSLSocketImpl extends AbstractConscryptSocket { - OpenSSLSocketImpl() throws IOException { - } + OpenSSLSocketImpl() throws IOException {} OpenSSLSocketImpl(String hostname, int port) throws IOException { super(hostname, port); @@ -43,18 +43,17 @@ public abstract class OpenSSLSocketImpl extends AbstractConscryptSocket { } OpenSSLSocketImpl(String hostname, int port, InetAddress clientAddress, int clientPort) - throws IOException { + throws IOException { super(hostname, port, clientAddress, clientPort); } - OpenSSLSocketImpl(InetAddress address, int port, InetAddress clientAddress, - int clientPort) - throws IOException { + OpenSSLSocketImpl(InetAddress address, int port, InetAddress clientAddress, int clientPort) + throws IOException { super(address, port, clientAddress, clientPort); } OpenSSLSocketImpl(Socket socket, String hostname, int port, boolean autoClose) - throws IOException { + throws IOException { super(socket, hostname, port, autoClose); } @@ -93,20 +92,17 @@ public void setHandshakeTimeout(int handshakeTimeoutMilliseconds) throws SocketE super.setHandshakeTimeout(handshakeTimeoutMilliseconds); } - @Override - public abstract SSLSession getHandshakeSession(); + @Override public abstract SSLSession getHandshakeSession(); - @Override - public abstract void setUseSessionTickets(boolean useSessionTickets); + @Override public abstract void setUseSessionTickets(boolean useSessionTickets); - @Override - public abstract void setChannelIdEnabled(boolean enabled); + @Override public abstract void setEchConfigList(byte[] echConfigList); - @Override - public abstract byte[] getChannelId() throws SSLException; + @Override public abstract void setChannelIdEnabled(boolean enabled); - @Override - public abstract void setChannelIdPrivateKey(PrivateKey privateKey); + @Override public abstract byte[] getChannelId() throws SSLException; + + @Override public abstract void setChannelIdPrivateKey(PrivateKey privateKey); /** * @deprecated NPN is not supported @@ -122,8 +118,7 @@ public final byte[] getNpnSelectedProtocol() { */ @Deprecated @SuppressWarnings("InlineMeSuggester") - public final void setNpnProtocols(byte[] npnProtocols) { - } + public final void setNpnProtocols(byte[] npnProtocols) {} /** * @deprecated use {@link #setApplicationProtocols(String[])} instead. @@ -149,7 +144,8 @@ public final byte[] getAlpnSelectedProtocol() { @Override @Deprecated public final void setAlpnProtocols(byte[] protocols) { - setApplicationProtocols(SSLUtils.decodeProtocols(protocols == null ? EmptyArray.BYTE : protocols)); + setApplicationProtocols( + SSLUtils.decodeProtocols(protocols == null ? EmptyArray.BYTE : protocols)); } @Override public abstract String getCurveNameForTesting(); diff --git a/common/src/main/java/org/conscrypt/OpenSSLX25519PrivateKey.java b/common/src/main/java/org/conscrypt/OpenSSLX25519PrivateKey.java index e816d2df0..af7bb7767 100644 --- a/common/src/main/java/org/conscrypt/OpenSSLX25519PrivateKey.java +++ b/common/src/main/java/org/conscrypt/OpenSSLX25519PrivateKey.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 The Android Open Source Project + * Copyright (C) 2022 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. @@ -29,19 +29,18 @@ public class OpenSSLX25519PrivateKey implements OpenSSLX25519Key, PrivateKey { private static final long serialVersionUID = -3136201500221850916L; - private static final byte[] PKCS8_PREAMBLE = new byte[]{ - 0x30, 0x2e, // Sequence: 46 bytes - 0x02, 0x01, 0x00, // Integer: 0 (version) - 0x30, 0x05, // Sequence: 5 bytes - 0x06, 0x03, 0x2b, 0x65, 0x6e, // OID: 1.3.101.110 (X25519) - 0x04, 0x22, 0x04, 0x20, // Octet string: 32 bytes + private static final byte[] PKCS8_PREAMBLE = new byte[] { + 0x30, 0x2e, // Sequence: 46 bytes + 0x02, 0x01, 0x00, // Integer: 0 (version) + 0x30, 0x05, // Sequence: 5 bytes + 0x06, 0x03, 0x2b, 0x65, 0x6e, // OID: 1.3.101.110 (X25519) + 0x04, 0x22, 0x04, 0x20, // Octet string: 32 bytes // Key bytes follow directly }; private byte[] uCoordinate; - public OpenSSLX25519PrivateKey(EncodedKeySpec keySpec) - throws InvalidKeySpecException { + public OpenSSLX25519PrivateKey(EncodedKeySpec keySpec) throws InvalidKeySpecException { byte[] encoded = keySpec.getEncoded(); if ("PKCS#8".equals(keySpec.getFormat())) { try { @@ -107,8 +106,10 @@ public boolean isDestroyed() { @Override public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof OpenSSLX25519PrivateKey)) return false; + if (this == o) + return true; + if (!(o instanceof OpenSSLX25519PrivateKey)) + return false; OpenSSLX25519PrivateKey that = (OpenSSLX25519PrivateKey) o; return Arrays.equals(uCoordinate, that.uCoordinate); } diff --git a/common/src/main/java/org/conscrypt/OpenSSLX25519PublicKey.java b/common/src/main/java/org/conscrypt/OpenSSLX25519PublicKey.java index 246ff64f0..ddeed1f51 100644 --- a/common/src/main/java/org/conscrypt/OpenSSLX25519PublicKey.java +++ b/common/src/main/java/org/conscrypt/OpenSSLX25519PublicKey.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 The Android Open Source Project + * Copyright (C) 2022 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. @@ -28,10 +28,10 @@ public class OpenSSLX25519PublicKey implements OpenSSLX25519Key, PublicKey { private static final long serialVersionUID = 453861992373478445L; private static final byte[] X509_PREAMBLE = new byte[] { - 0x30, 0x2a, // Sequence: 42 bytes - 0x30, 0x05, // Sequence: 5 bytes - 0x06, 0x03, 0x2b, 0x65, 0x6e, // OID: 1.3.101.110 (X25519) - 0x03, 0x21, 0x00, // Bit string: 256 bits + 0x30, 0x2a, // Sequence: 42 bytes + 0x30, 0x05, // Sequence: 5 bytes + 0x06, 0x03, 0x2b, 0x65, 0x6e, // OID: 1.3.101.110 (X25519) + 0x03, 0x21, 0x00, // Bit string: 256 bits // Key bytes follow directly }; @@ -98,8 +98,10 @@ public boolean equals(Object o) { throw new IllegalStateException("key is destroyed"); } - if (this == o) return true; - if (!(o instanceof OpenSSLX25519PublicKey)) return false; + if (this == o) + return true; + if (!(o instanceof OpenSSLX25519PublicKey)) + return false; OpenSSLX25519PublicKey that = (OpenSSLX25519PublicKey) o; return Arrays.equals(uCoordinate, that.uCoordinate); } diff --git a/common/src/main/java/org/conscrypt/OpenSSLX509CRLEntry.java b/common/src/main/java/org/conscrypt/OpenSSLX509CRLEntry.java index d798dafb6..b778e69a8 100644 --- a/common/src/main/java/org/conscrypt/OpenSSLX509CRLEntry.java +++ b/common/src/main/java/org/conscrypt/OpenSSLX509CRLEntry.java @@ -31,7 +31,7 @@ * An implementation of {@link X509CRLEntry} based on BoringSSL. */ final class OpenSSLX509CRLEntry extends X509CRLEntry { - private final long mContext; + private long mContext; private final Date revocationDate; OpenSSLX509CRLEntry(long ctx) throws ParsingException { @@ -53,10 +53,11 @@ public Set getCriticalExtensionOIDs() { * non-critical extensions. */ if ((critOids.length == 0) - && (NativeCrypto.get_X509_REVOKED_ext_oids( - mContext, NativeCrypto.EXTENSION_TYPE_NON_CRITICAL, this) - .length - == 0)) { + && (NativeCrypto + .get_X509_REVOKED_ext_oids(mContext, + NativeCrypto.EXTENSION_TYPE_NON_CRITICAL, this) + .length + == 0)) { return null; } @@ -79,10 +80,11 @@ public Set getNonCriticalExtensionOIDs() { * check critical extensions. */ if ((critOids.length == 0) - && (NativeCrypto.get_X509_REVOKED_ext_oids( - mContext, NativeCrypto.EXTENSION_TYPE_CRITICAL, this) - .length - == 0)) { + && (NativeCrypto + .get_X509_REVOKED_ext_oids(mContext, NativeCrypto.EXTENSION_TYPE_CRITICAL, + this) + .length + == 0)) { return null; } @@ -121,14 +123,16 @@ public Date getRevocationDate() { @Override public boolean hasExtensions() { - return (NativeCrypto.get_X509_REVOKED_ext_oids( - mContext, NativeCrypto.EXTENSION_TYPE_NON_CRITICAL, this) - .length - != 0) - || (NativeCrypto.get_X509_REVOKED_ext_oids( - mContext, NativeCrypto.EXTENSION_TYPE_CRITICAL, this) - .length - != 0); + return (NativeCrypto + .get_X509_REVOKED_ext_oids(mContext, + NativeCrypto.EXTENSION_TYPE_NON_CRITICAL, this) + .length + != 0) + || (NativeCrypto + .get_X509_REVOKED_ext_oids(mContext, + NativeCrypto.EXTENSION_TYPE_CRITICAL, this) + .length + != 0); } @Override diff --git a/common/src/main/java/org/conscrypt/OpenSslXwingKeyFactory.java b/common/src/main/java/org/conscrypt/OpenSslXwingKeyFactory.java index b8bdaa95e..4dcc801e8 100644 --- a/common/src/main/java/org/conscrypt/OpenSslXwingKeyFactory.java +++ b/common/src/main/java/org/conscrypt/OpenSslXwingKeyFactory.java @@ -40,8 +40,8 @@ protected PublicKey engineGeneratePublic(KeySpec keySpec) throws InvalidKeySpecE if (keySpec instanceof EncodedKeySpec) { return new OpenSslXwingPublicKey((EncodedKeySpec) keySpec); } - throw new InvalidKeySpecException( - "Currently only EncodedKeySpec is supported; was " + keySpec.getClass().getName()); + throw new InvalidKeySpecException("Currently only EncodedKeySpec is supported; was " + + keySpec.getClass().getName()); } @Override @@ -52,8 +52,8 @@ protected PrivateKey engineGeneratePrivate(KeySpec keySpec) throws InvalidKeySpe if (keySpec instanceof EncodedKeySpec) { return new OpenSslXwingPrivateKey((EncodedKeySpec) keySpec); } - throw new InvalidKeySpecException( - "Currently only EncodedKeySpec is supported; was " + keySpec.getClass().getName()); + throw new InvalidKeySpecException("Currently only EncodedKeySpec is supported; was " + + keySpec.getClass().getName()); } @Override @@ -65,32 +65,26 @@ protected T engineGetKeySpec(Key key, Class keySpec) if (keySpec == null) { throw new InvalidKeySpecException("keySpec == null"); } - try { - key = engineTranslateKey(key); - } catch (InvalidKeyException e) { - throw new InvalidKeySpecException("Unsupported key class: " + key.getClass(), e); - } if (key instanceof OpenSslXwingPublicKey) { OpenSslXwingPublicKey conscryptKey = (OpenSslXwingPublicKey) key; if (X509EncodedKeySpec.class.isAssignableFrom(keySpec)) { - @SuppressWarnings("unchecked") // safe because of isAssignableFrom check above - T result = (T) new X509EncodedKeySpec(key.getEncoded()); - return result; + throw new UnsupportedOperationException( + "X509EncodedKeySpec is currently not supported"); } else if (EncodedKeySpec.class.isAssignableFrom(keySpec)) { return KeySpecUtil.makeRawKeySpec(conscryptKey.getRaw(), keySpec); } } else if (key instanceof OpenSslXwingPrivateKey) { OpenSslXwingPrivateKey conscryptKey = (OpenSslXwingPrivateKey) key; if (PKCS8EncodedKeySpec.class.isAssignableFrom(keySpec)) { - @SuppressWarnings("unchecked") // safe because of isAssignableFrom check above - T result = (T) new PKCS8EncodedKeySpec(key.getEncoded()); - return result; + throw new UnsupportedOperationException( + "PKCS8EncodedKeySpec is currently not supported"); } else if (EncodedKeySpec.class.isAssignableFrom(keySpec)) { return KeySpecUtil.makeRawKeySpec(conscryptKey.getRaw(), keySpec); } } throw new InvalidKeySpecException("Unsupported key type and key spec combination; key=" - + key.getClass().getName() + ", keySpec=" + keySpec.getName()); + + key.getClass().getName() + + ", keySpec=" + keySpec.getName()); } @Override @@ -101,28 +95,7 @@ protected Key engineTranslateKey(Key key) throws InvalidKeyException { if ((key instanceof OpenSslXwingPublicKey) || (key instanceof OpenSslXwingPrivateKey)) { return key; } - if ((key instanceof PrivateKey) && key.getFormat().equals("PKCS#8")) { - byte[] encoded = key.getEncoded(); - if (encoded == null) { - throw new InvalidKeyException("Key does not support encoding"); - } - try { - return engineGeneratePrivate(new PKCS8EncodedKeySpec(encoded)); - } catch (InvalidKeySpecException e) { - throw new InvalidKeyException(e); - } - } else if ((key instanceof PublicKey) && key.getFormat().equals("X.509")) { - byte[] encoded = key.getEncoded(); - if (encoded == null) { - throw new InvalidKeyException("Key does not support encoding"); - } - try { - return engineGeneratePublic(new X509EncodedKeySpec(encoded)); - } catch (InvalidKeySpecException e) { - throw new InvalidKeyException(e); - } - } else { - throw new InvalidKeyException("Key is not a XWING key"); - } + throw new InvalidKeyException( + "Key must be OpenSslXwingPublicKey or OpenSslXwingPrivateKey"); } } diff --git a/common/src/main/java/org/conscrypt/OpenSslXwingPrivateKey.java b/common/src/main/java/org/conscrypt/OpenSslXwingPrivateKey.java index 059e12ebb..50693744c 100644 --- a/common/src/main/java/org/conscrypt/OpenSslXwingPrivateKey.java +++ b/common/src/main/java/org/conscrypt/OpenSslXwingPrivateKey.java @@ -30,47 +30,11 @@ public class OpenSslXwingPrivateKey implements PrivateKey { static final int PRIVATE_KEY_SIZE_BYTES = 32; - // The PKCS#8 encoding of a X-Wing private key is always the concatenation of a fixed - // prefix and the raw key. - private static final byte[] pkcs8Preamble = new byte[] { - 0x30, - 0x34, - 0x02, - 0x01, - 0x00, - 0x30, - 0x0d, - 0x06, - 0x0b, - 0x2b, - 0x06, - 0x01, - 0x04, - 0x01, - (byte) 0x83, - (byte) 0xe6, - 0x2d, - (byte) 0x81, - (byte) 0xc8, - (byte) 0x7a, - 0x04, - 0x20, - }; - private byte[] raw; public OpenSslXwingPrivateKey(EncodedKeySpec keySpec) throws InvalidKeySpecException { byte[] encoded = keySpec.getEncoded(); - if (keySpec.getFormat().equals("PKCS#8")) { - byte[] preamble = Arrays.copyOf(encoded, pkcs8Preamble.length); - if (!Arrays.equals(preamble, pkcs8Preamble)) { - throw new InvalidKeySpecException("Invalid X-Wing PKCS8 key preamble"); - } - raw = Arrays.copyOfRange(encoded, pkcs8Preamble.length, encoded.length); - if (raw.length != PRIVATE_KEY_SIZE_BYTES) { - throw new InvalidKeySpecException("Invalid key size"); - } - } else if (keySpec.getFormat().equalsIgnoreCase("raw")) { + if (keySpec.getFormat().equalsIgnoreCase("raw")) { if (encoded.length != PRIVATE_KEY_SIZE_BYTES) { throw new InvalidKeySpecException("Invalid key size"); } @@ -94,15 +58,12 @@ public String getAlgorithm() { @Override public String getFormat() { - return "PKCS#8"; + throw new UnsupportedOperationException("getFormat() not yet supported"); } @Override public byte[] getEncoded() { - if (raw == null) { - throw new IllegalStateException("key is destroyed"); - } - return ArrayUtils.concat(pkcs8Preamble, raw); + throw new UnsupportedOperationException("getEncoded() not yet supported"); } byte[] getRaw() { diff --git a/common/src/main/java/org/conscrypt/OpenSslXwingPublicKey.java b/common/src/main/java/org/conscrypt/OpenSslXwingPublicKey.java index bfd1b26e2..a7706bd34 100644 --- a/common/src/main/java/org/conscrypt/OpenSslXwingPublicKey.java +++ b/common/src/main/java/org/conscrypt/OpenSslXwingPublicKey.java @@ -29,48 +29,11 @@ public class OpenSslXwingPublicKey implements PublicKey { static final int PUBLIC_KEY_SIZE_BYTES = 1216; - // The X.509 encoding of a X-Wing public key is always the concatenation of a fixed - // prefix and the raw key. - private static final byte[] x509Preamble = new byte[] { - 0x30, - (byte) 0x82, - 0x04, - (byte) 0xd4, - 0x30, - 0x0d, - 0x06, - 0x0b, - 0x2b, - 0x06, - 0x01, - 0x04, - 0x01, - (byte) 0x83, - (byte) 0xe6, - 0x2d, - (byte) 0x81, - (byte) 0xc8, - (byte) 0x7a, - 0x03, - (byte) 0x82, - 0x04, - (byte) 0xc1, - 0x00, - }; - private final byte[] raw; public OpenSslXwingPublicKey(EncodedKeySpec keySpec) throws InvalidKeySpecException { byte[] encoded = keySpec.getEncoded(); - if (keySpec.getFormat().equals("X.509")) { - if (!ArrayUtils.startsWith(encoded, x509Preamble)) { - throw new InvalidKeySpecException("Invalid X-Wing X.509 key preamble"); - } - raw = Arrays.copyOfRange(encoded, x509Preamble.length, encoded.length); - if (raw.length != PUBLIC_KEY_SIZE_BYTES) { - throw new InvalidKeySpecException("Invalid key size"); - } - } else if (keySpec.getFormat().equalsIgnoreCase("raw")) { + if (keySpec.getFormat().equalsIgnoreCase("raw")) { if (encoded.length != PUBLIC_KEY_SIZE_BYTES) { throw new InvalidKeySpecException("Invalid key size"); } @@ -94,15 +57,12 @@ public String getAlgorithm() { @Override public String getFormat() { - return "X.509"; + throw new UnsupportedOperationException("getFormat() not yet supported"); } @Override public byte[] getEncoded() { - if (raw == null) { - throw new IllegalStateException("key is destroyed"); - } - return ArrayUtils.concat(x509Preamble, raw); + throw new UnsupportedOperationException("getEncoded() not yet supported"); } byte[] getRaw() { diff --git a/common/src/main/java/org/conscrypt/SSLParametersImpl.java b/common/src/main/java/org/conscrypt/SSLParametersImpl.java index f78b8691b..bc4c335ba 100644 --- a/common/src/main/java/org/conscrypt/SSLParametersImpl.java +++ b/common/src/main/java/org/conscrypt/SSLParametersImpl.java @@ -17,6 +17,8 @@ package org.conscrypt; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.security.AlgorithmConstraints; import java.security.KeyManagementException; import java.security.KeyStore; @@ -29,10 +31,13 @@ import java.util.Collection; import java.util.List; import java.util.Set; +import java.util.logging.Logger; + import javax.crypto.SecretKey; import javax.net.ssl.KeyManager; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SNIMatcher; +import javax.net.ssl.SSLException; import javax.net.ssl.TrustManager; import javax.net.ssl.TrustManagerFactory; import javax.net.ssl.X509KeyManager; @@ -48,6 +53,7 @@ * socket or not. */ final class SSLParametersImpl implements Cloneable { + private static final Logger logger = Logger.getLogger(SSLParametersImpl.class.getName()); // default source of X.509 certificate based authentication keys private static volatile X509KeyManager defaultX509KeyManager; @@ -73,6 +79,8 @@ final class SSLParametersImpl implements Cloneable { private final Spake2PlusTrustManager spake2PlusTrustManager; // source of Spake authentication or null if not provided private final Spake2PlusKeyManager spake2PlusKeyManager; + // getNetworkSecurityPolicy reflected method for x509TrustManager + private final Method getNetworkSecurityPolicy; // protocols enabled for SSL connection String[] enabledProtocols; @@ -109,6 +117,7 @@ final class SSLParametersImpl implements Cloneable { byte[] applicationProtocols = EmptyArray.BYTE; ApplicationProtocolSelectorAdapter applicationProtocolSelector; boolean useSessionTickets; + byte[] echConfigList; private Boolean useSni; /** @@ -125,9 +134,9 @@ final class SSLParametersImpl implements Cloneable { * See {@link javax.net.ssl.SSLContext#init(KeyManager[],TrustManager[], * SecureRandom)} for more information */ - SSLParametersImpl(KeyManager[] kms, TrustManager[] tms, - SecureRandom sr, ClientSessionContext clientSessionContext, - ServerSessionContext serverSessionContext, String[] protocols) + SSLParametersImpl(KeyManager[] kms, TrustManager[] tms, SecureRandom sr, + ClientSessionContext clientSessionContext, + ServerSessionContext serverSessionContext, String[] protocols) throws KeyManagementException { this.serverSessionContext = serverSessionContext; this.clientSessionContext = clientSessionContext; @@ -168,6 +177,8 @@ final class SSLParametersImpl implements Cloneable { "Spake2PlusTrustManager and Spake2PlusKeyManager should be set together"); } + getNetworkSecurityPolicy = getNetworkSecurityPolicyMethod(x509TrustManager); + // initialize the list of cipher suites and protocols enabled by default if (isSpake()) { enabledProtocols = new String[] {NativeCrypto.SUPPORTED_PROTOCOL_TLSV1_3}; @@ -175,13 +186,12 @@ final class SSLParametersImpl implements Cloneable { enabledProtocols = NativeCrypto.getDefaultProtocols().clone(); } else { String[] filteredProtocols = - filterFromProtocols(protocols, Arrays.asList(!Platform.isTlsV1Filtered() - ? new String[0] - : new String[] { + filterFromProtocols(protocols, Arrays.asList(Platform.isTlsV1Filtered() + ? new String[] { NativeCrypto.OBSOLETE_PROTOCOL_SSLV3, NativeCrypto.DEPRECATED_PROTOCOL_TLSV1, - NativeCrypto.DEPRECATED_PROTOCOL_TLSV1_1, - })); + NativeCrypto.DEPRECATED_PROTOCOL_TLSV1_1,} + : new String[0])); isEnabledProtocolsFiltered = protocols.length != filteredProtocols.length; enabledProtocols = NativeCrypto.checkEnabledProtocols(filteredProtocols).clone(); } @@ -201,15 +211,18 @@ final class SSLParametersImpl implements Cloneable { // Copy constructor for the purposes of changing the final fields @SuppressWarnings("deprecation") // for PSKKeyManager private SSLParametersImpl(ClientSessionContext clientSessionContext, - ServerSessionContext serverSessionContext, X509KeyManager x509KeyManager, - PSKKeyManager pskKeyManager, X509TrustManager x509TrustManager, - Spake2PlusTrustManager spake2PlusTrustManager, - Spake2PlusKeyManager spake2PlusKeyManager, SSLParametersImpl sslParams) { + ServerSessionContext serverSessionContext, + X509KeyManager x509KeyManager, PSKKeyManager pskKeyManager, + X509TrustManager x509TrustManager, + Spake2PlusTrustManager spake2PlusTrustManager, + Spake2PlusKeyManager spake2PlusKeyManager, + SSLParametersImpl sslParams) { this.clientSessionContext = clientSessionContext; this.serverSessionContext = serverSessionContext; this.x509KeyManager = x509KeyManager; this.pskKeyManager = pskKeyManager; this.x509TrustManager = x509TrustManager; + this.getNetworkSecurityPolicy = getNetworkSecurityPolicyMethod(x509TrustManager); this.spake2PlusKeyManager = spake2PlusKeyManager; this.spake2PlusTrustManager = spake2PlusTrustManager; @@ -235,6 +248,8 @@ private SSLParametersImpl(ClientSessionContext clientSessionContext, : sslParams.applicationProtocols.clone(); this.applicationProtocolSelector = sslParams.applicationProtocolSelector; this.useSessionTickets = sslParams.useSessionTickets; + this.echConfigList = + (sslParams.echConfigList == null) ? null : sslParams.echConfigList.clone(); this.useSni = sslParams.useSni; this.channelIdEnabled = sslParams.channelIdEnabled; } @@ -250,16 +265,23 @@ void initSpake() throws KeyManagementException { } } + private Method getNetworkSecurityPolicyMethod(X509TrustManager tm) { + if (tm == null) { + return null; + } + try { + return tm.getClass().getMethod("getNetworkSecurityPolicy"); + } catch (NoSuchMethodException ignored) { + return null; + } + } + static SSLParametersImpl getDefault() throws KeyManagementException { SSLParametersImpl result = defaultParameters; if (result == null) { // single-check idiom - defaultParameters = result = new SSLParametersImpl(null, - null, - null, - new ClientSessionContext(), - new ServerSessionContext(), - null); + defaultParameters = result = new SSLParametersImpl( + null, null, null, new ClientSessionContext(), new ServerSessionContext(), null); } return (SSLParametersImpl) result.clone(); } @@ -319,8 +341,8 @@ X509TrustManager getX509TrustManager() { */ String[] getEnabledCipherSuites() { if (Arrays.asList(enabledProtocols).contains(NativeCrypto.SUPPORTED_PROTOCOL_TLSV1_3)) { - return SSLUtils.concat( - NativeCrypto.SUPPORTED_TLS_1_3_CIPHER_SUITES, enabledCipherSuites); + return SSLUtils.concat(NativeCrypto.SUPPORTED_TLS_1_3_CIPHER_SUITES, + enabledCipherSuites); } return enabledCipherSuites.clone(); } @@ -332,9 +354,8 @@ void setEnabledCipherSuites(String[] cipherSuites) { // Filter out any TLS 1.3 cipher suites the user may have passed. Our TLS 1.3 suites // are always enabled, no matter what the user requests, so we only store the 1.0-1.2 // suites in enabledCipherSuites. - enabledCipherSuites = NativeCrypto.checkEnabledCipherSuites( - filterFromCipherSuites(cipherSuites, - NativeCrypto.SUPPORTED_TLS_1_3_CIPHER_SUITES_SET)); + enabledCipherSuites = NativeCrypto.checkEnabledCipherSuites(filterFromCipherSuites( + cipherSuites, NativeCrypto.SUPPORTED_TLS_1_3_CIPHER_SUITES_SET)); } /* @@ -353,14 +374,15 @@ void setEnabledProtocols(String[] protocols) { } else if (isSpake()) { return; } - String[] filteredProtocols = - filterFromProtocols(protocols, Arrays.asList(!Platform.isTlsV1Filtered() - ? new String[0] - : new String[] { - NativeCrypto.OBSOLETE_PROTOCOL_SSLV3, - NativeCrypto.DEPRECATED_PROTOCOL_TLSV1, - NativeCrypto.DEPRECATED_PROTOCOL_TLSV1_1, - })); + String[] filteredProtocols = filterFromProtocols( + protocols, + Arrays.asList(!Platform.isTlsV1Filtered() + ? new String[0] + : new String[] { + NativeCrypto.OBSOLETE_PROTOCOL_SSLV3, + NativeCrypto.DEPRECATED_PROTOCOL_TLSV1, + NativeCrypto.DEPRECATED_PROTOCOL_TLSV1_1, + })); isEnabledProtocolsFiltered = protocols.length != filteredProtocols.length; enabledProtocols = NativeCrypto.checkEnabledProtocols(filteredProtocols).clone(); } @@ -395,7 +417,8 @@ String[] getApplicationProtocols() { * Used for server-mode only. Sets or clears the application-provided ALPN protocol selector. * If set, will override the protocol list provided by setApplicationProtocols(String[]). */ - void setApplicationProtocolSelector(ApplicationProtocolSelectorAdapter applicationProtocolSelector) { + void setApplicationProtocolSelector( + ApplicationProtocolSelectorAdapter applicationProtocolSelector) { this.applicationProtocolSelector = applicationProtocolSelector; } @@ -475,6 +498,10 @@ void setUseSessionTickets(boolean useSessionTickets) { this.useSessionTickets = useSessionTickets; } + void setEchConfigList(byte[] echConfigList) { + this.echConfigList = echConfigList; + } + /* * Whether connections using this SSL connection should use the TLS * extension Server Name Indication (SNI). @@ -521,7 +548,7 @@ byte[] getOCSPResponse() { * to help with app compatibility. */ private static String[] filterFromProtocols(String[] protocols, - List obsoleteProtocols) { + List obsoleteProtocols) { if (protocols.length == 1 && obsoleteProtocols.contains(protocols[0])) { return EMPTY_STRING_ARRAY; } @@ -579,7 +606,7 @@ private boolean isSniEnabledByDefault() { */ interface AliasChooser { String chooseClientAlias(X509KeyManager keyManager, X500Principal[] issuers, - String[] keyTypes); + String[] keyTypes); String chooseServerAlias(X509KeyManager keyManager, String keyType); } @@ -610,12 +637,12 @@ protected Object clone() { SSLParametersImpl cloneWithTrustManager(X509TrustManager newTrustManager) { return new SSLParametersImpl(clientSessionContext, serverSessionContext, x509KeyManager, - pskKeyManager, newTrustManager, null, null, this); + pskKeyManager, newTrustManager, null, null, this); } SSLParametersImpl cloneWithSpake() { return new SSLParametersImpl(clientSessionContext, serverSessionContext, null, null, null, - spake2PlusTrustManager, spake2PlusKeyManager, this); + spake2PlusTrustManager, spake2PlusKeyManager, this); } private static X509KeyManager getDefaultX509KeyManager() throws KeyManagementException { @@ -635,7 +662,7 @@ private static X509KeyManager createDefaultX509KeyManager() throws KeyManagement X509KeyManager result = findFirstX509KeyManager(kms); if (result == null) { throw new KeyManagementException("No X509KeyManager among default KeyManagers: " - + Arrays.toString(kms)); + + Arrays.toString(kms)); } return result; } catch (NoSuchAlgorithmException e) { @@ -653,7 +680,7 @@ private static X509KeyManager createDefaultX509KeyManager() throws KeyManagement private static X509KeyManager findFirstX509KeyManager(KeyManager[] kms) { for (KeyManager km : kms) { if (km instanceof X509KeyManager) { - return (X509KeyManager)km; + return (X509KeyManager) km; } } return null; @@ -666,7 +693,7 @@ private static X509KeyManager findFirstX509KeyManager(KeyManager[] kms) { private static PSKKeyManager findFirstPSKKeyManager(KeyManager[] kms) { for (KeyManager km : kms) { if (km instanceof PSKKeyManager) { - return (PSKKeyManager)km; + return (PSKKeyManager) km; } else if (km != null) { try { return DuckTypedPSKKeyManager.getInstance(km); @@ -702,8 +729,7 @@ static X509TrustManager getDefaultX509TrustManager() throws KeyManagementExcepti return result; } - private static X509TrustManager createDefaultX509TrustManager() - throws KeyManagementException { + private static X509TrustManager createDefaultX509TrustManager() throws KeyManagementException { try { String algorithm = TrustManagerFactory.getDefaultAlgorithm(); TrustManagerFactory tmf = TrustManagerFactory.getInstance(algorithm); @@ -713,7 +739,7 @@ private static X509TrustManager createDefaultX509TrustManager() if (trustManager == null) { throw new KeyManagementException( "No X509TrustManager in among default TrustManagers: " - + Arrays.toString(tms)); + + Arrays.toString(tms)); } return trustManager; } catch (NoSuchAlgorithmException e) { @@ -783,7 +809,8 @@ void setUseCipherSuitesOrder(boolean useCipherSuitesOrder) { } private static String[] getDefaultCipherSuites(boolean x509CipherSuitesNeeded, - boolean pskCipherSuitesNeeded, boolean spake2PlusCipherSuitesNeeded) { + boolean pskCipherSuitesNeeded, + boolean spake2PlusCipherSuitesNeeded) { if (x509CipherSuitesNeeded) { // X.509 based cipher suites need to be listed. if (pskCipherSuitesNeeded) { @@ -805,17 +832,44 @@ private static String[] getDefaultCipherSuites(boolean x509CipherSuitesNeeded, } } else if (pskCipherSuitesNeeded) { // Only PSK cipher suites need to be listed. - return SSLUtils.concat( - NativeCrypto.DEFAULT_PSK_CIPHER_SUITES, - new String[] {NativeCrypto.TLS_EMPTY_RENEGOTIATION_INFO_SCSV}); + return SSLUtils.concat(NativeCrypto.DEFAULT_PSK_CIPHER_SUITES, + new String[] {NativeCrypto.TLS_EMPTY_RENEGOTIATION_INFO_SCSV}); } else { // Neither X.509 nor PSK cipher suites need to be listed. return new String[] {NativeCrypto.TLS_EMPTY_RENEGOTIATION_INFO_SCSV}; } } + private NetworkSecurityPolicy getPolicy() { + // If the TrustManager has a security policy attached, use it. We are using reflection here. + // The Android framework may provide a high-level TrustManager (e.g., RootTrustManager or + // NetworkSecurityTrustManager), which we need to query. + if (getNetworkSecurityPolicy != null) { + try { + Object objPolicy = getNetworkSecurityPolicy.invoke(x509TrustManager); + if (objPolicy instanceof NetworkSecurityPolicy) { + return (NetworkSecurityPolicy) objPolicy; + } + } catch (IllegalAccessException | IllegalArgumentException e) { + // This is the unlikely scenario where an external TrustManager is being used and it + // defines a getNetworkSecurityPolicy method which does not match our expectations. + logger.warning("Unable to call getNetworkSecurityPolicy on TrustManager: " + + e.getMessage()); + } catch (InvocationTargetException e) { + // getNetworkSecurityPolicy raised an exception. Unwrap it. + throw new RuntimeException( + "Unable to retrieve the NetworkSecurityPolicy associated " + + "with the TrustManager", + e.getCause()); + } + } + // Otherwise, rely on the global platform policy. + return ConscryptNetworkSecurityPolicy.getDefault(); + } + /* - * Checks whether SCT verification is enforced for a given hostname. + * Checks whether SCT verification is enforced for a given hostname. This + * will be used to decide if the TLS extension should be sent. */ boolean isCTVerificationEnabled(String hostname) { if (hostname == null) { @@ -826,7 +880,26 @@ boolean isCTVerificationEnabled(String hostname) { if (ctVerificationEnabled) { return true; } - return Platform.isCTVerificationRequired(hostname); + + return getPolicy().isCertificateTransparencyVerificationRequired(hostname); + } + + EchOptions getEchOptions(String hostname) throws SSLException { + switch (getPolicy().getDomainEncryptionMode(hostname)) { + case DISABLED: + return null; + case OPPORTUNISTIC: + return new EchOptions(echConfigList, /* enableGrease= */ false); + case ENABLED: + return new EchOptions(echConfigList, /* enableGrease= */ true); + case REQUIRED: + if (echConfigList == null) { + throw new SSLException("No ECH config provided when required"); + } + return new EchOptions(echConfigList, /* enableGrease= */ false); + default: + return null; + } } boolean isSpake() { diff --git a/common/src/main/java/org/conscrypt/ScryptSecretKeyFactory.java b/common/src/main/java/org/conscrypt/ScryptSecretKeyFactory.java index a58cfee38..87c5f0bb0 100644 --- a/common/src/main/java/org/conscrypt/ScryptSecretKeyFactory.java +++ b/common/src/main/java/org/conscrypt/ScryptSecretKeyFactory.java @@ -16,21 +16,20 @@ package org.conscrypt; +import java.io.UnsupportedEncodingException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; -import java.nio.charset.StandardCharsets; import java.security.InvalidKeyException; import java.security.spec.InvalidKeySpecException; import java.security.spec.KeySpec; + import javax.crypto.SecretKey; import javax.crypto.SecretKeyFactorySpi; @Internal public class ScryptSecretKeyFactory extends SecretKeyFactorySpi { - @Override protected SecretKey engineGenerateSecret(KeySpec inKeySpec) throws InvalidKeySpecException { - char[] password; byte[] salt; int n, r, p, keyOutputBits; @@ -62,10 +61,13 @@ protected SecretKey engineGenerateSecret(KeySpec inKeySpec) throws InvalidKeySpe throw new InvalidKeySpecException("Cannot produce fractional-byte outputs"); } - return new ScryptKey( - NativeCrypto.Scrypt_generate_key( - new String(password).getBytes(StandardCharsets.UTF_8), - salt, n, r, p, keyOutputBits / 8)); + try { + return new ScryptKey(NativeCrypto.Scrypt_generate_key( + new String(password).getBytes("UTF-8"), salt, n, r, p, keyOutputBits / 8)); + } catch (UnsupportedEncodingException e) { + // Impossible according to the Java docs: UTF-8 is always supported. + throw new IllegalStateException(e); + } } private Object getValue(KeySpec spec, String methodName) @@ -75,8 +77,8 @@ private Object getValue(KeySpec spec, String methodName) } @Override - protected KeySpec engineGetKeySpec( - SecretKey secretKey, @SuppressWarnings("rawtypes") Class aClass) + protected KeySpec engineGetKeySpec(SecretKey secretKey, + @SuppressWarnings("rawtypes") Class aClass) throws InvalidKeySpecException { if (secretKey == null) { throw new InvalidKeySpecException("Null KeySpec"); @@ -118,8 +120,6 @@ public byte[] getEncoded() { } private static class NotImplementedException extends RuntimeException { - private static final long serialVersionUID = -7755435858585859108L; - NotImplementedException() { super("Not implemented"); } diff --git a/common/src/main/java/org/conscrypt/TrustManagerImpl.java b/common/src/main/java/org/conscrypt/TrustManagerImpl.java index bedb2ce24..352e0a75a 100644 --- a/common/src/main/java/org/conscrypt/TrustManagerImpl.java +++ b/common/src/main/java/org/conscrypt/TrustManagerImpl.java @@ -61,6 +61,7 @@ import java.util.HashSet; import java.util.List; import java.util.Set; +import java.util.function.Supplier; import java.util.logging.Logger; import javax.net.ssl.HttpsURLConnection; @@ -72,14 +73,16 @@ /** * TrustManager implementation. The implementation is based on CertPathValidator - * PKIX and CertificateFactory X509 implementations. This implementations should + * PKIX and CertificateFactory X509 implementations. These implementations should * be provided by some certification provider. * * @see javax.net.ssl.X509ExtendedTrustManager + * @see org.conscrypt.ConscryptX509TrustManager */ @Internal @SuppressWarnings("CustomX509TrustManager") -public final class TrustManagerImpl extends X509ExtendedTrustManager { +public final class TrustManagerImpl + extends X509ExtendedTrustManager implements ConscryptX509TrustManager { private static final Logger logger = Logger.getLogger(TrustManagerImpl.class.getName()); /** @@ -88,8 +91,7 @@ public final class TrustManagerImpl extends X509ExtendedTrustManager { private static final TrustAnchorComparator TRUST_ANCHOR_COMPARATOR = new TrustAnchorComparator(); - private static final Set

* Throws {@link CertificateException} when no trusted chain can be found from {@code certs}. */ - public List getTrustedChainForServer(X509Certificate[] certs, - String authType, Socket socket) throws CertificateException { + public List getTrustedChainForServer(X509Certificate[] certs, String authType, + Socket socket) + throws CertificateException { SSLSession session = null; SSLParameters parameters = null; if (socket instanceof SSLSocket) { @@ -327,14 +355,15 @@ public List getTrustedChainForServer(X509Certificate[] certs, *

* Throws {@link CertificateException} when no trusted chain can be found from {@code certs}. */ - public List getTrustedChainForServer(X509Certificate[] certs, - String authType, SSLEngine engine) throws CertificateException { + public List getTrustedChainForServer(X509Certificate[] certs, String authType, + SSLEngine engine) + throws CertificateException { SSLSession session = engine.getHandshakeSession(); if (session == null) { throw new CertificateException("Not in handshake; no session available"); } return checkTrusted(certs, authType, session, engine.getSSLParameters(), - false /* client auth */); + false /* client auth */); } @Override @@ -356,7 +385,8 @@ public void checkServerTrusted(X509Certificate[] chain, String authType, SSLEngi * the certificates used for making the trust decision. */ public List checkServerTrusted(X509Certificate[] chain, String authType, - SSLSession session) throws CertificateException { + SSLSession session) + throws CertificateException { return checkTrusted(chain, authType, session, null, false /* client auth */); } @@ -369,8 +399,8 @@ public void handleTrustStorageUpdate() { } private List checkTrusted(X509Certificate[] certs, String authType, - SSLSession session, SSLParameters parameters, boolean clientAuth) - throws CertificateException { + SSLSession session, SSLParameters parameters, + boolean clientAuth) throws CertificateException { byte[] ocspData = null; byte[] tlsSctData = null; String hostname = null; @@ -407,8 +437,8 @@ private static byte[] getOcspDataFromSession(SSLSession session) { if (rawResponses instanceof List) { ocspResponses = (List) rawResponses; } - } catch (NoSuchMethodException | SecurityException - | IllegalAccessException | IllegalArgumentException ignored) { + } catch (NoSuchMethodException | SecurityException | IllegalAccessException + | IllegalArgumentException ignored) { // Method not available, fall through and return null } catch (InvocationTargetException e) { throw new RuntimeException(e.getCause()); @@ -437,8 +467,8 @@ private byte[] getTlsSctDataFromSession(SSLSession session) { if (rawData instanceof byte[]) { data = (byte[]) rawData; } - } catch (NoSuchMethodException | SecurityException - | IllegalAccessException | IllegalArgumentException ignored) { + } catch (NoSuchMethodException | SecurityException | IllegalAccessException + | IllegalArgumentException ignored) { // Method not available, fall through and return null } catch (InvocationTargetException e) { throw new RuntimeException(e.getCause()); @@ -447,8 +477,8 @@ private byte[] getTlsSctDataFromSession(SSLSession session) { } private List checkTrusted(X509Certificate[] certs, byte[] ocspData, - byte[] tlsSctData, String authType, String host, boolean clientAuth) - throws CertificateException { + byte[] tlsSctData, String authType, String host, + boolean clientAuth) throws CertificateException { if (certs == null || certs.length == 0 || authType == null || authType.isEmpty()) { throw new IllegalArgumentException("null or zero-length parameter"); } @@ -470,8 +500,8 @@ private List checkTrusted(X509Certificate[] certs, byte[] ocspD untrustedChain.add(leaf); } used.add(leaf); - return checkTrustedRecursive(certs, ocspData, tlsSctData, host, clientAuth, - untrustedChain, trustedChain, used); + return checkTrustedRecursive(certs, ocspData, tlsSctData, host, clientAuth, untrustedChain, + trustedChain, used); } /** @@ -498,9 +528,12 @@ private List checkTrusted(X509Certificate[] certs, byte[] ocspD * for trust decisions (e.g. showing the user a click through page based on the specific error). */ private List checkTrustedRecursive(X509Certificate[] certs, byte[] ocspData, - byte[] tlsSctData, String host, boolean clientAuth, - List untrustedChain, List trustAnchorChain, - Set used) throws CertificateException { + byte[] tlsSctData, String host, + boolean clientAuth, + List untrustedChain, + List trustAnchorChain, + Set used) + throws CertificateException { CertificateException lastException = null; X509Certificate current; if (trustAnchorChain.isEmpty()) { @@ -515,7 +548,7 @@ private List checkTrustedRecursive(X509Certificate[] certs, byt // 1. If the current certificate in the chain is self-signed verify the chain as is. if (current.getIssuerDN().equals(current.getSubjectDN())) { return verifyChain(untrustedChain, trustAnchorChain, host, clientAuth, ocspData, - tlsSctData); + tlsSctData); } // 2. Try building a chain via any trust anchors that issued the current certificate. @@ -536,7 +569,7 @@ private List checkTrustedRecursive(X509Certificate[] certs, byt trustAnchorChain.add(anchor); try { return checkTrustedRecursive(certs, ocspData, tlsSctData, host, clientAuth, - untrustedChain, trustAnchorChain, used); + untrustedChain, trustAnchorChain, used); } catch (CertificateException ex) { lastException = ex; } @@ -551,7 +584,7 @@ private List checkTrustedRecursive(X509Certificate[] certs, byt if (!trustAnchorChain.isEmpty()) { if (!seenIssuer) { return verifyChain(untrustedChain, trustAnchorChain, host, clientAuth, ocspData, - tlsSctData); + tlsSctData); } // Otherwise all chains based on the current trust anchor were rejected, fail. @@ -573,15 +606,17 @@ private List checkTrustedRecursive(X509Certificate[] certs, byt candidateIssuer.checkValidity(); ChainStrengthAnalyzer.checkCert(candidateIssuer); } catch (CertificateException ex) { - lastException = new CertificateException("Unacceptable certificate: " - + candidateIssuer.getSubjectX500Principal(), ex); + lastException = new CertificateException( + "Unacceptable certificate: " + + candidateIssuer.getSubjectX500Principal(), + ex); continue; } used.add(candidateIssuer); untrustedChain.add(candidateIssuer); try { return checkTrustedRecursive(certs, ocspData, tlsSctData, host, clientAuth, - untrustedChain, trustAnchorChain, used); + untrustedChain, trustAnchorChain, used); } catch (CertificateException ex) { lastException = ex; } @@ -604,7 +639,7 @@ private List checkTrustedRecursive(X509Certificate[] certs, byt untrustedChain.add(intermediateCert); try { return checkTrustedRecursive(certs, ocspData, tlsSctData, host, clientAuth, - untrustedChain, trustAnchorChain, used); + untrustedChain, trustAnchorChain, used); } catch (CertificateException ex) { lastException = ex; } @@ -626,13 +661,13 @@ private List checkTrustedRecursive(X509Certificate[] certs, byt } private List verifyChain(List untrustedChain, - List trustAnchorChain, String host, boolean clientAuth, byte[] ocspData, - byte[] tlsSctData) - throws CertificateException { + List trustAnchorChain, String host, + boolean clientAuth, byte[] ocspData, + byte[] tlsSctData) throws CertificateException { try { // build the cert path from the list of certs sans trust anchors - // TODO: check whether this is slow and should be replaced by a minimalistic CertPath impl - // since we already have built the path. + // TODO: check whether this is slow and should be replaced by a minimalistic CertPath + // impl since we already have built the path. CertPath certPath = factory.generateCertPath(untrustedChain); // Check that there are at least some trust anchors @@ -655,7 +690,8 @@ private List verifyChain(List untrustedChain, } // Check Certificate Transparency (if required). - if (!clientAuth && host != null && ct != null && ct.isCTVerificationRequired(host)) { + if (!clientAuth && host != null && ct != null + && policy.isCertificateTransparencyVerificationRequired(host)) { ct.checkCT(wholeChain, ocspData, tlsSctData, host); } @@ -711,8 +747,7 @@ private void setOcspResponses(PKIXParameters params, X509Certificate cert, byte[ } PKIXRevocationChecker revChecker = null; - List checkers = - new ArrayList<>(params.getCertPathCheckers()); + List checkers = new ArrayList<>(params.getCertPathCheckers()); for (PKIXCertPathChecker checker : checkers) { if (checker instanceof PKIXRevocationChecker) { revChecker = (PKIXRevocationChecker) checker; @@ -758,7 +793,6 @@ private static Collection sortPotentialAnchors(Set anc return sortedAnchors; } - /** * Comparator for sorting {@link TrustAnchor}s using a {@link CertificatePriorityComparator}. */ @@ -776,7 +810,7 @@ public int compare(TrustAnchor lhs, TrustAnchor rhs) { private static Set

- * This is a marker annotation and it has no specific attributes. - * @hide - */ -@Documented -@Retention(SOURCE) -@Target({FIELD, METHOD, PARAMETER, TYPE_USE}) -public @interface NonNull { - /** - * Min Android API level (inclusive) to which this annotation is applied. - */ - int from() default Integer.MIN_VALUE; - - /** - * Max Android API level to which this annotation is applied. - */ - int to() default Integer.MAX_VALUE; -} diff --git a/libcore-stub/src/main/java/libcore/util/Nullable.java b/libcore-stub/src/main/java/libcore/util/Nullable.java deleted file mode 100644 index 323fc1dc8..000000000 --- a/libcore-stub/src/main/java/libcore/util/Nullable.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (C) 2017 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 libcore.util; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.ElementType.TYPE_USE; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -/** - * Denotes that a type use can be a null. - *

- * This is a marker annotation and it has no specific attributes. - * @hide - */ -@Documented -@Retention(SOURCE) -@Target({FIELD, METHOD, PARAMETER, TYPE_USE}) -public @interface Nullable { - /** - * Min Android API level (inclusive) to which this annotation is applied. - */ - int from() default Integer.MIN_VALUE; - - /** - * Max Android API level to which this annotation is applied. - */ - int to() default Integer.MAX_VALUE; -} diff --git a/openjdk/build.gradle b/openjdk/build.gradle index b63b4c8de..c9b38d427 100644 --- a/openjdk/build.gradle +++ b/openjdk/build.gradle @@ -350,6 +350,15 @@ def testInterop = tasks.register("testInterop", Test) { } check.dependsOn testInterop +// Added to see results of new ECH tests when running tests from the command line +tasks.withType(Test).configureEach { + testLogging { + exceptionFormat "full" + events "started", "skipped", "passed", "failed" + showStandardStreams true + } +} + jacocoTestReport { additionalSourceDirs.from files("$rootDir/openjdk/src/test/java", "$rootDir/common/src/main/java") executionData tasks.withType(Test) @@ -415,7 +424,6 @@ model { if (toolChain in Clang || toolChain in Gcc) { cppCompiler.args "-Wall", - "-Werror", "-fPIC", "-O3", "-std=c++17", diff --git a/openjdk/src/main/java/org/conscrypt/ConscryptNetworkSecurityPolicy.java b/openjdk/src/main/java/org/conscrypt/ConscryptNetworkSecurityPolicy.java new file mode 100644 index 000000000..1e516c8fc --- /dev/null +++ b/openjdk/src/main/java/org/conscrypt/ConscryptNetworkSecurityPolicy.java @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2025 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 org.conscrypt.metrics.CertificateTransparencyVerificationReason; + +/** + * A default NetworkSecurityPolicy for OpenJDK. + */ +@Internal +public class ConscryptNetworkSecurityPolicy implements NetworkSecurityPolicy { + public static ConscryptNetworkSecurityPolicy getDefault() { + return new ConscryptNetworkSecurityPolicy(); + } + + @Override + public boolean isCertificateTransparencyVerificationRequired(String hostname) { + return false; + } + + @Override + public CertificateTransparencyVerificationReason getCertificateTransparencyVerificationReason( + String hostname) { + return CertificateTransparencyVerificationReason.UNKNOWN; + } + + @Override + public DomainEncryptionMode getDomainEncryptionMode(String hostname) { + return DomainEncryptionMode.UNKNOWN; + } +} diff --git a/openjdk/src/main/java/org/conscrypt/Platform.java b/openjdk/src/main/java/org/conscrypt/Platform.java index 1ca6f4958..4be4c871f 100644 --- a/openjdk/src/main/java/org/conscrypt/Platform.java +++ b/openjdk/src/main/java/org/conscrypt/Platform.java @@ -77,9 +77,11 @@ import java.util.List; import java.util.Locale; import java.util.Set; +import java.util.function.Supplier; import javax.crypto.spec.GCMParameterSpec; import javax.net.ssl.SSLEngine; +import javax.net.ssl.SSLException; import javax.net.ssl.SSLParameters; import javax.net.ssl.SSLSession; import javax.net.ssl.SSLSocketFactory; @@ -125,8 +127,7 @@ public static synchronized void setup(boolean deprecatedTlsV1, boolean enabledTl /** * Approximates the behavior of File.createTempFile without depending on SecureRandom. */ - static File createTempFile(String prefix, String suffix, File directory) - throws IOException { + static File createTempFile(String prefix, String suffix, File directory) throws IOException { if (directory == null) { throw new NullPointerException(); } @@ -247,18 +248,19 @@ static String getCurveName(ECParameterSpec spec) { @SuppressWarnings("unused") static void setCurveName(@SuppressWarnings("unused") ECParameterSpec spec, - @SuppressWarnings("unused") String curveName) { + @SuppressWarnings("unused") String curveName) { // This doesn't appear to be needed. } @SuppressWarnings("unused") static void setSocketWriteTimeout(@SuppressWarnings("unused") Socket s, - @SuppressWarnings("unused") long timeoutMillis) throws SocketException { + @SuppressWarnings("unused") long timeoutMillis) + throws SocketException { // TODO: figure this out on the RI } - static void setSSLParameters( - SSLParameters params, SSLParametersImpl impl, AbstractConscryptSocket socket) { + static void setSSLParameters(SSLParameters params, SSLParametersImpl impl, + AbstractConscryptSocket socket) { if (JAVA_VERSION >= 9) { Java9PlatformUtil.setSSLParameters(params, impl, socket); } else if (JAVA_VERSION >= 8) { @@ -268,8 +270,8 @@ static void setSSLParameters( } } - static void getSSLParameters( - SSLParameters params, SSLParametersImpl impl, AbstractConscryptSocket socket) { + static void getSSLParameters(SSLParameters params, SSLParametersImpl impl, + AbstractConscryptSocket socket) { if (JAVA_VERSION >= 9) { Java9PlatformUtil.getSSLParameters(params, impl, socket); } else if (JAVA_VERSION >= 8) { @@ -279,8 +281,8 @@ static void getSSLParameters( } } - static void setSSLParameters( - SSLParameters params, SSLParametersImpl impl, ConscryptEngine engine) { + static void setSSLParameters(SSLParameters params, SSLParametersImpl impl, + ConscryptEngine engine) { if (JAVA_VERSION >= 9) { Java9PlatformUtil.setSSLParameters(params, impl, engine); } else if (JAVA_VERSION >= 8) { @@ -290,8 +292,8 @@ static void setSSLParameters( } } - static void getSSLParameters( - SSLParameters params, SSLParametersImpl impl, ConscryptEngine engine) { + static void getSSLParameters(SSLParameters params, SSLParametersImpl impl, + ConscryptEngine engine) { if (JAVA_VERSION >= 9) { Java9PlatformUtil.getSSLParameters(params, impl, engine); } else if (JAVA_VERSION >= 8) { @@ -302,8 +304,8 @@ static void getSSLParameters( } @SuppressWarnings("unused") - static void setEndpointIdentificationAlgorithm( - SSLParameters params, String endpointIdentificationAlgorithm) { + static void setEndpointIdentificationAlgorithm(SSLParameters params, + String endpointIdentificationAlgorithm) { params.setEndpointIdentificationAlgorithm(endpointIdentificationAlgorithm); } @@ -314,7 +316,7 @@ static String getEndpointIdentificationAlgorithm(SSLParameters params) { @SuppressWarnings("unused") static void checkClientTrusted(X509TrustManager tm, X509Certificate[] chain, String authType, - AbstractConscryptSocket socket) throws CertificateException { + AbstractConscryptSocket socket) throws CertificateException { if (tm instanceof X509ExtendedTrustManager) { X509ExtendedTrustManager x509etm = (X509ExtendedTrustManager) tm; x509etm.checkClientTrusted(chain, authType, socket); @@ -325,7 +327,7 @@ static void checkClientTrusted(X509TrustManager tm, X509Certificate[] chain, Str @SuppressWarnings("unused") static void checkServerTrusted(X509TrustManager tm, X509Certificate[] chain, String authType, - AbstractConscryptSocket socket) throws CertificateException { + AbstractConscryptSocket socket) throws CertificateException { if (tm instanceof X509ExtendedTrustManager) { X509ExtendedTrustManager x509etm = (X509ExtendedTrustManager) tm; x509etm.checkServerTrusted(chain, authType, socket); @@ -336,7 +338,7 @@ static void checkServerTrusted(X509TrustManager tm, X509Certificate[] chain, Str @SuppressWarnings("unused") static void checkClientTrusted(X509TrustManager tm, X509Certificate[] chain, String authType, - ConscryptEngine engine) throws CertificateException { + ConscryptEngine engine) throws CertificateException { if (tm instanceof X509ExtendedTrustManager) { X509ExtendedTrustManager x509etm = (X509ExtendedTrustManager) tm; x509etm.checkClientTrusted(chain, authType, engine); @@ -347,7 +349,7 @@ static void checkClientTrusted(X509TrustManager tm, X509Certificate[] chain, Str @SuppressWarnings("unused") static void checkServerTrusted(X509TrustManager tm, X509Certificate[] chain, String authType, - ConscryptEngine engine) throws CertificateException { + ConscryptEngine engine) throws CertificateException { if (tm instanceof X509ExtendedTrustManager) { X509ExtendedTrustManager x509etm = (X509ExtendedTrustManager) tm; x509etm.checkServerTrusted(chain, authType, engine); @@ -387,7 +389,8 @@ static ConscryptEngineSocket createEngineSocket(SSLParametersImpl sslParameters) } static ConscryptEngineSocket createEngineSocket(String hostname, int port, - SSLParametersImpl sslParameters) throws IOException { + SSLParametersImpl sslParameters) + throws IOException { if (JAVA_VERSION >= 8) { return new Java8EngineSocket(hostname, port, sslParameters); } @@ -395,7 +398,8 @@ static ConscryptEngineSocket createEngineSocket(String hostname, int port, } static ConscryptEngineSocket createEngineSocket(InetAddress address, int port, - SSLParametersImpl sslParameters) throws IOException { + SSLParametersImpl sslParameters) + throws IOException { if (JAVA_VERSION >= 8) { return new Java8EngineSocket(address, port, sslParameters); } @@ -403,7 +407,8 @@ static ConscryptEngineSocket createEngineSocket(InetAddress address, int port, } static ConscryptEngineSocket createEngineSocket(String hostname, int port, - InetAddress clientAddress, int clientPort, SSLParametersImpl sslParameters) + InetAddress clientAddress, int clientPort, + SSLParametersImpl sslParameters) throws IOException { if (JAVA_VERSION >= 8) { return new Java8EngineSocket(hostname, port, clientAddress, clientPort, sslParameters); @@ -412,7 +417,8 @@ static ConscryptEngineSocket createEngineSocket(String hostname, int port, } static ConscryptEngineSocket createEngineSocket(InetAddress address, int port, - InetAddress clientAddress, int clientPort, SSLParametersImpl sslParameters) + InetAddress clientAddress, int clientPort, + SSLParametersImpl sslParameters) throws IOException { if (JAVA_VERSION >= 8) { return new Java8EngineSocket(address, port, clientAddress, clientPort, sslParameters); @@ -421,7 +427,9 @@ static ConscryptEngineSocket createEngineSocket(InetAddress address, int port, } static ConscryptEngineSocket createEngineSocket(Socket socket, String hostname, int port, - boolean autoClose, SSLParametersImpl sslParameters) throws IOException { + boolean autoClose, + SSLParametersImpl sslParameters) + throws IOException { if (JAVA_VERSION >= 8) { return new Java8EngineSocket(socket, hostname, port, autoClose, sslParameters); } @@ -437,7 +445,8 @@ static ConscryptFileDescriptorSocket createFileDescriptorSocket(SSLParametersImp } static ConscryptFileDescriptorSocket createFileDescriptorSocket(String hostname, int port, - SSLParametersImpl sslParameters) throws IOException { + SSLParametersImpl sslParameters) + throws IOException { if (JAVA_VERSION >= 8) { return new Java8FileDescriptorSocket(hostname, port, sslParameters); } @@ -445,7 +454,8 @@ static ConscryptFileDescriptorSocket createFileDescriptorSocket(String hostname, } static ConscryptFileDescriptorSocket createFileDescriptorSocket(InetAddress address, int port, - SSLParametersImpl sslParameters) throws IOException { + SSLParametersImpl sslParameters) + throws IOException { if (JAVA_VERSION >= 8) { return new Java8FileDescriptorSocket(address, port, sslParameters); } @@ -453,29 +463,35 @@ static ConscryptFileDescriptorSocket createFileDescriptorSocket(InetAddress addr } static ConscryptFileDescriptorSocket createFileDescriptorSocket(String hostname, int port, - InetAddress clientAddress, int clientPort, SSLParametersImpl sslParameters) + InetAddress clientAddress, + int clientPort, + SSLParametersImpl sslParameters) throws IOException { if (JAVA_VERSION >= 8) { - return new Java8FileDescriptorSocket( - hostname, port, clientAddress, clientPort, sslParameters); + return new Java8FileDescriptorSocket(hostname, port, clientAddress, clientPort, + sslParameters); } - return new ConscryptFileDescriptorSocket( - hostname, port, clientAddress, clientPort, sslParameters); + return new ConscryptFileDescriptorSocket(hostname, port, clientAddress, clientPort, + sslParameters); } static ConscryptFileDescriptorSocket createFileDescriptorSocket(InetAddress address, int port, - InetAddress clientAddress, int clientPort, SSLParametersImpl sslParameters) + InetAddress clientAddress, + int clientPort, + SSLParametersImpl sslParameters) throws IOException { if (JAVA_VERSION >= 8) { - return new Java8FileDescriptorSocket( - address, port, clientAddress, clientPort, sslParameters); + return new Java8FileDescriptorSocket(address, port, clientAddress, clientPort, + sslParameters); } - return new ConscryptFileDescriptorSocket( - address, port, clientAddress, clientPort, sslParameters); + return new ConscryptFileDescriptorSocket(address, port, clientAddress, clientPort, + sslParameters); } static ConscryptFileDescriptorSocket createFileDescriptorSocket(Socket socket, String hostname, - int port, boolean autoClose, SSLParametersImpl sslParameters) throws IOException { + int port, boolean autoClose, + SSLParametersImpl sslParameters) + throws IOException { if (JAVA_VERSION >= 8) { return new Java8FileDescriptorSocket(socket, hostname, port, autoClose, sslParameters); } @@ -532,7 +548,7 @@ static Object closeGuardGet() { @SuppressWarnings("unused") static void closeGuardOpen(@SuppressWarnings("unused") Object guardObj, - @SuppressWarnings("unused") String message) {} + @SuppressWarnings("unused") String message) {} @SuppressWarnings("unused") static void closeGuardClose(@SuppressWarnings("unused") Object guardObj) {} @@ -564,13 +580,13 @@ static String oidToAlgorithmName(String oid) { } catch (InvocationTargetException e) { Throwable cause = e.getCause(); if (cause instanceof RuntimeException) { - throw(RuntimeException) cause; + throw (RuntimeException) cause; } else if (cause instanceof Error) { - throw(Error) cause; + throw (Error) cause; } throw new RuntimeException(e); } catch (Exception ignored) { - //Ignored + // Ignored } return oid; } @@ -634,57 +650,8 @@ static boolean supportsX509ExtendedTrustManager() { return true; } - /** - * Check if SCT verification is required for a given hostname. - * - * SCT Verification is enabled using {@code Security} properties. - * The "conscrypt.ct.enable" property must be true, as well as a per domain property. - * The reverse notation of the domain name, prefixed with "conscrypt.ct.enforce." - * is used as the property name. - * Basic globbing is also supported. - * - * For example, for the domain foo.bar.com, the following properties will be - * looked up, in order of precedence. - * - conscrypt.ct.enforce.com.bar.foo - * - conscrypt.ct.enforce.com.bar.* - * - conscrypt.ct.enforce.com.* - * - conscrypt.ct.enforce.* - */ - public static boolean isCTVerificationRequired(String hostname) { - if (hostname == null) { - return false; - } - - String property = Security.getProperty("conscrypt.ct.enable"); - if (property == null || !Boolean.parseBoolean(property.toLowerCase(Locale.ROOT))) { - return false; - } - - List parts = Arrays.asList(hostname.split("\\.")); - Collections.reverse(parts); - - boolean enable = false; - StringBuilder propertyName = new StringBuilder("conscrypt.ct.enforce"); - // The loop keeps going on even once we've found a match - // This allows for finer grained settings on subdomains - for (String part : parts) { - property = Security.getProperty(propertyName + ".*"); - if (property != null) { - enable = Boolean.parseBoolean(property.toLowerCase(Locale.ROOT)); - } - propertyName.append(".").append(part); - } - - property = Security.getProperty(propertyName.toString()); - if (property != null) { - enable = Boolean.parseBoolean(property.toLowerCase(Locale.ROOT)); - } - return enable; - } - - public static CertificateTransparencyVerificationReason reasonCTVerificationRequired( - String hostname) { - return CertificateTransparencyVerificationReason.UNKNOWN; + static SSLException wrapInvalidEchDataException(SSLException e) { + return e; } static boolean supportsConscryptCertStore() { @@ -751,7 +718,8 @@ static CertBlocklist newDefaultBlocklist() { return null; } - static CertificateTransparency newDefaultCertificateTransparency() { + static CertificateTransparency newDefaultCertificateTransparency( + Supplier policySupplier) { return null; } @@ -823,7 +791,7 @@ public ClassLoader run() { } public static ConscryptHostnameVerifier getDefaultHostnameVerifier() { - return OkHostnameVerifier.strictInstance(); + return OkHostnameVerifier.strictInstance(); } @SuppressWarnings("unused") diff --git a/platform/src/main/ct_log_store.fbs b/platform/src/main/ct_log_store.fbs new file mode 100644 index 000000000..9a15f998a --- /dev/null +++ b/platform/src/main/ct_log_store.fbs @@ -0,0 +1,38 @@ +namespace com.android.org.conscrypt.ct.fbs; + +file_identifier "CTFB"; +file_extension "ctfb"; + +enum LogType:byte { + Unknown = 0, + Rfc6962 = 1, + Static = 2 +} + +enum LogState:byte { + Unknown = 0, + Pending = 1, + Qualified = 2, + Usable = 3, + Readonly = 4, + Retired = 5, + Rejected = 6 +} + +table Log { + log_id:string (key); + public_key:[byte]; + operator:string; + type:LogType; + state:LogState; + state_timestamp:long; +} + +table LogList { + version_major:long; + version_minor:long; + timestamp:long; + logs:[Log]; +} + +root_type LogList; diff --git a/platform/src/main/java/org/conscrypt/AndroidHpkeSpi.java b/platform/src/main/java/org/conscrypt/AndroidHpkeSpi.java index d54d57c88..e0d1a3827 100644 --- a/platform/src/main/java/org/conscrypt/AndroidHpkeSpi.java +++ b/platform/src/main/java/org/conscrypt/AndroidHpkeSpi.java @@ -37,51 +37,53 @@ public AndroidHpkeSpi(org.conscrypt.HpkeSpi delegate) { } @Override - public void engineInitSender(PublicKey recipientKey, @Nullable byte[] info, - PrivateKey senderKey, @Nullable byte[] psk, @Nullable byte[] psk_id) - throws InvalidKeyException { + public void engineInitSender(PublicKey recipientKey, byte @Nullable[] info, + PrivateKey senderKey, byte @Nullable[] psk, + byte @Nullable[] psk_id) throws InvalidKeyException { delegate.engineInitSender(recipientKey, info, senderKey, psk, psk_id); } @Override public void engineInitSenderForTesting(PublicKey recipientKey, byte[] info, - PrivateKey senderKey, byte[] psk, byte[] psk_id, byte[] sKe) - throws InvalidKeyException { + PrivateKey senderKey, byte[] psk, byte[] psk_id, + byte[] sKe) throws InvalidKeyException { delegate.engineInitSenderForTesting(recipientKey, info, senderKey, psk, psk_id, sKe); } @Override - public void engineInitSenderWithSeed(PublicKey recipientKey, @Nullable byte[] info, - PrivateKey senderKey, @Nullable byte[] psk, @Nullable byte[] psk_id, - @NonNull byte[] sKe) throws InvalidKeyException { + public void engineInitSenderWithSeed(PublicKey recipientKey, byte @Nullable[] info, + PrivateKey senderKey, byte @Nullable[] psk, + byte @Nullable[] psk_id, byte @NonNull[] sKe) + throws InvalidKeyException { delegate.engineInitSenderForTesting(recipientKey, info, senderKey, psk, psk_id, sKe); } @Override - public void engineInitRecipient(@NonNull byte[] encapsulated, PrivateKey recipientKey, - @Nullable byte[] info, PublicKey senderKey, @Nullable byte[] psk, - @Nullable byte[] psk_id) throws InvalidKeyException { + public void engineInitRecipient(byte @NonNull[] encapsulated, PrivateKey recipientKey, + byte @Nullable[] info, PublicKey senderKey, + byte @Nullable[] psk, byte @Nullable[] psk_id) + throws InvalidKeyException { delegate.engineInitRecipient(encapsulated, recipientKey, info, senderKey, psk, psk_id); } @Override - public @NonNull byte[] engineSeal(@NonNull byte[] plaintext, @Nullable byte[] aad) { + public byte @NonNull[] engineSeal(byte @NonNull[] plaintext, byte @Nullable[] aad) { return delegate.engineSeal(plaintext, aad); } @Override - public @NonNull byte[] engineOpen(@NonNull byte[] ciphertext, @Nullable byte[] aad) + public byte @NonNull[] engineOpen(byte @NonNull[] ciphertext, byte @Nullable[] aad) throws GeneralSecurityException { return delegate.engineOpen(ciphertext, aad); } @Override - public @NonNull byte[] engineExport(int length, @Nullable byte[] context) { + public byte @NonNull[] engineExport(int length, byte @Nullable[] context) { return delegate.engineExport(length, context); } @Override - public @NonNull byte[] getEncapsulated() { + public byte @NonNull[] getEncapsulated() { return delegate.getEncapsulated(); } @@ -102,4 +104,22 @@ public X25519_CHACHA20() { super(new HpkeImpl.X25519_CHACHA20()); } } + + public static class XwingHkdfSha256Aes128Gcm extends AndroidHpkeSpi { + public XwingHkdfSha256Aes128Gcm() { + super(new HpkeImpl.XwingHkdfSha256Aes128Gcm()); + } + } + + public static class XwingHkdfSha256Aes256Gcm extends AndroidHpkeSpi { + public XwingHkdfSha256Aes256Gcm() { + super(new HpkeImpl.XwingHkdfSha256Aes256Gcm()); + } + } + + public static class XwingHkdfSha256ChaCha20Poly1305 extends AndroidHpkeSpi { + public XwingHkdfSha256ChaCha20Poly1305() { + super(new HpkeImpl.XwingHkdfSha256ChaCha20Poly1305()); + } + } } diff --git a/platform/src/main/java/org/conscrypt/CertBlocklistImpl.java b/platform/src/main/java/org/conscrypt/CertBlocklistImpl.java index 305b74b86..963b94c9c 100644 --- a/platform/src/main/java/org/conscrypt/CertBlocklistImpl.java +++ b/platform/src/main/java/org/conscrypt/CertBlocklistImpl.java @@ -16,8 +16,13 @@ package org.conscrypt; +import static org.conscrypt.CertBlocklistEntry.Origin; + import static java.nio.charset.StandardCharsets.UTF_8; +import org.conscrypt.Platform; +import org.conscrypt.metrics.StatsLog; + import java.io.ByteArrayOutputStream; import java.io.Closeable; import java.io.FileNotFoundException; @@ -27,13 +32,12 @@ import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.PublicKey; -import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; +import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; -import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; @@ -41,11 +45,34 @@ @Internal public final class CertBlocklistImpl implements CertBlocklist { private static final Logger logger = Logger.getLogger(CertBlocklistImpl.class.getName()); + private static final String DIGEST_SHA1 = "SHA-1"; + private static final String DIGEST_SHA256 = "SHA-256"; + + private static class Entry implements CertBlocklistEntry { + private final Origin origin; + private final int index; + + public Entry(Origin origin, int index) { + this.origin = origin; + this.index = index; + } + + @Override + public Origin getOrigin() { + return origin; + } + + @Override + public int getIndex() { + return index; + } + } private final Set serialBlocklist; - private final Set sha1PubkeyBlocklist; - private final Set sha256PubkeyBlocklist; - private Map cache; + private final Map sha1PubkeyBlocklist; + private final Map sha256PubkeyBlocklist; + private final StatsLog metrics; + private Map> cache; /** * Number of entries in the cache. The cache contains public keys which are @@ -54,39 +81,83 @@ public final class CertBlocklistImpl implements CertBlocklist { */ private static final int CACHE_SIZE = 64; - /** - * public for testing only. - */ - public CertBlocklistImpl(Set serialBlocklist, Set sha1PubkeyBlocklist) { - this(serialBlocklist, sha1PubkeyBlocklist, Collections.emptySet()); - } - - public CertBlocklistImpl(Set serialBlocklist, Set sha1PubkeyBlocklist, - Set sha256PubkeyBlocklist) { - this.cache = Collections.synchronizedMap(new LinkedHashMap() { + private CertBlocklistImpl(Builder builder) { + this.cache = Collections.synchronizedMap(new LinkedHashMap>() { @Override - protected boolean removeEldestEntry(Map.Entry eldest) { + protected boolean removeEldestEntry( + Map.Entry> eldest) { return size() > CACHE_SIZE; } }); - this.serialBlocklist = serialBlocklist; - this.sha1PubkeyBlocklist = sha1PubkeyBlocklist; - this.sha256PubkeyBlocklist = sha256PubkeyBlocklist; + this.serialBlocklist = builder.serialBlocklist; + this.sha1PubkeyBlocklist = Collections.unmodifiableMap(builder.sha1PubkeyBlocklist); + this.sha256PubkeyBlocklist = Collections.unmodifiableMap(builder.sha256PubkeyBlocklist); + this.metrics = builder.metrics; + } + + public static class Builder { + private static String ANDROID_DATA = System.getenv("ANDROID_DATA"); + private static String BLOCKLIST_ROOT = ANDROID_DATA + "/misc/keychain/"; + private static String DEFAULT_PUBKEY_BLOCKLIST_PATH = + BLOCKLIST_ROOT + "pubkey_blacklist.txt"; + private static String DEFAULT_SERIAL_BLOCKLIST_PATH = + BLOCKLIST_ROOT + "serial_blacklist.txt"; + private static String DEFAULT_PUBKEY_SHA256_BLOCKLIST_PATH = + BLOCKLIST_ROOT + "pubkey_sha256_blocklist.txt"; + + private Set serialBlocklist; + private Map sha1PubkeyBlocklist; + private Map sha256PubkeyBlocklist; + private StatsLog metrics; + + public Builder setMetrics(StatsLog metrics) { + this.metrics = metrics; + return this; + } + + public Builder loadSha1Default() { + sha1PubkeyBlocklist = + readPublicKeyBlockList(DEFAULT_PUBKEY_BLOCKLIST_PATH, DIGEST_SHA1); + return this; + } + + public Builder loadSha256Default() { + sha256PubkeyBlocklist = + readPublicKeyBlockList(DEFAULT_PUBKEY_SHA256_BLOCKLIST_PATH, DIGEST_SHA256); + return this; + } + + public Builder loadSerialDefault() { + serialBlocklist = readSerialBlockList(DEFAULT_SERIAL_BLOCKLIST_PATH); + return this; + } + + public Builder loadAllDefaults() { + loadSha1Default(); + loadSha256Default(); + loadSerialDefault(); + return this; + } + + public CertBlocklistImpl build() { + if (sha1PubkeyBlocklist == null) { + sha1PubkeyBlocklist = Collections.emptyMap(); + } + if (sha256PubkeyBlocklist == null) { + sha256PubkeyBlocklist = Collections.emptyMap(); + } + if (serialBlocklist == null) { + serialBlocklist = Collections.emptySet(); + } + if (metrics == null) { + metrics = Platform.getStatsLog(); + } + return new CertBlocklistImpl(this); + } } - public static CertBlocklist getDefault() { - String androidData = System.getenv("ANDROID_DATA"); - String blocklistRoot = androidData + "/misc/keychain/"; - String defaultPubkeyBlocklistPath = blocklistRoot + "pubkey_blacklist.txt"; - String defaultSerialBlocklistPath = blocklistRoot + "serial_blacklist.txt"; - String defaultPubkeySha256BlocklistPath = blocklistRoot + "pubkey_sha256_blocklist.txt"; - - Set sha1PubkeyBlocklist = - readPublicKeyBlockList(defaultPubkeyBlocklistPath, "SHA-1"); - Set sha256PubkeyBlocklist = - readPublicKeyBlockList(defaultPubkeySha256BlocklistPath, "SHA-256"); - Set serialBlocklist = readSerialBlockList(defaultSerialBlocklistPath); - return new CertBlocklistImpl(serialBlocklist, sha1PubkeyBlocklist, sha256PubkeyBlocklist); + public static CertBlocklistImpl getDefault() { + return new Builder().loadAllDefaults().build(); } private static boolean isHex(String value) { @@ -164,11 +235,12 @@ private static Set readSerialBlockList(String path) { Set bl = new HashSet(); String serialBlocklist = readBlocklist(path); if (!serialBlocklist.equals("")) { - for (String value : serialBlocklist.split(",", -1)) { + for (String value : serialBlocklist.split(",", /* limit= */ -1)) { try { bl.add(new BigInteger(value, 16)); } catch (NumberFormatException e) { - logger.log(Level.WARNING, "Tried to blacklist invalid serial number " + value, e); + logger.log(Level.WARNING, "Tried to blacklist invalid serial number " + value, + e); } } } @@ -177,62 +249,51 @@ private static Set readSerialBlockList(String path) { return Collections.unmodifiableSet(bl); } - static final byte[][] SHA1_BUILTINS = { + // clang-format off + static final byte[] SHA1_TEST = { // Blocklist test cert for CTS. The cert and key can be found in // src/test/resources/blocklist_test_ca.pem and // src/test/resources/blocklist_test_ca_key.pem. - "bae78e6bed65a2bf60ddedde7fd91e825865e93d".getBytes(UTF_8), - // From - // http://src.chromium.org/viewvc/chrome/branches/782/src/net/base/x509_certificate.cc?r1=98750&r2=98749&pathrev=98750 - // C=NL, O=DigiNotar, CN=DigiNotar Root CA/emailAddress=info@diginotar.nl - "410f36363258f30b347d12ce4863e433437806a8".getBytes(UTF_8), - // Subject: CN=DigiNotar Cyber CA - // Issuer: CN=GTE CyberTrust Global Root - "ba3e7bd38cd7e1e6b9cd4c219962e59d7a2f4e37".getBytes(UTF_8), - // Subject: CN=DigiNotar Services 1024 CA - // Issuer: CN=Entrust.net - "e23b8d105f87710a68d9248050ebefc627be4ca6".getBytes(UTF_8), - // Subject: CN=DigiNotar PKIoverheid CA Organisatie - G2 - // Issuer: CN=Staat der Nederlanden Organisatie CA - G2 - "7b2e16bc39bcd72b456e9f055d1de615b74945db".getBytes(UTF_8), - // Subject: CN=DigiNotar PKIoverheid CA Overheid en Bedrijven - // Issuer: CN=Staat der Nederlanden Overheid CA - "e8f91200c65cee16e039b9f883841661635f81c5".getBytes(UTF_8), - // From http://src.chromium.org/viewvc/chrome?view=rev&revision=108479 - // Subject: O=Digicert Sdn. Bhd. - // Issuer: CN=GTE CyberTrust Global Root - "0129bcd5b448ae8d2496d1c3e19723919088e152".getBytes(UTF_8), - // Subject: CN=e-islem.kktcmerkezbankasi.org/emailAddress=ileti@kktcmerkezbankasi.org - // Issuer: CN=T\xC3\x9CRKTRUST Elektronik Sunucu Sertifikas\xC4\xB1 Hizmetleri - "5f3ab33d55007054bc5e3e5553cd8d8465d77c61".getBytes(UTF_8), - // Subject: CN=*.EGO.GOV.TR 93 - // Issuer: CN=T\xC3\x9CRKTRUST Elektronik Sunucu Sertifikas\xC4\xB1 Hizmetleri - "783333c9687df63377efceddd82efa9101913e8e".getBytes(UTF_8), - // Subject: Subject: C=FR, O=DG Tr\xC3\xA9sor, CN=AC DG Tr\xC3\xA9sor SSL - // Issuer: C=FR, O=DGTPE, CN=AC DGTPE Signature Authentification - "3ecf4bbbe46096d514bb539bb913d77aa4ef31bf".getBytes(UTF_8), + // bae78e6bed65a2bf60ddedde7fd91e825865e93d + (byte) 0xba, (byte) 0xe7, (byte) 0x8e, (byte) 0x6b, (byte) 0xed, + (byte) 0x65, (byte) 0xa2, (byte) 0xbf, (byte) 0x60, (byte) 0xdd, + (byte) 0xed, (byte) 0xde, (byte) 0x7f, (byte) 0xd9, (byte) 0x1e, + (byte) 0x82, (byte) 0x58, (byte) 0x65, (byte) 0xe9, (byte) 0x3d, }; - static final byte[][] SHA256_BUILTINS = { + static final byte[] SHA256_TEST = { // Blocklist test cert for CTS. The cert and key can be found in // src/test/resources/blocklist_test_ca2.pem and // src/test/resources/blocklist_test_ca2_key.pem. - "809964b15e9bd312993d9984045551f503f2cf8e68f39188921ba30fe623f9fd".getBytes(UTF_8), + // 809964b15e9bd312993d9984045551f503f2cf8e68f39188921ba30fe623f9fd + (byte) 0x80, (byte) 0x99, (byte) 0x64, (byte) 0xb1, (byte) 0x5e, + (byte) 0x9b, (byte) 0xd3, (byte) 0x12, (byte) 0x99, (byte) 0x3d, + (byte) 0x99, (byte) 0x84, (byte) 0x04, (byte) 0x55, (byte) 0x51, + (byte) 0xf5, (byte) 0x03, (byte) 0xf2, (byte) 0xcf, (byte) 0x8e, + (byte) 0x68, (byte) 0xf3, (byte) 0x91, (byte) 0x88, (byte) 0x92, + (byte) 0x1b, (byte) 0xa3, (byte) 0x0f, (byte) 0xe6, (byte) 0x23, + (byte) 0xf9, (byte) 0xfd, }; + // clang-format on - private static Set readPublicKeyBlockList(String path, String hashType) { - Set bl; + private static Map readPublicKeyBlockList(String path, String hashType) { + Map bl = new HashMap(); switch (hashType) { - case "SHA-1": - bl = new HashSet(toByteArrays(SHA1_BUILTINS)); + case DIGEST_SHA1: + bl.put(new ByteArray(SHA1_TEST), new Entry(Origin.SHA1_TEST, /* index= */ 0)); break; - case "SHA-256": - bl = new HashSet(toByteArrays(SHA256_BUILTINS)); + case DIGEST_SHA256: + bl.put(new ByteArray(SHA256_TEST), new Entry(Origin.SHA256_TEST, /* index= */ 0)); + // Blocklist statically included in Conscrypt. See constants/. + for (int i = 0; i < StaticBlocklist.PUBLIC_KEYS.length; i++) { + bl.put(new ByteArray(StaticBlocklist.PUBLIC_KEYS[i]), + new Entry(Origin.SHA256_BUILT_IN, /* index= */ i)); + } break; default: - throw new RuntimeException( - "Unknown hashType: " + hashType + ". Expected SHA-1 or SHA-256"); + throw new RuntimeException("Unknown hashType: " + hashType + + ". Expected SHA-1 or SHA-256"); } MessageDigest md; @@ -242,17 +303,21 @@ private static Set readPublicKeyBlockList(String path, String hashTyp logger.log(Level.SEVERE, "Unable to get " + hashType + " MessageDigest", e); return bl; } + // The hashes are encoded with hexadecimal values. There should be // twice as many characters as the digest length in bytes. int hashLength = md.getDigestLength() * 2; - // attempt to augment it with values taken from gservices + // Attempt to augment it with values taken from /data/misc/keychain. String pubkeyBlocklist = readBlocklist(path); + Origin origin = (DIGEST_SHA1.equals(hashType)) ? Origin.SHA1_FILE : Origin.SHA256_FILE; if (!pubkeyBlocklist.equals("")) { - for (String value : pubkeyBlocklist.split(",", -1)) { + String[] fileBlocklist = pubkeyBlocklist.split(",", /* limit= */ -1); + for (int i = 0; i < fileBlocklist.length; i++) { + String value = fileBlocklist[i]; value = value.trim(); if (isPubkeyHash(value, hashLength)) { - bl.add(new ByteArray(value.getBytes(UTF_8))); + bl.putIfAbsent(new ByteArray(Hex.decodeHex(value)), new Entry(origin, i)); } else { logger.log(Level.WARNING, "Tried to blocklist invalid pubkey " + value); } @@ -262,20 +327,17 @@ private static Set readPublicKeyBlockList(String path, String hashTyp return bl; } - private static boolean isPublicKeyBlockListed( - byte[] encodedPublicKey, Set blocklist, String hashType) { + private static Entry isPublicKeyBlockListed(byte[] encodedPublicKey, + Map blocklist, String hashType) { MessageDigest md; try { md = MessageDigest.getInstance(hashType); } catch (NoSuchAlgorithmException e) { logger.log(Level.SEVERE, "Unable to get " + hashType + " MessageDigest", e); - return false; + return null; } - ByteArray out = new ByteArray(toHex(md.digest(encodedPublicKey))); - if (blocklist.contains(out)) { - return true; - } - return false; + ByteArray out = new ByteArray(md.digest(encodedPublicKey)); + return blocklist.get(out); } @Override @@ -285,51 +347,38 @@ public boolean isPublicKeyBlockListed(PublicKey publicKey) { // for a Map, its underlying array (encodedPublicKey) should not be // modified. ByteArray cacheKey = new ByteArray(encodedPublicKey); - Boolean cachedResult = cache.get(cacheKey); + Optional cachedResult = cache.get(cacheKey); if (cachedResult != null) { - return cachedResult.booleanValue(); + if (cachedResult.isPresent()) { + metrics.reportBlocklistHit(cachedResult.get()); + return true; + } + return false; } if (!sha1PubkeyBlocklist.isEmpty()) { - if (isPublicKeyBlockListed(encodedPublicKey, sha1PubkeyBlocklist, "SHA-1")) { - cache.put(cacheKey, true); + Entry entry = + isPublicKeyBlockListed(encodedPublicKey, sha1PubkeyBlocklist, DIGEST_SHA1); + if (entry != null) { + cache.put(cacheKey, Optional.of(entry)); + metrics.reportBlocklistHit(entry); return true; } } if (!sha256PubkeyBlocklist.isEmpty()) { - if (isPublicKeyBlockListed(encodedPublicKey, sha256PubkeyBlocklist, "SHA-256")) { - cache.put(cacheKey, true); + Entry entry = + isPublicKeyBlockListed(encodedPublicKey, sha256PubkeyBlocklist, DIGEST_SHA256); + if (entry != null) { + cache.put(cacheKey, Optional.of(entry)); + metrics.reportBlocklistHit(entry); return true; } } - cache.put(cacheKey, false); + cache.put(cacheKey, Optional.empty()); return false; } - private static final byte[] HEX_TABLE = { (byte) '0', (byte) '1', (byte) '2', (byte) '3', - (byte) '4', (byte) '5', (byte) '6', (byte) '7', (byte) '8', (byte) '9', (byte) 'a', - (byte) 'b', (byte) 'c', (byte) 'd', (byte) 'e', (byte) 'f'}; - - private static byte[] toHex(byte[] in) { - byte[] out = new byte[in.length * 2]; - int outIndex = 0; - for (int i = 0; i < in.length; i++) { - int value = in[i] & 0xff; - out[outIndex++] = HEX_TABLE[value >> 4]; - out[outIndex++] = HEX_TABLE[value & 0xf]; - } - return out; - } - @Override public boolean isSerialNumberBlockListed(BigInteger serial) { return serialBlocklist.contains(serial); } - - private static List toByteArrays(byte[]... allBytes) { - List byteArrays = new ArrayList<>(allBytes.length + 1); - for (byte[] bytes : allBytes) { - byteArrays.add(new ByteArray(bytes)); - } - return byteArrays; - } } diff --git a/platform/src/main/java/org/conscrypt/ConscryptNetworkSecurityPolicy.java b/platform/src/main/java/org/conscrypt/ConscryptNetworkSecurityPolicy.java new file mode 100644 index 000000000..ff0f9a625 --- /dev/null +++ b/platform/src/main/java/org/conscrypt/ConscryptNetworkSecurityPolicy.java @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2025 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 org.conscrypt.metrics.CertificateTransparencyVerificationReason; + +/** + * ConscryptNetworkSecurityPolicy for the platform (mainline). + * + * The Conscrypt-internal interface NetworkSecurityPolicy is ignored when exporting the API. + */ +@SuppressWarnings("HiddenSuperclass") +public class ConscryptNetworkSecurityPolicy implements NetworkSecurityPolicy { + private final libcore.net.NetworkSecurityPolicy policy; + + public static ConscryptNetworkSecurityPolicy getDefault() { + return new ConscryptNetworkSecurityPolicy(libcore.net.NetworkSecurityPolicy.getInstance()); + } + + public ConscryptNetworkSecurityPolicy(libcore.net.NetworkSecurityPolicy policy) { + this.policy = policy; + } + + @Override + public boolean isCertificateTransparencyVerificationRequired(String hostname) { + return policy.isCertificateTransparencyVerificationRequired(hostname); + } + + @Override + public CertificateTransparencyVerificationReason getCertificateTransparencyVerificationReason( + String hostname) { + if (Platform.isSdkGreater(33) + && com.android.libcore.Flags.networkSecurityPolicyReasonCtEnabledApi()) { + CertificateTransparencyVerificationReason reason = plaformCtReasonToConscryptReason( + policy.getCertificateTransparencyVerificationReason(hostname)); + if (reason != CertificateTransparencyVerificationReason.UNKNOWN) { + return reason; + } + } + if (policy.isCertificateTransparencyVerificationRequired("")) { + return CertificateTransparencyVerificationReason.APP_OPT_IN; + } else if (policy.isCertificateTransparencyVerificationRequired(hostname)) { + return CertificateTransparencyVerificationReason.DOMAIN_OPT_IN; + } + return CertificateTransparencyVerificationReason.UNKNOWN; + } + + private static CertificateTransparencyVerificationReason plaformCtReasonToConscryptReason( + int platformReason) { + switch (platformReason) { + case libcore.net.NetworkSecurityPolicy.CERTIFICATE_TRANSPARENCY_REASON_APP_OPT_IN: + return CertificateTransparencyVerificationReason.APP_OPT_IN; + case libcore.net.NetworkSecurityPolicy.CERTIFICATE_TRANSPARENCY_REASON_DOMAIN_OPT_IN: + return CertificateTransparencyVerificationReason.DOMAIN_OPT_IN; + case libcore.net.NetworkSecurityPolicy + .CERTIFICATE_TRANSPARENCY_REASON_SDK_TARGET_DEFAULT_ENABLED: + return CertificateTransparencyVerificationReason.SDK_TARGET_DEFAULT_ENABLED; + default: + return CertificateTransparencyVerificationReason.UNKNOWN; + } + } + + @Override + public DomainEncryptionMode getDomainEncryptionMode(String hostname) { + // Domain encryption is enabled if it is supported by the platform AND + // the API is available in libcore. + if (org.conscrypt.net.flags.Flags.encryptedClientHelloPlatform() + && com.android.libcore.Flags.networkSecurityPolicyEchApi()) { + return platformToConscryptEncryptionMode(policy.getDomainEncryptionMode(hostname)); + } + return DomainEncryptionMode.UNKNOWN; + } + + private static DomainEncryptionMode platformToConscryptEncryptionMode(int platformMode) { + switch (platformMode) { + case libcore.net.NetworkSecurityPolicy.DOMAIN_ENCRYPTION_MODE_DISABLED: + return DomainEncryptionMode.DISABLED; + case libcore.net.NetworkSecurityPolicy.DOMAIN_ENCRYPTION_MODE_OPPORTUNISTIC: + return DomainEncryptionMode.OPPORTUNISTIC; + case libcore.net.NetworkSecurityPolicy.DOMAIN_ENCRYPTION_MODE_ENABLED: + return DomainEncryptionMode.ENABLED; + case libcore.net.NetworkSecurityPolicy.DOMAIN_ENCRYPTION_MODE_REQUIRED: + return DomainEncryptionMode.REQUIRED; + default: + return DomainEncryptionMode.UNKNOWN; + } + } +} diff --git a/platform/src/main/java/org/conscrypt/Hex.java b/platform/src/main/java/org/conscrypt/Hex.java index 54542680a..7cdfe0479 100644 --- a/platform/src/main/java/org/conscrypt/Hex.java +++ b/platform/src/main/java/org/conscrypt/Hex.java @@ -20,26 +20,14 @@ * Helper class for dealing with hexadecimal strings. */ @Internal -// public for testing by TrustedCertificateStoreTest -// TODO(nathanmittler): Move to InternalUtil? public final class Hex { private Hex() {} - private final static char[] DIGITS = { - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; - - public static String bytesToHexString(byte[] bytes) { - char[] buf = new char[bytes.length * 2]; - int c = 0; - for (byte b : bytes) { - buf[c++] = DIGITS[(b >> 4) & 0xf]; - buf[c++] = DIGITS[b & 0xf]; - } - return new String(buf); - } + private final static char[] DIGITS = {'0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; public static String intToHexString(int i, int minWidth) { - int bufLen = 8; // Max number of hex digits in an int + int bufLen = 8; // Max number of hex digits in an int char[] buf = new char[bufLen]; int cursor = bufLen; @@ -49,4 +37,33 @@ public static String intToHexString(int i, int minWidth) { return new String(buf, cursor, bufLen - cursor); } + + public static byte[] decodeHex(String encoded) throws IllegalArgumentException { + if ((encoded.length() % 2) != 0) { + throw new IllegalArgumentException("Invalid input length: " + encoded.length()); + } + + int resultLengthBytes = encoded.length() / 2; + byte[] result = new byte[resultLengthBytes]; + + int resultOffset = 0; + int i = 0; + for (int len = encoded.length(); i < len; i += 2) { + result[resultOffset++] = + (byte) ((toDigit(encoded.charAt(i)) << 4) | toDigit(encoded.charAt(i + 1))); + } + + return result; + } + + private static int toDigit(char pseudoCodePoint) throws IllegalArgumentException { + if ('0' <= pseudoCodePoint && pseudoCodePoint <= '9') { + return pseudoCodePoint - '0'; + } else if ('a' <= pseudoCodePoint && pseudoCodePoint <= 'f') { + return 10 + (pseudoCodePoint - 'a'); + } else if ('A' <= pseudoCodePoint && pseudoCodePoint <= 'F') { + return 10 + (pseudoCodePoint - 'A'); + } + throw new IllegalArgumentException("Illegal char: " + pseudoCodePoint); + } } diff --git a/platform/src/main/java/org/conscrypt/Platform.java b/platform/src/main/java/org/conscrypt/Platform.java index 638fc6b5d..67fd5e584 100644 --- a/platform/src/main/java/org/conscrypt/Platform.java +++ b/platform/src/main/java/org/conscrypt/Platform.java @@ -26,8 +26,7 @@ import dalvik.system.BlockGuard; import dalvik.system.CloseGuard; import dalvik.system.VMRuntime; - -import libcore.net.NetworkSecurityPolicy; +import dalvik.system.ZygoteHooks; import org.conscrypt.NativeCrypto; import org.conscrypt.ct.CertificateTransparency; @@ -37,12 +36,15 @@ import org.conscrypt.ct.PolicyImpl; import org.conscrypt.flags.Flags; import org.conscrypt.metrics.CertificateTransparencyVerificationReason; +import org.conscrypt.metrics.NoopStatsLog; import org.conscrypt.metrics.OptionalMethod; import org.conscrypt.metrics.Source; import org.conscrypt.metrics.StatsLog; import org.conscrypt.metrics.StatsLogImpl; +import java.io.BufferedReader; import java.io.FileDescriptor; +import java.io.FileReader; import java.io.IOException; import java.lang.System; import java.lang.reflect.Field; @@ -66,6 +68,7 @@ import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.function.Supplier; import javax.crypto.spec.GCMParameterSpec; import javax.net.ssl.HttpsURLConnection; @@ -73,6 +76,7 @@ import javax.net.ssl.SNIMatcher; import javax.net.ssl.SNIServerName; import javax.net.ssl.SSLEngine; +import javax.net.ssl.SSLException; import javax.net.ssl.SSLParameters; import javax.net.ssl.SSLSession; import javax.net.ssl.SSLSocketFactory; @@ -84,12 +88,19 @@ @Internal final public class Platform { - private static class NoPreloadHolder { public static final Platform MAPPER = new Platform(); } + private static class NoPreloadHolder { + public static final Platform MAPPER = new Platform(); + } private static boolean DEPRECATED_TLS_V1 = true; private static boolean ENABLED_TLS_V1 = false; private static boolean FILTERED_TLS_V1 = true; + private static boolean RUNNING_IN_ZYGOTE = true; + private static final boolean canProbeZygote; + private static final boolean canCallZygoteMethod; static { + canProbeZygote = isSdkGreater(32); + canCallZygoteMethod = isSdkGreater(36); NativeCrypto.setTlsV1DeprecationStatus(DEPRECATED_TLS_V1, ENABLED_TLS_V1); } @@ -102,6 +113,7 @@ public static synchronized void setup(boolean deprecatedTlsV1, boolean enabledTl FILTERED_TLS_V1 = !enabledTlsV1; NoPreloadHolder.MAPPER.ping(); NativeCrypto.setTlsV1DeprecationStatus(DEPRECATED_TLS_V1, ENABLED_TLS_V1); + RUNNING_IN_ZYGOTE = inZygote(); } /** @@ -162,15 +174,16 @@ static void setSocketWriteTimeout(Socket s, long timeoutMillis) throws SocketExc } } - static void setSSLParameters( - SSLParameters params, SSLParametersImpl impl, AbstractConscryptSocket socket) { + static void setSSLParameters(SSLParameters params, SSLParametersImpl impl, + AbstractConscryptSocket socket) { impl.setEndpointIdentificationAlgorithm(params.getEndpointIdentificationAlgorithm()); impl.setUseCipherSuitesOrder(params.getUseCipherSuitesOrder()); try { Method getNamedGroupsMethod = params.getClass().getMethod("getNamedGroups"); impl.setNamedGroups((String[]) getNamedGroupsMethod.invoke(params)); - } catch (NoSuchMethodException | IllegalArgumentException e) { + } catch (NoSuchMethodException | IllegalArgumentException | IllegalAccessException + | InvocationTargetException e) { // Do nothing. } @@ -186,8 +199,8 @@ static void setSSLParameters( impl.setApplicationProtocols(params.getApplicationProtocols()); } - static void getSSLParameters( - SSLParameters params, SSLParametersImpl impl, AbstractConscryptSocket socket) { + static void getSSLParameters(SSLParameters params, SSLParametersImpl impl, + AbstractConscryptSocket socket) { params.setEndpointIdentificationAlgorithm(impl.getEndpointIdentificationAlgorithm()); params.setUseCipherSuitesOrder(impl.getUseCipherSuitesOrder()); @@ -195,7 +208,8 @@ static void getSSLParameters( Method setNamedGroupsMethod = params.getClass().getMethod("setNamedGroups", String[].class); setNamedGroupsMethod.invoke(params, (Object) impl.getNamedGroups()); - } catch (NoSuchMethodException | IllegalArgumentException e) { + } catch (NoSuchMethodException | IllegalArgumentException | IllegalAccessException + | InvocationTargetException e) { // Do nothing. } @@ -206,17 +220,19 @@ static void getSSLParameters( params.setApplicationProtocols(impl.getApplicationProtocols()); } - static void setSSLParameters( - SSLParameters params, SSLParametersImpl impl, ConscryptEngine engine) { + static void setSSLParameters(SSLParameters params, SSLParametersImpl impl, + ConscryptEngine engine) { impl.setEndpointIdentificationAlgorithm(params.getEndpointIdentificationAlgorithm()); impl.setUseCipherSuitesOrder(params.getUseCipherSuitesOrder()); try { Method getNamedGroupsMethod = params.getClass().getMethod("getNamedGroups"); impl.setNamedGroups((String[]) getNamedGroupsMethod.invoke(params)); - } catch (NoSuchMethodException | IllegalArgumentException e) { + } catch (NoSuchMethodException | IllegalArgumentException | IllegalAccessException + | InvocationTargetException e) { // Do nothing. } + List serverNames = params.getServerNames(); if (serverNames != null) { for (SNIServerName serverName : serverNames) { @@ -229,8 +245,8 @@ static void setSSLParameters( impl.setApplicationProtocols(params.getApplicationProtocols()); } - static void getSSLParameters( - SSLParameters params, SSLParametersImpl impl, ConscryptEngine engine) { + static void getSSLParameters(SSLParameters params, SSLParametersImpl impl, + ConscryptEngine engine) { params.setEndpointIdentificationAlgorithm(impl.getEndpointIdentificationAlgorithm()); params.setUseCipherSuitesOrder(impl.getUseCipherSuitesOrder()); @@ -238,9 +254,11 @@ static void getSSLParameters( Method setNamedGroupsMethod = params.getClass().getMethod("setNamedGroups", String[].class); setNamedGroupsMethod.invoke(params, (Object) impl.getNamedGroups()); - } catch (NoSuchMethodException | IllegalArgumentException e) { + } catch (NoSuchMethodException | IllegalArgumentException | IllegalAccessException + | InvocationTargetException e) { // Do nothing. } + if (impl.getUseSni() && AddressUtils.isValidSniHostname(engine.getHostname())) { params.setServerNames(Collections.singletonList( new SNIHostName(engine.getHostname()))); @@ -253,18 +271,19 @@ static void getSSLParameters( * Socket, SSLEngine, or String (legacy Android). */ private static boolean checkTrusted(String methodName, X509TrustManager tm, - X509Certificate[] chain, String authType, Class argumentClass, - Object argumentInstance) throws CertificateException { + X509Certificate[] chain, String authType, + Class argumentClass, Object argumentInstance) + throws CertificateException { // Use duck-typing to try and call the hostname-aware method if available. try { - Method method = tm.getClass().getMethod( - methodName, X509Certificate[].class, String.class, argumentClass); + Method method = tm.getClass().getMethod(methodName, X509Certificate[].class, + String.class, argumentClass); method.invoke(tm, chain, authType, argumentInstance); return true; } catch (NoSuchMethodException | IllegalAccessException ignored) { } catch (InvocationTargetException e) { if (e.getCause() instanceof CertificateException) { - throw(CertificateException) e.getCause(); + throw (CertificateException) e.getCause(); } throw new RuntimeException(e.getCause()); } @@ -272,49 +291,49 @@ private static boolean checkTrusted(String methodName, X509TrustManager tm, } static void checkClientTrusted(X509TrustManager tm, X509Certificate[] chain, String authType, - AbstractConscryptSocket socket) throws CertificateException { + AbstractConscryptSocket socket) throws CertificateException { if (tm instanceof X509ExtendedTrustManager) { X509ExtendedTrustManager x509etm = (X509ExtendedTrustManager) tm; x509etm.checkClientTrusted(chain, authType, socket); } else if (!checkTrusted("checkClientTrusted", tm, chain, authType, Socket.class, socket) - && !checkTrusted("checkClientTrusted", tm, chain, authType, String.class, - socket.getHandshakeSession().getPeerHost())) { + && !checkTrusted("checkClientTrusted", tm, chain, authType, String.class, + socket.getHandshakeSession().getPeerHost())) { tm.checkClientTrusted(chain, authType); } } static void checkServerTrusted(X509TrustManager tm, X509Certificate[] chain, String authType, - AbstractConscryptSocket socket) throws CertificateException { + AbstractConscryptSocket socket) throws CertificateException { if (tm instanceof X509ExtendedTrustManager) { X509ExtendedTrustManager x509etm = (X509ExtendedTrustManager) tm; x509etm.checkServerTrusted(chain, authType, socket); } else if (!checkTrusted("checkServerTrusted", tm, chain, authType, Socket.class, socket) - && !checkTrusted("checkServerTrusted", tm, chain, authType, String.class, - socket.getHandshakeSession().getPeerHost())) { + && !checkTrusted("checkServerTrusted", tm, chain, authType, String.class, + socket.getHandshakeSession().getPeerHost())) { tm.checkServerTrusted(chain, authType); } } static void checkClientTrusted(X509TrustManager tm, X509Certificate[] chain, String authType, - ConscryptEngine engine) throws CertificateException { + ConscryptEngine engine) throws CertificateException { if (tm instanceof X509ExtendedTrustManager) { X509ExtendedTrustManager x509etm = (X509ExtendedTrustManager) tm; x509etm.checkClientTrusted(chain, authType, engine); } else if (!checkTrusted("checkClientTrusted", tm, chain, authType, SSLEngine.class, engine) - && !checkTrusted("checkClientTrusted", tm, chain, authType, String.class, - engine.getHandshakeSession().getPeerHost())) { + && !checkTrusted("checkClientTrusted", tm, chain, authType, String.class, + engine.getHandshakeSession().getPeerHost())) { tm.checkClientTrusted(chain, authType); } } static void checkServerTrusted(X509TrustManager tm, X509Certificate[] chain, String authType, - ConscryptEngine engine) throws CertificateException { + ConscryptEngine engine) throws CertificateException { if (tm instanceof X509ExtendedTrustManager) { X509ExtendedTrustManager x509etm = (X509ExtendedTrustManager) tm; x509etm.checkServerTrusted(chain, authType, engine); } else if (!checkTrusted("checkServerTrusted", tm, chain, authType, SSLEngine.class, engine) - && !checkTrusted("checkServerTrusted", tm, chain, authType, String.class, - engine.getHandshakeSession().getPeerHost())) { + && !checkTrusted("checkServerTrusted", tm, chain, authType, String.class, + engine.getHandshakeSession().getPeerHost())) { tm.checkServerTrusted(chain, authType); } } @@ -333,29 +352,35 @@ static ConscryptEngineSocket createEngineSocket(SSLParametersImpl sslParameters) } static ConscryptEngineSocket createEngineSocket(String hostname, int port, - SSLParametersImpl sslParameters) throws IOException { + SSLParametersImpl sslParameters) + throws IOException { return new Java8EngineSocket(hostname, port, sslParameters); } static ConscryptEngineSocket createEngineSocket(InetAddress address, int port, - SSLParametersImpl sslParameters) throws IOException { + SSLParametersImpl sslParameters) + throws IOException { return new Java8EngineSocket(address, port, sslParameters); } static ConscryptEngineSocket createEngineSocket(String hostname, int port, - InetAddress clientAddress, int clientPort, SSLParametersImpl sslParameters) + InetAddress clientAddress, int clientPort, + SSLParametersImpl sslParameters) throws IOException { return new Java8EngineSocket(hostname, port, clientAddress, clientPort, sslParameters); } static ConscryptEngineSocket createEngineSocket(InetAddress address, int port, - InetAddress clientAddress, int clientPort, SSLParametersImpl sslParameters) + InetAddress clientAddress, int clientPort, + SSLParametersImpl sslParameters) throws IOException { return new Java8EngineSocket(address, port, clientAddress, clientPort, sslParameters); } static ConscryptEngineSocket createEngineSocket(Socket socket, String hostname, int port, - boolean autoClose, SSLParametersImpl sslParameters) throws IOException { + boolean autoClose, + SSLParametersImpl sslParameters) + throws IOException { return new Java8EngineSocket(socket, hostname, port, autoClose, sslParameters); } @@ -365,31 +390,39 @@ static ConscryptFileDescriptorSocket createFileDescriptorSocket(SSLParametersImp } static ConscryptFileDescriptorSocket createFileDescriptorSocket(String hostname, int port, - SSLParametersImpl sslParameters) throws IOException { + SSLParametersImpl sslParameters) + throws IOException { return new Java8FileDescriptorSocket(hostname, port, sslParameters); } static ConscryptFileDescriptorSocket createFileDescriptorSocket(InetAddress address, int port, - SSLParametersImpl sslParameters) throws IOException { + SSLParametersImpl sslParameters) + throws IOException { return new Java8FileDescriptorSocket(address, port, sslParameters); } static ConscryptFileDescriptorSocket createFileDescriptorSocket(String hostname, int port, - InetAddress clientAddress, int clientPort, SSLParametersImpl sslParameters) + InetAddress clientAddress, + int clientPort, + SSLParametersImpl sslParameters) throws IOException { - return new Java8FileDescriptorSocket( - hostname, port, clientAddress, clientPort, sslParameters); + return new Java8FileDescriptorSocket(hostname, port, clientAddress, clientPort, + sslParameters); } static ConscryptFileDescriptorSocket createFileDescriptorSocket(InetAddress address, int port, - InetAddress clientAddress, int clientPort, SSLParametersImpl sslParameters) + InetAddress clientAddress, + int clientPort, + SSLParametersImpl sslParameters) throws IOException { - return new Java8FileDescriptorSocket( - address, port, clientAddress, clientPort, sslParameters); + return new Java8FileDescriptorSocket(address, port, clientAddress, clientPort, + sslParameters); } static ConscryptFileDescriptorSocket createFileDescriptorSocket(Socket socket, String hostname, - int port, boolean autoClose, SSLParametersImpl sslParameters) throws IOException { + int port, boolean autoClose, + SSLParametersImpl sslParameters) + throws IOException { return new Java8FileDescriptorSocket(socket, hostname, port, autoClose, sslParameters); } @@ -516,23 +549,8 @@ static boolean supportsX509ExtendedTrustManager() { return true; } - public static boolean isCTVerificationRequired(String hostname) { - if (Flags.certificateTransparencyPlatform()) { - return NetworkSecurityPolicy.getInstance() - .isCertificateTransparencyVerificationRequired(hostname); - } - return false; - } - - public static CertificateTransparencyVerificationReason reasonCTVerificationRequired( - String hostname) { - if (NetworkSecurityPolicy.getInstance().isCertificateTransparencyVerificationRequired("")) { - return CertificateTransparencyVerificationReason.APP_OPT_IN; - } else if (NetworkSecurityPolicy.getInstance() - .isCertificateTransparencyVerificationRequired(hostname)) { - return CertificateTransparencyVerificationReason.DOMAIN_OPT_IN; - } - return CertificateTransparencyVerificationReason.UNKNOWN; + static SSLException wrapInvalidEchDataException(SSLException e) { + return new android.net.ssl.InvalidEchDataException(e.getMessage()); } static boolean supportsConscryptCertStore() { @@ -557,11 +575,13 @@ static CertBlocklist newDefaultBlocklist() { return CertBlocklistImpl.getDefault(); } - static CertificateTransparency newDefaultCertificateTransparency() { + static CertificateTransparency newDefaultCertificateTransparency( + Supplier policySupplier) { org.conscrypt.ct.Policy policy = new org.conscrypt.ct.PolicyImpl(); org.conscrypt.ct.LogStore logStore = new org.conscrypt.ct.LogStoreImpl(policy); org.conscrypt.ct.Verifier verifier = new org.conscrypt.ct.Verifier(logStore); - return new CertificateTransparency(logStore, policy, verifier, getStatsLog()); + return new CertificateTransparency(logStore, policy, verifier, getStatsLog(), + policySupplier); } static boolean serverNamePermitted(SSLParametersImpl parameters, String serverName) { @@ -593,7 +613,14 @@ static long getMillisSinceBoot() { } public static StatsLog getStatsLog() { - return StatsLogImpl.getInstance(); + if (!RUNNING_IN_ZYGOTE) { + return StatsLogImpl.getInstance(); + } + if (!inZygote()) { + RUNNING_IN_ZYGOTE = false; + return StatsLogImpl.getInstance(); + } + return NoopStatsLog.getInstance(); } public static Source getStatsSource() { @@ -615,7 +642,7 @@ public static synchronized boolean isTlsV1Deprecated() { public static synchronized boolean isTlsV1Filtered() { Object targetSdkVersion = getTargetSdkVersion(); if ((targetSdkVersion != null) && ((int) targetSdkVersion > 35) - && ((int) targetSdkVersion < 100)) + && ((int) targetSdkVersion < 100)) return false; return FILTERED_TLS_V1; } @@ -628,16 +655,40 @@ public static boolean isPakeSupported() { return true; } + private static boolean inZygote() { + if (canCallZygoteMethod) { + return ZygoteHooks.isInZygote(); + } + if (canProbeZygote) { + try { + Class zygoteHooksClass = Class.forName("dalvik.system.ZygoteHooks"); + Method inZygoteMethod = zygoteHooksClass.getDeclaredMethod("inZygote"); + Object inZygote = inZygoteMethod.invoke(null); + if (inZygote == null) { + return true; + } + return (boolean) inZygote; + } catch (IllegalAccessException | NullPointerException | InvocationTargetException + | ClassNotFoundException | NoSuchMethodException e) { + return true; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + // For previous releases, we have no mechanism to test if we are in Zygote. + // Assume we are not, to conserve the existing behaviour. + return false; + } + static Object getTargetSdkVersion() { try { Class vmRuntimeClass = Class.forName("dalvik.system.VMRuntime"); Method getRuntimeMethod = vmRuntimeClass.getDeclaredMethod("getRuntime"); Method getTargetSdkVersionMethod = - vmRuntimeClass.getDeclaredMethod("getTargetSdkVersion"); + vmRuntimeClass.getDeclaredMethod("getTargetSdkVersion"); Object vmRuntime = getRuntimeMethod.invoke(null); return getTargetSdkVersionMethod.invoke(vmRuntime); - } catch (IllegalAccessException | - NullPointerException | InvocationTargetException e) { + } catch (IllegalAccessException | NullPointerException | InvocationTargetException e) { return null; } catch (Exception e) { throw new RuntimeException(e); @@ -653,7 +704,7 @@ public static boolean isSdkGreater(int sdk) { Object sdkVersion = getSdkVersionMethod.invoke(vmRuntime); return (sdkVersion != null) && ((int) sdkVersion > sdk); } catch (IllegalAccessException | NullPointerException | InvocationTargetException - | NoSuchMethodException e) { + | NoSuchMethodException e) { return false; } catch (Exception e) { throw new RuntimeException(e); diff --git a/platform/src/main/java/org/conscrypt/ct/LogStoreImpl.java b/platform/src/main/java/org/conscrypt/ct/LogStoreImpl.java index fc875e907..e18c3ef3b 100644 --- a/platform/src/main/java/org/conscrypt/ct/LogStoreImpl.java +++ b/platform/src/main/java/org/conscrypt/ct/LogStoreImpl.java @@ -37,32 +37,29 @@ import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.security.PublicKey; -import java.text.DateFormat; -import java.text.ParseException; -import java.text.SimpleDateFormat; import java.util.Arrays; import java.util.Base64; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.Map; +import java.util.function.Supplier; import java.util.logging.Level; import java.util.logging.Logger; @Internal public class LogStoreImpl implements LogStore { private static final Logger logger = Logger.getLogger(LogStoreImpl.class.getName()); - private static final String BASE_PATH = "misc/keychain/ct"; - private static final int COMPAT_VERSION = 1; - private static final String CURRENT = "current"; - private static final String LOG_LIST_FILENAME = "log_list.json"; - private static final Path DEFAULT_LOG_LIST; + private static final int COMPAT_VERSION = 2; + private static final Path logListPrefix; + private static final Path logListSuffix; + private static final long LOG_LIST_CHECK_INTERVAL_IN_MS = 10L * 60 * 1_000; // 10 minutes static { String androidData = System.getenv("ANDROID_DATA"); - String compatVersion = String.format("v%d", COMPAT_VERSION); - DEFAULT_LOG_LIST = - Paths.get(androidData, BASE_PATH, compatVersion, CURRENT, LOG_LIST_FILENAME); + // /data/misc/keychain/ct/v1/current/log_list.json + logListPrefix = Paths.get(androidData, "misc", "keychain", "ct"); + logListSuffix = Paths.get("current", "log_list.json"); } private final Path logList; @@ -73,20 +70,34 @@ public class LogStoreImpl implements LogStore { private int minorVersion; private long timestamp; private Map logs; + private long logListLastModified; + private Supplier clock; + private long logListLastChecked; - public LogStoreImpl(Policy policy) { - this(policy, DEFAULT_LOG_LIST); + /* We do not have access to InstantSource. Implement a similar pattern using Supplier. */ + static class SystemTimeSupplier implements Supplier { + @Override + public Long get() { + return System.currentTimeMillis(); + } } - public LogStoreImpl(Policy policy, Path logList) { - this(policy, logList, Platform.getStatsLog()); + private static Path getPathForCompatVersion(int compatVersion) { + String version = String.format("v%d", compatVersion); + return logListPrefix.resolve(version).resolve(logListSuffix); + } + + public LogStoreImpl(Policy policy) { + this(policy, getPathForCompatVersion(COMPAT_VERSION), Platform.getStatsLog(), + new SystemTimeSupplier()); } - public LogStoreImpl(Policy policy, Path logList, StatsLog metrics) { + public LogStoreImpl(Policy policy, Path logList, StatsLog metrics, Supplier clock) { this.state = State.UNINITIALIZED; this.policy = policy; this.logList = logList; this.metrics = metrics; + this.clock = clock; } @Override @@ -112,8 +123,7 @@ public int getMinorVersion() { @Override public int getCompatVersion() { - // Currently, there is only one compatibility version supported. If we - // are loaded or initialized, it means the expected compatibility + // If we are loaded or initialized, it means the expected compatibility // version was found. if (state == State.LOADED || state == State.COMPLIANT || state == State.NON_COMPLIANT) { return COMPAT_VERSION; @@ -123,6 +133,9 @@ public int getCompatVersion() { @Override public int getMinCompatVersionAvailable() { + if (Files.exists(getPathForCompatVersion(1))) { + return 1; + } return getCompatVersion(); } @@ -145,26 +158,55 @@ public LogInfo getKnownLog(byte[] logId) { /* Ensures the log list is loaded. * Returns true if the log list is usable. */ - private boolean ensureLogListIsLoaded() { - synchronized (this) { - State previousState = state; - if (state == State.UNINITIALIZED) { - state = loadLogList(); - } - if (state == State.LOADED && policy != null) { - state = policy.isLogStoreCompliant(this) ? State.COMPLIANT : State.NON_COMPLIANT; + private synchronized boolean ensureLogListIsLoaded() { + resetLogListIfRequired(); + State previousState = state; + if (state == State.UNINITIALIZED) { + state = loadLogList(); + } + if (state == State.LOADED && policy != null) { + state = policy.isLogStoreCompliant(this) ? State.COMPLIANT : State.NON_COMPLIANT; + } + if (state != previousState) { + metrics.updateCTLogListStatusChanged(this); + } + return state == State.COMPLIANT; + } + + private synchronized void resetLogListIfRequired() { + long now = clock.get(); + if (now >= this.logListLastChecked + && now < this.logListLastChecked + LOG_LIST_CHECK_INTERVAL_IN_MS) { + return; + } + this.logListLastChecked = now; + try { + long lastModified = Files.getLastModifiedTime(logList).toMillis(); + if (this.logListLastModified == lastModified) { + // The log list has the same last modified timestamp. Keep our + // current cached value. + return; } - if (state != previousState) { - metrics.updateCTLogListStatusChanged(this); + } catch (IOException e) { + if (this.logListLastModified == 0) { + // The log list is not accessible now and it has never been + // previously, there is nothing to do. + return; } - return state == State.COMPLIANT; } + this.state = State.UNINITIALIZED; + this.logs = null; + this.timestamp = 0; + this.majorVersion = 0; + this.minorVersion = 0; } private State loadLogList() { byte[] content; + long lastModified; try { content = Files.readAllBytes(logList); + lastModified = Files.getLastModifiedTime(logList).toMillis(); } catch (IOException e) { return State.NOT_FOUND; } @@ -182,39 +224,18 @@ private State loadLogList() { try { majorVersion = parseMajorVersion(json.getString("version")); minorVersion = parseMinorVersion(json.getString("version")); - timestamp = parseTimestamp(json.getString("log_list_timestamp")); + timestamp = json.getLong("log_list_timestamp"); JSONArray operators = json.getJSONArray("operators"); for (int i = 0; i < operators.length(); i++) { JSONObject operator = operators.getJSONObject(i); String operatorName = operator.getString("name"); - JSONArray logs = operator.getJSONArray("logs"); - for (int j = 0; j < logs.length(); j++) { - JSONObject log = logs.getJSONObject(j); - - LogInfo.Builder builder = - new LogInfo.Builder() - .setDescription(log.getString("description")) - .setPublicKey(parsePubKey(log.getString("key"))) - .setUrl(log.getString("url")) - .setOperator(operatorName); - JSONObject stateObject = log.optJSONObject("state"); - if (stateObject != null) { - String state = stateObject.keys().next(); - String stateTimestamp = - stateObject.getJSONObject(state).getString("timestamp"); - builder.setState(parseState(state), parseTimestamp(stateTimestamp)); - } - - LogInfo logInfo = builder.build(); - byte[] logId = Base64.getDecoder().decode(log.getString("log_id")); - - // The logId computed using the public key should match the log_id field. - if (!Arrays.equals(logInfo.getID(), logId)) { - throw new IllegalArgumentException("logId does not match publicKey"); - } + JSONArray logs = operator.getJSONArray("logs"); + addLogsToMap(logs, operatorName, LogInfo.TYPE_RFC6962, logsMap); - logsMap.put(new ByteArray(logId), logInfo); + JSONArray tiledLogs = operator.optJSONArray("tiled_logs"); + if (tiledLogs != null) { + addLogsToMap(tiledLogs, operatorName, LogInfo.TYPE_STATIC_CT_API, logsMap); } } } catch (JSONException | IllegalArgumentException e) { @@ -222,9 +243,45 @@ private State loadLogList() { return State.MALFORMED; } this.logs = Collections.unmodifiableMap(logsMap); + this.logListLastModified = lastModified; return State.LOADED; } + private void addLogsToMap(JSONArray logs, String operatorName, int logType, + Map logsMap) throws JSONException { + for (int j = 0; j < logs.length(); j++) { + JSONObject log = logs.getJSONObject(j); + LogInfo.Builder builder = new LogInfo.Builder() + .setPublicKey(parsePubKey(log.getString("key"))) + .setType(logType) + .setOperator(operatorName); + JSONObject stateObject = log.optJSONObject("state"); + if (stateObject != null) { + String state = stateObject.keys().next(); + long stateTimestamp = stateObject.getJSONObject(state).getLong("timestamp"); + builder.setState(parseState(state), stateTimestamp); + } + LogInfo logInfo = builder.build(); + + String logIdFromList = log.getString("log_id"); + // The logId computed using the public key should match the log_id field. + byte[] logId = Base64.getDecoder().decode(logIdFromList); + if (!Arrays.equals(logInfo.getID(), logId)) { + throw new IllegalArgumentException("logId does not match publicKey"); + } + + // Verify that the log is in a known state now. This might fail if + // there is an issue with the device's clock which can cause false + // positives when validating SCTs. + if (logInfo.getStateAt(clock.get()) == LogInfo.STATE_UNKNOWN) { + throw new IllegalArgumentException("Log current state is " + + "unknown, logId: " + logIdFromList); + } + + logsMap.put(new ByteArray(logId), logInfo); + } + } + private static int parseMajorVersion(String version) { int pos = version.indexOf("."); if (pos == -1) { @@ -268,19 +325,6 @@ private static int parseState(String state) { } } - // ISO 8601 - private static DateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssX"); - - @SuppressWarnings("JavaUtilDate") - private static long parseTimestamp(String timestamp) { - try { - Date date = dateFormatter.parse(timestamp); - return date.getTime(); - } catch (ParseException e) { - throw new IllegalArgumentException(e); - } - } - private static PublicKey parsePubKey(String key) { byte[] pem = ("-----BEGIN PUBLIC KEY-----\n" + key + "\n-----END PUBLIC KEY-----") .getBytes(US_ASCII); diff --git a/platform/src/main/java/org/conscrypt/ct/PolicyImpl.java b/platform/src/main/java/org/conscrypt/ct/PolicyImpl.java index 652745dca..dd48cf971 100644 --- a/platform/src/main/java/org/conscrypt/ct/PolicyImpl.java +++ b/platform/src/main/java/org/conscrypt/ct/PolicyImpl.java @@ -50,14 +50,14 @@ public boolean isLogStoreCompliantAt(LogStore store, long atTime) { } @Override - public PolicyCompliance doesResultConformToPolicy( - VerificationResult result, X509Certificate leaf) { + public PolicyCompliance doesResultConformToPolicy(VerificationResult result, + X509Certificate leaf) { long now = System.currentTimeMillis(); return doesResultConformToPolicyAt(result, leaf, now); } - public PolicyCompliance doesResultConformToPolicyAt( - VerificationResult result, X509Certificate leaf, long atTime) { + public PolicyCompliance doesResultConformToPolicyAt(VerificationResult result, + X509Certificate leaf, long atTime) { List validSCTs = new ArrayList(result.getValidSCTs()); /* While the log list supports logs without a state, these entries are * not supported by the log policy. Filter them out. */ @@ -122,14 +122,14 @@ private void filterOutAfterRetired(List scts) { while (it.hasNext()) { VerifiedSCT vsct = it.next(); if (vsct.getLogInfo().getState() == LogInfo.STATE_RETIRED - && minTimestamp > vsct.getLogInfo().getStateTimestamp()) { + && minTimestamp > vsct.getLogInfo().getStateTimestamp()) { it.remove(); } } } - private PolicyCompliance conformEmbeddedSCTs( - Set embeddedValidSCTs, X509Certificate leaf, long atTime) { + private PolicyCompliance conformEmbeddedSCTs(Set embeddedValidSCTs, + X509Certificate leaf, long atTime) { /* 1. At least one Embedded SCT from a CT Log that was Qualified, * Usable, or ReadOnly at the time of check; */ @@ -178,7 +178,7 @@ private PolicyCompliance conformEmbeddedSCTs( return PolicyCompliance.NOT_ENOUGH_SCTS; } - /* 3. Among the SCTs satisfying requirements 1 and 2, at least two SCTs + /* 3. Among the SCTs satisfying requirements 2, at least two SCTs * must be issued from distinct CT Log Operators as recognized by * Chrome. */ @@ -190,11 +190,25 @@ private PolicyCompliance conformEmbeddedSCTs( return PolicyCompliance.NOT_ENOUGH_DIVERSE_SCTS; } + /* 4. Among the SCTs satisfying requirement 2, at least one SCT must be + * issued from a log recognized by Chrome as being RFC6962-compliant. + */ + boolean foundRfc6962Log = false; + for (LogInfo logInfo : validLogs) { + if (logInfo.getType() == LogInfo.TYPE_RFC6962) { + foundRfc6962Log = true; + break; + } + } + if (!foundRfc6962Log) { + return PolicyCompliance.NO_RFC6962_LOG; + } + return PolicyCompliance.COMPLY; } - private PolicyCompliance conformOCSPorTLSSCTs( - Set ocspOrTLSValidSCTs, long atTime) { + private PolicyCompliance conformOCSPorTLSSCTs(Set ocspOrTLSValidSCTs, + long atTime) { /* 1. At least two SCTs from a CT Log that was Qualified, Usable, or * ReadOnly at the time of check; */ @@ -223,6 +237,20 @@ private PolicyCompliance conformOCSPorTLSSCTs( return PolicyCompliance.NOT_ENOUGH_DIVERSE_SCTS; } + /* 3. Among the SCTs satisfying requirement 1, at least one SCT must be + * issued from a log recognized by Chrome as being RFC6962-compliant. + */ + boolean foundRfc6962Log = false; + for (LogInfo logInfo : validLogs) { + if (logInfo.getType() == LogInfo.TYPE_RFC6962) { + foundRfc6962Log = true; + break; + } + } + if (!foundRfc6962Log) { + return PolicyCompliance.NO_RFC6962_LOG; + } + return PolicyCompliance.COMPLY; } } diff --git a/platform/src/test/java/org/conscrypt/AndroidHpkeSpiTest.java b/platform/src/test/java/org/conscrypt/AndroidHpkeSpiTest.java index 94b4f515e..8901b4077 100644 --- a/platform/src/test/java/org/conscrypt/AndroidHpkeSpiTest.java +++ b/platform/src/test/java/org/conscrypt/AndroidHpkeSpiTest.java @@ -27,11 +27,13 @@ @RunWith(JUnit4.class) public class AndroidHpkeSpiTest { - private static final String[] HPKE_NAMES = new String[]{ - "DHKEM_X25519_HKDF_SHA256/HKDF_SHA256/AES_128_GCM", - "DHKEM_X25519_HKDF_SHA256/HKDF_SHA256/AES_256_GCM", - "DHKEM_X25519_HKDF_SHA256/HKDF_SHA256/CHACHA20POLY1305" - }; + private static final String[] HPKE_NAMES = + new String[] {"DHKEM_X25519_HKDF_SHA256/HKDF_SHA256/AES_128_GCM", + "DHKEM_X25519_HKDF_SHA256/HKDF_SHA256/AES_256_GCM", + "DHKEM_X25519_HKDF_SHA256/HKDF_SHA256/CHACHA20POLY1305", + "XWING/HKDF_SHA256/AES_128_GCM", + "XWING/HKDF_SHA256/AES_256_GCM", + "XWING/HKDF_SHA256/CHACHA20POLY1305"}; // This only needs to test the wrapper functionality as the implementation and client // APIs are tested elsewhere. What we're looking for is that HPKE SPI instances returned @@ -44,8 +46,7 @@ public void functionalTest() throws Exception { Class platformSpiClass = TestUtils.findClass("android.crypto.hpke.HpkeSpi"); Provider provider = TestUtils.getConscryptProvider(); for (String algorithm : HPKE_NAMES) { - Object spi = provider.getService("ConscryptHpke", algorithm) - .newInstance(null); + Object spi = provider.getService("ConscryptHpke", algorithm).newInstance(null); assertNotNull(spi); if (platformSpiClass != null) { assertTrue(platformSpiClass.isAssignableFrom(spi.getClass())); diff --git a/platform/src/test/java/org/conscrypt/CertBlocklistTest.java b/platform/src/test/java/org/conscrypt/CertBlocklistTest.java index 4c89e1873..e37730b3b 100644 --- a/platform/src/test/java/org/conscrypt/CertBlocklistTest.java +++ b/platform/src/test/java/org/conscrypt/CertBlocklistTest.java @@ -16,25 +16,30 @@ package org.conscrypt; +import static com.google.common.truth.Truth.assertThat; + +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import org.conscrypt.metrics.NoopStatsLog; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + import java.io.InputStream; import java.security.KeyStore; import java.security.cert.Certificate; import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; +import java.util.ArrayList; import java.util.Collection; -import javax.net.ssl.X509TrustManager; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; +import javax.net.ssl.X509TrustManager; @RunWith(JUnit4.class) public class CertBlocklistTest { - private static final String BLOCKLIST_CA = "test_blocklist_ca.pem"; private static final String BLOCKLIST_CA2 = "test_blocklist_ca2.pem"; private static final String BLOCKLISTED_CHAIN = "blocklist_test_chain.pem"; @@ -81,7 +86,8 @@ public void testBlocklistedRootOfTrust() throws Exception { assertUntrusted(chain, getTrustManager(blocklistedCa)); } - /** Test that the path building correctly routes around a blocklisted cert where there are + /** + * Test that the path building correctly routes around a blocklisted cert where there are * other valid paths available. This prevents breakage where a cert was cross signed by a * blocklisted CA but is still valid due to also being cross signed by CAs that remain trusted. * Path: @@ -101,6 +107,44 @@ public void testBlocklistedIntermediateFallback() throws Exception { assertUntrusted(chain, getTrustManager(blocklistedCa)); } + static class FakeStatsLog extends NoopStatsLog { + public ArrayList entries = new ArrayList<>(); + + @Override + public void reportBlocklistHit(CertBlocklistEntry entry) { + entries.add(entry); + } + } + + @Test + public void isPublicKeyBlockListed_hitBlocklist_hitIsReported() throws Exception { + X509Certificate blocklistedCa = loadCertificate(BLOCKLIST_CA); + FakeStatsLog fakeMetrics = new FakeStatsLog(); + CertBlocklist blocklist = + new CertBlocklistImpl.Builder().loadAllDefaults().setMetrics(fakeMetrics).build(); + + blocklist.isPublicKeyBlockListed(blocklistedCa.getPublicKey()); + + assertThat(fakeMetrics.entries).hasSize(1); + CertBlocklistEntry entry = fakeMetrics.entries.get(0); + assertThat(entry.getOrigin()).isEqualTo(CertBlocklistEntry.Origin.SHA1_TEST); + assertThat(entry.getIndex()).isEqualTo(0); + } + + @Test + public void isPublicKeyBlockListed_hitBlocklistTwiceWithSameKey_hitIsReportedTwice() + throws Exception { + X509Certificate blocklistedCa = loadCertificate(BLOCKLIST_CA); + FakeStatsLog fakeMetrics = new FakeStatsLog(); + CertBlocklist blocklist = + new CertBlocklistImpl.Builder().loadAllDefaults().setMetrics(fakeMetrics).build(); + + blocklist.isPublicKeyBlockListed(blocklistedCa.getPublicKey()); + blocklist.isPublicKeyBlockListed(blocklistedCa.getPublicKey()); + + assertThat(fakeMetrics.entries).hasSize(2); + } + private static X509Certificate loadCertificate(String file) throws Exception { return loadCertificates(file)[0]; } diff --git a/platform/src/test/java/org/conscrypt/SpakeTest.java b/platform/src/test/java/org/conscrypt/SpakeTest.java index c535a05b0..3bd170ee7 100644 --- a/platform/src/test/java/org/conscrypt/SpakeTest.java +++ b/platform/src/test/java/org/conscrypt/SpakeTest.java @@ -69,7 +69,8 @@ public class SpakeTest { Executors.newCachedThreadPool(t -> new Thread(threadGroup, t)); private Pair createContexts(PakeClientKeyManagerParameters clientParams, - PakeServerKeyManagerParameters serverParams) throws Exception { + PakeServerKeyManagerParameters serverParams) + throws Exception { InetAddress hostC = TestUtils.getLoopbackAddress(); InetAddress hostS = TestUtils.getLoopbackAddress(); @@ -488,7 +489,7 @@ public void testSpake2PlusAndOthersInvalid() throws Exception { SSLContext sslContext = SSLContext.getInstance("TlsV1.3"); // Should throw due to both SPAKE and x509 key managers assertThrows(KeyManagementException.class, - () -> sslContext.init(keyManagersWithx509, trustManagers, null)); + () -> sslContext.init(keyManagersWithx509, trustManagers, null)); } @Test @@ -517,8 +518,8 @@ public void testSpake2PlusNoTrustOrKeyInvalid() throws Exception { SSLContext sslContext = SSLContext.getInstance("TlsV1.3"); assertThrows(KeyManagementException.class, () -> sslContext.init(keyManagers, null, null)); - assertThrows( - KeyManagementException.class, () -> sslContext.init(null, trustManagers, null)); + assertThrows(KeyManagementException.class, + () -> sslContext.init(null, trustManagers, null)); } @Test diff --git a/platform/src/test/java/org/conscrypt/TlsDeprecationTest.java b/platform/src/test/java/org/conscrypt/TlsDeprecationTest.java index a04788625..0ebb329ce 100644 --- a/platform/src/test/java/org/conscrypt/TlsDeprecationTest.java +++ b/platform/src/test/java/org/conscrypt/TlsDeprecationTest.java @@ -16,27 +16,30 @@ package org.conscrypt; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.junit.Assume.assumeFalse; + import libcore.junit.util.SwitchTargetSdkVersionRule; import libcore.junit.util.SwitchTargetSdkVersionRule.TargetSdkVersion; -import java.security.Provider; -import javax.net.ssl.SSLSocket; +import org.conscrypt.javax.net.ssl.TestSSLContext; +import org.junit.Rule; import org.junit.Test; -import org.junit.runner.RunWith; import org.junit.rules.TestRule; -import org.junit.Rule; +import org.junit.runner.RunWith; import org.junit.runners.JUnit4; -import org.conscrypt.javax.net.ssl.TestSSLContext; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.assertThrows; -import static org.junit.Assert.fail; -import static org.junit.Assume.assumeFalse; +import java.security.Provider; + +import javax.net.ssl.SSLSocket; @RunWith(JUnit4.class) public class TlsDeprecationTest { + // android-add: test rule for switching target SDK version to 36. @Test @TargetSdkVersion(36) @@ -45,8 +48,10 @@ public void test_SSLSocket_SSLv3Unsupported_36() throws Exception { TestSSLContext context = TestSSLContext.create(); final SSLSocket client = (SSLSocket) context.clientContext.getSocketFactory().createSocket(); - assertThrows(IllegalArgumentException.class, () -> client.setEnabledProtocols(new String[] {"SSLv3"})); - assertThrows(IllegalArgumentException.class, () -> client.setEnabledProtocols(new String[] {"SSL"})); + assertThrows(IllegalArgumentException.class, + () -> client.setEnabledProtocols(new String[] {"SSLv3"})); + assertThrows(IllegalArgumentException.class, + () -> client.setEnabledProtocols(new String[] {"SSL"})); } @Test @@ -59,7 +64,8 @@ public void test_SSLSocket_SSLv3Unsupported_34() throws Exception { // For app compatibility, SSLv3 is stripped out when setting only. client.setEnabledProtocols(new String[] {"SSLv3"}); assertEquals(0, client.getEnabledProtocols().length); - assertThrows(IllegalArgumentException.class, () -> client.setEnabledProtocols(new String[] {"SSL"})); + assertThrows(IllegalArgumentException.class, + () -> client.setEnabledProtocols(new String[] {"SSL"})); } @Test @@ -92,8 +98,9 @@ public void test_TLSv1Filtered_36() throws Exception { TestSSLContext context = TestSSLContext.create(); final SSLSocket client = (SSLSocket) context.clientContext.getSocketFactory().createSocket(); - assertThrows(IllegalArgumentException.class, () -> - client.setEnabledProtocols(new String[] {"TLSv1", "TLSv1.1", "TLSv1.2"})); + assertThrows( + IllegalArgumentException.class, + () -> client.setEnabledProtocols(new String[] {"TLSv1", "TLSv1.1", "TLSv1.2"})); } @Test diff --git a/platform/src/test/java/org/conscrypt/ct/LogStoreImplTest.java b/platform/src/test/java/org/conscrypt/ct/LogStoreImplTest.java index 57b9cc45c..0eeb43f58 100644 --- a/platform/src/test/java/org/conscrypt/ct/LogStoreImplTest.java +++ b/platform/src/test/java/org/conscrypt/ct/LogStoreImplTest.java @@ -24,25 +24,24 @@ import org.conscrypt.OpenSSLKey; import org.conscrypt.metrics.NoopStatsLog; +import org.junit.After; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; import java.io.ByteArrayInputStream; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.FileWriter; import java.io.IOException; -import java.io.OutputStreamWriter; -import java.io.PrintWriter; -import java.security.PublicKey; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.Base64; +import java.util.function.Supplier; @RunWith(JUnit4.class) public class LogStoreImplTest { + /** FakeStatsLog captures the events being reported */ static class FakeStatsLog extends NoopStatsLog { public ArrayList states = new ArrayList(); @@ -58,8 +57,8 @@ public boolean isLogStoreCompliant(LogStore store) { return true; } @Override - public PolicyCompliance doesResultConformToPolicy( - VerificationResult result, X509Certificate leaf) { + public PolicyCompliance doesResultConformToPolicy(VerificationResult result, + X509Certificate leaf) { return PolicyCompliance.COMPLY; } }; @@ -70,19 +69,37 @@ public boolean isLogStoreCompliant(LogStore store) { return false; } @Override - public PolicyCompliance doesResultConformToPolicy( - VerificationResult result, X509Certificate leaf) { + public PolicyCompliance doesResultConformToPolicy(VerificationResult result, + X509Certificate leaf) { return PolicyCompliance.COMPLY; } }; - @Test - public void test_loadValidLogList() throws Exception { - // clang-format off - String content = "" + + /* Time supplier that can be set to any arbitrary time */ + static class TimeSupplier implements Supplier { + private long currentTimeInMs; + + TimeSupplier(long currentTimeInMs) { + this.currentTimeInMs = currentTimeInMs; + } + + @Override + public Long get() { + return currentTimeInMs; + } + + public void setCurrentTimeInMs(long currentTimeInMs) { + this.currentTimeInMs = currentTimeInMs; + } + } + + private static final long JAN2024 = 1704103200000L; + private static final long JAN2022 = 1641031200000L; + // clang-format off + static final String validLogList = "" + "{" + " \"version\": \"1.1\"," + -" \"log_list_timestamp\": \"2024-01-01T11:55:12Z\"," + +" \"log_list_timestamp\": 1704070861000," + " \"operators\": [" + " {" + " \"name\": \"Operator 1\"," + @@ -96,12 +113,12 @@ public void test_loadValidLogList() throws Exception { " \"mmd\": 86400," + " \"state\": {" + " \"usable\": {" + -" \"timestamp\": \"2022-11-01T18:54:00Z\"" + +" \"timestamp\": 1667328840000" + " }" + " }," + " \"temporal_interval\": {" + -" \"start_inclusive\": \"2024-01-01T00:00:00Z\"," + -" \"end_exclusive\": \"2025-01-01T00:00:00Z\"" + +" \"start_inclusive\": 1704070861000," + +" \"end_exclusive\": 1735693261000" + " }" + " }," + " {" + @@ -112,12 +129,12 @@ public void test_loadValidLogList() throws Exception { " \"mmd\": 86400," + " \"state\": {" + " \"usable\": {" + -" \"timestamp\": \"2023-11-26T12:00:00Z\"" + +" \"timestamp\": 1700960461000" + " }" + " }," + " \"temporal_interval\": {" + -" \"start_inclusive\": \"2025-01-01T00:00:00Z\"," + -" \"end_exclusive\": \"2025-07-01T00:00:00Z\"" + +" \"start_inclusive\": 1735693261000," + +" \"end_exclusive\": 1751331661000" + " }" + " }" + " ]" + @@ -134,81 +151,222 @@ public void test_loadValidLogList() throws Exception { " \"mmd\": 86400," + " \"state\": {" + " \"usable\": {" + -" \"timestamp\": \"2022-11-30T17:00:00Z\"" + +" \"timestamp\": 1669770061000" + " }" + " }," + " \"temporal_interval\": {" + -" \"start_inclusive\": \"2024-01-01T00:00:00Z\"," + -" \"end_exclusive\": \"2025-01-01T00:00:00Z\"" + +" \"start_inclusive\": 1704070861000," + +" \"end_exclusive\": 1735693261000" + +" }" + +" }" + +" ]," + +" \"tiled_logs\": [" + +" {" + +" \"description\": \"Operator 2 'Test2025' log\"," + +" \"log_id\": \"DleUvPOuqT4zGyyZB7P3kN+bwj1xMiXdIaklrGHFTiE=\"," + +" \"key\": \"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEB/we6GOO/xwxivy4HhkrYFAAPo6e2nc346Wo2o2U+GvoPWSPJz91s/xrEvA3Bk9kWHUUXVZS5morFEzsgdHqPg==\"," + +" \"submission_url\": \"https://operator2.example.com/tiled/test2025\"," + +" \"monitoring_url\": \"https://operator2.exmaple.com/tiled_monitor/test2025\"," + +" \"mmd\": 86400," + +" \"state\": {" + +" \"usable\": {" + +" \"timestamp\": 1667328840000" + +" }" + +" }," + +" \"temporal_interval\": {" + +" \"start_inclusive\": 1767225600000," + +" \"end_exclusive\": 1782864000000" + " }" + " }" + " ]" + " }" + " ]" + "}"; - // clang-format on + // clang-format on - FakeStatsLog metrics = new FakeStatsLog(); - File logList = writeFile(content); - LogStore store = new LogStoreImpl(alwaysCompliantStorePolicy, logList.toPath(), metrics); + Path grandparentDir; + Path parentDir; + Path logList; - assertNull("A null logId should return null", store.getKnownLog(null)); + @After + public void tearDown() throws Exception { + if (logList != null) { + Files.deleteIfExists(logList); + Files.deleteIfExists(parentDir); + Files.deleteIfExists(grandparentDir); + } + } + @Test + public void loadValidLogList_returnsCompliantState() throws Exception { + FakeStatsLog metrics = new FakeStatsLog(); + logList = writeLogList(validLogList); + TimeSupplier fakeTime = new TimeSupplier(/* currentTimeInMs= */ JAN2024); + LogStore store = new LogStoreImpl(alwaysCompliantStorePolicy, logList, metrics, fakeTime); byte[] pem = ("-----BEGIN PUBLIC KEY-----\n" - + "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEHblsqctplMVc5ramA7vSuNxUQxcomQwGAVAdnWTAWUYr" - + "3MgDHQW0LagJ95lB7QT75Ve6JgT2EVLOFGU7L3YrwA==" - + "\n-----END PUBLIC KEY-----\n") + + "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEHblsqctplMVc5ramA7vSuNxUQxcomQwGAVAdnW" + + "TAWUYr" + + "3MgDHQW0LagJ95lB7QT75Ve6JgT2EVLOFGU7L3YrwA==" + + "\n-----END PUBLIC KEY-----\n") .getBytes(US_ASCII); ByteArrayInputStream is = new ByteArrayInputStream(pem); - LogInfo log1 = new LogInfo.Builder() .setPublicKey(OpenSSLKey.fromPublicKeyPemInputStream(is).getPublicKey()) - .setDescription("Operator 1 'Test2024' log") - .setUrl("https://operator1.example.com/logs/test2024/") + .setType(LogInfo.TYPE_RFC6962) .setState(LogInfo.STATE_USABLE, 1667328840000L) .setOperator("Operator 1") .build(); byte[] log1Id = Base64.getDecoder().decode("7s3QZNXbGs7FXLedtM0TojKHRny87N7DUUhZRnEftZs="); + + assertNull("A null logId should return null", store.getKnownLog(/* logId= */ null)); assertEquals("An existing logId should be returned", log1, store.getKnownLog(log1Id)); - assertEquals("One metric update should be emitted", metrics.states.size(), 1); + assertEquals("One metric update should be emitted", 1, metrics.states.size()); assertEquals("The metric update for log list state should be compliant", - metrics.states.get(0), LogStore.State.COMPLIANT); + LogStore.State.COMPLIANT, metrics.states.get(0)); } @Test - public void test_loadMalformedLogList() throws Exception { + public void loadMalformedLogList_returnsMalformedState() throws Exception { FakeStatsLog metrics = new FakeStatsLog(); String content = "}}"; - File logList = writeFile(content); - LogStore store = new LogStoreImpl(alwaysCompliantStorePolicy, logList.toPath(), metrics); + logList = writeLogList(content); + TimeSupplier fakeTime = new TimeSupplier(/* currentTimeInMs= */ JAN2024); + LogStore store = new LogStoreImpl(alwaysCompliantStorePolicy, logList, metrics, fakeTime); + + assertEquals("The log state should be malformed", LogStore.State.MALFORMED, + store.getState()); + assertEquals("One metric update should be emitted", 1, metrics.states.size()); + assertEquals("The metric update for log list state should be malformed", + LogStore.State.MALFORMED, metrics.states.get(0)); + } - assertEquals( - "The log state should be malformed", store.getState(), LogStore.State.MALFORMED); - assertEquals("One metric update should be emitted", metrics.states.size(), 1); + @Test + public void loadFutureLogList_returnsMalformedState() throws Exception { + FakeStatsLog metrics = new FakeStatsLog(); + logList = writeLogList(validLogList); // The logs are usable from 2024 onwards. + TimeSupplier fakeTime = new TimeSupplier(/* currentTimeInMs= */ JAN2022); + LogStore store = new LogStoreImpl(alwaysCompliantStorePolicy, logList, metrics, fakeTime); + + assertEquals("The log state should be malformed", LogStore.State.MALFORMED, + store.getState()); + assertEquals("One metric update should be emitted", 1, metrics.states.size()); assertEquals("The metric update for log list state should be malformed", - metrics.states.get(0), LogStore.State.MALFORMED); + LogStore.State.MALFORMED, metrics.states.get(0)); } @Test - public void test_loadMissingLogList() throws Exception { + public void loadMissingLogList_returnsNotFoundState() throws Exception { FakeStatsLog metrics = new FakeStatsLog(); - File logList = new File("does_not_exist"); - LogStore store = new LogStoreImpl(alwaysCompliantStorePolicy, logList.toPath(), metrics); + Path missingLogList = Paths.get("missing_dir", "missing_subdir", "does_not_exist_log_list"); + TimeSupplier fakeTime = new TimeSupplier(/* currentTimeInMs= */ JAN2024); + LogStore store = + new LogStoreImpl(alwaysCompliantStorePolicy, missingLogList, metrics, fakeTime); - assertEquals( - "The log state should be not found", store.getState(), LogStore.State.NOT_FOUND); - assertEquals("One metric update should be emitted", metrics.states.size(), 1); + assertEquals("The log state should be not found", LogStore.State.NOT_FOUND, + store.getState()); + assertEquals("One metric update should be emitted", 1, metrics.states.size()); assertEquals("The metric update for log list state should be not found", - metrics.states.get(0), LogStore.State.NOT_FOUND); + LogStore.State.NOT_FOUND, metrics.states.get(0)); } - private File writeFile(String content) throws IOException { - File file = File.createTempFile("test", null); - file.deleteOnExit(); - try (FileWriter fw = new FileWriter(file)) { - fw.write(content); - } + @Test + public void loadMissingAndThenFoundLogList_logListIsLoaded() throws Exception { + // Arrange + FakeStatsLog metrics = new FakeStatsLog(); + // Allocate a temporary file path and delete it. We keep the temporary + // path so that we can add a valid log list later on. + logList = writeLogList(""); + Files.deleteIfExists(logList); + Files.deleteIfExists(parentDir); + Files.deleteIfExists(grandparentDir); + TimeSupplier fakeTime = new TimeSupplier(/* currentTimeInMs= */ JAN2024); + LogStore store = new LogStoreImpl(alwaysCompliantStorePolicy, logList, metrics, fakeTime); + assertEquals("The log state should be not found", LogStore.State.NOT_FOUND, + store.getState()); + + // Act + Files.createDirectory(grandparentDir); + Files.createDirectory(parentDir); + Files.write(logList, validLogList.getBytes()); + + // Assert + // 5min < 10min, we should not check the log list yet. + fakeTime.setCurrentTimeInMs(JAN2024 + 5L * 60 * 1000); + assertEquals("The log state should be not found", LogStore.State.NOT_FOUND, + store.getState()); + + // 12min, the log list should be reloadable. + fakeTime.setCurrentTimeInMs(JAN2024 + 12L * 60 * 1000); + assertEquals("The log state should be compliant", LogStore.State.COMPLIANT, + store.getState()); + } + + @Test + public void loadMissingThenTimeTravelBackwardsAndThenFoundLogList_logListIsLoaded() + throws Exception { + FakeStatsLog metrics = new FakeStatsLog(); + // Allocate a temporary file path and delete it. We keep the temporary + // path so that we can add a valid log list later on. + logList = writeLogList(""); + Files.deleteIfExists(logList); + Files.deleteIfExists(parentDir); + Files.deleteIfExists(grandparentDir); + TimeSupplier fakeTime = new TimeSupplier(/* currentTimeInMs= */ JAN2024 + 100L * 60 * 1000); + LogStore store = new LogStoreImpl(alwaysCompliantStorePolicy, logList, metrics, fakeTime); + assertEquals("The log state should be not found", LogStore.State.NOT_FOUND, + store.getState()); + + Files.createDirectory(grandparentDir); + Files.createDirectory(parentDir); + Files.write(logList, validLogList.getBytes()); + // Move back in time. + fakeTime.setCurrentTimeInMs(JAN2024); + + assertEquals("The log state should be compliant", LogStore.State.COMPLIANT, + store.getState()); + } + + @Test + public void loadExistingAndThenRemovedLogList_logListIsNotFound() throws Exception { + FakeStatsLog metrics = new FakeStatsLog(); + logList = writeLogList(validLogList); + TimeSupplier fakeTime = new TimeSupplier(/* currentTimeInMs= */ JAN2024); + LogStore store = new LogStoreImpl(alwaysCompliantStorePolicy, logList, metrics, fakeTime); + assertEquals("The log should be loaded", LogStore.State.COMPLIANT, store.getState()); + + Files.delete(logList); + // 12min, the log list should be reloadable. + fakeTime.setCurrentTimeInMs(JAN2024 + 12L * 60 * 1000); + + assertEquals("The log should have been refreshed", LogStore.State.NOT_FOUND, + store.getState()); + } + + @Test + public void loadExistingLogListAndThenMoveDirectory_logListIsNotFound() throws Exception { + FakeStatsLog metrics = new FakeStatsLog(); + logList = writeLogList(validLogList); + TimeSupplier fakeTime = new TimeSupplier(/* currentTimeInMs= */ JAN2024); + LogStore store = new LogStoreImpl(alwaysCompliantStorePolicy, logList, metrics, fakeTime); + assertEquals("The log should be loaded", LogStore.State.COMPLIANT, store.getState()); + + Path oldParentDir = parentDir; + parentDir = grandparentDir.resolve("more_current"); + Files.move(oldParentDir, parentDir); + logList = parentDir.resolve("log_list.json"); + // 12min, the log list should be reloadable. + fakeTime.setCurrentTimeInMs(JAN2024 + 12L * 60 * 1000); + + assertEquals("The log should have been refreshed", LogStore.State.NOT_FOUND, + store.getState()); + } + + private Path writeLogList(String content) throws IOException { + grandparentDir = Files.createTempDirectory("v1"); + parentDir = Files.createDirectory(grandparentDir.resolve("current")); + Path file = Files.createFile(parentDir.resolve("log_list.json")); + Files.write(file, content.getBytes()); return file; } } diff --git a/platform/src/test/java/org/conscrypt/ct/PolicyImplTest.java b/platform/src/test/java/org/conscrypt/ct/PolicyImplTest.java index a7a50a8da..7a1a13712 100644 --- a/platform/src/test/java/org/conscrypt/ct/PolicyImplTest.java +++ b/platform/src/test/java/org/conscrypt/ct/PolicyImplTest.java @@ -36,9 +36,11 @@ public class PolicyImplTest { private static final String OPERATOR2 = "operator 2"; private static LogInfo usableOp1Log1; private static LogInfo usableOp1Log2; + private static LogInfo usableStaticOp1Log; private static LogInfo retiredOp1LogOld; private static LogInfo retiredOp1LogNew; private static LogInfo usableOp2Log; + private static LogInfo usableStaticOp2Log; private static LogInfo retiredOp2Log; private static SignedCertificateTimestamp embeddedSCT; private static SignedCertificateTimestamp ocspSCT; @@ -89,37 +91,49 @@ public static void setUp() { */ usableOp1Log1 = new LogInfo.Builder() .setPublicKey(new FakePublicKey(new byte[] {0x01})) - .setUrl("") + .setType(LogInfo.TYPE_RFC6962) .setOperator(OPERATOR1) .setState(LogInfo.STATE_USABLE, JAN2022) .build(); usableOp1Log2 = new LogInfo.Builder() .setPublicKey(new FakePublicKey(new byte[] {0x02})) - .setUrl("") + .setType(LogInfo.TYPE_RFC6962) .setOperator(OPERATOR1) .setState(LogInfo.STATE_USABLE, JAN2022) .build(); + usableStaticOp1Log = new LogInfo.Builder() + .setPublicKey(new FakePublicKey(new byte[] {0x07})) + .setType(LogInfo.TYPE_STATIC_CT_API) + .setOperator(OPERATOR1) + .setState(LogInfo.STATE_USABLE, JAN2022) + .build(); retiredOp1LogOld = new LogInfo.Builder() .setPublicKey(new FakePublicKey(new byte[] {0x03})) - .setUrl("") + .setType(LogInfo.TYPE_RFC6962) .setOperator(OPERATOR1) .setState(LogInfo.STATE_RETIRED, JAN2022) .build(); retiredOp1LogNew = new LogInfo.Builder() .setPublicKey(new FakePublicKey(new byte[] {0x06})) - .setUrl("") + .setType(LogInfo.TYPE_RFC6962) .setOperator(OPERATOR1) .setState(LogInfo.STATE_RETIRED, JUN2023) .build(); usableOp2Log = new LogInfo.Builder() .setPublicKey(new FakePublicKey(new byte[] {0x04})) - .setUrl("") + .setType(LogInfo.TYPE_RFC6962) .setOperator(OPERATOR2) .setState(LogInfo.STATE_USABLE, JAN2022) .build(); + usableStaticOp2Log = new LogInfo.Builder() + .setPublicKey(new FakePublicKey(new byte[] {0x08})) + .setType(LogInfo.TYPE_STATIC_CT_API) + .setOperator(OPERATOR2) + .setState(LogInfo.STATE_USABLE, JAN2022) + .build(); retiredOp2Log = new LogInfo.Builder() .setPublicKey(new FakePublicKey(new byte[] {0x05})) - .setUrl("") + .setType(LogInfo.TYPE_RFC6962) .setOperator(OPERATOR2) .setState(LogInfo.STATE_RETIRED, JAN2022) .build(); @@ -128,9 +142,11 @@ public static void setUp() { * previous step (see the Verifier class). */ embeddedSCT = new SignedCertificateTimestamp(SignedCertificateTimestamp.Version.V1, null, - JAN2023, null, null, SignedCertificateTimestamp.Origin.EMBEDDED); + JAN2023, null, null, + SignedCertificateTimestamp.Origin.EMBEDDED); ocspSCT = new SignedCertificateTimestamp(SignedCertificateTimestamp.Version.V1, null, - JAN2023, null, null, SignedCertificateTimestamp.Origin.OCSP_RESPONSE); + JAN2023, null, null, + SignedCertificateTimestamp.Origin.OCSP_RESPONSE); } @Test @@ -140,7 +156,7 @@ public void emptyVerificationResult() throws Exception { X509Certificate leaf = new FakeX509Certificate(); assertEquals("An empty VerificationResult", PolicyCompliance.NOT_ENOUGH_SCTS, - p.doesResultConformToPolicyAt(result, leaf, JAN2024)); + p.doesResultConformToPolicyAt(result, leaf, JAN2024)); } public void validVerificationResult(SignedCertificateTimestamp sct) throws Exception { @@ -162,7 +178,7 @@ public void validVerificationResult(SignedCertificateTimestamp sct) throws Excep X509Certificate leaf = new FakeX509Certificate(); assertEquals("Two valid SCTs from different operators", PolicyCompliance.COMPLY, - p.doesResultConformToPolicyAt(result, leaf, JAN2024)); + p.doesResultConformToPolicyAt(result, leaf, JAN2024)); } @Test @@ -195,7 +211,7 @@ public void validEmbeddedWithRetiredVerificationResult() throws Exception { X509Certificate leaf = new FakeX509Certificate(); assertEquals("One valid, one retired SCTs from different operators", - PolicyCompliance.COMPLY, p.doesResultConformToPolicyAt(result, leaf, JAN2024)); + PolicyCompliance.COMPLY, p.doesResultConformToPolicyAt(result, leaf, JAN2024)); } @Test @@ -218,8 +234,8 @@ public void invalidOCSPWithRecentRetiredVerificationResult() throws Exception { X509Certificate leaf = new FakeX509Certificate(); assertEquals("One valid, one retired SCTs from different operators", - PolicyCompliance.NOT_ENOUGH_SCTS, - p.doesResultConformToPolicyAt(result, leaf, JAN2024)); + PolicyCompliance.NOT_ENOUGH_SCTS, + p.doesResultConformToPolicyAt(result, leaf, JAN2024)); } public void invalidWithRetiredVerificationResult(SignedCertificateTimestamp sct) @@ -242,8 +258,8 @@ public void invalidWithRetiredVerificationResult(SignedCertificateTimestamp sct) X509Certificate leaf = new FakeX509Certificate(); assertEquals("One valid, one retired (before SCT timestamp) SCTs from different operators", - PolicyCompliance.NOT_ENOUGH_SCTS, - p.doesResultConformToPolicyAt(result, leaf, JAN2024)); + PolicyCompliance.NOT_ENOUGH_SCTS, + p.doesResultConformToPolicyAt(result, leaf, JAN2024)); } @Test @@ -269,7 +285,7 @@ public void invalidOneSctVerificationResult(SignedCertificateTimestamp sct) thro X509Certificate leaf = new FakeX509Certificate(); assertEquals("One valid SCT", PolicyCompliance.NOT_ENOUGH_SCTS, - p.doesResultConformToPolicyAt(result, leaf, JAN2024)); + p.doesResultConformToPolicyAt(result, leaf, JAN2024)); } @Test @@ -302,7 +318,7 @@ public void invalidTwoRetiredSctsVerificationResult(SignedCertificateTimestamp s X509Certificate leaf = new FakeX509Certificate(); assertEquals("Two retired SCTs from different operators", PolicyCompliance.NOT_ENOUGH_SCTS, - p.doesResultConformToPolicyAt(result, leaf, JAN2024)); + p.doesResultConformToPolicyAt(result, leaf, JAN2024)); } @Test @@ -335,7 +351,7 @@ public void invalidTwoSctsSameOperatorVerificationResult(SignedCertificateTimest X509Certificate leaf = new FakeX509Certificate(); assertEquals("Two SCTs from the same operator", PolicyCompliance.NOT_ENOUGH_DIVERSE_SCTS, - p.doesResultConformToPolicyAt(result, leaf, JAN2024)); + p.doesResultConformToPolicyAt(result, leaf, JAN2024)); } @Test @@ -368,7 +384,72 @@ public void invalidOneEmbeddedOneOCSPVerificationResult() throws Exception { X509Certificate leaf = new FakeX509Certificate(); assertEquals("Two valid SCTs with different origins", PolicyCompliance.NOT_ENOUGH_SCTS, - p.doesResultConformToPolicyAt(result, leaf, JAN2024)); + p.doesResultConformToPolicyAt(result, leaf, JAN2024)); + } + + public void validVerificationResultPartialStatic(SignedCertificateTimestamp sct) + throws Exception { + PolicyImpl p = new PolicyImpl(); + + VerifiedSCT vsct1 = new VerifiedSCT.Builder(sct) + .setStatus(VerifiedSCT.Status.VALID) + .setLogInfo(usableOp1Log1) + .build(); + + VerifiedSCT vsct2 = new VerifiedSCT.Builder(sct) + .setStatus(VerifiedSCT.Status.VALID) + .setLogInfo(usableStaticOp2Log) + .build(); + + VerificationResult result = new VerificationResult(); + result.add(vsct1); + result.add(vsct2); + + X509Certificate leaf = new FakeX509Certificate(); + assertEquals("Two valid SCTs from different operators", PolicyCompliance.COMPLY, + p.doesResultConformToPolicyAt(result, leaf, JAN2024)); + } + + @Test + public void validEmbeddedVerificationResultPartialStatic() throws Exception { + validVerificationResultPartialStatic(embeddedSCT); + } + + @Test + public void validOCSPVerificationResultPartialStatic() throws Exception { + validVerificationResultPartialStatic(ocspSCT); + } + + public void invalidTwoSctsAllStatic(SignedCertificateTimestamp sct) throws Exception { + PolicyImpl p = new PolicyImpl(); + + VerifiedSCT vsct1 = new VerifiedSCT.Builder(sct) + .setStatus(VerifiedSCT.Status.VALID) + .setLogInfo(usableStaticOp1Log) + .build(); + + VerifiedSCT vsct2 = new VerifiedSCT.Builder(sct) + .setStatus(VerifiedSCT.Status.VALID) + .setLogInfo(usableStaticOp2Log) + .build(); + + VerificationResult result = new VerificationResult(); + result.add(vsct1); + result.add(vsct2); + + X509Certificate leaf = new FakeX509Certificate(); + assertEquals("Two static SCTs", PolicyCompliance.NO_RFC6962_LOG, + p.doesResultConformToPolicyAt(result, leaf, JAN2024)); + } + + @Test + public void invalidEmbeddedTwoSctsAllStaticsVerificationResult() throws Exception { + invalidTwoSctsAllStatic(embeddedSCT); + } + + @Test + public void invalidOCSPTwoSctsAllStaticsVerificationResult() throws Exception { + invalidTwoSctsAllStatic(ocspSCT); } @Test diff --git a/testing/src/main/java/org/conscrypt/TestUtils.java b/testing/src/main/java/org/conscrypt/TestUtils.java index f62a23466..aceb6a764 100644 --- a/testing/src/main/java/org/conscrypt/TestUtils.java +++ b/testing/src/main/java/org/conscrypt/TestUtils.java @@ -85,7 +85,7 @@ public final class TestUtils { private static final String PROTOCOL_TLS_V1_1 = "TLSv1.1"; // For interop testing we need a JDK Provider that can do TLS 1.2 as 1.x may be disabled // in Conscrypt and 1.3 does not (yet) handle interoperability with the JDK Provider. - private static final String[] DESIRED_JDK_PROTOCOLS = new String[] { PROTOCOL_TLS_V1_2 }; + private static final String[] DESIRED_JDK_PROTOCOLS = new String[] {PROTOCOL_TLS_V1_2}; private static final Provider JDK_PROVIDER = getNonConscryptTlsProvider(); private static final byte[] CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".getBytes(UTF_8); @@ -174,7 +174,7 @@ public static boolean isClassAvailable(String classname) { private static void assumeClassAvailable(String classname) { Assume.assumeTrue("Skipping test: " + classname + " unavailable", - isClassAvailable(classname)); + isClassAvailable(classname)); } public static void assumeSNIHostnameAvailable() { @@ -198,7 +198,8 @@ public static void assumeSetEndpointIdentificationAlgorithmAvailable() { // Ignored } Assume.assumeTrue("Skipping test: " - + "SSLParameters.setEndpointIdentificationAlgorithm unavailable", supported); + + "SSLParameters.setEndpointIdentificationAlgorithm unavailable", + supported); } public static void assumeAEADAvailable() { @@ -221,8 +222,7 @@ public static void assumeAndroid() { public static void assumeAllowsUnsignedCrypto() { // The Oracle JRE disallows loading crypto providers from unsigned jars - Assume.assumeTrue(isAndroid() - || !System.getProperty("java.vm.name").contains("HotSpot")); + Assume.assumeTrue(isAndroid() || !System.getProperty("java.vm.name").contains("HotSpot")); } public static void assumeSHA2WithDSAAvailable() { @@ -250,23 +250,22 @@ public static InetAddress getLoopbackAddress() { } } - public static Provider getConscryptProvider(boolean isTlsV1Deprecated, - boolean isTlsV1Enabled) { + public static Provider getConscryptProvider(boolean isTlsV1Deprecated, boolean isTlsV1Enabled) { try { String defaultName = (String) conscryptClass("Platform") - .getDeclaredMethod("getDefaultProviderName") - .invoke(null); + .getDeclaredMethod("getDefaultProviderName") + .invoke(null); Constructor c = conscryptClass("OpenSSLProvider") - .getDeclaredConstructor(String.class, Boolean.TYPE, - String.class, Boolean.TYPE, Boolean.TYPE); + .getDeclaredConstructor(String.class, Boolean.TYPE, String.class, + Boolean.TYPE, Boolean.TYPE); if (!isClassAvailable("javax.net.ssl.X509ExtendedTrustManager")) { - return (Provider) c.newInstance(defaultName, false, "TLSv1.3", - isTlsV1Deprecated, isTlsV1Enabled); + return (Provider) c.newInstance(defaultName, false, "TLSv1.3", isTlsV1Deprecated, + isTlsV1Enabled); } else { - return (Provider) c.newInstance(defaultName, true, "TLSv1.3", - isTlsV1Deprecated, isTlsV1Enabled); + return (Provider) c.newInstance(defaultName, true, "TLSv1.3", isTlsV1Deprecated, + isTlsV1Enabled); } } catch (Exception e) { throw new RuntimeException(e); @@ -311,8 +310,8 @@ public static PublicKey readPublicKeyPemFile(String name) public static List readCsvResource(String resourceName) throws IOException { InputStream stream = openTestFile(resourceName); List lines = new ArrayList<>(); - try (BufferedReader reader - = new BufferedReader(new InputStreamReader(stream, StandardCharsets.UTF_8))) { + try (BufferedReader reader = + new BufferedReader(new InputStreamReader(stream, StandardCharsets.UTF_8))) { String line; while ((line = reader.readLine()) != null) { if (line.isEmpty() || line.startsWith("#")) { @@ -328,8 +327,8 @@ public static List readTestVectors(String resourceName) throws IOExc InputStream stream = openTestFile(resourceName); List result = new ArrayList<>(); TestVector current = null; - try (BufferedReader reader - = new BufferedReader(new InputStreamReader(stream, StandardCharsets.UTF_8))) { + try (BufferedReader reader = + new BufferedReader(new InputStreamReader(stream, StandardCharsets.UTF_8))) { String line; int lineNumber = 0; while ((line = reader.readLine()) != null) { @@ -348,7 +347,7 @@ public static List readTestVectors(String resourceName) throws IOExc result.add(current); } else if (current == null) { throw new IllegalStateException("Vectors must start with a name: line " - + lineNumber); + + lineNumber); } current.put(label, value); } @@ -381,8 +380,8 @@ public static Class findClass(String name) { } } - public static SSLSocketFactory setUseEngineSocket( - SSLSocketFactory conscryptFactory, boolean useEngineSocket) { + public static SSLSocketFactory setUseEngineSocket(SSLSocketFactory conscryptFactory, + boolean useEngineSocket) { try { Class clazz = conscryptClass("Conscrypt"); Method method = @@ -394,12 +393,12 @@ public static SSLSocketFactory setUseEngineSocket( } } - public static SSLServerSocketFactory setUseEngineSocket( - SSLServerSocketFactory conscryptFactory, boolean useEngineSocket) { + public static SSLServerSocketFactory setUseEngineSocket(SSLServerSocketFactory conscryptFactory, + boolean useEngineSocket) { try { Class clazz = conscryptClass("Conscrypt"); - Method method = clazz.getMethod( - "setUseEngineSocket", SSLServerSocketFactory.class, boolean.class); + Method method = clazz.getMethod("setUseEngineSocket", SSLServerSocketFactory.class, + boolean.class); method.invoke(null, conscryptFactory, useEngineSocket); return conscryptFactory; } catch (Exception e) { @@ -409,13 +408,14 @@ public static SSLServerSocketFactory setUseEngineSocket( static boolean getUseEngineSocketByDefault() { try { - boolean sfDefault = getBooleanField( - "OpenSSLSocketFactoryImpl", "useEngineSocketByDefault"); - boolean ssfDefault = getBooleanField( - "OpenSSLServerSocketFactoryImpl", "useEngineSocketByDefault"); + boolean sfDefault = + getBooleanField("OpenSSLSocketFactoryImpl", "useEngineSocketByDefault"); + boolean ssfDefault = + getBooleanField("OpenSSLServerSocketFactoryImpl", "useEngineSocketByDefault"); if (sfDefault != ssfDefault) { - throw new IllegalStateException("Socket factory and server socket factory must\n" + - "use the same default implementation during testing"); + throw new IllegalStateException( + "Socket factory and server socket factory must\n" + + "use the same default implementation during testing"); } return sfDefault; } catch (Exception e) { @@ -459,16 +459,17 @@ public static String[] getCommonProtocolSuites() { SSLContext conscryptContext = newClientSslContext(getConscryptProvider()); // No point building a Set here due to small list sizes. List conscryptProtocols = getSupportedProtocols(conscryptContext); - Predicate predicate = p -> conscryptProtocols.contains(p) - // TODO(prb): Certificate auth fails when connecting Conscrypt and JDK's TLS 1.3. - && !p.equals(PROTOCOL_TLS_V1_3); + Predicate predicate = p + -> conscryptProtocols.contains(p) + // TODO(prb): Certificate auth fails when connecting Conscrypt and JDK's TLS 1.3. + && !p.equals(PROTOCOL_TLS_V1_3); return getSupportedProtocols(jdkContext, predicate); } public static String[] getCommonCipherSuites() { SSLContext jdkContext = newClientSslContext(getJdkProvider()); SSLContext conscryptContext = newClientSslContext(getConscryptProvider()); - Set conscryptCiphers = new HashSet<>(getSupportedCiphers(conscryptContext)); + Set conscryptCiphers = new HashSet<>(getSupportedCiphers(conscryptContext)); Predicate predicate = c -> isTlsCipherSuite(c) && conscryptCiphers.contains(c); return getSupportedCiphers(jdkContext, predicate); } @@ -479,8 +480,8 @@ public static List getSupportedCiphers(SSLContext ctx) { public static String[] getSupportedCiphers(SSLContext ctx, Predicate predicate) { return Arrays.stream(ctx.getDefaultSSLParameters().getCipherSuites()) - .filter(predicate) - .toArray(String[]::new); + .filter(predicate) + .toArray(String[] ::new); } public static String[] getSupportedProtocols() { @@ -494,14 +495,13 @@ public static List getSupportedProtocols(SSLContext ctx) { public static String[] getSupportedProtocols(SSLContext ctx, Predicate predicate) { return Arrays.stream(ctx.getDefaultSSLParameters().getProtocols()) - .filter(predicate) - .toArray(String[]::new); + .filter(predicate) + .toArray(String[] ::new); } private static boolean isTlsCipherSuite(String cipher) { - return !cipher.startsWith("SSL_") - && !cipher.startsWith("TLS_EMPTY") - && !cipher.contains("_RC4_"); + return !cipher.startsWith("SSL_") && !cipher.startsWith("TLS_EMPTY") + && !cipher.contains("_RC4_"); } public static void assumeTlsV11Enabled(SSLContext context) { @@ -579,8 +579,9 @@ static SSLContext initSslContext(SSLContext context, TestKeyStore keyStore) { * Performs the initial TLS handshake between the two {@link SSLEngine} instances. */ public static void doEngineHandshake(SSLEngine clientEngine, SSLEngine serverEngine, - ByteBuffer clientAppBuffer, ByteBuffer clientPacketBuffer, ByteBuffer serverAppBuffer, - ByteBuffer serverPacketBuffer, boolean beginHandshake) throws SSLException { + ByteBuffer clientAppBuffer, ByteBuffer clientPacketBuffer, + ByteBuffer serverAppBuffer, ByteBuffer serverPacketBuffer, + boolean beginHandshake) throws SSLException { if (beginHandshake) { clientEngine.beginHandshake(); serverEngine.beginHandshake(); @@ -635,9 +636,9 @@ public static void doEngineHandshake(SSLEngine clientEngine, SSLEngine serverEng assertEquals(serverPacketBuffer.position() - sTOcPos, clientResult.bytesConsumed()); assertEquals(clientPacketBuffer.position() - cTOsPos, serverResult.bytesConsumed()); assertEquals(clientAppBuffer.position() - clientAppReadBufferPos, - clientResult.bytesProduced()); + clientResult.bytesProduced()); assertEquals(serverAppBuffer.position() - serverAppReadBufferPos, - serverResult.bytesProduced()); + serverResult.bytesProduced()); clientPacketBuffer.compact(); serverPacketBuffer.compact(); @@ -701,7 +702,8 @@ public static byte[] decodeHex(String encoded) throws IllegalArgumentException { *

* Throws an {@code IllegalArgumentException} if the input is malformed. */ - public static byte[] decodeHex(String encoded, boolean allowSingleChar) throws IllegalArgumentException { + public static byte[] decodeHex(String encoded, boolean allowSingleChar) + throws IllegalArgumentException { return decodeHex(encoded.toCharArray(), allowSingleChar); } @@ -722,7 +724,8 @@ public static byte[] decodeHex(char[] encoded) throws IllegalArgumentException { *

* Throws an {@code IllegalArgumentException} if the input is malformed. */ - public static byte[] decodeHex(char[] encoded, boolean allowSingleChar) throws IllegalArgumentException { + public static byte[] decodeHex(char[] encoded, boolean allowSingleChar) + throws IllegalArgumentException { int resultLengthBytes = (encoded.length + 1) / 2; byte[] result = new byte[resultLengthBytes]; @@ -730,7 +733,8 @@ public static byte[] decodeHex(char[] encoded, boolean allowSingleChar) throws I int i = 0; if (allowSingleChar) { if ((encoded.length % 2) != 0) { - // Odd number of digits -- the first digit is the lower 4 bits of the first result byte. + // Odd number of digits -- the first digit is the lower 4 bits of the first result + // byte. result[resultOffset++] = (byte) toDigit(encoded, i); i++; } @@ -760,8 +764,7 @@ private static int toDigit(char[] str, int offset) throws IllegalArgumentExcepti return 10 + (pseudoCodePoint - 'A'); } - throw new IllegalArgumentException("Illegal char: " + str[offset] + - " at offset " + offset); + throw new IllegalArgumentException("Illegal char: " + str[offset] + " at offset " + offset); } private static final char[] HEX_CHARS = "0123456789abcdef".toCharArray(); @@ -789,8 +792,8 @@ public static String encodeBase64(byte[] data) { for (int i = 0; i < data.length; i += 3) { int padding = (i + 2 < data.length) ? 0 : (i + 3 - data.length); byte b1 = data[i]; - byte b2 = padding >= 2 ? 0 : data[i+1]; - byte b3 = padding >= 1 ? 0 : data[i+2]; + byte b2 = padding >= 2 ? 0 : data[i + 1]; + byte b3 = padding >= 1 ? 0 : data[i + 2]; char c1 = BASE64_ALPHABET.charAt((b1 & 0xFF) >>> 2); char c2 = BASE64_ALPHABET.charAt(((b1 & 0x03) << 4) | ((b2 & 0xFF) >>> 4)); @@ -823,16 +826,16 @@ public static byte[] decodeBase64(String data) { int outputindex = 0; for (int i = 0; i < data.length(); i += 4) { char c1 = data.charAt(i); - char c2 = data.charAt(i+1); - char c3 = (i+2 < data.length()) ? data.charAt(i+2) : 'A'; - char c4 = (i+3 < data.length()) ? data.charAt(i+3) : 'A'; + char c2 = data.charAt(i + 1); + char c3 = (i + 2 < data.length()) ? data.charAt(i + 2) : 'A'; + char c4 = (i + 3 < data.length()) ? data.charAt(i + 3) : 'A'; - byte b1 = (byte) - (BASE64_ALPHABET.indexOf(c1) << 2 | BASE64_ALPHABET.indexOf(c2) >>> 4); - byte b2 = (byte) - ((BASE64_ALPHABET.indexOf(c2) & 0x0F) << 4 | BASE64_ALPHABET.indexOf(c3) >>> 2); - byte b3 = (byte) - ((BASE64_ALPHABET.indexOf(c3) & 0x03) << 6 | BASE64_ALPHABET.indexOf(c4)); + byte b1 = (byte) (BASE64_ALPHABET.indexOf(c1) << 2 + | BASE64_ALPHABET.indexOf(c2) >>> 4); + byte b2 = (byte) ((BASE64_ALPHABET.indexOf(c2) & 0x0F) << 4 + | BASE64_ALPHABET.indexOf(c3) >>> 2); + byte b3 = (byte) ((BASE64_ALPHABET.indexOf(c3) & 0x03) << 6 + | BASE64_ALPHABET.indexOf(c4)); output[outputindex++] = b1; if (outputindex < output.length) { @@ -907,9 +910,7 @@ public static boolean isJavaxCertificateSupported() { // due to version skew etc then return the default value. public static boolean callPlatformMethod(String methodName, boolean defaultValue) { try { - return (Boolean) conscryptClass("Platform") - .getDeclaredMethod(methodName) - .invoke(null); + return (Boolean) conscryptClass("Platform").getDeclaredMethod(methodName).invoke(null); } catch (NoSuchMethodException e) { return defaultValue; } catch (ClassNotFoundException | IllegalAccessException | InvocationTargetException e) { @@ -925,8 +926,8 @@ public interface ThrowingRunnable { // Stress test a throwing Runnable with default counts and allowing exceptions, // e.g. to ensure abuse of non-thread-safe code doesn't cause native crashes. - public static void stressTestAllowingExceptions( - int threadCount, int iterationCount, ThrowingRunnable runnable) throws Exception { + public static void stressTestAllowingExceptions(int threadCount, int iterationCount, + ThrowingRunnable runnable) throws Exception { stressTest(threadCount, iterationCount, true, runnable); } @@ -953,7 +954,7 @@ public static void stressTest(int threadCount, int iterationCount, ThrowingRunna * @param runnable a {@link ThrowingRunnable} containing the code to test */ private static void stressTest(int threadCount, int iterationCount, boolean allowExceptions, - ThrowingRunnable runnable) throws Exception { + ThrowingRunnable runnable) throws Exception { ExecutorService es = Executors.newFixedThreadPool(threadCount); final CountDownLatch latch = new CountDownLatch(threadCount); diff --git a/testing/src/main/java/org/conscrypt/java/security/StandardNames.java b/testing/src/main/java/org/conscrypt/java/security/StandardNames.java index 7c9094563..3506b42f3 100644 --- a/testing/src/main/java/org/conscrypt/java/security/StandardNames.java +++ b/testing/src/main/java/org/conscrypt/java/security/StandardNames.java @@ -20,6 +20,9 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; +import org.conscrypt.TestUtils; + +import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; @@ -29,8 +32,6 @@ import java.util.Set; import java.util.TreeSet; -import org.conscrypt.TestUtils; - /** * This class defines expected string names for protocols, key types, * client and server auth types, cipher suites. @@ -59,7 +60,8 @@ public final class StandardNames { public static final boolean IS_RI = !"Dalvik Core Library".equals(System.getProperty("java.specification.name")); - public static final String JSSE_PROVIDER_NAME = IS_RI ? "Conscrypt" : "AndroidOpenSSL"; + public static final String JSSE_PROVIDER_NAME = + "AndroidOpenSSL"; // google3 patch, see copy.bara.sky public static final String KEY_MANAGER_FACTORY_DEFAULT = IS_RI ? "SunX509" : "PKIX"; public static final String TRUST_MANAGER_FACTORY_DEFAULT = "PKIX"; @@ -128,8 +130,8 @@ private static void provideCipherPaddings(String algorithm, String[] newPaddings } @SuppressWarnings("EnumOrdinal") - private static void provideSslContextEnabledProtocols( - String algorithm, TLSVersion minimum, TLSVersion maximum) { + private static void provideSslContextEnabledProtocols(String algorithm, TLSVersion minimum, + TLSVersion maximum) { if (minimum.ordinal() > maximum.ordinal()) { throw new RuntimeException("TLS version: minimum > maximum"); } @@ -155,19 +157,26 @@ private static void provideSslContextEnabledProtocols( provideCipherPaddings("AES", new String[] {"PKCS7Padding"}); } - provideSslContextEnabledProtocols("TLS", TLSVersion.TLSv1, TLSVersion.TLSv13); - provideSslContextEnabledProtocols("TLSv1", TLSVersion.TLSv1, TLSVersion.TLSv12); - provideSslContextEnabledProtocols("TLSv1.1", TLSVersion.TLSv1, TLSVersion.TLSv12); - provideSslContextEnabledProtocols("TLSv1.2", TLSVersion.TLSv1, TLSVersion.TLSv12); - provideSslContextEnabledProtocols("TLSv1.3", TLSVersion.TLSv1, TLSVersion.TLSv13); - provideSslContextEnabledProtocols("Default", TLSVersion.TLSv1, TLSVersion.TLSv13); + if (TestUtils.isTlsV1Supported()) { + provideSslContextEnabledProtocols("TLS", TLSVersion.TLSv1, TLSVersion.TLSv13); + provideSslContextEnabledProtocols("TLSv1", TLSVersion.TLSv1, TLSVersion.TLSv12); + provideSslContextEnabledProtocols("TLSv1.1", TLSVersion.TLSv1, TLSVersion.TLSv12); + provideSslContextEnabledProtocols("TLSv1.2", TLSVersion.TLSv1, TLSVersion.TLSv12); + provideSslContextEnabledProtocols("TLSv1.3", TLSVersion.TLSv1, TLSVersion.TLSv13); + provideSslContextEnabledProtocols("Default", TLSVersion.TLSv1, TLSVersion.TLSv13); + } else { + provideSslContextEnabledProtocols("TLS", TLSVersion.TLSv12, TLSVersion.TLSv13); + provideSslContextEnabledProtocols("TLSv1.2", TLSVersion.TLSv12, TLSVersion.TLSv12); + provideSslContextEnabledProtocols("TLSv1.3", TLSVersion.TLSv12, TLSVersion.TLSv13); + provideSslContextEnabledProtocols("Default", TLSVersion.TLSv12, TLSVersion.TLSv13); + } } public static final String SSL_CONTEXT_PROTOCOLS_DEFAULT = "Default"; public static final Set SSL_CONTEXT_PROTOCOLS = new HashSet( - Arrays.asList(SSL_CONTEXT_PROTOCOLS_DEFAULT, "TLS", "TLSv1", "TLSv1.1", "TLSv1.2", "TLSv1.3")); - public static final Set SSL_CONTEXT_PROTOCOLS_WITH_DEFAULT_CONFIG = new HashSet( - Arrays.asList(SSL_CONTEXT_PROTOCOLS_DEFAULT, "TLS", "TLSv1.3")); + Arrays.asList(SSL_CONTEXT_PROTOCOLS_DEFAULT, "TLS", "TLSv1.2", "TLSv1.3")); + public static final Set SSL_CONTEXT_PROTOCOLS_WITH_DEFAULT_CONFIG = + new HashSet(Arrays.asList(SSL_CONTEXT_PROTOCOLS_DEFAULT, "TLS", "TLSv1.3")); // Deprecated TLS protocols... May or may not be present or enabled. public static final Set SSL_CONTEXT_PROTOCOLS_DEPRECATED = new HashSet<>(); static { @@ -191,8 +200,15 @@ private static void provideSslContextEnabledProtocols( } } - public static final Set SSL_SOCKET_PROTOCOLS = - new HashSet(Arrays.asList("TLSv1", "TLSv1.1", "TLSv1.2", "TLSv1.3")); + public static final Set SSL_SOCKET_PROTOCOLS = new HashSet<>(); + static { + SSL_SOCKET_PROTOCOLS.add("TLSv1.2"); + SSL_SOCKET_PROTOCOLS.add("TLSv1.3"); + if (TestUtils.isTlsV1Supported()) { + SSL_SOCKET_PROTOCOLS.add("TLSv1"); + SSL_SOCKET_PROTOCOLS.add("TLSv1.1"); + } + } private enum TLSVersion { SSLv3("SSLv3"), @@ -222,11 +238,11 @@ private enum TLSVersion { * or GENERIC (for TLS 1.3 cipher suites that don't imply a specific * key exchange method). */ - public static final Set SERVER_AUTH_TYPES = new HashSet(Arrays.asList("DHE_DSS", - "DHE_DSS_EXPORT", "DHE_RSA", "DHE_RSA_EXPORT", "DH_DSS_EXPORT", "DH_RSA_EXPORT", - "DH_anon", "DH_anon_EXPORT", "KRB5", "KRB5_EXPORT", "RSA", "RSA_EXPORT", - "RSA_EXPORT1024", "ECDH_ECDSA", "ECDH_RSA", "ECDHE_ECDSA", "ECDHE_RSA", "UNKNOWN", - "GENERIC")); + public static final Set SERVER_AUTH_TYPES = new HashSet( + Arrays.asList("DHE_DSS", "DHE_DSS_EXPORT", "DHE_RSA", "DHE_RSA_EXPORT", "DH_DSS_EXPORT", + "DH_RSA_EXPORT", "DH_anon", "DH_anon_EXPORT", "KRB5", "KRB5_EXPORT", + "RSA", "RSA_EXPORT", "RSA_EXPORT1024", "ECDH_ECDSA", "ECDH_RSA", + "ECDHE_ECDSA", "ECDHE_RSA", "UNKNOWN", "GENERIC")); public static final String CIPHER_SUITE_INVALID = "SSL_NULL_WITH_NULL_NULL"; @@ -278,68 +294,43 @@ private static void addOpenSsl(String cipherSuite) { * Cipher suites that are not negotiated when TLSv1.2 is selected on the RI. */ public static final List CIPHER_SUITES_OBSOLETE_TLS12 = Arrays.asList( - "SSL_RSA_WITH_DES_CBC_SHA", - "SSL_DHE_RSA_WITH_DES_CBC_SHA", - "SSL_DHE_DSS_WITH_DES_CBC_SHA", - "SSL_DH_anon_WITH_DES_CBC_SHA", - "SSL_RSA_EXPORT_WITH_RC4_40_MD5", - "SSL_DH_anon_EXPORT_WITH_RC4_40_MD5", - "SSL_RSA_EXPORT_WITH_DES40_CBC_SHA", - "SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA", - "SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA", - "SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA"); + "SSL_RSA_WITH_DES_CBC_SHA", "SSL_DHE_RSA_WITH_DES_CBC_SHA", + "SSL_DHE_DSS_WITH_DES_CBC_SHA", "SSL_DH_anon_WITH_DES_CBC_SHA", + "SSL_RSA_EXPORT_WITH_RC4_40_MD5", "SSL_DH_anon_EXPORT_WITH_RC4_40_MD5", + "SSL_RSA_EXPORT_WITH_DES40_CBC_SHA", "SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA", + "SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA", "SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA"); /** * Cipher suites that are only supported with TLS 1.3. */ public static final List CIPHER_SUITES_TLS13 = Arrays.asList( - "TLS_AES_128_GCM_SHA256", - "TLS_AES_256_GCM_SHA384", - "TLS_CHACHA20_POLY1305_SHA256"); + "TLS_AES_128_GCM_SHA256", "TLS_AES_256_GCM_SHA384", "TLS_CHACHA20_POLY1305_SHA256"); // NOTE: This list needs to be kept in sync with Javadoc of javax.net.ssl.SSLSocket and // javax.net.ssl.SSLEngine. private static final List CIPHER_SUITES_AES_HARDWARE = Arrays.asList( - "TLS_AES_128_GCM_SHA256", - "TLS_AES_256_GCM_SHA384", - "TLS_CHACHA20_POLY1305_SHA256", - "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", - "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", + "TLS_AES_128_GCM_SHA256", "TLS_AES_256_GCM_SHA384", "TLS_CHACHA20_POLY1305_SHA256", + "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256", - "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", - "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", - "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256", - "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", - "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", - "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", - "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", - "TLS_RSA_WITH_AES_128_GCM_SHA256", - "TLS_RSA_WITH_AES_256_GCM_SHA384", - "TLS_RSA_WITH_AES_128_CBC_SHA", - "TLS_RSA_WITH_AES_256_CBC_SHA", - CIPHER_SUITE_SECURE_RENEGOTIATION); + "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", + "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256", "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", + "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", + "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", "TLS_RSA_WITH_AES_128_GCM_SHA256", + "TLS_RSA_WITH_AES_256_GCM_SHA384", "TLS_RSA_WITH_AES_128_CBC_SHA", + "TLS_RSA_WITH_AES_256_CBC_SHA", CIPHER_SUITE_SECURE_RENEGOTIATION); // NOTE: This list needs to be kept in sync with Javadoc of javax.net.ssl.SSLSocket and // javax.net.ssl.SSLEngine. private static final List CIPHER_SUITES_SOFTWARE = Arrays.asList( - "TLS_AES_128_GCM_SHA256", - "TLS_AES_256_GCM_SHA384", - "TLS_CHACHA20_POLY1305_SHA256", + "TLS_AES_128_GCM_SHA256", "TLS_AES_256_GCM_SHA384", "TLS_CHACHA20_POLY1305_SHA256", "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256", - "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", - "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", - "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256", - "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", - "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", - "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", - "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", - "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", - "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", - "TLS_RSA_WITH_AES_128_GCM_SHA256", - "TLS_RSA_WITH_AES_256_GCM_SHA384", - "TLS_RSA_WITH_AES_128_CBC_SHA", - "TLS_RSA_WITH_AES_256_CBC_SHA", - CIPHER_SUITE_SECURE_RENEGOTIATION); + "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", + "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256", "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", + "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", + "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", + "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", "TLS_RSA_WITH_AES_128_GCM_SHA256", + "TLS_RSA_WITH_AES_256_GCM_SHA384", "TLS_RSA_WITH_AES_128_CBC_SHA", + "TLS_RSA_WITH_AES_256_CBC_SHA", CIPHER_SUITE_SECURE_RENEGOTIATION); // NOTE: This list needs to be kept in sync with Javadoc of javax.net.ssl.SSLSocket and // javax.net.ssl.SSLEngine. @@ -350,10 +341,8 @@ private static void addOpenSsl(String cipherSuite) { // NOTE: This list needs to be kept in sync with Javadoc of javax.net.ssl.SSLSocket and // javax.net.ssl.SSLEngine. public static final List CIPHER_SUITES_DEFAULT_PSK = Arrays.asList( - "TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256", - "TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA", - "TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA", - "TLS_PSK_WITH_AES_128_CBC_SHA", + "TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256", "TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA", + "TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA", "TLS_PSK_WITH_AES_128_CBC_SHA", "TLS_PSK_WITH_AES_256_CBC_SHA"); // Should be updated to match BoringSSL's defaults when they change. @@ -368,8 +357,8 @@ private static void addOpenSsl(String cipherSuite) { * suites in a test for those that want to verify separately that * all cipher suites were included. */ - private static Set assertValidCipherSuites( - Set expected, String[] cipherSuites) { + private static Set assertValidCipherSuites(Set expected, + String[] cipherSuites) { assertNotNull(cipherSuites); assertTrue(cipherSuites.length != 0); @@ -448,11 +437,23 @@ public static void assertValidCipherSuites(String[] cipherSuites) { assertValidCipherSuites(CIPHER_SUITES, cipherSuites); } + private static final List OPTIONAL_CIPHER_SUITES = + Arrays.asList("SSL_RSA_WITH_3DES_EDE_CBC_SHA"); + /** * Assert that the provided list of cipher suites matches the supported list. */ public static void assertSupportedCipherSuites(String[] cipherSuites) { - assertSupportedCipherSuites(CIPHER_SUITES, cipherSuites); + List filteredCipherSuites = new ArrayList<>(); + for (String cipherSuite : cipherSuites) { + if (OPTIONAL_CIPHER_SUITES.contains(cipherSuite)) { + continue; + } + filteredCipherSuites.add(cipherSuite); + } + String[] filteredCipherSuitesArray = new String[filteredCipherSuites.size()]; + filteredCipherSuites.toArray(filteredCipherSuitesArray); + assertSupportedCipherSuites(CIPHER_SUITES, filteredCipherSuitesArray); } /** @@ -472,8 +473,8 @@ public static void assertDefaultEllipticCurves(String[] curves) { } public static void assertSSLContextEnabledProtocols(String version, String[] protocols) { - Set expected = new HashSet<>( - Arrays.asList(SSL_CONTEXT_PROTOCOLS_ENABLED.get(version))); + Set expected = + new HashSet<>(Arrays.asList(SSL_CONTEXT_PROTOCOLS_ENABLED.get(version))); Set actual = new HashSet<>(Arrays.asList(protocols)); // Ignore deprecated protocols, which are set earlier based diff --git a/testing/src/main/java/org/conscrypt/testing/OpaqueProvider.java b/testing/src/main/java/org/conscrypt/testing/OpaqueProvider.java index 2a9e2059f..b88bb2875 100644 --- a/testing/src/main/java/org/conscrypt/testing/OpaqueProvider.java +++ b/testing/src/main/java/org/conscrypt/testing/OpaqueProvider.java @@ -2,6 +2,8 @@ import static org.junit.Assert.fail; +import org.conscrypt.java.security.StandardNames; + import java.math.BigInteger; import java.security.AlgorithmParameters; import java.security.InvalidAlgorithmParameterException; @@ -23,325 +25,327 @@ import java.security.interfaces.RSAPrivateKey; import java.security.spec.AlgorithmParameterSpec; import java.security.spec.ECParameterSpec; + import javax.crypto.BadPaddingException; import javax.crypto.Cipher; import javax.crypto.CipherSpi; import javax.crypto.IllegalBlockSizeException; import javax.crypto.NoSuchPaddingException; import javax.crypto.ShortBufferException; -import org.conscrypt.java.security.StandardNames; /** * A provider that supplies and can use keys whose keying material is hidden from callers. */ @SuppressWarnings("serial") public class OpaqueProvider extends Provider { + public static final String NAME = "OpaqueProvider"; + + public OpaqueProvider() { + super(NAME, 1.0, "test provider"); + put("Signature.NONEwithECDSA", OpaqueSignatureSpi.ECDSA.class.getName()); + put("Cipher.RSA/ECB/NoPadding", OpaqueCipherSpi.NoPadding.class.getName()); + put("Cipher.RSA/ECB/PKCS1Padding", OpaqueCipherSpi.PKCS1Padding.class.getName()); + } + + /** + * Returns an opaque key that wraps the given key. + */ + public static PrivateKey wrapKey(PrivateKey key) { + if (key instanceof RSAPrivateKey) { + return new OpaqueDelegatingRSAPrivateKey((RSAPrivateKey) key); + } else if (key instanceof ECPrivateKey) { + return new OpaqueDelegatingECPrivateKey((ECPrivateKey) key); + } else { + fail("Unknown key type: " + key.getClass().getName()); + return null; + } + } + + /** + * Returns an opaque key that wraps the given key and is additionally marked with the + * appropriate FooPrivateKey interface for that key type. + */ + public static PrivateKey wrapKeyMarked(PrivateKey key) { + if (key instanceof RSAPrivateKey) { + return new OpaqueDelegatingMarkedRSAPrivateKey((RSAPrivateKey) key); + } else if (key instanceof ECPrivateKey) { + return new OpaqueDelegatingMarkedECPrivateKey((ECPrivateKey) key); + } else { + fail("Unknown key type: " + key.getClass().getName()); + return null; + } + } + + private static class OpaqueSignatureSpi extends SignatureSpi { + private final String algorithm; + private Signature delegate; + + OpaqueSignatureSpi(String algorithm) { + this.algorithm = algorithm; + } + + public final static class ECDSA extends OpaqueSignatureSpi { + public ECDSA() { + super("NONEwithECDSA"); + } + } + + @Override + protected void engineInitVerify(PublicKey publicKey) throws InvalidKeyException { + fail("Cannot verify"); + } + + @Override + protected void engineInitSign(PrivateKey privateKey) throws InvalidKeyException { + DelegatingPrivateKey opaqueKey = (DelegatingPrivateKey) privateKey; + try { + delegate = Signature.getInstance(algorithm); + } catch (NoSuchAlgorithmException e) { + throw new InvalidKeyException(e); + } + delegate.initSign(opaqueKey.getDelegate()); + } + + @Override + protected void engineUpdate(byte b) throws SignatureException { + delegate.update(b); + } + + @Override + protected void engineUpdate(byte[] b, int off, int len) throws SignatureException { + delegate.update(b, off, len); + } + + @Override + protected byte[] engineSign() throws SignatureException { + return delegate.sign(); + } + + @Override + protected boolean engineVerify(byte[] sigBytes) throws SignatureException { + return delegate.verify(sigBytes); + } + + @SuppressWarnings("deprecation") + @Override + protected void engineSetParameter(String param, Object value) + throws InvalidParameterException { + delegate.setParameter(param, value); + } + + @SuppressWarnings("deprecation") + @Override + protected Object engineGetParameter(String param) throws InvalidParameterException { + return delegate.getParameter(param); + } + } + + private static class OpaqueCipherSpi extends CipherSpi { + private Cipher delegate; + private final String algorithm; + + public OpaqueCipherSpi(String algorithm) { + this.algorithm = algorithm; + } + + public final static class NoPadding extends OpaqueCipherSpi { + public NoPadding() { + super("RSA/ECB/NoPadding"); + } + } + + public final static class PKCS1Padding extends OpaqueCipherSpi { + public PKCS1Padding() { + super("RSA/ECB/PKCS1Padding"); + } + } + + @Override + protected void engineSetMode(String mode) throws NoSuchAlgorithmException { + fail(); + } + + @Override + protected void engineSetPadding(String padding) throws NoSuchPaddingException { + fail(); + } + + @Override + protected int engineGetBlockSize() { + return delegate.getBlockSize(); + } + + @Override + protected int engineGetOutputSize(int inputLen) { + return delegate.getOutputSize(inputLen); + } + + @Override + protected byte[] engineGetIV() { + return delegate.getIV(); + } + + @Override + protected AlgorithmParameters engineGetParameters() { + return delegate.getParameters(); + } + + @Override + protected void engineInit(int opmode, Key key, SecureRandom random) + throws InvalidKeyException { + getCipher(); + delegate.init(opmode, ((DelegatingPrivateKey) key).getDelegate(), random); + } + + void getCipher() throws InvalidKeyException { + try { + delegate = Cipher.getInstance(algorithm, StandardNames.JSSE_PROVIDER_NAME); + } catch (NoSuchAlgorithmException | NoSuchPaddingException + | NoSuchProviderException e) { + throw new InvalidKeyException(e); + } + } + + @Override + protected void engineInit(int opmode, Key key, AlgorithmParameterSpec params, + SecureRandom random) + throws InvalidKeyException, InvalidAlgorithmParameterException { + getCipher(); + delegate.init(opmode, ((DelegatingPrivateKey) key).getDelegate(), params, random); + } + + @Override + protected void engineInit(int opmode, Key key, AlgorithmParameters params, + SecureRandom random) + throws InvalidKeyException, InvalidAlgorithmParameterException { + getCipher(); + delegate.init(opmode, ((DelegatingPrivateKey) key).getDelegate(), params, random); + } + + @Override + protected byte[] engineUpdate(byte[] input, int inputOffset, int inputLen) { + return delegate.update(input, inputOffset, inputLen); + } + + @Override + protected int engineUpdate(byte[] input, int inputOffset, int inputLen, byte[] output, + int outputOffset) throws ShortBufferException { + return delegate.update(input, inputOffset, inputLen, output, outputOffset); + } + + @Override + protected byte[] engineDoFinal(byte[] input, int inputOffset, int inputLen) + throws IllegalBlockSizeException, BadPaddingException { + return delegate.doFinal(input, inputOffset, inputLen); + } + + @Override + protected int engineDoFinal(byte[] input, int inputOffset, int inputLen, byte[] output, + int outputOffset) + throws ShortBufferException, IllegalBlockSizeException, BadPaddingException { + return delegate.doFinal(input, inputOffset, inputLen, output, outputOffset); + } + } + + private interface DelegatingPrivateKey { + PrivateKey getDelegate(); + } + + private static class OpaqueDelegatingECPrivateKey + implements ECKey, PrivateKey, DelegatingPrivateKey { + private final ECPrivateKey delegate; + + private OpaqueDelegatingECPrivateKey(ECPrivateKey delegate) { + this.delegate = delegate; + } + + @Override + public PrivateKey getDelegate() { + return delegate; + } + + @Override + public String getAlgorithm() { + return delegate.getAlgorithm(); + } + + @Override + public String getFormat() { + return null; + } + + @Override + public byte[] getEncoded() { + return null; + } + + @Override + public ECParameterSpec getParams() { + return delegate.getParams(); + } + } + + private static class OpaqueDelegatingMarkedECPrivateKey + extends OpaqueDelegatingECPrivateKey implements ECPrivateKey { + private OpaqueDelegatingMarkedECPrivateKey(ECPrivateKey delegate) { + super(delegate); + } + + @Override + public BigInteger getS() { + throw new UnsupportedOperationException("Nope"); + } + } + + private static class OpaqueDelegatingRSAPrivateKey + implements RSAKey, PrivateKey, DelegatingPrivateKey { + private final RSAPrivateKey delegate; + + private OpaqueDelegatingRSAPrivateKey(RSAPrivateKey delegate) { + this.delegate = delegate; + } + + // g3-add: getParams() + @Override + public AlgorithmParameterSpec getParams() { + return delegate.getParams(); + } + + @Override + public String getAlgorithm() { + return delegate.getAlgorithm(); + } + + @Override + public String getFormat() { + return null; + } + + @Override + public byte[] getEncoded() { + return null; + } + + @Override + public BigInteger getModulus() { + return delegate.getModulus(); + } + + @Override + public PrivateKey getDelegate() { + return delegate; + } + } + + private static class OpaqueDelegatingMarkedRSAPrivateKey + extends OpaqueDelegatingRSAPrivateKey implements RSAPrivateKey { + private OpaqueDelegatingMarkedRSAPrivateKey(RSAPrivateKey delegate) { + super(delegate); + } - public static final String NAME = "OpaqueProvider"; - - public OpaqueProvider() { - super(NAME, 1.0, "test provider"); - put("Signature.NONEwithECDSA", OpaqueSignatureSpi.ECDSA.class.getName()); - put("Cipher.RSA/ECB/NoPadding", OpaqueCipherSpi.NoPadding.class.getName()); - put("Cipher.RSA/ECB/PKCS1Padding", OpaqueCipherSpi.PKCS1Padding.class.getName()); - } - - /** - * Returns an opaque key that wraps the given key. - */ - public static PrivateKey wrapKey(PrivateKey key) { - if (key instanceof RSAPrivateKey) { - return new OpaqueDelegatingRSAPrivateKey((RSAPrivateKey) key); - } else if (key instanceof ECPrivateKey) { - return new OpaqueDelegatingECPrivateKey((ECPrivateKey) key); - } else { - fail("Unknown key type: " + key.getClass().getName()); - return null; - } - } - - /** - * Returns an opaque key that wraps the given key and is additionally marked with the - * appropriate FooPrivateKey interface for that key type. - */ - public static PrivateKey wrapKeyMarked(PrivateKey key) { - if (key instanceof RSAPrivateKey) { - return new OpaqueDelegatingMarkedRSAPrivateKey((RSAPrivateKey) key); - } else if (key instanceof ECPrivateKey) { - return new OpaqueDelegatingMarkedECPrivateKey((ECPrivateKey) key); - } else { - fail("Unknown key type: " + key.getClass().getName()); - return null; - } - } - - private static class OpaqueSignatureSpi extends SignatureSpi { - private final String algorithm; - private Signature delegate; - - OpaqueSignatureSpi(String algorithm) { - this.algorithm = algorithm; - } - - public final static class ECDSA extends OpaqueSignatureSpi { - public ECDSA() { - super("NONEwithECDSA"); - } - } - - @Override - protected void engineInitVerify(PublicKey publicKey) throws InvalidKeyException { - fail("Cannot verify"); - } - - @Override - protected void engineInitSign(PrivateKey privateKey) throws InvalidKeyException { - DelegatingPrivateKey opaqueKey = (DelegatingPrivateKey) privateKey; - try { - delegate = Signature.getInstance(algorithm); - } catch (NoSuchAlgorithmException e) { - throw new InvalidKeyException(e); - } - delegate.initSign(opaqueKey.getDelegate()); - } - - @Override - protected void engineUpdate(byte b) throws SignatureException { - delegate.update(b); - } - - @Override - protected void engineUpdate(byte[] b, int off, int len) throws SignatureException { - delegate.update(b, off, len); - } - - @Override - protected byte[] engineSign() throws SignatureException { - return delegate.sign(); - } - - @Override - protected boolean engineVerify(byte[] sigBytes) throws SignatureException { - return delegate.verify(sigBytes); - } - - @SuppressWarnings("deprecation") - @Override - protected void engineSetParameter(String param, Object value) - throws InvalidParameterException { - delegate.setParameter(param, value); - } - - @SuppressWarnings("deprecation") - @Override - protected Object engineGetParameter(String param) throws InvalidParameterException { - return delegate.getParameter(param); - } - } - - private static class OpaqueCipherSpi extends CipherSpi { - private Cipher delegate; - private final String algorithm; - - public OpaqueCipherSpi(String algorithm) { - this.algorithm = algorithm; - } - - public final static class NoPadding extends OpaqueCipherSpi { - public NoPadding() { - super("RSA/ECB/NoPadding"); - } - } - - public final static class PKCS1Padding extends OpaqueCipherSpi { - public PKCS1Padding() { - super("RSA/ECB/PKCS1Padding"); - } - } - - @Override - protected void engineSetMode(String mode) throws NoSuchAlgorithmException { - fail(); - } - - @Override - protected void engineSetPadding(String padding) throws NoSuchPaddingException { - fail(); - } - - @Override - protected int engineGetBlockSize() { - return delegate.getBlockSize(); - } - - @Override - protected int engineGetOutputSize(int inputLen) { - return delegate.getOutputSize(inputLen); - } - - @Override - protected byte[] engineGetIV() { - return delegate.getIV(); - } - - @Override - protected AlgorithmParameters engineGetParameters() { - return delegate.getParameters(); - } - - @Override - protected void engineInit(int opmode, Key key, SecureRandom random) - throws InvalidKeyException { - getCipher(); - delegate.init(opmode, ((DelegatingPrivateKey) key).getDelegate(), random); - } - - void getCipher() throws InvalidKeyException { - try { - delegate = Cipher.getInstance(algorithm, StandardNames.JSSE_PROVIDER_NAME); - } catch (NoSuchAlgorithmException | NoSuchPaddingException | NoSuchProviderException e) { - throw new InvalidKeyException(e); - } - } - - @Override - protected void engineInit( - int opmode, Key key, AlgorithmParameterSpec params, SecureRandom random) - throws InvalidKeyException, InvalidAlgorithmParameterException { - getCipher(); - delegate.init(opmode, ((DelegatingPrivateKey) key).getDelegate(), params, random); - } - - @Override - protected void engineInit( - int opmode, Key key, AlgorithmParameters params, SecureRandom random) - throws InvalidKeyException, InvalidAlgorithmParameterException { - getCipher(); - delegate.init(opmode, ((DelegatingPrivateKey) key).getDelegate(), params, random); - } - - @Override - protected byte[] engineUpdate(byte[] input, int inputOffset, int inputLen) { - return delegate.update(input, inputOffset, inputLen); - } - - @Override - protected int engineUpdate(byte[] input, int inputOffset, int inputLen, byte[] output, - int outputOffset) throws ShortBufferException { - return delegate.update(input, inputOffset, inputLen, output, outputOffset); - } - - @Override - protected byte[] engineDoFinal(byte[] input, int inputOffset, int inputLen) - throws IllegalBlockSizeException, BadPaddingException { - return delegate.doFinal(input, inputOffset, inputLen); - } - - @Override - protected int engineDoFinal( - byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) - throws ShortBufferException, IllegalBlockSizeException, BadPaddingException { - return delegate.doFinal(input, inputOffset, inputLen, output, outputOffset); - } - } - - private interface DelegatingPrivateKey { PrivateKey getDelegate(); } - - private static class OpaqueDelegatingECPrivateKey - implements ECKey, PrivateKey, DelegatingPrivateKey { - private final ECPrivateKey delegate; - - private OpaqueDelegatingECPrivateKey(ECPrivateKey delegate) { - this.delegate = delegate; - } - - @Override - public PrivateKey getDelegate() { - return delegate; - } - - @Override - public String getAlgorithm() { - return delegate.getAlgorithm(); - } - - @Override - public String getFormat() { - return null; - } - - @Override - public byte[] getEncoded() { - return null; - } - - @Override - public ECParameterSpec getParams() { - return delegate.getParams(); - } - } - - private static class OpaqueDelegatingMarkedECPrivateKey extends OpaqueDelegatingECPrivateKey - implements ECPrivateKey { - private OpaqueDelegatingMarkedECPrivateKey(ECPrivateKey delegate) { - super(delegate); - } - - @Override - public BigInteger getS() { - throw new UnsupportedOperationException("Nope"); - } - } - - private static class OpaqueDelegatingRSAPrivateKey - implements RSAKey, PrivateKey, DelegatingPrivateKey { - - private final RSAPrivateKey delegate; - - private OpaqueDelegatingRSAPrivateKey(RSAPrivateKey delegate) { - this.delegate = delegate; - } - - @Override - public AlgorithmParameterSpec getParams() { - return delegate.getParams(); - } - - @Override - public String getAlgorithm() { - return delegate.getAlgorithm(); - } - - @Override - public String getFormat() { - return null; - } - - @Override - public byte[] getEncoded() { - return null; - } - - @Override - public BigInteger getModulus() { - return delegate.getModulus(); - } - - @Override - public PrivateKey getDelegate() { - return delegate; - } - } - - private static class OpaqueDelegatingMarkedRSAPrivateKey extends OpaqueDelegatingRSAPrivateKey - implements RSAPrivateKey { - private OpaqueDelegatingMarkedRSAPrivateKey(RSAPrivateKey delegate) { - super(delegate); - } - - @Override - public BigInteger getPrivateExponent() { - throw new UnsupportedOperationException("Nope"); + @Override + public BigInteger getPrivateExponent() { + throw new UnsupportedOperationException("Nope"); + } } - } }