diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 54f23fa01..3b1db4589 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -526,6 +526,10 @@ jobs:
DIR="$(find m2/org/conscrypt/conscrypt-openjdk-uber -maxdepth 1 -mindepth 1 -type d -print)"
VERSION="${DIR##*/}"
TESTJAR="$(find testjar -name '*-tests.jar')"
+ EXTRA_FLAGS=""
+ if [ "${{ matrix.java }}" != "8" ]; then
+ EXTRA_FLAGS="--add-opens=java.base/java.net=ALL-UNNAMED"
+ fi
# SIGTERM handler, e.g. for when tests hang and time out.
# Send SIGQUIT to test process to get thread dump, give it
# a few seconds to complete and then kill it.
@@ -537,7 +541,7 @@ jobs:
kill -KILL "$TESTPID"
exit 1
}
- java -jar junit-platform-console-standalone.jar execute -cp "$DIR/conscrypt-openjdk-uber-$VERSION.jar${{ matrix.separator }}$TESTJAR" -n='org.conscrypt.ConscryptOpenJdkSuite' --scan-classpath --reports-dir=results --fail-if-no-tests &
+ java $EXTRA_FLAGS -jar junit-platform-console-standalone.jar execute -cp "$DIR/conscrypt-openjdk-uber-$VERSION.jar${{ matrix.separator }}$TESTJAR" -n='org.conscrypt.ConscryptOpenJdkSuite' --scan-classpath --reports-dir=results --fail-if-no-tests &
case $(uname -s) in
Darwin|Linux)
trap dump_threads SIGTERM SIGINT
diff --git a/AndroidManifest_instrumentation_test.xml b/AndroidManifest_instrumentation_test.xml
new file mode 100644
index 000000000..238c4f152
--- /dev/null
+++ b/AndroidManifest_instrumentation_test.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/LICENSE b/LICENSE
index d64569567..9f687a821 100644
--- a/LICENSE
+++ b/LICENSE
@@ -200,3 +200,57 @@
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.
+
+===============================================================================
+
+Path = constants/src/gen/java/cert_verify_proc_blocklist.inc
+
+===============================================================================
+// Copyright 2015 The Chromium Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google LLC nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+===============================================================================
+
+Path = common/src/test/resources/crypto/*
+
+===============================================================================
+Terms Of Use
+
+This software was developed by employees of the National Institute of Standards
+and Technology (NIST), and others. This software has been contributed to the
+public domain. Pursuant to title 15 Untied States Code Section 105, works of
+NIST employees are not subject to copyright protection in the United States and
+are considered to be in the public domain. As a result, a formal license is
+not needed to use this software.
+
+This software is provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS,
+IMPLIED OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT AND DATA
+ACCURACY. NIST does not warrant or make any representations regarding the use
+of the software or the results thereof, including but not limited to the
+correctness, accuracy, reliability or usefulness of this software.
\ No newline at end of file
diff --git a/README.md b/README.md
index 7157e18a5..112edaf71 100644
--- a/README.md
+++ b/README.md
@@ -150,7 +150,7 @@ Use the [os-maven-plugin](https://github.com/trustin/os-maven-plugin) to add the
org.conscrypt
conscrypt-openjdk
- 2.6.0
+ 2.6.1
${os.detected.classifier}
```
@@ -173,7 +173,7 @@ buildscript {
apply plugin: "com.google.osdetector"
dependencies {
- compile 'org.conscrypt:conscrypt-openjdk:2.6.0:' + osdetector.classifier
+ compile 'org.conscrypt:conscrypt-openjdk:2.6.1:' + osdetector.classifier
}
```
@@ -191,14 +191,14 @@ To depend on the uber jar, simply use the `conscrypt-openjdk-uber` artifacts.
org.conscrypt
conscrypt-openjdk-uber
- 2.6.0
+ 2.6.1
```
##### Gradle
```gradle
dependencies {
- compile 'org.conscrypt:conscrypt-openjdk-uber:2.6.0'
+ compile 'org.conscrypt:conscrypt-openjdk-uber:2.6.1'
}
```
@@ -211,7 +211,7 @@ arm64-v8a.
```gradle
dependencies {
- implementation 'org.conscrypt:conscrypt-android:2.6.0'
+ implementation 'org.conscrypt:conscrypt-android:2.6.1'
}
```
diff --git a/android-stub/build.gradle b/android-stub/build.gradle
index 9037248c9..e9fb808c7 100644
--- a/android-stub/build.gradle
+++ b/android-stub/build.gradle
@@ -11,3 +11,10 @@ dependencies {
// Disable the javadoc task.
tasks.withType(Javadoc).configureEach { enabled = false }
+
+// The stubs are used to validate the build but are not expected to be called.
+// Skip these lints.
+tasks.withType(JavaCompile).configureEach {
+ options.errorprone.disable("unused")
+ options.errorprone.disable("DoNotCallSuggester")
+}
diff --git a/android-stub/src/main/java/com/android/org/conscrypt/OpenSSLSocketImpl.java b/android-stub/src/main/java/com/android/org/conscrypt/OpenSSLSocketImpl.java
index a2be95473..66a5311f4 100644
--- a/android-stub/src/main/java/com/android/org/conscrypt/OpenSSLSocketImpl.java
+++ b/android-stub/src/main/java/com/android/org/conscrypt/OpenSSLSocketImpl.java
@@ -174,14 +174,6 @@ public void setHostname(String hostname) {
throw new RuntimeException("Stub!");
}
- public void setChannelIdEnabled(boolean enabled) {
- throw new RuntimeException("Stub!");
- }
-
- public byte[] getChannelId() throws SSLException {
- throw new RuntimeException("Stub!");
- }
-
public void setChannelIdPrivateKey(PrivateKey privateKey) {
throw new RuntimeException("Stub!");
}
diff --git a/android/build.gradle b/android/build.gradle
index e8413a2b0..e5cf34de3 100644
--- a/android/build.gradle
+++ b/android/build.gradle
@@ -129,6 +129,7 @@ dependencies {
androidTestImplementation libs.bouncycastle.apis
androidTestImplementation libs.bouncycastle.provider
androidTestImplementation libs.mockito.android
+ androidTestImplementation libs.truth
androidTestImplementation('androidx.test.espresso:espresso-core:3.1.1', {
exclude module: 'support-annotations'
exclude module: 'support-v4'
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/KitKatPlatformOpenSSLSocketImplAdapter.java b/android/src/main/java/org/conscrypt/KitKatPlatformOpenSSLSocketImplAdapter.java
index 2f567ded5..de295f098 100644
--- a/android/src/main/java/org/conscrypt/KitKatPlatformOpenSSLSocketImplAdapter.java
+++ b/android/src/main/java/org/conscrypt/KitKatPlatformOpenSSLSocketImplAdapter.java
@@ -402,21 +402,6 @@ public void setHostname(String hostname) {
delegate.setHostname(hostname);
}
- @Override
- public void setChannelIdEnabled(boolean enabled) {
- delegate.setChannelIdEnabled(enabled);
- }
-
- @Override
- public byte[] getChannelId() throws SSLException {
- return delegate.getChannelId();
- }
-
- @Override
- public void setChannelIdPrivateKey(PrivateKey privateKey) {
- delegate.setChannelIdPrivateKey(privateKey);
- }
-
@Override
public void setSoWriteTimeout(int writeTimeoutMilliseconds) throws SocketException {
delegate.setSoWriteTimeout(writeTimeoutMilliseconds);
diff --git a/android/src/main/java/org/conscrypt/Platform.java b/android/src/main/java/org/conscrypt/Platform.java
index 552248eeb..5426bdd3b 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;
@@ -258,7 +260,8 @@ 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.
}
}
@@ -284,7 +287,9 @@ public static void setSSLParameters(SSLParameters params, SSLParametersImpl impl
socket.setHostname(sniHostname);
}
}
- } catch (NoSuchMethodException | IllegalAccessException ignored) {
+ } catch (NoSuchMethodException ignored) {
+ // Ignored
+ } catch (IllegalAccessException ignored) {
// Ignored
} catch (InvocationTargetException e) {
throw new RuntimeException(e.getCause());
@@ -302,7 +307,9 @@ public static void setSSLParameters(SSLParameters params, SSLParametersImpl impl
engine.setHostname(sniHostname);
}
}
- } catch (NoSuchMethodException | IllegalAccessException ignored) {
+ } catch (NoSuchMethodException ignored) {
+ // Ignored
+ } catch (IllegalAccessException ignored) {
// Ignored
} catch (InvocationTargetException e) {
throw new RuntimeException(e.getCause());
@@ -341,7 +348,8 @@ 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.
}
}
@@ -364,7 +372,9 @@ public static void getSSLParameters(SSLParameters params, SSLParametersImpl impl
if (Build.VERSION.SDK_INT >= 24) {
setParametersSniHostname(params, impl, socket);
}
- } catch (NoSuchMethodException | IllegalAccessException ignored) {
+ } catch (NoSuchMethodException ignored) {
+ // Ignored
+ } catch (IllegalAccessException ignored) {
// Ignored
} catch (InvocationTargetException e) {
throw new RuntimeException(e.getCause());
@@ -391,7 +401,9 @@ public static void getSSLParameters(SSLParameters params, SSLParametersImpl impl
if (Build.VERSION.SDK_INT >= 24) {
setParametersSniHostname(params, impl, engine);
}
- } catch (NoSuchMethodException | IllegalAccessException ignored) {
+ } catch (NoSuchMethodException ignored) {
+ // Ignored
+ } catch (IllegalAccessException ignored) {
// Ignored
} catch (InvocationTargetException e) {
throw new RuntimeException(e.getCause());
@@ -571,68 +583,6 @@ static ConscryptEngineSocket createEngineSocket(Socket socket, String hostname,
return new ConscryptEngineSocket(socket, hostname, port, autoClose, sslParameters);
}
- static ConscryptFileDescriptorSocket createFileDescriptorSocket(SSLParametersImpl sslParameters)
- throws IOException {
- if (Build.VERSION.SDK_INT >= 24) {
- return new Java8FileDescriptorSocket(sslParameters);
- }
- return new ConscryptFileDescriptorSocket(sslParameters);
- }
-
- static ConscryptFileDescriptorSocket createFileDescriptorSocket(String hostname, int port,
- SSLParametersImpl sslParameters)
- throws IOException {
- if (Build.VERSION.SDK_INT >= 24) {
- return new Java8FileDescriptorSocket(hostname, port, sslParameters);
- }
- return new ConscryptFileDescriptorSocket(hostname, port, sslParameters);
- }
-
- static ConscryptFileDescriptorSocket createFileDescriptorSocket(InetAddress address, int port,
- SSLParametersImpl sslParameters)
- throws IOException {
- if (Build.VERSION.SDK_INT >= 24) {
- return new Java8FileDescriptorSocket(address, port, sslParameters);
- }
- return new ConscryptFileDescriptorSocket(address, port, sslParameters);
- }
-
- static ConscryptFileDescriptorSocket createFileDescriptorSocket(String hostname, int port,
- InetAddress clientAddress,
- int clientPort,
- SSLParametersImpl sslParameters)
- throws IOException {
- if (Build.VERSION.SDK_INT >= 24) {
- return new Java8FileDescriptorSocket(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)
- throws IOException {
- if (Build.VERSION.SDK_INT >= 24) {
- return new Java8FileDescriptorSocket(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 {
- if (Build.VERSION.SDK_INT >= 24) {
- return new Java8FileDescriptorSocket(socket, hostname, port, autoClose, sslParameters);
- }
- return new ConscryptFileDescriptorSocket(socket, hostname, port, autoClose, sslParameters);
- }
-
/**
* Wrap the SocketFactory with the platform wrapper if needed for compatability.
*/
@@ -871,59 +821,13 @@ 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;
+ static SSLException wrapInvalidEchDataException(SSLException e) {
+ return e;
}
- public static CertificateTransparencyVerificationReason reasonCTVerificationRequired(
- String hostname) {
- return CertificateTransparencyVerificationReason.UNKNOWN;
+ static SSLException wrapEchRejectedException(EchRejectedException e, String hostname,
+ byte[] retryConfigs) {
+ return e;
}
static boolean supportsConscryptCertStore() {
@@ -952,7 +856,8 @@ static CertBlocklist newDefaultBlocklist() {
return null;
}
- static CertificateTransparency newDefaultCertificateTransparency() {
+ static CertificateTransparency newDefaultCertificateTransparency(
+ Supplier policySupplier) {
return null;
}
diff --git a/common/src/jni/main/cpp/conscrypt/jniutil.cc b/common/src/jni/main/cpp/conscrypt/jniutil.cc
index a57c6d810..f6b726e15 100644
--- a/common/src/jni/main/cpp/conscrypt/jniutil.cc
+++ b/common/src/jni/main/cpp/conscrypt/jniutil.cc
@@ -14,12 +14,14 @@
* limitations under the License.
*/
-#include
+// clang-format off
#include
-#include
-#include
+#include
+#include
#include
+#include
+// clang-format on
namespace conscrypt {
namespace jniutil {
@@ -93,10 +95,7 @@ void init(JavaVM* vm, JNIEnv* env) {
openSslInputStreamClass = getGlobalRefToClass(
env, TO_STRING(JNI_JARJAR_PREFIX) "org/conscrypt/OpenSSLBIOInputStream");
sslHandshakeCallbacksClass = getGlobalRefToClass(
- env,
- TO_STRING(
- JNI_JARJAR_PREFIX) "org/conscrypt/"
- "NativeCrypto$SSLHandshakeCallbacks");
+ env, TO_STRING(JNI_JARJAR_PREFIX) "org/conscrypt/NativeCrypto$SSLHandshakeCallbacks");
nativeRef_address = getFieldRef(env, nativeRefClass, "address", "J");
#if defined(ANDROID) && !defined(CONSCRYPT_OPENJDK)
@@ -181,8 +180,8 @@ int jniGetFDFromFileDescriptor(JNIEnv* env, jobject fileDescriptor) {
}
extern bool isDirectByteBufferInstance(JNIEnv* env, jobject buffer) {
- // Some versions of ART do not check the buffer validity when handling
- // GetDirectBufferAddress() and GetDirectBufferCapacity().
+ // Some versions of ART do not check the buffer validity when handling GetDirectBufferAddress()
+ // and GetDirectBufferCapacity().
if (buffer == nullptr) {
return false;
}
@@ -194,8 +193,7 @@ extern bool isDirectByteBufferInstance(JNIEnv* env, jobject buffer) {
bool isGetByteArrayElementsLikelyToReturnACopy(size_t size) {
#if defined(ANDROID) && !defined(CONSCRYPT_OPENJDK)
- // ART's GetByteArrayElements creates copies only for arrays smaller than 12
- // kB.
+ // ART's GetByteArrayElements creates copies only for arrays smaller than 12 kB.
return size <= 12 * 1024;
#else
(void)size;
@@ -347,6 +345,9 @@ int throwForCipherError(JNIEnv* env, int reason, const char* message,
case CIPHER_R_BUFFER_TOO_SMALL:
return throwShortBufferException(env, message);
break;
+ case ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED:
+ return throwIllegalStateException(env, message);
+ break;
}
return defaultThrow(env, message);
}
@@ -451,9 +452,8 @@ void throwExceptionFromBoringSSLError(JNIEnv* env, CONSCRYPT_UNUSED const char*
return;
}
- // If there's an error from BoringSSL it may have been caused by an exception
- // in Java code, so ensure there isn't a pending exception before we throw a
- // new one.
+ // If there's an error from BoringSSL it may have been caused by an exception in Java code, so
+ // ensure there isn't a pending exception before we throw a new one.
if (!env->ExceptionCheck()) {
char message[256];
ERR_error_string_n(error, message, sizeof(message));
@@ -516,6 +516,12 @@ int throwSSLProtocolExceptionStr(JNIEnv* env, const char* message) {
return conscrypt::jniutil::throwException(env, "javax/net/ssl/SSLProtocolException", message);
}
+int throwEchRejectedException(JNIEnv* env, const char* message) {
+ JNI_TRACE("throwEchRejectedException %s", message);
+ return conscrypt::jniutil::throwException(
+ env, TO_STRING(JNI_JARJAR_PREFIX) "org/conscrypt/EchRejectedException", message);
+}
+
int throwSSLExceptionWithSslErrors(JNIEnv* env, SSL* ssl, int sslErrorCode, const char* message,
int (*actualThrow)(JNIEnv*, const char*)) {
if (message == nullptr) {
@@ -571,6 +577,7 @@ int throwSSLExceptionWithSslErrors(JNIEnv* env, SSL* ssl, int sslErrorCode, cons
}
char* allocStr = str;
+ unsigned long first_err = 0;
// For protocol errors, SSL might have more information.
if (sslErrorCode == SSL_ERROR_NONE || sslErrorCode == SSL_ERROR_SSL) {
@@ -583,6 +590,9 @@ int throwSSLExceptionWithSslErrors(JNIEnv* env, SSL* ssl, int sslErrorCode, cons
int flags;
// NOLINTNEXTLINE(runtime/int)
unsigned long err = ERR_get_error_line_data(&file, &line, &data, &flags);
+ if (first_err == 0) {
+ first_err = err;
+ }
if (err == 0) {
break;
}
@@ -616,7 +626,12 @@ int throwSSLExceptionWithSslErrors(JNIEnv* env, SSL* ssl, int sslErrorCode, cons
int ret;
if (sslErrorCode == SSL_ERROR_SSL) {
- ret = throwSSLProtocolExceptionStr(env, allocStr);
+ if (first_err != 0 && ERR_GET_LIB(first_err) == ERR_LIB_SSL &&
+ ERR_GET_REASON(first_err) == SSL_R_ECH_REJECTED) {
+ ret = throwEchRejectedException(env, allocStr);
+ } else {
+ ret = throwSSLProtocolExceptionStr(env, allocStr);
+ }
} else {
ret = actualThrow(env, allocStr);
}
diff --git a/common/src/jni/main/cpp/conscrypt/native_crypto.cc b/common/src/jni/main/cpp/conscrypt/native_crypto.cc
index 9f8bf4ee3..276927ca5 100644
--- a/common/src/jni/main/cpp/conscrypt/native_crypto.cc
+++ b/common/src/jni/main/cpp/conscrypt/native_crypto.cc
@@ -34,6 +34,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -823,747 +824,774 @@ void init_engine_globals() {
#define THROW_SOCKETTIMEOUTEXCEPTION (-3)
#define THROWN_EXCEPTION (-4)
-/**
- * private static native int EVP_PKEY_new_RSA(byte[] n, byte[] e, byte[] d,
- * byte[] p, byte[] q);
- */
-static jlong NativeCrypto_EVP_PKEY_new_RSA(JNIEnv* env, jclass, jbyteArray n, jbyteArray e,
- jbyteArray d, jbyteArray p, jbyteArray q,
- jbyteArray dmp1, jbyteArray dmq1, jbyteArray iqmp) {
+static jbyteArray NativeCrypto_wrap_EC_private_key_pkcs8(JNIEnv* env, jclass,
+ jbyteArray rawKeyBytes) {
CHECK_ERROR_QUEUE_ON_RETURN;
- JNI_TRACE(
- "EVP_PKEY_new_RSA(n=%p, e=%p, d=%p, p=%p, q=%p, dmp1=%p, dmq1=%p, "
- "iqmp=%p)",
- n, e, d, p, q, dmp1, dmq1, iqmp);
+ JNI_TRACE("NativeCrypto_wrap_EC_private_key_pkcs8");
+ if (rawKeyBytes == nullptr) {
+ conscrypt::jniutil::throwNullPointerException(env, "rawKeyBytes == null");
+ return nullptr;
+ }
- if (e == nullptr && d == nullptr) {
- conscrypt::jniutil::throwException(env, "java/lang/IllegalArgumentException",
- "e == null && d == null");
- JNI_TRACE("NativeCrypto_EVP_PKEY_new_RSA => e == null && d == null");
- return 0;
+ ScopedByteArrayRO bytes(env, rawKeyBytes);
+ if (bytes.get() == nullptr) {
+ return nullptr;
}
- bssl::UniquePtr nBN, eBN, dBN, pBN, qBN, dmp1BN, dmq1BN, iqmpBN;
- nBN = arrayToBignum(env, n);
- if (!nBN) {
- return 0;
+ CBS cbs;
+ CBS_init(&cbs, reinterpret_cast(bytes.get()), bytes.size());
+ bssl::UniquePtr ec_key(EC_KEY_parse_private_key(&cbs, nullptr));
+ if (!ec_key || CBS_len(&cbs) != 0) {
+ conscrypt::jniutil::throwExceptionFromBoringSSLError(
+ env, "Error parsing EC private key", conscrypt::jniutil::throwParsingException);
+ return nullptr;
}
- if (e != nullptr) {
- eBN = arrayToBignum(env, e);
- if (!eBN) {
- return 0;
- }
+
+ bssl::UniquePtr pkey(EVP_PKEY_new());
+ if (!pkey) {
+ conscrypt::jniutil::throwExceptionFromBoringSSLError(env, "EVP_PKEY_new failed");
+ return nullptr;
}
- if (d != nullptr) {
- dBN = arrayToBignum(env, d);
- if (!dBN) {
- return 0;
- }
+
+ if (!EVP_PKEY_assign_EC_KEY(pkey.get(), ec_key.get())) {
+ conscrypt::jniutil::throwExceptionFromBoringSSLError(env, "EVP_PKEY_assign_EC_KEY");
+ return nullptr;
}
- if (p != nullptr) {
- pBN = arrayToBignum(env, p);
- if (!pBN) {
- return 0;
- }
+ ec_key.release(); // pkey now owns the ec_key
+
+ bssl::ScopedCBB cbb;
+ if (!CBB_init(cbb.get(), 0)) {
+ conscrypt::jniutil::throwOutOfMemory(env, "CBB_init failed");
+ return nullptr;
}
- if (q != nullptr) {
- qBN = arrayToBignum(env, q);
- if (!qBN) {
- return 0;
- }
+ if (!EVP_marshal_private_key(cbb.get(), pkey.get())) {
+ conscrypt::jniutil::throwExceptionFromBoringSSLError(env, "EVP_marshal_private_key");
+ return nullptr;
}
- if (dmp1 != nullptr) {
- dmp1BN = arrayToBignum(env, dmp1);
- if (!dmp1BN) {
- return 0;
- }
+
+ uint8_t* out_data;
+ size_t out_len;
+ if (!CBB_finish(cbb.get(), &out_data, &out_len)) {
+ conscrypt::jniutil::throwExceptionFromBoringSSLError(env, "CBB_finish");
+ return nullptr;
}
- if (dmq1 != nullptr) {
- dmq1BN = arrayToBignum(env, dmq1);
- if (!dmq1BN) {
- return 0;
- }
+ bssl::UniquePtr free_data(out_data);
+
+ jbyteArray result = env->NewByteArray(out_len);
+ if (result != nullptr) {
+ env->SetByteArrayRegion(result, 0, out_len, reinterpret_cast(out_data));
}
- if (iqmp != nullptr) {
- iqmpBN = arrayToBignum(env, iqmp);
- if (!iqmpBN) {
- return 0;
- }
+ return result;
+}
+
+static jbyteArray NativeCrypto_wrap_RSA_private_key_pkcs8(JNIEnv* env, jclass,
+ jbyteArray rawKeyBytes) {
+ CHECK_ERROR_QUEUE_ON_RETURN;
+ JNI_TRACE("NativeCrypto_wrap_RSA_private_key_pkcs8");
+ if (rawKeyBytes == nullptr) {
+ conscrypt::jniutil::throwNullPointerException(env, "rawKeyBytes == null");
+ return nullptr;
}
- // Determine what kind of key this is.
- //
- // TODO(davidben): The caller already knows what kind of key they expect.
- // Ideally we would have separate APIs for the caller. However, we currently
- // tolerate, say, an RSAPrivateCrtKeySpec where most fields are null and
- // silently make a public key out of it. This is probably a mistake, but would
- // need to be a breaking change.
- bssl::UniquePtr rsa;
- if (!dBN) {
- rsa.reset(RSA_new_public_key(nBN.get(), eBN.get()));
- } else if (!eBN) {
- rsa.reset(RSA_new_private_key_no_e(nBN.get(), dBN.get()));
- } else if (!pBN || !qBN || !dmp1BN || !dmq1BN || !iqmpBN) {
- rsa.reset(RSA_new_private_key_no_crt(nBN.get(), eBN.get(), dBN.get()));
- } else {
- rsa.reset(RSA_new_private_key(nBN.get(), eBN.get(), dBN.get(), pBN.get(), qBN.get(),
- dmp1BN.get(), dmq1BN.get(), iqmpBN.get()));
+ ScopedByteArrayRO bytes(env, rawKeyBytes);
+ if (bytes.get() == nullptr) {
+ return nullptr;
}
- if (rsa == nullptr) {
- conscrypt::jniutil::throwExceptionFromBoringSSLError(env, "EVP_PKEY_new_RSA");
- return 0;
+
+ CBS cbs;
+ CBS_init(&cbs, reinterpret_cast(bytes.get()), bytes.size());
+ bssl::UniquePtr rsa(RSA_parse_private_key(&cbs));
+ if (!rsa || CBS_len(&cbs) != 0) {
+ conscrypt::jniutil::throwParsingException(env, "Error parsing RSA private key");
+ ERR_clear_error();
+ return nullptr;
}
bssl::UniquePtr pkey(EVP_PKEY_new());
- if (pkey.get() == nullptr) {
- conscrypt::jniutil::throwRuntimeException(env, "EVP_PKEY_new failed");
- return 0;
- }
- if (EVP_PKEY_assign_RSA(pkey.get(), rsa.get()) != 1) {
- conscrypt::jniutil::throwRuntimeException(env, "EVP_PKEY_new failed");
- ERR_clear_error();
- return 0;
+ if (!pkey) {
+ conscrypt::jniutil::throwExceptionFromBoringSSLError(env, "EVP_PKEY_new failed");
+ return nullptr;
}
- OWNERSHIP_TRANSFERRED(rsa);
- JNI_TRACE(
- "EVP_PKEY_new_RSA(n=%p, e=%p, d=%p, p=%p, q=%p dmp1=%p, dmq1=%p, "
- "iqmp=%p) => %p",
- n, e, d, p, q, dmp1, dmq1, iqmp, pkey.get());
- return reinterpret_cast(pkey.release());
-}
-static jlong NativeCrypto_EVP_PKEY_new_EC_KEY(JNIEnv* env, jclass, jobject groupRef,
- jobject pubkeyRef, jbyteArray keyJavaBytes) {
- CHECK_ERROR_QUEUE_ON_RETURN;
- JNI_TRACE("EVP_PKEY_new_EC_KEY(%p, %p, %p)", groupRef, pubkeyRef, keyJavaBytes);
- const EC_GROUP* group = fromContextObject(env, groupRef);
- if (group == nullptr) {
- return 0;
+ if (!EVP_PKEY_assign_RSA(pkey.get(), rsa.get())) {
+ conscrypt::jniutil::throwExceptionFromBoringSSLError(env, "EVP_PKEY_assign_RSA");
+ return nullptr;
}
- const EC_POINT* pubkey =
- pubkeyRef == nullptr ? nullptr : fromContextObject(env, pubkeyRef);
- JNI_TRACE("EVP_PKEY_new_EC_KEY(%p, %p, %p) <- ptr", group, pubkey, keyJavaBytes);
+ rsa.release(); // pkey now owns the rsa
- bssl::UniquePtr key(nullptr);
- if (keyJavaBytes != nullptr) {
- key = arrayToBignum(env, keyJavaBytes);
- if (!key) {
- return 0;
- }
+ bssl::ScopedCBB cbb;
+ if (!CBB_init(cbb.get(), 0)) {
+ conscrypt::jniutil::throwOutOfMemory(env, "CBB_init failed");
+ return nullptr;
+ }
+ if (!EVP_marshal_private_key(cbb.get(), pkey.get())) {
+ conscrypt::jniutil::throwExceptionFromBoringSSLError(env, "EVP_marshal_private_key");
+ return nullptr;
}
- bssl::UniquePtr eckey(EC_KEY_new());
- if (eckey.get() == nullptr) {
- conscrypt::jniutil::throwRuntimeException(env, "EC_KEY_new failed");
- return 0;
+ uint8_t* out_data;
+ size_t out_len;
+ if (!CBB_finish(cbb.get(), &out_data, &out_len)) {
+ conscrypt::jniutil::throwExceptionFromBoringSSLError(env, "CBB_finish");
+ return nullptr;
}
+ bssl::UniquePtr free_data(out_data);
- if (EC_KEY_set_group(eckey.get(), group) != 1) {
- JNI_TRACE("EVP_PKEY_new_EC_KEY(%p, %p, %p) > EC_KEY_set_group failed", group, pubkey,
- keyJavaBytes);
- conscrypt::jniutil::throwExceptionFromBoringSSLError(env, "EC_KEY_set_group");
- return 0;
+ jbyteArray result = env->NewByteArray(out_len);
+ if (result == nullptr) {
+ return nullptr;
}
+ env->SetByteArrayRegion(result, 0, out_len, reinterpret_cast(out_data));
+ return result;
+}
- if (pubkey != nullptr) {
- if (EC_KEY_set_public_key(eckey.get(), pubkey) != 1) {
- JNI_TRACE("EVP_PKEY_new_EC_KEY(%p, %p, %p) => EC_KEY_set_private_key failed", group,
- pubkey, keyJavaBytes);
- conscrypt::jniutil::throwExceptionFromBoringSSLError(env, "EC_KEY_set_public_key");
- return 0;
- }
+static jbyteArray NativeCrypto_wrap_RSA_public_key_x509(JNIEnv* env, jclass,
+ jbyteArray rawKeyBytes) {
+ CHECK_ERROR_QUEUE_ON_RETURN;
+ JNI_TRACE("NativeCrypto_wrap_RSA_public_key_x509");
+ if (rawKeyBytes == nullptr) {
+ conscrypt::jniutil::throwNullPointerException(env, "rawKeyBytes == null");
+ return nullptr;
}
- if (key.get() != nullptr) {
- if (EC_KEY_set_private_key(eckey.get(), key.get()) != 1) {
- JNI_TRACE("EVP_PKEY_new_EC_KEY(%p, %p, %p) => EC_KEY_set_private_key failed", group,
- pubkey, keyJavaBytes);
- conscrypt::jniutil::throwExceptionFromBoringSSLError(env, "EC_KEY_set_private_key");
- return 0;
- }
- if (pubkey == nullptr) {
- bssl::UniquePtr calcPubkey(EC_POINT_new(group));
- if (!EC_POINT_mul(group, calcPubkey.get(), key.get(), nullptr, nullptr, nullptr)) {
- JNI_TRACE("EVP_PKEY_new_EC_KEY(%p, %p, %p) => can't calculate public key", group,
- pubkey, keyJavaBytes);
- conscrypt::jniutil::throwExceptionFromBoringSSLError(env, "EC_KEY_set_private_key");
- return 0;
- }
- EC_KEY_set_public_key(eckey.get(), calcPubkey.get());
- }
+ ScopedByteArrayRO bytes(env, rawKeyBytes);
+ if (bytes.get() == nullptr) {
+ return nullptr;
}
- if (!EC_KEY_check_key(eckey.get())) {
- JNI_TRACE("EVP_KEY_new_EC_KEY(%p, %p, %p) => invalid key created", group, pubkey,
- keyJavaBytes);
- conscrypt::jniutil::throwExceptionFromBoringSSLError(env, "EC_KEY_check_key");
- return 0;
+ CBS cbs;
+ CBS_init(&cbs, reinterpret_cast(bytes.get()), bytes.size());
+ bssl::UniquePtr rsa(RSA_parse_public_key(&cbs));
+ if (!rsa || CBS_len(&cbs) != 0) {
+ conscrypt::jniutil::throwParsingException(env, "Error parsing RSA public key");
+ ERR_clear_error();
+ return nullptr;
}
bssl::UniquePtr pkey(EVP_PKEY_new());
- if (pkey.get() == nullptr) {
- JNI_TRACE("EVP_PKEY_new_EC(%p, %p, %p) => threw error", group, pubkey, keyJavaBytes);
+ if (!pkey) {
conscrypt::jniutil::throwExceptionFromBoringSSLError(env, "EVP_PKEY_new failed");
- return 0;
- }
- if (EVP_PKEY_assign_EC_KEY(pkey.get(), eckey.get()) != 1) {
- JNI_TRACE("EVP_PKEY_new_EC(%p, %p, %p) => threw error", group, pubkey, keyJavaBytes);
- conscrypt::jniutil::throwRuntimeException(env, "EVP_PKEY_assign_EC_KEY failed");
- ERR_clear_error();
- return 0;
+ return nullptr;
}
- OWNERSHIP_TRANSFERRED(eckey);
- JNI_TRACE("EVP_PKEY_new_EC_KEY(%p, %p, %p) => %p", group, pubkey, keyJavaBytes, pkey.get());
- return reinterpret_cast(pkey.release());
-}
+ if (!EVP_PKEY_assign_RSA(pkey.get(), rsa.get())) {
+ conscrypt::jniutil::throwExceptionFromBoringSSLError(env, "EVP_PKEY_assign_RSA");
+ return nullptr;
+ }
+ rsa.release(); // pkey now owns the rsa
-static int NativeCrypto_EVP_PKEY_type(JNIEnv* env, jclass, jobject pkeyRef) {
- CHECK_ERROR_QUEUE_ON_RETURN;
- EVP_PKEY* pkey = fromContextObject(env, pkeyRef);
- JNI_TRACE("EVP_PKEY_type(%p)", pkey);
+ bssl::ScopedCBB cbb;
+ if (!CBB_init(cbb.get(), 0)) {
+ conscrypt::jniutil::throwOutOfMemory(env, "CBB_init failed");
+ return nullptr;
+ }
+ if (!EVP_marshal_public_key(cbb.get(), pkey.get())) {
+ conscrypt::jniutil::throwExceptionFromBoringSSLError(env, "EVP_marshal_public_key");
+ return nullptr;
+ }
- if (pkey == nullptr) {
- return -1;
+ uint8_t* out_data;
+ size_t out_len;
+ if (!CBB_finish(cbb.get(), &out_data, &out_len)) {
+ conscrypt::jniutil::throwExceptionFromBoringSSLError(env, "CBB_finish");
+ return nullptr;
}
+ bssl::UniquePtr free_data(out_data);
- int result = EVP_PKEY_id(pkey);
- JNI_TRACE("EVP_PKEY_type(%p) => %d", pkey, result);
+ jbyteArray result = env->NewByteArray(out_len);
+ if (result == nullptr) {
+ return nullptr;
+ }
+ env->SetByteArrayRegion(result, 0, out_len, reinterpret_cast(out_data));
return result;
}
-typedef int print_func(BIO*, const EVP_PKEY*, int, ASN1_PCTX*);
-
-static jstring evp_print_func(JNIEnv* env, jobject pkeyRef, print_func* func,
- const char* debug_name) {
- EVP_PKEY* pkey = fromContextObject(env, pkeyRef);
- JNI_TRACE("%s(%p)", debug_name, pkey);
-
- if (pkey == nullptr) {
+static jbyteArray NativeCrypto_wrap_EC_public_key_x509(JNIEnv* env, jclass, jbyteArray rawKeyBytes,
+ jstring curveNameJava) {
+ CHECK_ERROR_QUEUE_ON_RETURN;
+ JNI_TRACE("NativeCrypto_wrap_EC_public_key_x509");
+ if (rawKeyBytes == nullptr) {
+ conscrypt::jniutil::throwNullPointerException(env, "rawKeyBytes == null");
+ return nullptr;
+ }
+ if (curveNameJava == nullptr) {
+ conscrypt::jniutil::throwNullPointerException(env, "curveName == null");
return nullptr;
}
- bssl::UniquePtr buffer(BIO_new(BIO_s_mem()));
- if (buffer.get() == nullptr) {
- conscrypt::jniutil::throwOutOfMemory(env, "Unable to allocate BIO");
+ ScopedUtfChars curveName(env, curveNameJava);
+ if (curveName.c_str() == nullptr) {
return nullptr;
}
- if (func(buffer.get(), pkey, 0, nullptr) != 1) {
- conscrypt::jniutil::throwExceptionFromBoringSSLError(env, debug_name);
+ int nid = OBJ_sn2nid(curveName.c_str());
+ if (nid == NID_undef) {
+ conscrypt::jniutil::throwParsingException(
+ env, "Error parsing EC public key: unknown curve name");
return nullptr;
}
- // Null terminate this
- BIO_write(buffer.get(), "\0", 1);
-
- char* tmp;
- BIO_get_mem_data(buffer.get(), &tmp);
- jstring description = env->NewStringUTF(tmp);
- JNI_TRACE("%s(%p) => \"%s\"", debug_name, pkey, tmp);
- return description;
-}
+ ScopedByteArrayRO bytes(env, rawKeyBytes);
+ if (bytes.get() == nullptr) {
+ return nullptr;
+ }
-static jstring NativeCrypto_EVP_PKEY_print_public(JNIEnv* env, jclass, jobject pkeyRef) {
- CHECK_ERROR_QUEUE_ON_RETURN;
- return evp_print_func(env, pkeyRef, EVP_PKEY_print_public, "EVP_PKEY_print_public");
-}
+ bssl::UniquePtr ec(EC_KEY_new_by_curve_name(nid));
+ if (!ec) {
+ conscrypt::jniutil::throwExceptionFromBoringSSLError(env,
+ "EC_KEY_new_by_curve_name failed");
+ return nullptr;
+ }
-static jstring NativeCrypto_EVP_PKEY_print_params(JNIEnv* env, jclass, jobject pkeyRef) {
- CHECK_ERROR_QUEUE_ON_RETURN;
- return evp_print_func(env, pkeyRef, EVP_PKEY_print_params, "EVP_PKEY_print_params");
-}
+ const uint8_t* ptr = reinterpret_cast(bytes.get());
+ EC_KEY* raw_ec = ec.get();
+ if (!o2i_ECPublicKey(&raw_ec, &ptr, bytes.size())) {
+ conscrypt::jniutil::throwParsingException(env, "Error parsing EC public key");
+ ERR_clear_error();
+ return nullptr;
+ }
-static void NativeCrypto_EVP_PKEY_free(JNIEnv* env, jclass, jlong pkeyRef) {
- CHECK_ERROR_QUEUE_ON_RETURN;
- EVP_PKEY* pkey = reinterpret_cast(pkeyRef);
- JNI_TRACE("EVP_PKEY_free(%p)", pkey);
+ bssl::UniquePtr pkey(EVP_PKEY_new());
+ if (!pkey) {
+ conscrypt::jniutil::throwExceptionFromBoringSSLError(env, "EVP_PKEY_new failed");
+ return nullptr;
+ }
- if (pkey != nullptr) {
- EVP_PKEY_free(pkey);
+ if (!EVP_PKEY_assign_EC_KEY(pkey.get(), ec.get())) {
+ conscrypt::jniutil::throwExceptionFromBoringSSLError(env, "EVP_PKEY_assign_EC_KEY");
+ return nullptr;
}
-}
+ ec.release(); // pkey now owns the ec_key
-static jint NativeCrypto_EVP_PKEY_cmp(JNIEnv* env, jclass, jobject pkey1Ref, jobject pkey2Ref) {
- CHECK_ERROR_QUEUE_ON_RETURN;
- JNI_TRACE("EVP_PKEY_cmp(%p, %p)", pkey1Ref, pkey2Ref);
- EVP_PKEY* pkey1 = fromContextObject(env, pkey1Ref);
- if (pkey1 == nullptr) {
- JNI_TRACE("EVP_PKEY_cmp => pkey1 == null");
- return 0;
+ bssl::ScopedCBB cbb;
+ if (!CBB_init(cbb.get(), 0)) {
+ conscrypt::jniutil::throwOutOfMemory(env, "CBB_init failed");
+ return nullptr;
}
- EVP_PKEY* pkey2 = fromContextObject(env, pkey2Ref);
- if (pkey2 == nullptr) {
- JNI_TRACE("EVP_PKEY_cmp => pkey2 == null");
- return 0;
+ if (!EVP_marshal_public_key(cbb.get(), pkey.get())) {
+ conscrypt::jniutil::throwExceptionFromBoringSSLError(env, "EVP_marshal_public_key");
+ return nullptr;
}
- JNI_TRACE("EVP_PKEY_cmp(%p, %p) <- ptr", pkey1, pkey2);
- int result = EVP_PKEY_cmp(pkey1, pkey2);
- JNI_TRACE("EVP_PKEY_cmp(%p, %p) => %d", pkey1, pkey2, result);
+ uint8_t* out_data;
+ size_t out_len;
+ if (!CBB_finish(cbb.get(), &out_data, &out_len)) {
+ conscrypt::jniutil::throwExceptionFromBoringSSLError(env, "CBB_finish");
+ return nullptr;
+ }
+ bssl::UniquePtr free_data(out_data);
+
+ jbyteArray result = env->NewByteArray(out_len);
+ if (result == nullptr) {
+ return nullptr;
+ }
+ env->SetByteArrayRegion(result, 0, out_len, reinterpret_cast(out_data));
return result;
}
-/*
- * static native byte[] EVP_marshal_private_key(long)
- */
-static jbyteArray NativeCrypto_EVP_marshal_private_key(JNIEnv* env, jclass, jobject pkeyRef) {
+static jbyteArray NativeCrypto_unwrap_RSA_private_key_pkcs8(JNIEnv* env, jclass,
+ jbyteArray rawKeyBytes) {
CHECK_ERROR_QUEUE_ON_RETURN;
- EVP_PKEY* pkey = fromContextObject(env, pkeyRef);
- JNI_TRACE("EVP_marshal_private_key(%p)", pkey);
+ JNI_TRACE("NativeCrypto_unwrap_RSA_private_key_pkcs8");
+ if (rawKeyBytes == nullptr) {
+ conscrypt::jniutil::throwNullPointerException(env, "rawKeyBytes == null");
+ return nullptr;
+ }
- if (pkey == nullptr) {
+ ScopedByteArrayRO bytes(env, rawKeyBytes);
+ if (bytes.get() == nullptr) {
+ return nullptr;
+ }
+
+ CBS cbs;
+ CBS_init(&cbs, reinterpret_cast(bytes.get()), bytes.size());
+ bssl::UniquePtr pkey(EVP_parse_private_key(&cbs));
+ if (!pkey || CBS_len(&cbs) != 0) {
+ conscrypt::jniutil::throwParsingException(env, "Error parsing PKCS#8 private key");
+ ERR_clear_error();
+ return nullptr;
+ }
+
+ RSA* rsa = EVP_PKEY_get0_RSA(pkey.get());
+ if (rsa == nullptr) {
+ conscrypt::jniutil::throwParsingException(env, "Key is not an RSA key");
+ ERR_clear_error();
return nullptr;
}
bssl::ScopedCBB cbb;
- if (!CBB_init(cbb.get(), 64)) {
+ if (!CBB_init(cbb.get(), 0)) {
conscrypt::jniutil::throwOutOfMemory(env, "CBB_init failed");
- JNI_TRACE("CBB_init failed");
+ return nullptr;
+ }
+ if (!RSA_marshal_private_key(cbb.get(), rsa)) {
+ conscrypt::jniutil::throwExceptionFromBoringSSLError(env, "RSA_marshal_private_key");
return nullptr;
}
- if (!EVP_marshal_private_key(cbb.get(), pkey)) {
- conscrypt::jniutil::throwExceptionFromBoringSSLError(env, "EVP_marshal_private_key");
- JNI_TRACE("key=%p EVP_marshal_private_key => error", pkey);
+ uint8_t* out_data;
+ size_t out_len;
+ if (!CBB_finish(cbb.get(), &out_data, &out_len)) {
+ conscrypt::jniutil::throwExceptionFromBoringSSLError(env, "CBB_finish");
return nullptr;
}
+ bssl::UniquePtr free_data(out_data);
- return CBBToByteArray(env, cbb.get());
+ jbyteArray result = env->NewByteArray(out_len);
+ if (result == nullptr) {
+ return nullptr;
+ }
+ env->SetByteArrayRegion(result, 0, out_len, reinterpret_cast(out_data));
+ return result;
}
-/*
- * static native long EVP_parse_private_key(byte[])
- */
-static jlong NativeCrypto_EVP_parse_private_key(JNIEnv* env, jclass, jbyteArray keyJavaBytes) {
+static jbyteArray NativeCrypto_unwrap_RSA_public_key_x509(JNIEnv* env, jclass,
+ jbyteArray rawKeyBytes) {
CHECK_ERROR_QUEUE_ON_RETURN;
- JNI_TRACE("EVP_parse_private_key(%p)", keyJavaBytes);
+ JNI_TRACE("NativeCrypto_unwrap_RSA_public_key_x509");
+ if (rawKeyBytes == nullptr) {
+ conscrypt::jniutil::throwNullPointerException(env, "rawKeyBytes == null");
+ return nullptr;
+ }
- ScopedByteArrayRO bytes(env, keyJavaBytes);
+ ScopedByteArrayRO bytes(env, rawKeyBytes);
if (bytes.get() == nullptr) {
- JNI_TRACE("bytes=%p EVP_parse_private_key => threw exception", keyJavaBytes);
- return 0;
+ return nullptr;
}
CBS cbs;
CBS_init(&cbs, reinterpret_cast(bytes.get()), bytes.size());
- bssl::UniquePtr pkey(EVP_parse_private_key(&cbs));
- // We intentionally do not check that cbs is exhausted, as JCA providers
- // typically allow parsing keys from buffers that are larger than the
- // contained key structure so we do the same for compatibility.
- if (!pkey) {
- conscrypt::jniutil::throwParsingException(env, "Error parsing private key");
+ bssl::UniquePtr pkey(EVP_parse_public_key(&cbs));
+ if (!pkey || CBS_len(&cbs) != 0) {
+ conscrypt::jniutil::throwParsingException(env, "Error parsing X.509 SPKI public key");
ERR_clear_error();
- JNI_TRACE("bytes=%p EVP_parse_private_key => threw exception", keyJavaBytes);
- return 0;
+ return nullptr;
}
- JNI_TRACE("bytes=%p EVP_parse_private_key => %p", keyJavaBytes, pkey.get());
- return reinterpret_cast(pkey.release());
-}
+ RSA* rsa = EVP_PKEY_get0_RSA(pkey.get());
+ if (rsa == nullptr) {
+ conscrypt::jniutil::throwParsingException(env, "Key is not an RSA key");
+ ERR_clear_error();
+ return nullptr;
+ }
-static const EVP_PKEY_ALG* GetAlg(int pkeyType) {
- switch (pkeyType) {
- case EVP_PKEY_ED25519:
- return EVP_pkey_ed25519();
- case EVP_PKEY_X25519:
- return EVP_pkey_x25519();
- case EVP_PKEY_ML_DSA_44:
- return EVP_pkey_ml_dsa_44();
- case EVP_PKEY_ML_DSA_65:
- return EVP_pkey_ml_dsa_65();
- case EVP_PKEY_ML_DSA_87:
- return EVP_pkey_ml_dsa_87();
- default:
- return nullptr;
+ bssl::ScopedCBB cbb;
+ if (!CBB_init(cbb.get(), 0)) {
+ conscrypt::jniutil::throwOutOfMemory(env, "CBB_init failed");
+ return nullptr;
+ }
+ if (!RSA_marshal_public_key(cbb.get(), rsa)) {
+ conscrypt::jniutil::throwExceptionFromBoringSSLError(env, "RSA_marshal_public_key");
+ return nullptr;
+ }
+
+ uint8_t* out_data;
+ size_t out_len;
+ if (!CBB_finish(cbb.get(), &out_data, &out_len)) {
+ conscrypt::jniutil::throwExceptionFromBoringSSLError(env, "CBB_finish");
+ return nullptr;
}
+ bssl::UniquePtr free_data(out_data);
+
+ jbyteArray result = env->NewByteArray(out_len);
+ if (result == nullptr) {
+ return nullptr;
+ }
+ env->SetByteArrayRegion(result, 0, out_len, reinterpret_cast(out_data));
+ return result;
}
-static jlong NativeCrypto_EVP_PKEY_from_private_key_info(JNIEnv* env, jclass,
- jbyteArray key_java_bytes,
- jintArray algs) {
+static jbyteArray NativeCrypto_unwrap_EC_private_key_pkcs8(JNIEnv* env, jclass,
+ jbyteArray rawKeyBytes) {
CHECK_ERROR_QUEUE_ON_RETURN;
- JNI_TRACE("EVP_PKEY_from_private_key_info(_, %p)", algs);
-
- if (key_java_bytes == nullptr) {
- conscrypt::jniutil::throwNullPointerException(env, "key_java_bytes == null");
- return 0;
+ JNI_TRACE("NativeCrypto_unwrap_EC_private_key_pkcs8");
+ if (rawKeyBytes == nullptr) {
+ conscrypt::jniutil::throwNullPointerException(env, "rawKeyBytes == null");
+ return nullptr;
}
- ScopedByteArrayRO bytes(env, key_java_bytes);
+ ScopedByteArrayRO bytes(env, rawKeyBytes);
if (bytes.get() == nullptr) {
- JNI_TRACE("EVP_PKEY_from_private_key_info => threw exception");
- conscrypt::jniutil::throwOutOfMemory(env, "Unable to allocate buffer for bytes");
- return 0;
+ return nullptr;
}
- size_t num_algs = static_cast(env->GetArrayLength(algs));
- if (num_algs == 0) {
- conscrypt::jniutil::throwException(env, "java/lang/IllegalArgumentException",
- "algs.length == 0");
- return 0;
- }
- ScopedIntArrayRO algs_ro(env, algs);
- std::vector alg_pointers(num_algs);
- for (size_t i = 0; i < num_algs; ++i) {
- const EVP_PKEY_ALG* alg = GetAlg(algs_ro.get()[i]);
- if (alg == nullptr) {
- conscrypt::jniutil::throwException(env, "java/lang/IllegalArgumentException",
- "unsupported pkeyType");
- return 0;
- }
- alg_pointers[i] = alg;
+ CBS cbs;
+ CBS_init(&cbs, reinterpret_cast(bytes.get()), bytes.size());
+ bssl::UniquePtr pkey(EVP_parse_private_key(&cbs));
+ if (!pkey || CBS_len(&cbs) != 0) {
+ conscrypt::jniutil::throwParsingException(env, "Error parsing PKCS#8 private key");
+ ERR_clear_error();
+ return nullptr;
}
- bssl::UniquePtr pkey(
- EVP_PKEY_from_private_key_info(reinterpret_cast(bytes.get()),
- bytes.size(), alg_pointers.data(), alg_pointers.size()));
- if (pkey.get() == nullptr) {
- conscrypt::jniutil::throwParsingException(env, "Error parsing private key");
+ EC_KEY* ec = EVP_PKEY_get0_EC_KEY(pkey.get());
+ if (ec == nullptr) {
+ conscrypt::jniutil::throwParsingException(env, "Key is not an EC key");
ERR_clear_error();
- JNI_TRACE("EVP_PKEY_from_private_key_info => threw exception");
- return 0;
+ return nullptr;
}
- return reinterpret_cast(pkey.release());
+ bssl::ScopedCBB cbb;
+ if (!CBB_init(cbb.get(), 0)) {
+ conscrypt::jniutil::throwOutOfMemory(env, "CBB_init failed");
+ return nullptr;
+ }
+ if (!EC_KEY_marshal_private_key(cbb.get(), ec, EC_PKEY_NO_PUBKEY)) {
+ conscrypt::jniutil::throwExceptionFromBoringSSLError(env, "EC_KEY_marshal_private_key");
+ return nullptr;
+ }
+
+ uint8_t* out_data;
+ size_t out_len;
+ if (!CBB_finish(cbb.get(), &out_data, &out_len)) {
+ conscrypt::jniutil::throwExceptionFromBoringSSLError(env, "CBB_finish");
+ return nullptr;
+ }
+ bssl::UniquePtr free_data(out_data);
+
+ jbyteArray result = env->NewByteArray(out_len);
+ if (result == nullptr) {
+ return nullptr;
+ }
+ env->SetByteArrayRegion(result, 0, out_len, reinterpret_cast(out_data));
+ return result;
}
-static jlong NativeCrypto_EVP_PKEY_from_subject_public_key_info(JNIEnv* env, jclass,
- jbyteArray key_java_bytes,
- jintArray algs) {
+static jbyteArray NativeCrypto_unwrap_EC_public_key_x509(JNIEnv* env, jclass,
+ jbyteArray rawKeyBytes) {
CHECK_ERROR_QUEUE_ON_RETURN;
- JNI_TRACE("EVP_PKEY_from_subject_public_key_info(%p, %p)", key_java_bytes, algs);
-
- if (key_java_bytes == nullptr) {
- conscrypt::jniutil::throwNullPointerException(env, "key_java_bytes == null");
- return 0;
+ JNI_TRACE("NativeCrypto_unwrap_EC_public_key_x509");
+ if (rawKeyBytes == nullptr) {
+ conscrypt::jniutil::throwNullPointerException(env, "rawKeyBytes == null");
+ return nullptr;
}
- ScopedByteArrayRO bytes(env, key_java_bytes);
+ ScopedByteArrayRO bytes(env, rawKeyBytes);
if (bytes.get() == nullptr) {
- JNI_TRACE("bytes=%p EVP_PKEY_from_subject_public_key_info => threw exception",
- key_java_bytes);
- conscrypt::jniutil::throwOutOfMemory(env, "Unable to allocate buffer for bytes");
- return 0;
+ return nullptr;
}
- size_t num_algs = static_cast(env->GetArrayLength(algs));
- if (num_algs == 0) {
- conscrypt::jniutil::throwException(env, "java/lang/IllegalArgumentException",
- "algs.length == 0");
- return 0;
- }
- ScopedIntArrayRO algs_ro(env, algs);
- std::vector alg_pointers(num_algs);
- for (size_t i = 0; i < num_algs; ++i) {
- const EVP_PKEY_ALG* alg = GetAlg(algs_ro.get()[i]);
- if (alg == nullptr) {
- conscrypt::jniutil::throwException(env, "java/lang/IllegalArgumentException",
- "unsupported pkeyType");
- return 0;
- }
- alg_pointers[i] = alg;
+ CBS cbs;
+ CBS_init(&cbs, reinterpret_cast(bytes.get()), bytes.size());
+ bssl::UniquePtr pkey(EVP_parse_public_key(&cbs));
+ if (!pkey || CBS_len(&cbs) != 0) {
+ conscrypt::jniutil::throwParsingException(env, "Error parsing X.509 SPKI public key");
+ ERR_clear_error();
+ return nullptr;
}
- bssl::UniquePtr pkey(EVP_PKEY_from_subject_public_key_info(
- reinterpret_cast(bytes.get()), bytes.size(), alg_pointers.data(),
- alg_pointers.size()));
- if (pkey.get() == nullptr) {
- conscrypt::jniutil::throwParsingException(env, "Error parsing public key");
+ EC_KEY* ec = EVP_PKEY_get0_EC_KEY(pkey.get());
+ if (ec == nullptr) {
+ conscrypt::jniutil::throwParsingException(env, "Key is not an EC key");
ERR_clear_error();
- JNI_TRACE("bytes=%p EVP_PKEY_from_subject_public_key_info => threw exception",
- key_java_bytes);
- return 0;
+ return nullptr;
}
- JNI_TRACE("bytes=%p EVP_PKEY_from_subject_public_key_info => %p", key_java_bytes, pkey.get());
- return reinterpret_cast(pkey.release());
+ uint8_t* out_data = nullptr;
+ int out_len = i2o_ECPublicKey(ec, &out_data);
+ if (out_len <= 0) {
+ conscrypt::jniutil::throwExceptionFromBoringSSLError(env, "i2o_ECPublicKey");
+ return nullptr;
+ }
+ bssl::UniquePtr free_data(out_data);
+
+ jbyteArray result = env->NewByteArray(out_len);
+ if (result == nullptr) {
+ return nullptr;
+ }
+ env->SetByteArrayRegion(result, 0, out_len, reinterpret_cast(out_data));
+ return result;
}
-static jlong NativeCrypto_EVP_PKEY_from_raw_private_key(JNIEnv* env, jclass, jint pkey_type,
- jbyteArray key_java_bytes) {
+/**
+ * private static native int EVP_PKEY_new_RSA(byte[] n, byte[] e, byte[] d,
+ * byte[] p, byte[] q);
+ */
+static jlong NativeCrypto_EVP_PKEY_new_RSA(JNIEnv* env, jclass, jbyteArray n, jbyteArray e,
+ jbyteArray d, jbyteArray p, jbyteArray q,
+ jbyteArray dmp1, jbyteArray dmq1, jbyteArray iqmp) {
CHECK_ERROR_QUEUE_ON_RETURN;
- JNI_TRACE("EVP_PKEY_from_raw_private_key(%p)", key_java_bytes);
+ JNI_TRACE(
+ "EVP_PKEY_new_RSA(n=%p, e=%p, d=%p, p=%p, q=%p, dmp1=%p, dmq1=%p, "
+ "iqmp=%p)",
+ n, e, d, p, q, dmp1, dmq1, iqmp);
- if (key_java_bytes == nullptr) {
- conscrypt::jniutil::throwNullPointerException(env, "key_java_bytes == null");
+ if (e == nullptr && d == nullptr) {
+ conscrypt::jniutil::throwException(env, "java/lang/IllegalArgumentException",
+ "e == null && d == null");
+ JNI_TRACE("NativeCrypto_EVP_PKEY_new_RSA => e == null && d == null");
return 0;
}
- ScopedByteArrayRO bytes(env, key_java_bytes);
- if (bytes.get() == nullptr) {
- JNI_TRACE("key_java_bytes=%p EVP_PKEY_from_raw_private_key => threw exception",
- key_java_bytes);
- conscrypt::jniutil::throwOutOfMemory(env, "Unable to allocate buffer for bytes");
+ bssl::UniquePtr nBN, eBN, dBN, pBN, qBN, dmp1BN, dmq1BN, iqmpBN;
+ nBN = arrayToBignum(env, n);
+ if (!nBN) {
return 0;
}
+ if (e != nullptr) {
+ eBN = arrayToBignum(env, e);
+ if (!eBN) {
+ return 0;
+ }
+ }
+ if (d != nullptr) {
+ dBN = arrayToBignum(env, d);
+ if (!dBN) {
+ return 0;
+ }
+ }
+ if (p != nullptr) {
+ pBN = arrayToBignum(env, p);
+ if (!pBN) {
+ return 0;
+ }
+ }
+ if (q != nullptr) {
+ qBN = arrayToBignum(env, q);
+ if (!qBN) {
+ return 0;
+ }
+ }
+ if (dmp1 != nullptr) {
+ dmp1BN = arrayToBignum(env, dmp1);
+ if (!dmp1BN) {
+ return 0;
+ }
+ }
+ if (dmq1 != nullptr) {
+ dmq1BN = arrayToBignum(env, dmq1);
+ if (!dmq1BN) {
+ return 0;
+ }
+ }
+ if (iqmp != nullptr) {
+ iqmpBN = arrayToBignum(env, iqmp);
+ if (!iqmpBN) {
+ return 0;
+ }
+ }
- const EVP_PKEY_ALG* alg;
- if (pkey_type == EVP_PKEY_ED25519) {
- alg = EVP_pkey_ed25519();
- } else if (pkey_type == EVP_PKEY_X25519) {
- alg = EVP_pkey_x25519();
+ // Determine what kind of key this is.
+ //
+ // TODO(davidben): The caller already knows what kind of key they expect.
+ // Ideally we would have separate APIs for the caller. However, we currently
+ // tolerate, say, an RSAPrivateCrtKeySpec where most fields are null and
+ // silently make a public key out of it. This is probably a mistake, but would
+ // need to be a breaking change.
+ bssl::UniquePtr rsa;
+ if (!dBN) {
+ rsa.reset(RSA_new_public_key(nBN.get(), eBN.get()));
+ } else if (!eBN) {
+ rsa.reset(RSA_new_private_key_no_e(nBN.get(), dBN.get()));
+ } else if (!pBN || !qBN || !dmp1BN || !dmq1BN || !iqmpBN) {
+ rsa.reset(RSA_new_private_key_no_crt(nBN.get(), eBN.get(), dBN.get()));
} else {
- conscrypt::jniutil::throwException(env, "java/lang/IllegalArgumentException",
- "unsupported pkey_type");
+ rsa.reset(RSA_new_private_key(nBN.get(), eBN.get(), dBN.get(), pBN.get(), qBN.get(),
+ dmp1BN.get(), dmq1BN.get(), iqmpBN.get()));
+ }
+ if (rsa == nullptr) {
+ conscrypt::jniutil::throwExceptionFromBoringSSLError(env, "EVP_PKEY_new_RSA");
return 0;
}
- bssl::UniquePtr pkey(EVP_PKEY_from_raw_private_key(
- alg, reinterpret_cast(bytes.get()), bytes.size()));
- if (!pkey) {
- conscrypt::jniutil::throwParsingException(env, "Error parsing private key");
+ bssl::UniquePtr pkey(EVP_PKEY_new());
+ if (pkey.get() == nullptr) {
+ conscrypt::jniutil::throwRuntimeException(env, "EVP_PKEY_new failed");
ERR_clear_error();
- JNI_TRACE("key_java_bytes=%p EVP_PKEY_from_raw_private_key => threw exception",
- key_java_bytes);
return 0;
}
-
- JNI_TRACE("key_java_bytes=%p EVP_PKEY_from_raw_private_key => %p", key_java_bytes, pkey.get());
+ if (EVP_PKEY_assign_RSA(pkey.get(), rsa.get()) != 1) {
+ conscrypt::jniutil::throwRuntimeException(env, "EVP_PKEY_new failed");
+ ERR_clear_error();
+ return 0;
+ }
+ OWNERSHIP_TRANSFERRED(rsa);
+ JNI_TRACE(
+ "EVP_PKEY_new_RSA(n=%p, e=%p, d=%p, p=%p, q=%p dmp1=%p, dmq1=%p, "
+ "iqmp=%p) => %p",
+ n, e, d, p, q, dmp1, dmq1, iqmp, pkey.get());
return reinterpret_cast(pkey.release());
}
-static jbyteArray NativeCrypto_EVP_PKEY_get_raw_private_key(JNIEnv* env, jclass, jobject pkey_ref) {
+static jlong NativeCrypto_EVP_PKEY_new_EC_KEY(JNIEnv* env, jclass, jobject groupRef,
+ jobject pubkeyRef, jbyteArray keyJavaBytes) {
CHECK_ERROR_QUEUE_ON_RETURN;
- JNI_TRACE("EVP_PKEY_get_raw_private_key(%p)", pkey_ref);
-
- EVP_PKEY* pkey = fromContextObject(env, pkey_ref);
- if (pkey == nullptr) {
- return nullptr;
+ JNI_TRACE("EVP_PKEY_new_EC_KEY(%p, %p, %p)", groupRef, pubkeyRef, keyJavaBytes);
+ const EC_GROUP* group = fromContextObject(env, groupRef);
+ if (group == nullptr) {
+ return 0;
}
+ const EC_POINT* pubkey =
+ pubkeyRef == nullptr ? nullptr : fromContextObject(env, pubkeyRef);
+ JNI_TRACE("EVP_PKEY_new_EC_KEY(%p, %p, %p) <- ptr", group, pubkey, keyJavaBytes);
- size_t key_length = 0;
- if (EVP_PKEY_get_raw_private_key(pkey, nullptr, &key_length) == 0) {
- JNI_TRACE("key=%p EVP_PKEY_get_raw_private_key => error", pkey);
- conscrypt::jniutil::throwExceptionFromBoringSSLError(env, "EVP_PKEY_get_raw_private_key");
- return nullptr;
+ bssl::UniquePtr key(nullptr);
+ if (keyJavaBytes != nullptr) {
+ key = arrayToBignum(env, keyJavaBytes);
+ if (!key) {
+ return 0;
+ }
}
- ScopedLocalRef raw_key_array(env,
- env->NewByteArray(static_cast(key_length)));
-
- if (raw_key_array.get() == nullptr) {
- JNI_TRACE("key=%p EVP_PKEY_get_raw_private_key: creating byte array failed", pkey);
- conscrypt::jniutil::throwOutOfMemory(env, "Unable to allocate buffer for raw_key_array");
- return nullptr;
- }
- ScopedByteArrayRW raw_key(env, raw_key_array.get());
- if (raw_key.get() == nullptr) {
- JNI_TRACE("EVP_PKEY_get_raw_private_key: using byte array failed");
- conscrypt::jniutil::throwOutOfMemory(env, "Unable to allocate buffer for raw_key");
- return nullptr;
+ bssl::UniquePtr eckey(EC_KEY_new());
+ if (eckey.get() == nullptr) {
+ conscrypt::jniutil::throwRuntimeException(env, "EC_KEY_new failed");
+ return 0;
}
- if (EVP_PKEY_get_raw_private_key(pkey, reinterpret_cast(raw_key.get()),
- &key_length) == 0) {
- JNI_TRACE("key=%p EVP_PKEY_get_raw_private_key => error", pkey);
- conscrypt::jniutil::throwExceptionFromBoringSSLError(env, "EVP_PKEY_get_raw_private_key");
- return nullptr;
+ if (EC_KEY_set_group(eckey.get(), group) != 1) {
+ JNI_TRACE("EVP_PKEY_new_EC_KEY(%p, %p, %p) > EC_KEY_set_group failed", group, pubkey,
+ keyJavaBytes);
+ conscrypt::jniutil::throwExceptionFromBoringSSLError(env, "EC_KEY_set_group");
+ return 0;
}
- return raw_key_array.release();
-}
-static jlong NativeCrypto_EVP_PKEY_from_raw_public_key(JNIEnv* env, jclass, jint pkey_type,
- jbyteArray key_java_bytes) {
- CHECK_ERROR_QUEUE_ON_RETURN;
- JNI_TRACE("EVP_PKEY_from_raw_public_key(%p)", key_java_bytes);
+ if (pubkey != nullptr) {
+ if (EC_KEY_set_public_key(eckey.get(), pubkey) != 1) {
+ JNI_TRACE("EVP_PKEY_new_EC_KEY(%p, %p, %p) => EC_KEY_set_private_key failed", group,
+ pubkey, keyJavaBytes);
+ conscrypt::jniutil::throwExceptionFromBoringSSLError(env, "EC_KEY_set_public_key");
+ return 0;
+ }
+ }
- if (key_java_bytes == nullptr) {
- conscrypt::jniutil::throwNullPointerException(env, "key_java_bytes == null");
- return 0;
+ if (key.get() != nullptr) {
+ if (EC_KEY_set_private_key(eckey.get(), key.get()) != 1) {
+ JNI_TRACE("EVP_PKEY_new_EC_KEY(%p, %p, %p) => EC_KEY_set_private_key failed", group,
+ pubkey, keyJavaBytes);
+ conscrypt::jniutil::throwExceptionFromBoringSSLError(env, "EC_KEY_set_private_key");
+ return 0;
+ }
+ if (pubkey == nullptr) {
+ bssl::UniquePtr calcPubkey(EC_POINT_new(group));
+ if (!EC_POINT_mul(group, calcPubkey.get(), key.get(), nullptr, nullptr, nullptr)) {
+ JNI_TRACE("EVP_PKEY_new_EC_KEY(%p, %p, %p) => can't calculate public key", group,
+ pubkey, keyJavaBytes);
+ conscrypt::jniutil::throwExceptionFromBoringSSLError(env, "EC_KEY_set_private_key");
+ return 0;
+ }
+ EC_KEY_set_public_key(eckey.get(), calcPubkey.get());
+ }
}
- ScopedByteArrayRO bytes(env, key_java_bytes);
- if (bytes.get() == nullptr) {
- JNI_TRACE("bytes=%p EVP_PKEY_from_raw_public_key => threw exception", key_java_bytes);
- conscrypt::jniutil::throwOutOfMemory(env, "Unable to allocate buffer for key_java_bytes");
+ if (!EC_KEY_check_key(eckey.get())) {
+ JNI_TRACE("EVP_KEY_new_EC_KEY(%p, %p, %p) => invalid key created", group, pubkey,
+ keyJavaBytes);
+ conscrypt::jniutil::throwExceptionFromBoringSSLError(env, "EC_KEY_check_key");
return 0;
}
- const EVP_PKEY_ALG* alg = GetAlg(pkey_type);
- if (alg == nullptr) {
- conscrypt::jniutil::throwException(env, "java/lang/IllegalArgumentException",
- "unsupported pkeyType");
+ bssl::UniquePtr pkey(EVP_PKEY_new());
+ if (pkey.get() == nullptr) {
+ JNI_TRACE("EVP_PKEY_new_EC(%p, %p, %p) => threw error", group, pubkey, keyJavaBytes);
+ conscrypt::jniutil::throwExceptionFromBoringSSLError(env, "EVP_PKEY_new failed");
return 0;
}
-
- bssl::UniquePtr pkey(EVP_PKEY_from_raw_public_key(
- alg, reinterpret_cast(bytes.get()), bytes.size()));
- if (!pkey) {
- conscrypt::jniutil::throwParsingException(env, "Error parsing public key");
+ if (EVP_PKEY_assign_EC_KEY(pkey.get(), eckey.get()) != 1) {
+ JNI_TRACE("EVP_PKEY_new_EC(%p, %p, %p) => threw error", group, pubkey, keyJavaBytes);
+ conscrypt::jniutil::throwRuntimeException(env, "EVP_PKEY_assign_EC_KEY failed");
ERR_clear_error();
- JNI_TRACE("bytes=%p EVP_PKEY_from_raw_public_key => threw exception", key_java_bytes);
return 0;
}
+ OWNERSHIP_TRANSFERRED(eckey);
- JNI_TRACE("bytes=%p EVP_PKEY_from_raw_public_key => %p", key_java_bytes, pkey.get());
+ JNI_TRACE("EVP_PKEY_new_EC_KEY(%p, %p, %p) => %p", group, pubkey, keyJavaBytes, pkey.get());
return reinterpret_cast(pkey.release());
}
-static jbyteArray NativeCrypto_EVP_PKEY_get_raw_public_key(JNIEnv* env, jclass, jobject pkey_ref) {
+static int NativeCrypto_EVP_PKEY_type(JNIEnv* env, jclass, jobject pkeyRef) {
CHECK_ERROR_QUEUE_ON_RETURN;
- JNI_TRACE("EVP_PKEY_get_raw_public_key(%p)", pkey_ref);
+ EVP_PKEY* pkey = fromContextObject(env, pkeyRef);
+ JNI_TRACE("EVP_PKEY_type(%p)", pkey);
- EVP_PKEY* pkey = fromContextObject(env, pkey_ref);
if (pkey == nullptr) {
- return nullptr;
+ return -1;
}
- size_t key_length = 0;
- if (EVP_PKEY_get_raw_public_key(pkey, nullptr, &key_length) == 0) {
- conscrypt::jniutil::throwExceptionFromBoringSSLError(env, "EVP_PKEY_get_raw_public_key");
- return nullptr;
- }
-
- ScopedLocalRef raw_key_array(env,
- env->NewByteArray(static_cast(key_length)));
- if (raw_key_array.get() == nullptr) {
- JNI_TRACE("EVP_PKEY_get_raw_public_key: creating byte array failed");
- conscrypt::jniutil::throwOutOfMemory(env, "Unable to allocate buffer for raw_key_array");
- return nullptr;
- }
- ScopedByteArrayRW raw_key(env, raw_key_array.get());
- if (raw_key.get() == nullptr) {
- JNI_TRACE("EVP_PKEY_get_raw_public_key: using byte array failed");
- conscrypt::jniutil::throwOutOfMemory(env, "Unable to allocate buffer for raw_key");
- return nullptr;
- }
-
- if (EVP_PKEY_get_raw_public_key(pkey, reinterpret_cast(raw_key.get()), &key_length) ==
- 0) {
- conscrypt::jniutil::throwExceptionFromBoringSSLError(env, "EVP_PKEY_get_raw_public_key");
- return nullptr;
- }
- return raw_key_array.release();
-}
-
-static jlong NativeCrypto_EVP_PKEY_from_private_seed(JNIEnv* env, jclass, jint pkeyType,
- jbyteArray javaSeedBytes) {
- CHECK_ERROR_QUEUE_ON_RETURN;
- JNI_TRACE("EVP_PKEY_from_private_seed(%p)", javaSeedBytes);
-
- if (javaSeedBytes == nullptr) {
- JNI_TRACE("EVP_PKEY_from_private_seed => threw exception");
- conscrypt::jniutil::throwNullPointerException(env, "javaSeedBytes == null");
- return 0;
- }
-
- ScopedByteArrayRO seed(env, javaSeedBytes);
- if (seed.get() == nullptr) {
- JNI_TRACE("bytes=%p EVP_PKEY_from_private_seed => threw exception", javaSeedBytes);
- conscrypt::jniutil::throwOutOfMemory(env, "Unable to allocate buffer for seed");
- return 0;
- }
-
- const EVP_PKEY_ALG* alg;
- if (pkeyType == EVP_PKEY_ML_DSA_44) {
- alg = EVP_pkey_ml_dsa_44();
- } else if (pkeyType == EVP_PKEY_ML_DSA_65) {
- alg = EVP_pkey_ml_dsa_65();
- } else if (pkeyType == EVP_PKEY_ML_DSA_87) {
- alg = EVP_pkey_ml_dsa_87();
- } else {
- conscrypt::jniutil::throwInvalidKeyException(env, "unsupported pkeyType");
- return 0;
- }
-
- bssl::UniquePtr pkey(EVP_PKEY_from_private_seed(
- alg, reinterpret_cast(seed.get()), seed.size()));
-
- if (!pkey) {
- conscrypt::jniutil::throwParsingException(env, "Error parsing private key");
- ERR_clear_error();
- JNI_TRACE("bytes=%p EVP_PKEY_from_private_seed => threw exception", javaSeedBytes);
- return 0;
- }
-
- JNI_TRACE("bytes=%p EVP_PKEY_from_private_seed => %p", javaSeedBytes, pkey.get());
- return reinterpret_cast(pkey.release());
+ int result = EVP_PKEY_id(pkey);
+ JNI_TRACE("EVP_PKEY_type(%p) => %d", pkey, result);
+ return result;
}
-static jbyteArray NativeCrypto_EVP_PKEY_get_private_seed(JNIEnv* env, jclass, jobject pkeyRef) {
- CHECK_ERROR_QUEUE_ON_RETURN;
- JNI_TRACE("EVP_PKEY_get_private_seed(%p)", pkeyRef);
+typedef int print_func(BIO*, const EVP_PKEY*, int, ASN1_PCTX*);
+static jstring evp_print_func(JNIEnv* env, jobject pkeyRef, print_func* func,
+ const char* debug_name) {
EVP_PKEY* pkey = fromContextObject(env, pkeyRef);
+ JNI_TRACE("%s(%p)", debug_name, pkey);
+
if (pkey == nullptr) {
return nullptr;
}
- size_t seed_length = 0;
- if (EVP_PKEY_get_private_seed(pkey, nullptr, &seed_length) == 0) {
- conscrypt::jniutil::throwExceptionFromBoringSSLError(env, "EVP_PKEY_get_private_seed");
+ bssl::UniquePtr buffer(BIO_new(BIO_s_mem()));
+ if (buffer.get() == nullptr) {
+ conscrypt::jniutil::throwOutOfMemory(env, "Unable to allocate BIO");
return nullptr;
}
- ScopedLocalRef seedArray(env, env->NewByteArray(static_cast(seed_length)));
- if (seedArray.get() == nullptr) {
- JNI_TRACE("EVP_PKEY_get_raw_private_key: creating byte array failed");
- conscrypt::jniutil::throwOutOfMemory(env, "Unable to allocate buffer for seedArray");
- return nullptr;
- }
- ScopedByteArrayRW seed(env, seedArray.get());
- if (seed.get() == nullptr) {
- JNI_TRACE("EVP_PKEY_get_raw_private_key: using byte array failed");
- conscrypt::jniutil::throwOutOfMemory(env, "Unable to allocate buffer for seed");
+ if (func(buffer.get(), pkey, 0, nullptr) != 1) {
+ conscrypt::jniutil::throwExceptionFromBoringSSLError(env, debug_name);
return nullptr;
}
+ // Null terminate this
+ BIO_write(buffer.get(), "\0", 1);
- if (EVP_PKEY_get_private_seed(pkey, reinterpret_cast(seed.get()), &seed_length) ==
- 0) {
- conscrypt::jniutil::throwExceptionFromBoringSSLError(env, "EVP_PKEY_get_private_seed");
- return nullptr;
- }
- return seedArray.release();
+ char* tmp;
+ BIO_get_mem_data(buffer.get(), &tmp);
+ jstring description = env->NewStringUTF(tmp);
+
+ JNI_TRACE("%s(%p) => \"%s\"", debug_name, pkey, tmp);
+ return description;
}
-static jbyteArray NativeCrypto_EVP_raw_X25519_private_key(JNIEnv* env, jclass cls,
- jbyteArray keyJavaBytes) {
+static jstring NativeCrypto_EVP_PKEY_print_public(JNIEnv* env, jclass, jobject pkeyRef) {
CHECK_ERROR_QUEUE_ON_RETURN;
- JNI_TRACE("NativeCrypto_EVP_raw_X25519_private_key(%p)", keyJavaBytes);
+ return evp_print_func(env, pkeyRef, EVP_PKEY_print_public, "EVP_PKEY_print_public");
+}
- jlong key_ptr = NativeCrypto_EVP_parse_private_key(env, cls, keyJavaBytes);
- if (key_ptr == 0) {
- return nullptr;
- }
- bssl::UniquePtr pkey(reinterpret_cast(key_ptr));
- if (EVP_PKEY_id(pkey.get()) != EVP_PKEY_X25519) {
- conscrypt::jniutil::throwInvalidKeyException(env, "Invalid key type");
- return nullptr;
- }
+static jstring NativeCrypto_EVP_PKEY_print_params(JNIEnv* env, jclass, jobject pkeyRef) {
+ CHECK_ERROR_QUEUE_ON_RETURN;
+ return evp_print_func(env, pkeyRef, EVP_PKEY_print_params, "EVP_PKEY_print_params");
+}
- size_t key_length = X25519_PRIVATE_KEY_LEN;
- ScopedLocalRef byteArray(env, env->NewByteArray(static_cast(key_length)));
- if (byteArray.get() == nullptr) {
- conscrypt::jniutil::throwOutOfMemory(env, "Allocating byte[]");
- JNI_TRACE("NativeCrypto_EVP_raw_X25519_private_key: byte array creation failed");
- return nullptr;
- }
+static void NativeCrypto_EVP_PKEY_free(JNIEnv* env, jclass, jlong pkeyRef) {
+ CHECK_ERROR_QUEUE_ON_RETURN;
+ EVP_PKEY* pkey = reinterpret_cast(pkeyRef);
+ JNI_TRACE("EVP_PKEY_free(%p)", pkey);
- ScopedByteArrayRW bytes(env, byteArray.get());
- if (bytes.get() == nullptr) {
- conscrypt::jniutil::throwOutOfMemory(env, "Allocating scoped byte array");
- JNI_TRACE("NativeCrypto_EVP_raw_X25519_private_key: scoped byte array failed");
- return nullptr;
+ if (pkey != nullptr) {
+ EVP_PKEY_free(pkey);
}
+}
- 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;
+static jint NativeCrypto_EVP_PKEY_cmp(JNIEnv* env, jclass, jobject pkey1Ref, jobject pkey2Ref) {
+ CHECK_ERROR_QUEUE_ON_RETURN;
+ JNI_TRACE("EVP_PKEY_cmp(%p, %p)", pkey1Ref, pkey2Ref);
+ EVP_PKEY* pkey1 = fromContextObject(env, pkey1Ref);
+ if (pkey1 == nullptr) {
+ JNI_TRACE("EVP_PKEY_cmp => pkey1 == null");
+ return 0;
}
- jbyteArray result = byteArray.release();
- JNI_TRACE("bytes=%p NativeCrypto_EVP_raw_X25519_private_key => %p", keyJavaBytes, result);
+ EVP_PKEY* pkey2 = fromContextObject(env, pkey2Ref);
+ if (pkey2 == nullptr) {
+ JNI_TRACE("EVP_PKEY_cmp => pkey2 == null");
+ return 0;
+ }
+ JNI_TRACE("EVP_PKEY_cmp(%p, %p) <- ptr", pkey1, pkey2);
+
+ int result = EVP_PKEY_cmp(pkey1, pkey2);
+ JNI_TRACE("EVP_PKEY_cmp(%p, %p) => %d", pkey1, pkey2, result);
return result;
}
/*
- * static native byte[] EVP_marshal_public_key(long)
+ * static native byte[] EVP_marshal_private_key(long)
*/
-static jbyteArray NativeCrypto_EVP_marshal_public_key(JNIEnv* env, jclass, jobject pkeyRef) {
+static jbyteArray NativeCrypto_EVP_marshal_private_key(JNIEnv* env, jclass, jobject pkeyRef) {
CHECK_ERROR_QUEUE_ON_RETURN;
EVP_PKEY* pkey = fromContextObject(env, pkeyRef);
- JNI_TRACE("EVP_marshal_public_key(%p)", pkey);
+ JNI_TRACE("EVP_marshal_private_key(%p)", pkey);
if (pkey == nullptr) {
return nullptr;
@@ -1576,9 +1604,9 @@ static jbyteArray NativeCrypto_EVP_marshal_public_key(JNIEnv* env, jclass, jobje
return nullptr;
}
- if (!EVP_marshal_public_key(cbb.get(), pkey)) {
- conscrypt::jniutil::throwExceptionFromBoringSSLError(env, "EVP_marshal_public_key");
- JNI_TRACE("key=%p EVP_marshal_public_key => error", pkey);
+ if (!EVP_marshal_private_key(cbb.get(), pkey)) {
+ conscrypt::jniutil::throwExceptionFromBoringSSLError(env, "EVP_marshal_private_key");
+ JNI_TRACE("key=%p EVP_marshal_private_key => error", pkey);
return nullptr;
}
@@ -1586,1696 +1614,1752 @@ static jbyteArray NativeCrypto_EVP_marshal_public_key(JNIEnv* env, jclass, jobje
}
/*
- * static native long EVP_parse_public_key(byte[])
+ * static native long EVP_parse_private_key(byte[])
*/
-static jlong NativeCrypto_EVP_parse_public_key(JNIEnv* env, jclass, jbyteArray keyJavaBytes) {
+static jlong NativeCrypto_EVP_parse_private_key(JNIEnv* env, jclass, jbyteArray keyJavaBytes) {
CHECK_ERROR_QUEUE_ON_RETURN;
- JNI_TRACE("EVP_parse_public_key(%p)", keyJavaBytes);
+ JNI_TRACE("EVP_parse_private_key(%p)", keyJavaBytes);
ScopedByteArrayRO bytes(env, keyJavaBytes);
if (bytes.get() == nullptr) {
- JNI_TRACE("bytes=%p EVP_parse_public_key => threw exception", keyJavaBytes);
+ JNI_TRACE("bytes=%p EVP_parse_private_key => threw exception", keyJavaBytes);
return 0;
}
CBS cbs;
CBS_init(&cbs, reinterpret_cast(bytes.get()), bytes.size());
- bssl::UniquePtr pkey(EVP_parse_public_key(&cbs));
+ bssl::UniquePtr pkey(EVP_parse_private_key(&cbs));
// We intentionally do not check that cbs is exhausted, as JCA providers
// typically allow parsing keys from buffers that are larger than the
// contained key structure so we do the same for compatibility.
if (!pkey) {
- conscrypt::jniutil::throwParsingException(env, "Error parsing public key");
+ conscrypt::jniutil::throwParsingException(env, "Error parsing private key");
ERR_clear_error();
- JNI_TRACE("bytes=%p EVP_parse_public_key => threw exception", keyJavaBytes);
+ JNI_TRACE("bytes=%p EVP_parse_private_key => threw exception", keyJavaBytes);
return 0;
}
- JNI_TRACE("bytes=%p EVP_parse_public_key => %p", keyJavaBytes, pkey.get());
+ JNI_TRACE("bytes=%p EVP_parse_private_key => %p", keyJavaBytes, pkey.get());
return reinterpret_cast(pkey.release());
}
-static jlong NativeCrypto_getRSAPrivateKeyWrapper(JNIEnv* env, jclass, jobject javaKey,
- jbyteArray modulusBytes) {
- CHECK_ERROR_QUEUE_ON_RETURN;
- JNI_TRACE("getRSAPrivateKeyWrapper(%p, %p)", javaKey, modulusBytes);
+static const EVP_PKEY_ALG* GetAlg(int pkeyType) {
+ switch (pkeyType) {
+ case EVP_PKEY_ED25519:
+ return EVP_pkey_ed25519();
+ case EVP_PKEY_X25519:
+ return EVP_pkey_x25519();
+ case EVP_PKEY_ML_DSA_44:
+ return EVP_pkey_ml_dsa_44();
+ case EVP_PKEY_ML_DSA_65:
+ return EVP_pkey_ml_dsa_65();
+ case EVP_PKEY_ML_DSA_87:
+ return EVP_pkey_ml_dsa_87();
+ default:
+ return nullptr;
+ }
+}
- ensure_engine_globals();
+static jlong NativeCrypto_EVP_PKEY_from_private_key_info(JNIEnv* env, jclass,
+ jbyteArray key_java_bytes,
+ jintArray algs) {
+ CHECK_ERROR_QUEUE_ON_RETURN;
+ JNI_TRACE("EVP_PKEY_from_private_key_info(_, %p)", algs);
- // The PSS padding code needs access to the actual n, so set it even though we
- // don't set any other parts of the key
- bssl::UniquePtr n = arrayToBignum(env, modulusBytes);
- if (n == nullptr) {
+ if (key_java_bytes == nullptr) {
+ conscrypt::jniutil::throwNullPointerException(env, "key_java_bytes == null");
return 0;
}
- // TODO(crbug.com/boringssl/602): RSA_METHOD is not the ideal abstraction to
- // use here.
- bssl::UniquePtr rsa(RSA_new_method_no_e(g_engine, n.get()));
- if (rsa == nullptr) {
- conscrypt::jniutil::throwOutOfMemory(env, "Unable to allocate RSA key");
+ ScopedByteArrayRO bytes(env, key_java_bytes);
+ if (bytes.get() == nullptr) {
+ JNI_TRACE("EVP_PKEY_from_private_key_info => threw exception");
+ conscrypt::jniutil::throwOutOfMemory(env, "Unable to allocate buffer for bytes");
return 0;
}
- auto ex_data = new KeyExData;
- ex_data->private_key = env->NewGlobalRef(javaKey);
- RSA_set_ex_data(rsa.get(), g_rsa_exdata_index, ex_data);
-
- bssl::UniquePtr pkey(EVP_PKEY_new());
- if (pkey.get() == nullptr) {
- JNI_TRACE("getRSAPrivateKeyWrapper failed");
- conscrypt::jniutil::throwRuntimeException(env,
- "NativeCrypto_getRSAPrivateKeyWrapper failed");
- ERR_clear_error();
+ size_t num_algs = static_cast(env->GetArrayLength(algs));
+ if (num_algs == 0) {
+ conscrypt::jniutil::throwException(env, "java/lang/IllegalArgumentException",
+ "algs.length == 0");
return 0;
}
-
- if (EVP_PKEY_assign_RSA(pkey.get(), rsa.get()) != 1) {
- conscrypt::jniutil::throwRuntimeException(env, "getRSAPrivateKeyWrapper failed");
+ ScopedIntArrayRO algs_ro(env, algs);
+ std::vector alg_pointers(num_algs);
+ for (size_t i = 0; i < num_algs; ++i) {
+ const EVP_PKEY_ALG* alg = GetAlg(algs_ro.get()[i]);
+ if (alg == nullptr) {
+ conscrypt::jniutil::throwException(env, "java/lang/IllegalArgumentException",
+ "unsupported pkeyType");
+ return 0;
+ }
+ alg_pointers[i] = alg;
+ }
+
+ bssl::UniquePtr pkey(
+ EVP_PKEY_from_private_key_info(reinterpret_cast(bytes.get()),
+ bytes.size(), alg_pointers.data(), alg_pointers.size()));
+ if (pkey.get() == nullptr) {
+ conscrypt::jniutil::throwParsingException(env, "Error parsing private key");
ERR_clear_error();
+ JNI_TRACE("EVP_PKEY_from_private_key_info => threw exception");
return 0;
}
- OWNERSHIP_TRANSFERRED(rsa);
- JNI_TRACE("getRSAPrivateKeyWrapper(%p, %p) => %p", javaKey, modulusBytes, pkey.get());
+
return reinterpret_cast(pkey.release());
}
-static jlong NativeCrypto_getECPrivateKeyWrapper(JNIEnv* env, jclass, jobject javaKey,
- jobject groupRef) {
+static jlong NativeCrypto_EVP_PKEY_from_subject_public_key_info(JNIEnv* env, jclass,
+ jbyteArray key_java_bytes,
+ jintArray algs) {
CHECK_ERROR_QUEUE_ON_RETURN;
- EC_GROUP* group = fromContextObject(env, groupRef);
- JNI_TRACE("getECPrivateKeyWrapper(%p, %p)", javaKey, group);
- if (group == nullptr) {
- return 0;
- }
-
- ensure_engine_globals();
+ JNI_TRACE("EVP_PKEY_from_subject_public_key_info(%p, %p)", key_java_bytes, algs);
- bssl::UniquePtr ecKey(EC_KEY_new_method(g_engine));
- if (ecKey.get() == nullptr) {
- conscrypt::jniutil::throwOutOfMemory(env, "Unable to allocate EC key");
+ if (key_java_bytes == nullptr) {
+ conscrypt::jniutil::throwNullPointerException(env, "key_java_bytes == null");
return 0;
}
- if (EC_KEY_set_group(ecKey.get(), group) != 1) {
- JNI_TRACE("getECPrivateKeyWrapper(%p, %p) => EC_KEY_set_group error", javaKey, group);
- conscrypt::jniutil::throwExceptionFromBoringSSLError(env, "EC_KEY_set_group");
+ ScopedByteArrayRO bytes(env, key_java_bytes);
+ if (bytes.get() == nullptr) {
+ JNI_TRACE("bytes=%p EVP_PKEY_from_subject_public_key_info => threw exception",
+ key_java_bytes);
+ conscrypt::jniutil::throwOutOfMemory(env, "Unable to allocate buffer for bytes");
return 0;
}
- auto ex_data = new KeyExData;
- ex_data->private_key = env->NewGlobalRef(javaKey);
-
- if (!EC_KEY_set_ex_data(ecKey.get(), g_ecdsa_exdata_index, ex_data)) {
- env->DeleteGlobalRef(ex_data->private_key);
- delete ex_data;
- conscrypt::jniutil::throwRuntimeException(env, "EC_KEY_set_ex_data");
- ERR_clear_error();
+ size_t num_algs = static_cast(env->GetArrayLength(algs));
+ if (num_algs == 0) {
+ conscrypt::jniutil::throwException(env, "java/lang/IllegalArgumentException",
+ "algs.length == 0");
return 0;
}
+ ScopedIntArrayRO algs_ro(env, algs);
+ std::vector alg_pointers(num_algs);
+ for (size_t i = 0; i < num_algs; ++i) {
+ const EVP_PKEY_ALG* alg = GetAlg(algs_ro.get()[i]);
+ if (alg == nullptr) {
+ conscrypt::jniutil::throwException(env, "java/lang/IllegalArgumentException",
+ "unsupported pkeyType");
+ return 0;
+ }
+ alg_pointers[i] = alg;
+ }
- bssl::UniquePtr pkey(EVP_PKEY_new());
+ bssl::UniquePtr pkey(EVP_PKEY_from_subject_public_key_info(
+ reinterpret_cast(bytes.get()), bytes.size(), alg_pointers.data(),
+ alg_pointers.size()));
if (pkey.get() == nullptr) {
- JNI_TRACE("getECPrivateKeyWrapper failed");
- conscrypt::jniutil::throwRuntimeException(env,
- "NativeCrypto_getECPrivateKeyWrapper failed");
+ conscrypt::jniutil::throwParsingException(env, "Error parsing public key");
ERR_clear_error();
+ JNI_TRACE("bytes=%p EVP_PKEY_from_subject_public_key_info => threw exception",
+ key_java_bytes);
return 0;
}
- if (EVP_PKEY_assign_EC_KEY(pkey.get(), ecKey.get()) != 1) {
- conscrypt::jniutil::throwRuntimeException(env, "getECPrivateKeyWrapper failed");
- ERR_clear_error();
- return 0;
- }
- OWNERSHIP_TRANSFERRED(ecKey);
+ JNI_TRACE("bytes=%p EVP_PKEY_from_subject_public_key_info => %p", key_java_bytes, pkey.get());
return reinterpret_cast(pkey.release());
}
-/*
- * public static native int RSA_generate_key(int modulusBits, byte[]
- * publicExponent);
- */
-static jlong NativeCrypto_RSA_generate_key_ex(JNIEnv* env, jclass, jint modulusBits,
- jbyteArray publicExponent) {
+static jlong NativeCrypto_EVP_PKEY_from_raw_private_key(JNIEnv* env, jclass, jint pkey_type,
+ jbyteArray key_java_bytes) {
CHECK_ERROR_QUEUE_ON_RETURN;
- JNI_TRACE("RSA_generate_key_ex(%d, %p)", modulusBits, publicExponent);
-
- bssl::UniquePtr e = arrayToBignum(env, publicExponent);
- if (e == nullptr) {
- return 0;
- }
+ JNI_TRACE("EVP_PKEY_from_raw_private_key(%p)", key_java_bytes);
- bssl::UniquePtr rsa(RSA_new());
- if (rsa.get() == nullptr) {
- conscrypt::jniutil::throwOutOfMemory(env, "Unable to allocate RSA key");
+ if (key_java_bytes == nullptr) {
+ conscrypt::jniutil::throwNullPointerException(env, "key_java_bytes == null");
return 0;
}
- if (RSA_generate_key_ex(rsa.get(), modulusBits, e.get(), nullptr) != 1) {
- conscrypt::jniutil::throwExceptionFromBoringSSLError(env, "RSA_generate_key_ex failed");
+ ScopedByteArrayRO bytes(env, key_java_bytes);
+ if (bytes.get() == nullptr) {
+ JNI_TRACE("key_java_bytes=%p EVP_PKEY_from_raw_private_key => threw exception",
+ key_java_bytes);
+ conscrypt::jniutil::throwOutOfMemory(env, "Unable to allocate buffer for bytes");
return 0;
}
- bssl::UniquePtr pkey(EVP_PKEY_new());
- if (pkey.get() == nullptr) {
- conscrypt::jniutil::throwOutOfMemory(env, "Unable to allocate RSA key");
+ const EVP_PKEY_ALG* alg;
+ if (pkey_type == EVP_PKEY_ED25519) {
+ alg = EVP_pkey_ed25519();
+ } else if (pkey_type == EVP_PKEY_X25519) {
+ alg = EVP_pkey_x25519();
+ } else {
+ conscrypt::jniutil::throwException(env, "java/lang/IllegalArgumentException",
+ "unsupported pkey_type");
return 0;
}
- if (EVP_PKEY_assign_RSA(pkey.get(), rsa.get()) != 1) {
- conscrypt::jniutil::throwRuntimeException(env, "RSA_generate_key_ex failed");
+ bssl::UniquePtr pkey(EVP_PKEY_from_raw_private_key(
+ alg, reinterpret_cast(bytes.get()), bytes.size()));
+ if (!pkey) {
+ conscrypt::jniutil::throwParsingException(env, "Error parsing private key");
ERR_clear_error();
+ JNI_TRACE("key_java_bytes=%p EVP_PKEY_from_raw_private_key => threw exception",
+ key_java_bytes);
return 0;
}
- OWNERSHIP_TRANSFERRED(rsa);
- JNI_TRACE("RSA_generate_key_ex(n=%d, e=%p) => %p", modulusBits, publicExponent, pkey.get());
+ JNI_TRACE("key_java_bytes=%p EVP_PKEY_from_raw_private_key => %p", key_java_bytes, pkey.get());
return reinterpret_cast(pkey.release());
}
-static jint NativeCrypto_RSA_size(JNIEnv* env, jclass, jobject pkeyRef) {
+static jbyteArray NativeCrypto_EVP_PKEY_get_raw_private_key(JNIEnv* env, jclass, jobject pkey_ref) {
CHECK_ERROR_QUEUE_ON_RETURN;
- EVP_PKEY* pkey = fromContextObject(env, pkeyRef);
- JNI_TRACE("RSA_size(%p)", pkey);
+ JNI_TRACE("EVP_PKEY_get_raw_private_key(%p)", pkey_ref);
+ EVP_PKEY* pkey = fromContextObject(env, pkey_ref);
if (pkey == nullptr) {
+ return nullptr;
+ }
+
+ size_t key_length = 0;
+ if (EVP_PKEY_get_raw_private_key(pkey, nullptr, &key_length) == 0) {
+ JNI_TRACE("key=%p EVP_PKEY_get_raw_private_key => error", pkey);
+ conscrypt::jniutil::throwExceptionFromBoringSSLError(env, "EVP_PKEY_get_raw_private_key");
+ return nullptr;
+ }
+
+ ScopedLocalRef raw_key_array(env,
+ env->NewByteArray(static_cast(key_length)));
+
+ if (raw_key_array.get() == nullptr) {
+ JNI_TRACE("key=%p EVP_PKEY_get_raw_private_key: creating byte array failed", pkey);
+ conscrypt::jniutil::throwOutOfMemory(env, "Unable to allocate buffer for raw_key_array");
+ return nullptr;
+ }
+ ScopedByteArrayRW raw_key(env, raw_key_array.get());
+ if (raw_key.get() == nullptr) {
+ JNI_TRACE("EVP_PKEY_get_raw_private_key: using byte array failed");
+ conscrypt::jniutil::throwOutOfMemory(env, "Unable to allocate buffer for raw_key");
+ return nullptr;
+ }
+
+ if (EVP_PKEY_get_raw_private_key(pkey, reinterpret_cast(raw_key.get()),
+ &key_length) == 0) {
+ JNI_TRACE("key=%p EVP_PKEY_get_raw_private_key => error", pkey);
+ conscrypt::jniutil::throwExceptionFromBoringSSLError(env, "EVP_PKEY_get_raw_private_key");
+ return nullptr;
+ }
+ return raw_key_array.release();
+}
+
+static jlong NativeCrypto_EVP_PKEY_from_raw_public_key(JNIEnv* env, jclass, jint pkey_type,
+ jbyteArray key_java_bytes) {
+ CHECK_ERROR_QUEUE_ON_RETURN;
+ JNI_TRACE("EVP_PKEY_from_raw_public_key(%p)", key_java_bytes);
+
+ if (key_java_bytes == nullptr) {
+ conscrypt::jniutil::throwNullPointerException(env, "key_java_bytes == null");
return 0;
}
- bssl::UniquePtr rsa(EVP_PKEY_get1_RSA(pkey));
- if (rsa.get() == nullptr) {
- conscrypt::jniutil::throwRuntimeException(env, "RSA_size failed");
+ ScopedByteArrayRO bytes(env, key_java_bytes);
+ if (bytes.get() == nullptr) {
+ JNI_TRACE("bytes=%p EVP_PKEY_from_raw_public_key => threw exception", key_java_bytes);
+ conscrypt::jniutil::throwOutOfMemory(env, "Unable to allocate buffer for key_java_bytes");
+ return 0;
+ }
+
+ const EVP_PKEY_ALG* alg = GetAlg(pkey_type);
+ if (alg == nullptr) {
+ conscrypt::jniutil::throwException(env, "java/lang/IllegalArgumentException",
+ "unsupported pkeyType");
+ return 0;
+ }
+
+ bssl::UniquePtr pkey(EVP_PKEY_from_raw_public_key(
+ alg, reinterpret_cast(bytes.get()), bytes.size()));
+ if (!pkey) {
+ conscrypt::jniutil::throwParsingException(env, "Error parsing public key");
ERR_clear_error();
+ JNI_TRACE("bytes=%p EVP_PKEY_from_raw_public_key => threw exception", key_java_bytes);
return 0;
}
- return static_cast(RSA_size(rsa.get()));
+ JNI_TRACE("bytes=%p EVP_PKEY_from_raw_public_key => %p", key_java_bytes, pkey.get());
+ return reinterpret_cast(pkey.release());
}
-typedef int RSACryptOperation(size_t flen, const unsigned char* from, unsigned char* to, RSA* rsa,
- int padding);
-
-static jint RSA_crypt_operation(RSACryptOperation operation, const char* caller, JNIEnv* env,
- jint flen, jbyteArray fromJavaBytes, jbyteArray toJavaBytes,
- jobject pkeyRef, jint padding) {
+static jbyteArray NativeCrypto_EVP_PKEY_get_raw_public_key(JNIEnv* env, jclass, jobject pkey_ref) {
CHECK_ERROR_QUEUE_ON_RETURN;
- EVP_PKEY* pkey = fromContextObject(env, pkeyRef);
- JNI_TRACE("%s(%d, %p, %p, %p)", caller, flen, fromJavaBytes, toJavaBytes, pkey);
+ JNI_TRACE("EVP_PKEY_get_raw_public_key(%p)", pkey_ref);
+ EVP_PKEY* pkey = fromContextObject(env, pkey_ref);
if (pkey == nullptr) {
- return -1;
+ return nullptr;
}
- bssl::UniquePtr rsa(EVP_PKEY_get1_RSA(pkey));
- if (rsa.get() == nullptr) {
- return -1;
+ size_t key_length = 0;
+ if (EVP_PKEY_get_raw_public_key(pkey, nullptr, &key_length) == 0) {
+ conscrypt::jniutil::throwExceptionFromBoringSSLError(env, "EVP_PKEY_get_raw_public_key");
+ return nullptr;
}
- ScopedByteArrayRO from(env, fromJavaBytes);
- if (from.get() == nullptr) {
- return -1;
+ ScopedLocalRef raw_key_array(env,
+ env->NewByteArray(static_cast(key_length)));
+ if (raw_key_array.get() == nullptr) {
+ JNI_TRACE("EVP_PKEY_get_raw_public_key: creating byte array failed");
+ conscrypt::jniutil::throwOutOfMemory(env, "Unable to allocate buffer for raw_key_array");
+ return nullptr;
+ }
+ ScopedByteArrayRW raw_key(env, raw_key_array.get());
+ if (raw_key.get() == nullptr) {
+ JNI_TRACE("EVP_PKEY_get_raw_public_key: using byte array failed");
+ conscrypt::jniutil::throwOutOfMemory(env, "Unable to allocate buffer for raw_key");
+ return nullptr;
}
- ScopedByteArrayRW to(env, toJavaBytes);
- if (to.get() == nullptr) {
- return -1;
+ if (EVP_PKEY_get_raw_public_key(pkey, reinterpret_cast(raw_key.get()), &key_length) ==
+ 0) {
+ conscrypt::jniutil::throwExceptionFromBoringSSLError(env, "EVP_PKEY_get_raw_public_key");
+ return nullptr;
}
+ return raw_key_array.release();
+}
- int resultSize =
- 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);
- JNI_TRACE("%s => threw error", caller);
- return -1;
+static jlong NativeCrypto_EVP_PKEY_from_private_seed(JNIEnv* env, jclass, jint pkeyType,
+ jbyteArray javaSeedBytes) {
+ CHECK_ERROR_QUEUE_ON_RETURN;
+ JNI_TRACE("EVP_PKEY_from_private_seed(%p)", javaSeedBytes);
+
+ if (javaSeedBytes == nullptr) {
+ JNI_TRACE("EVP_PKEY_from_private_seed => threw exception");
+ conscrypt::jniutil::throwNullPointerException(env, "javaSeedBytes == null");
+ return 0;
}
- JNI_TRACE("%s(%d, %p, %p, %p) => %d", caller, flen, fromJavaBytes, toJavaBytes, pkey,
- resultSize);
- return static_cast(resultSize);
-}
+ ScopedByteArrayRO seed(env, javaSeedBytes);
+ if (seed.get() == nullptr) {
+ JNI_TRACE("bytes=%p EVP_PKEY_from_private_seed => threw exception", javaSeedBytes);
+ conscrypt::jniutil::throwOutOfMemory(env, "Unable to allocate buffer for seed");
+ return 0;
+ }
-static jint NativeCrypto_RSA_private_encrypt(JNIEnv* env, jclass, jint flen,
- jbyteArray fromJavaBytes, jbyteArray toJavaBytes,
- jobject pkeyRef, jint padding) {
- CHECK_ERROR_QUEUE_ON_RETURN;
- return RSA_crypt_operation(RSA_private_encrypt, __FUNCTION__, env, flen, fromJavaBytes,
- toJavaBytes, pkeyRef, padding);
-}
-static jint NativeCrypto_RSA_public_decrypt(JNIEnv* env, jclass, jint flen,
- jbyteArray fromJavaBytes, jbyteArray toJavaBytes,
- jobject pkeyRef, jint padding) {
- CHECK_ERROR_QUEUE_ON_RETURN;
- return RSA_crypt_operation(RSA_public_decrypt, __FUNCTION__, env, flen, fromJavaBytes,
- toJavaBytes, pkeyRef, padding);
-}
-static jint NativeCrypto_RSA_public_encrypt(JNIEnv* env, jclass, jint flen,
- jbyteArray fromJavaBytes, jbyteArray toJavaBytes,
- jobject pkeyRef, jint padding) {
- CHECK_ERROR_QUEUE_ON_RETURN;
- return RSA_crypt_operation(RSA_public_encrypt, __FUNCTION__, env, flen, fromJavaBytes,
- toJavaBytes, pkeyRef, padding);
-}
-static jint NativeCrypto_RSA_private_decrypt(JNIEnv* env, jclass, jint flen,
- jbyteArray fromJavaBytes, jbyteArray toJavaBytes,
- jobject pkeyRef, jint padding) {
- CHECK_ERROR_QUEUE_ON_RETURN;
- return RSA_crypt_operation(RSA_private_decrypt, __FUNCTION__, env, flen, fromJavaBytes,
- toJavaBytes, pkeyRef, padding);
+ const EVP_PKEY_ALG* alg;
+ if (pkeyType == EVP_PKEY_ML_DSA_44) {
+ alg = EVP_pkey_ml_dsa_44();
+ } else if (pkeyType == EVP_PKEY_ML_DSA_65) {
+ alg = EVP_pkey_ml_dsa_65();
+ } else if (pkeyType == EVP_PKEY_ML_DSA_87) {
+ alg = EVP_pkey_ml_dsa_87();
+ } else {
+ conscrypt::jniutil::throwInvalidKeyException(env, "unsupported pkeyType");
+ return 0;
+ }
+
+ bssl::UniquePtr pkey(EVP_PKEY_from_private_seed(
+ alg, reinterpret_cast(seed.get()), seed.size()));
+
+ if (!pkey) {
+ conscrypt::jniutil::throwParsingException(env, "Error parsing private key");
+ ERR_clear_error();
+ JNI_TRACE("bytes=%p EVP_PKEY_from_private_seed => threw exception", javaSeedBytes);
+ return 0;
+ }
+
+ JNI_TRACE("bytes=%p EVP_PKEY_from_private_seed => %p", javaSeedBytes, pkey.get());
+ return reinterpret_cast(pkey.release());
}
-/*
- * public static native byte[][] get_RSA_public_params(long);
- */
-static jobjectArray NativeCrypto_get_RSA_public_params(JNIEnv* env, jclass, jobject pkeyRef) {
+static jbyteArray NativeCrypto_EVP_PKEY_get_private_seed(JNIEnv* env, jclass, jobject pkeyRef) {
CHECK_ERROR_QUEUE_ON_RETURN;
- EVP_PKEY* pkey = fromContextObject(env, pkeyRef);
- JNI_TRACE("get_RSA_public_params(%p)", pkey);
+ JNI_TRACE("EVP_PKEY_get_private_seed(%p)", pkeyRef);
+ EVP_PKEY* pkey = fromContextObject(env, pkeyRef);
if (pkey == nullptr) {
return nullptr;
}
- bssl::UniquePtr rsa(EVP_PKEY_get1_RSA(pkey));
- if (rsa.get() == nullptr) {
- conscrypt::jniutil::throwExceptionFromBoringSSLError(env, "get_RSA_public_params failed");
+ size_t seed_length = 0;
+ if (EVP_PKEY_get_private_seed(pkey, nullptr, &seed_length) == 0) {
+ conscrypt::jniutil::throwExceptionFromBoringSSLError(env, "EVP_PKEY_get_private_seed");
return nullptr;
}
- jobjectArray joa = env->NewObjectArray(2, conscrypt::jniutil::byteArrayClass, nullptr);
- if (joa == nullptr) {
+ ScopedLocalRef seedArray(env, env->NewByteArray(static_cast(seed_length)));
+ if (seedArray.get() == nullptr) {
+ JNI_TRACE("EVP_PKEY_get_raw_private_key: creating byte array failed");
+ conscrypt::jniutil::throwOutOfMemory(env, "Unable to allocate buffer for seedArray");
return nullptr;
}
-
- jbyteArray n = bignumToArray(env, RSA_get0_n(rsa.get()), "n");
- if (env->ExceptionCheck()) {
+ ScopedByteArrayRW seed(env, seedArray.get());
+ if (seed.get() == nullptr) {
+ JNI_TRACE("EVP_PKEY_get_raw_private_key: using byte array failed");
+ conscrypt::jniutil::throwOutOfMemory(env, "Unable to allocate buffer for seed");
return nullptr;
}
- env->SetObjectArrayElement(joa, 0, n);
- jbyteArray e = bignumToArray(env, RSA_get0_e(rsa.get()), "e");
- if (env->ExceptionCheck()) {
+ if (EVP_PKEY_get_private_seed(pkey, reinterpret_cast(seed.get()), &seed_length) ==
+ 0) {
+ conscrypt::jniutil::throwExceptionFromBoringSSLError(env, "EVP_PKEY_get_private_seed");
return nullptr;
}
- env->SetObjectArrayElement(joa, 1, e);
-
- return joa;
+ return seedArray.release();
}
-/*
- * public static native byte[][] get_RSA_private_params(long);
- */
-static jobjectArray NativeCrypto_get_RSA_private_params(JNIEnv* env, jclass, jobject pkeyRef) {
+static jbyteArray NativeCrypto_EVP_raw_X25519_private_key(JNIEnv* env, jclass cls,
+ jbyteArray keyJavaBytes) {
CHECK_ERROR_QUEUE_ON_RETURN;
- EVP_PKEY* pkey = fromContextObject(env, pkeyRef);
- JNI_TRACE("get_RSA_public_params(%p)", pkey);
+ JNI_TRACE("NativeCrypto_EVP_raw_X25519_private_key(%p)", keyJavaBytes);
- if (pkey == nullptr) {
+ jlong key_ptr = NativeCrypto_EVP_parse_private_key(env, cls, keyJavaBytes);
+ if (key_ptr == 0) {
return nullptr;
}
-
- bssl::UniquePtr rsa(EVP_PKEY_get1_RSA(pkey));
- if (rsa.get() == nullptr) {
- conscrypt::jniutil::throwExceptionFromBoringSSLError(env, "get_RSA_public_params failed");
+ bssl::UniquePtr pkey(reinterpret_cast(key_ptr));
+ if (EVP_PKEY_id(pkey.get()) != EVP_PKEY_X25519) {
+ conscrypt::jniutil::throwInvalidKeyException(env, "Invalid key type");
return nullptr;
}
- jobjectArray joa = env->NewObjectArray(8, conscrypt::jniutil::byteArrayClass, nullptr);
- if (joa == nullptr) {
+ size_t key_length = X25519_PRIVATE_KEY_LEN;
+ ScopedLocalRef byteArray(env, env->NewByteArray(static_cast(key_length)));
+ if (byteArray.get() == nullptr) {
+ conscrypt::jniutil::throwOutOfMemory(env, "Allocating byte[]");
+ JNI_TRACE("NativeCrypto_EVP_raw_X25519_private_key: byte array creation failed");
return nullptr;
}
- jbyteArray n = bignumToArray(env, RSA_get0_n(rsa.get()), "n");
- if (env->ExceptionCheck()) {
+ ScopedByteArrayRW bytes(env, byteArray.get());
+ if (bytes.get() == nullptr) {
+ conscrypt::jniutil::throwOutOfMemory(env, "Allocating scoped byte array");
+ JNI_TRACE("NativeCrypto_EVP_raw_X25519_private_key: scoped byte array failed");
return nullptr;
}
- env->SetObjectArrayElement(joa, 0, n);
- if (RSA_get0_e(rsa.get()) != nullptr) {
- jbyteArray e = bignumToArray(env, RSA_get0_e(rsa.get()), "e");
- if (env->ExceptionCheck()) {
- return nullptr;
- }
- env->SetObjectArrayElement(joa, 1, e);
+ 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;
}
+ jbyteArray result = byteArray.release();
+ JNI_TRACE("bytes=%p NativeCrypto_EVP_raw_X25519_private_key => %p", keyJavaBytes, result);
+ return result;
+}
- if (RSA_get0_d(rsa.get()) != nullptr) {
- jbyteArray d = bignumToArray(env, RSA_get0_d(rsa.get()), "d");
- if (env->ExceptionCheck()) {
- return nullptr;
- }
- env->SetObjectArrayElement(joa, 2, d);
- }
+/*
+ * static native byte[] EVP_marshal_public_key(long)
+ */
+static jbyteArray NativeCrypto_EVP_marshal_public_key(JNIEnv* env, jclass, jobject pkeyRef) {
+ CHECK_ERROR_QUEUE_ON_RETURN;
+ EVP_PKEY* pkey = fromContextObject(env, pkeyRef);
+ JNI_TRACE("EVP_marshal_public_key(%p)", pkey);
- if (RSA_get0_p(rsa.get()) != nullptr) {
- jbyteArray p = bignumToArray(env, RSA_get0_p(rsa.get()), "p");
- if (env->ExceptionCheck()) {
- return nullptr;
- }
- env->SetObjectArrayElement(joa, 3, p);
+ if (pkey == nullptr) {
+ return nullptr;
}
- if (RSA_get0_q(rsa.get()) != nullptr) {
- jbyteArray q = bignumToArray(env, RSA_get0_q(rsa.get()), "q");
- if (env->ExceptionCheck()) {
- return nullptr;
- }
- env->SetObjectArrayElement(joa, 4, q);
+ bssl::ScopedCBB cbb;
+ if (!CBB_init(cbb.get(), 64)) {
+ conscrypt::jniutil::throwOutOfMemory(env, "CBB_init failed");
+ JNI_TRACE("CBB_init failed");
+ return nullptr;
}
- if (RSA_get0_dmp1(rsa.get()) != nullptr) {
- jbyteArray dmp1 = bignumToArray(env, RSA_get0_dmp1(rsa.get()), "dmp1");
- if (env->ExceptionCheck()) {
- return nullptr;
- }
- env->SetObjectArrayElement(joa, 5, dmp1);
+ if (!EVP_marshal_public_key(cbb.get(), pkey)) {
+ conscrypt::jniutil::throwExceptionFromBoringSSLError(env, "EVP_marshal_public_key");
+ JNI_TRACE("key=%p EVP_marshal_public_key => error", pkey);
+ return nullptr;
}
- if (RSA_get0_dmq1(rsa.get()) != nullptr) {
- jbyteArray dmq1 = bignumToArray(env, RSA_get0_dmq1(rsa.get()), "dmq1");
- if (env->ExceptionCheck()) {
- return nullptr;
- }
- env->SetObjectArrayElement(joa, 6, dmq1);
+ return CBBToByteArray(env, cbb.get());
+}
+
+/*
+ * static native long EVP_parse_public_key(byte[])
+ */
+static jlong NativeCrypto_EVP_parse_public_key(JNIEnv* env, jclass, jbyteArray keyJavaBytes) {
+ CHECK_ERROR_QUEUE_ON_RETURN;
+ JNI_TRACE("EVP_parse_public_key(%p)", keyJavaBytes);
+
+ ScopedByteArrayRO bytes(env, keyJavaBytes);
+ if (bytes.get() == nullptr) {
+ JNI_TRACE("bytes=%p EVP_parse_public_key => threw exception", keyJavaBytes);
+ return 0;
}
- if (RSA_get0_iqmp(rsa.get()) != nullptr) {
- jbyteArray iqmp = bignumToArray(env, RSA_get0_iqmp(rsa.get()), "iqmp");
- if (env->ExceptionCheck()) {
- return nullptr;
- }
- env->SetObjectArrayElement(joa, 7, iqmp);
+ CBS cbs;
+ CBS_init(&cbs, reinterpret_cast(bytes.get()), bytes.size());
+ bssl::UniquePtr pkey(EVP_parse_public_key(&cbs));
+ // We intentionally do not check that cbs is exhausted, as JCA providers
+ // typically allow parsing keys from buffers that are larger than the
+ // contained key structure so we do the same for compatibility.
+ if (!pkey) {
+ conscrypt::jniutil::throwParsingException(env, "Error parsing public key");
+ ERR_clear_error();
+ JNI_TRACE("bytes=%p EVP_parse_public_key => threw exception", keyJavaBytes);
+ return 0;
}
- return joa;
+ JNI_TRACE("bytes=%p EVP_parse_public_key => %p", keyJavaBytes, pkey.get());
+ return reinterpret_cast(pkey.release());
}
-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) {
+static jlong NativeCrypto_getRSAPrivateKeyWrapper(JNIEnv* env, jclass, jobject javaKey,
+ jbyteArray modulusBytes) {
CHECK_ERROR_QUEUE_ON_RETURN;
- JNI_TRACE("chacha20_encrypt_decrypt");
- ScopedByteArrayRO in(env, inBytes);
- if (in.get() == nullptr) {
- JNI_TRACE(
- "chacha20_encrypt_decrypt => threw exception: could not read input "
- "bytes");
- return;
- }
- ScopedByteArrayRW out(env, outBytes);
- if (out.get() == nullptr) {
- JNI_TRACE(
- "chacha20_encrypt_decrypt => threw exception: could not read output "
- "bytes");
- return;
- }
- ScopedByteArrayRO key(env, keyBytes);
- if (key.get() == nullptr) {
- JNI_TRACE(
- "chacha20_encrypt_decrypt => threw exception: could not read key "
- "bytes");
- return;
- }
- ScopedByteArrayRO nonce(env, nonceBytes);
- if (nonce.get() == nullptr) {
- JNI_TRACE(
- "chacha20_encrypt_decrypt => threw exception: could not read nonce "
- "bytes");
- return;
- }
-
- CRYPTO_chacha_20(reinterpret_cast(out.get()) + outOffset,
- reinterpret_cast(in.get()) + inOffset, length,
- reinterpret_cast(key.get()),
- reinterpret_cast(nonce.get()), blockCounter);
-}
+ JNI_TRACE("getRSAPrivateKeyWrapper(%p, %p)", javaKey, modulusBytes);
-static jlong NativeCrypto_EC_GROUP_new_by_curve_name(JNIEnv* env, jclass, jstring curveNameJava) {
- CHECK_ERROR_QUEUE_ON_RETURN;
- JNI_TRACE("EC_GROUP_new_by_curve_name(%p)", curveNameJava);
+ ensure_engine_globals();
- ScopedUtfChars curveName(env, curveNameJava);
- if (curveName.c_str() == nullptr) {
+ // The PSS padding code needs access to the actual n, so set it even though we
+ // don't set any other parts of the key
+ bssl::UniquePtr n = arrayToBignum(env, modulusBytes);
+ if (n == nullptr) {
return 0;
}
- JNI_TRACE("EC_GROUP_new_by_curve_name(%s)", curveName.c_str());
- int nid = OBJ_sn2nid(curveName.c_str());
- if (nid == NID_undef) {
- JNI_TRACE("EC_GROUP_new_by_curve_name(%s) => unknown NID name", curveName.c_str());
+ // TODO(crbug.com/boringssl/602): RSA_METHOD is not the ideal abstraction to
+ // use here.
+ bssl::UniquePtr rsa(RSA_new_method_no_e(g_engine, n.get()));
+ if (rsa == nullptr) {
+ conscrypt::jniutil::throwOutOfMemory(env, "Unable to allocate RSA key");
return 0;
}
- EC_GROUP* group = EC_GROUP_new_by_curve_name(nid);
- if (group == nullptr) {
- JNI_TRACE("EC_GROUP_new_by_curve_name(%s) => unknown NID %d", curveName.c_str(), nid);
+ auto ex_data = new KeyExData;
+ ex_data->private_key = env->NewGlobalRef(javaKey);
+ RSA_set_ex_data(rsa.get(), g_rsa_exdata_index, ex_data);
+
+ bssl::UniquePtr pkey(EVP_PKEY_new());
+ if (pkey.get() == nullptr) {
+ JNI_TRACE("getRSAPrivateKeyWrapper failed");
+ conscrypt::jniutil::throwRuntimeException(env,
+ "NativeCrypto_getRSAPrivateKeyWrapper failed");
ERR_clear_error();
return 0;
}
- JNI_TRACE("EC_GROUP_new_by_curve_name(%s) => %p", curveName.c_str(), group);
- return reinterpret_cast(group);
+ if (EVP_PKEY_assign_RSA(pkey.get(), rsa.get()) != 1) {
+ conscrypt::jniutil::throwRuntimeException(env, "getRSAPrivateKeyWrapper failed");
+ ERR_clear_error();
+ return 0;
+ }
+ OWNERSHIP_TRANSFERRED(rsa);
+ JNI_TRACE("getRSAPrivateKeyWrapper(%p, %p) => %p", javaKey, modulusBytes, pkey.get());
+ return reinterpret_cast(pkey.release());
}
-static jlong NativeCrypto_EC_GROUP_new_arbitrary(JNIEnv* env, jclass, jbyteArray pBytes,
- jbyteArray aBytes, jbyteArray bBytes,
- jbyteArray xBytes, jbyteArray yBytes,
- jbyteArray orderBytes, jint cofactorInt) {
+static jlong NativeCrypto_getECPrivateKeyWrapper(JNIEnv* env, jclass, jobject javaKey,
+ jobject groupRef) {
CHECK_ERROR_QUEUE_ON_RETURN;
- JNI_TRACE("EC_GROUP_new_arbitrary");
-
- if (cofactorInt < 1) {
- conscrypt::jniutil::throwException(env, "java/lang/IllegalArgumentException",
- "cofactor < 1");
+ EC_GROUP* group = fromContextObject(env, groupRef);
+ JNI_TRACE("getECPrivateKeyWrapper(%p, %p)", javaKey, group);
+ if (group == nullptr) {
return 0;
}
- bssl::UniquePtr p = arrayToBignum(env, pBytes);
- if (p == nullptr) {
- return 0;
- }
- bssl::UniquePtr a = arrayToBignum(env, aBytes);
- if (a == nullptr) {
+ ensure_engine_globals();
+
+ bssl::UniquePtr ecKey(EC_KEY_new_method(g_engine));
+ if (ecKey.get() == nullptr) {
+ conscrypt::jniutil::throwOutOfMemory(env, "Unable to allocate EC key");
return 0;
}
- bssl::UniquePtr b = arrayToBignum(env, bBytes);
- if (b == nullptr) {
+
+ if (EC_KEY_set_group(ecKey.get(), group) != 1) {
+ JNI_TRACE("getECPrivateKeyWrapper(%p, %p) => EC_KEY_set_group error", javaKey, group);
+ conscrypt::jniutil::throwExceptionFromBoringSSLError(env, "EC_KEY_set_group");
return 0;
}
- bssl::UniquePtr x = arrayToBignum(env, xBytes);
- if (x == nullptr) {
+
+ auto ex_data = new KeyExData;
+ ex_data->private_key = env->NewGlobalRef(javaKey);
+
+ if (!EC_KEY_set_ex_data(ecKey.get(), g_ecdsa_exdata_index, ex_data)) {
+ env->DeleteGlobalRef(ex_data->private_key);
+ delete ex_data;
+ conscrypt::jniutil::throwRuntimeException(env, "EC_KEY_set_ex_data");
+ ERR_clear_error();
return 0;
}
- bssl::UniquePtr y = arrayToBignum(env, yBytes);
- if (y == nullptr) {
+
+ bssl::UniquePtr pkey(EVP_PKEY_new());
+ if (pkey.get() == nullptr) {
+ JNI_TRACE("getECPrivateKeyWrapper failed");
+ conscrypt::jniutil::throwRuntimeException(env,
+ "NativeCrypto_getECPrivateKeyWrapper failed");
+ ERR_clear_error();
return 0;
}
- bssl::UniquePtr order = arrayToBignum(env, orderBytes);
- if (order == nullptr) {
+
+ if (EVP_PKEY_assign_EC_KEY(pkey.get(), ecKey.get()) != 1) {
+ conscrypt::jniutil::throwRuntimeException(env, "getECPrivateKeyWrapper failed");
+ ERR_clear_error();
return 0;
}
- bssl::UniquePtr cofactor(BN_new());
- if (cofactor == nullptr || !BN_set_word(cofactor.get(), static_cast(cofactorInt))) {
+ OWNERSHIP_TRANSFERRED(ecKey);
+ return reinterpret_cast(pkey.release());
+}
+
+/*
+ * public static native int RSA_generate_key(int modulusBits, byte[]
+ * publicExponent);
+ */
+static jlong NativeCrypto_RSA_generate_key_ex(JNIEnv* env, jclass, jint modulusBits,
+ jbyteArray publicExponent) {
+ CHECK_ERROR_QUEUE_ON_RETURN;
+ JNI_TRACE("RSA_generate_key_ex(%d, %p)", modulusBits, publicExponent);
+
+ bssl::UniquePtr e = arrayToBignum(env, publicExponent);
+ if (e == nullptr) {
return 0;
}
- bssl::UniquePtr ctx(BN_CTX_new());
- bssl::UniquePtr group(EC_GROUP_new_curve_GFp(p.get(), a.get(), b.get(), ctx.get()));
- if (group.get() == nullptr) {
- JNI_TRACE("EC_GROUP_new_curve_GFp => null");
- conscrypt::jniutil::throwExceptionFromBoringSSLError(env, "EC_GROUP_new_curve_GFp");
+ bssl::UniquePtr rsa(RSA_new());
+ if (rsa.get() == nullptr) {
+ conscrypt::jniutil::throwOutOfMemory(env, "Unable to allocate RSA key");
return 0;
}
- bssl::UniquePtr generator(EC_POINT_new(group.get()));
- if (generator.get() == nullptr) {
- JNI_TRACE("EC_POINT_new => null");
- ERR_clear_error();
+ if (RSA_generate_key_ex(rsa.get(), modulusBits, e.get(), nullptr) != 1) {
+ conscrypt::jniutil::throwExceptionFromBoringSSLError(env, "RSA_generate_key_ex failed");
return 0;
}
- 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");
+ bssl::UniquePtr pkey(EVP_PKEY_new());
+ if (pkey.get() == nullptr) {
+ conscrypt::jniutil::throwOutOfMemory(env, "Unable to allocate RSA key");
+ ERR_clear_error();
return 0;
}
- if (!EC_GROUP_set_generator(group.get(), generator.get(), order.get(), cofactor.get())) {
- JNI_TRACE("EC_GROUP_set_generator => error");
- conscrypt::jniutil::throwExceptionFromBoringSSLError(env, "EC_GROUP_set_generator");
+ if (EVP_PKEY_assign_RSA(pkey.get(), rsa.get()) != 1) {
+ conscrypt::jniutil::throwRuntimeException(env, "RSA_generate_key_ex failed");
+ ERR_clear_error();
return 0;
}
- JNI_TRACE("EC_GROUP_new_arbitrary => %p", group.get());
- return reinterpret_cast(group.release());
+ OWNERSHIP_TRANSFERRED(rsa);
+ JNI_TRACE("RSA_generate_key_ex(n=%d, e=%p) => %p", modulusBits, publicExponent, pkey.get());
+ return reinterpret_cast(pkey.release());
}
-static jstring NativeCrypto_EC_GROUP_get_curve_name(JNIEnv* env, jclass, jobject groupRef) {
+static jint NativeCrypto_RSA_size(JNIEnv* env, jclass, jobject pkeyRef) {
CHECK_ERROR_QUEUE_ON_RETURN;
- const EC_GROUP* group = fromContextObject(env, groupRef);
- JNI_TRACE("EC_GROUP_get_curve_name(%p)", group);
+ EVP_PKEY* pkey = fromContextObject(env, pkeyRef);
+ JNI_TRACE("RSA_size(%p)", pkey);
- if (group == nullptr) {
- JNI_TRACE("EC_GROUP_get_curve_name => group == null");
- return nullptr;
+ if (pkey == nullptr) {
+ return 0;
}
- int nid = EC_GROUP_get_curve_name(group);
- if (nid == NID_undef) {
- JNI_TRACE("EC_GROUP_get_curve_name(%p) => unnamed curve", group);
- return nullptr;
+ bssl::UniquePtr rsa(EVP_PKEY_get1_RSA(pkey));
+ if (rsa.get() == nullptr) {
+ conscrypt::jniutil::throwRuntimeException(env, "RSA_size failed");
+ ERR_clear_error();
+ return 0;
}
- const char* shortName = OBJ_nid2sn(nid);
- JNI_TRACE("EC_GROUP_get_curve_name(%p) => \"%s\"", group, shortName);
- return env->NewStringUTF(shortName);
+ return static_cast(RSA_size(rsa.get()));
}
-static jobjectArray NativeCrypto_EC_GROUP_get_curve(JNIEnv* env, jclass, jobject groupRef) {
+typedef int RSACryptOperation(size_t flen, const unsigned char* from, unsigned char* to, RSA* rsa,
+ int padding);
+
+static jint RSA_crypt_operation(RSACryptOperation operation, const char* caller, JNIEnv* env,
+ jint flen, jbyteArray fromJavaBytes, jbyteArray toJavaBytes,
+ jobject pkeyRef, jint padding) {
CHECK_ERROR_QUEUE_ON_RETURN;
- const EC_GROUP* group = fromContextObject(env, groupRef);
- JNI_TRACE("EC_GROUP_get_curve(%p)", group);
- if (group == nullptr) {
- JNI_TRACE("EC_GROUP_get_curve => group == null");
- return nullptr;
- }
+ EVP_PKEY* pkey = fromContextObject(env, pkeyRef);
+ JNI_TRACE("%s(%d, %p, %p, %p)", caller, flen, fromJavaBytes, toJavaBytes, pkey);
- bssl::UniquePtr p(BN_new());
- bssl::UniquePtr a(BN_new());
- bssl::UniquePtr b(BN_new());
+ if (pkey == nullptr) {
+ return -1;
+ }
- int ret = EC_GROUP_get_curve_GFp(group, p.get(), a.get(), b.get(), nullptr);
- if (ret != 1) {
- conscrypt::jniutil::throwExceptionFromBoringSSLError(env, "EC_GROUP_get_curve");
- return nullptr;
+ bssl::UniquePtr rsa(EVP_PKEY_get1_RSA(pkey));
+ if (rsa.get() == nullptr) {
+ return -1;
}
- jobjectArray joa = env->NewObjectArray(3, conscrypt::jniutil::byteArrayClass, nullptr);
- if (joa == nullptr) {
- return nullptr;
+ ScopedByteArrayRO from(env, fromJavaBytes);
+ if (from.get() == nullptr) {
+ return -1;
}
- jbyteArray pArray = bignumToArray(env, p.get(), "p");
- if (env->ExceptionCheck()) {
- return nullptr;
+ ScopedByteArrayRW to(env, toJavaBytes);
+ if (to.get() == nullptr) {
+ return -1;
}
- env->SetObjectArrayElement(joa, 0, pArray);
- jbyteArray aArray = bignumToArray(env, a.get(), "a");
- if (env->ExceptionCheck()) {
- return nullptr;
+ int resultSize =
+ 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);
+ JNI_TRACE("%s => threw error", caller);
+ return -1;
}
- env->SetObjectArrayElement(joa, 1, aArray);
- jbyteArray bArray = bignumToArray(env, b.get(), "b");
- if (env->ExceptionCheck()) {
- return nullptr;
- }
- env->SetObjectArrayElement(joa, 2, bArray);
+ JNI_TRACE("%s(%d, %p, %p, %p) => %d", caller, flen, fromJavaBytes, toJavaBytes, pkey,
+ resultSize);
+ return static_cast(resultSize);
+}
- JNI_TRACE("EC_GROUP_get_curve(%p) => %p", group, joa);
- return joa;
+static jint NativeCrypto_RSA_private_encrypt(JNIEnv* env, jclass, jint flen,
+ jbyteArray fromJavaBytes, jbyteArray toJavaBytes,
+ jobject pkeyRef, jint padding) {
+ CHECK_ERROR_QUEUE_ON_RETURN;
+ return RSA_crypt_operation(RSA_private_encrypt, __FUNCTION__, env, flen, fromJavaBytes,
+ toJavaBytes, pkeyRef, padding);
+}
+static jint NativeCrypto_RSA_public_decrypt(JNIEnv* env, jclass, jint flen,
+ jbyteArray fromJavaBytes, jbyteArray toJavaBytes,
+ jobject pkeyRef, jint padding) {
+ CHECK_ERROR_QUEUE_ON_RETURN;
+ return RSA_crypt_operation(RSA_public_decrypt, __FUNCTION__, env, flen, fromJavaBytes,
+ toJavaBytes, pkeyRef, padding);
+}
+static jint NativeCrypto_RSA_public_encrypt(JNIEnv* env, jclass, jint flen,
+ jbyteArray fromJavaBytes, jbyteArray toJavaBytes,
+ jobject pkeyRef, jint padding) {
+ CHECK_ERROR_QUEUE_ON_RETURN;
+ return RSA_crypt_operation(RSA_public_encrypt, __FUNCTION__, env, flen, fromJavaBytes,
+ toJavaBytes, pkeyRef, padding);
+}
+static jint NativeCrypto_RSA_private_decrypt(JNIEnv* env, jclass, jint flen,
+ jbyteArray fromJavaBytes, jbyteArray toJavaBytes,
+ jobject pkeyRef, jint padding) {
+ CHECK_ERROR_QUEUE_ON_RETURN;
+ return RSA_crypt_operation(RSA_private_decrypt, __FUNCTION__, env, flen, fromJavaBytes,
+ toJavaBytes, pkeyRef, padding);
}
-static jbyteArray NativeCrypto_EC_GROUP_get_order(JNIEnv* env, jclass, jobject groupRef) {
+/*
+ * public static native byte[][] get_RSA_public_params(long);
+ */
+static jobjectArray NativeCrypto_get_RSA_public_params(JNIEnv* env, jclass, jobject pkeyRef) {
CHECK_ERROR_QUEUE_ON_RETURN;
- const EC_GROUP* group = fromContextObject(env, groupRef);
- JNI_TRACE("EC_GROUP_get_order(%p)", group);
- if (group == nullptr) {
+ EVP_PKEY* pkey = fromContextObject(env, pkeyRef);
+ JNI_TRACE("get_RSA_public_params(%p)", pkey);
+
+ if (pkey == nullptr) {
return nullptr;
}
- bssl::UniquePtr order(BN_new());
- if (order.get() == nullptr) {
- JNI_TRACE("EC_GROUP_get_order(%p) => can't create BN", group);
- conscrypt::jniutil::throwOutOfMemory(env, "BN_new");
+ bssl::UniquePtr rsa(EVP_PKEY_get1_RSA(pkey));
+ if (rsa.get() == nullptr) {
+ conscrypt::jniutil::throwExceptionFromBoringSSLError(env, "get_RSA_public_params failed");
return nullptr;
}
- if (EC_GROUP_get_order(group, order.get(), nullptr) != 1) {
- JNI_TRACE("EC_GROUP_get_order(%p) => threw error", group);
- conscrypt::jniutil::throwExceptionFromBoringSSLError(env, "EC_GROUP_get_order");
+ jobjectArray joa = env->NewObjectArray(2, conscrypt::jniutil::byteArrayClass, nullptr);
+ if (joa == nullptr) {
return nullptr;
}
- jbyteArray orderArray = bignumToArray(env, order.get(), "order");
+ jbyteArray n = bignumToArray(env, RSA_get0_n(rsa.get()), "n");
if (env->ExceptionCheck()) {
return nullptr;
}
+ env->SetObjectArrayElement(joa, 0, n);
- JNI_TRACE("EC_GROUP_get_order(%p) => %p", group, orderArray);
- return orderArray;
-}
-
-static jint NativeCrypto_EC_GROUP_get_degree(JNIEnv* env, jclass, jobject groupRef) {
- CHECK_ERROR_QUEUE_ON_RETURN;
- const EC_GROUP* group = fromContextObject(env, groupRef);
- JNI_TRACE("EC_GROUP_get_degree(%p)", group);
- if (group == nullptr) {
- return 0;
- }
-
- jint degree = static_cast(EC_GROUP_get_degree(group));
- if (degree == 0) {
- JNI_TRACE("EC_GROUP_get_degree(%p) => unsupported", group);
- conscrypt::jniutil::throwRuntimeException(env, "not supported");
- ERR_clear_error();
- return 0;
+ jbyteArray e = bignumToArray(env, RSA_get0_e(rsa.get()), "e");
+ if (env->ExceptionCheck()) {
+ return nullptr;
}
+ env->SetObjectArrayElement(joa, 1, e);
- JNI_TRACE("EC_GROUP_get_degree(%p) => %d", group, degree);
- return degree;
+ return joa;
}
-static jbyteArray NativeCrypto_EC_GROUP_get_cofactor(JNIEnv* env, jclass, jobject groupRef) {
+/*
+ * public static native byte[][] get_RSA_private_params(long);
+ */
+static jobjectArray NativeCrypto_get_RSA_private_params(JNIEnv* env, jclass, jobject pkeyRef) {
CHECK_ERROR_QUEUE_ON_RETURN;
- const EC_GROUP* group = fromContextObject(env, groupRef);
- JNI_TRACE("EC_GROUP_get_cofactor(%p)", group);
- if (group == nullptr) {
+ EVP_PKEY* pkey = fromContextObject(env, pkeyRef);
+ JNI_TRACE("get_RSA_public_params(%p)", pkey);
+
+ if (pkey == nullptr) {
return nullptr;
}
- bssl::UniquePtr cofactor(BN_new());
- if (cofactor.get() == nullptr) {
- JNI_TRACE("EC_GROUP_get_cofactor(%p) => can't create BN", group);
- conscrypt::jniutil::throwOutOfMemory(env, "BN_new");
+ bssl::UniquePtr rsa(EVP_PKEY_get1_RSA(pkey));
+ if (rsa.get() == nullptr) {
+ conscrypt::jniutil::throwExceptionFromBoringSSLError(env, "get_RSA_public_params failed");
return nullptr;
}
- if (EC_GROUP_get_cofactor(group, cofactor.get(), nullptr) != 1) {
- JNI_TRACE("EC_GROUP_get_cofactor(%p) => threw error", group);
- conscrypt::jniutil::throwExceptionFromBoringSSLError(env, "EC_GROUP_get_cofactor");
+ jobjectArray joa = env->NewObjectArray(8, conscrypt::jniutil::byteArrayClass, nullptr);
+ if (joa == nullptr) {
return nullptr;
}
- jbyteArray cofactorArray = bignumToArray(env, cofactor.get(), "cofactor");
+ jbyteArray n = bignumToArray(env, RSA_get0_n(rsa.get()), "n");
if (env->ExceptionCheck()) {
return nullptr;
}
+ env->SetObjectArrayElement(joa, 0, n);
- JNI_TRACE("EC_GROUP_get_cofactor(%p) => %p", group, cofactorArray);
- return cofactorArray;
-}
-
-static void NativeCrypto_EC_GROUP_clear_free(JNIEnv* env, jclass, jlong groupRef) {
- CHECK_ERROR_QUEUE_ON_RETURN;
- EC_GROUP* group = reinterpret_cast(groupRef);
- JNI_TRACE("EC_GROUP_clear_free(%p)", group);
-
- if (group == nullptr) {
- JNI_TRACE("EC_GROUP_clear_free => group == null");
- conscrypt::jniutil::throwNullPointerException(env, "group == null");
- return;
+ if (RSA_get0_e(rsa.get()) != nullptr) {
+ jbyteArray e = bignumToArray(env, RSA_get0_e(rsa.get()), "e");
+ if (env->ExceptionCheck()) {
+ return nullptr;
+ }
+ env->SetObjectArrayElement(joa, 1, e);
}
- EC_GROUP_free(group);
- JNI_TRACE("EC_GROUP_clear_free(%p) => success", group);
-}
-
-static jlong NativeCrypto_EC_GROUP_get_generator(JNIEnv* env, jclass, jobject groupRef) {
- CHECK_ERROR_QUEUE_ON_RETURN;
- const EC_GROUP* group = fromContextObject(env, groupRef);
- JNI_TRACE("EC_GROUP_get_generator(%p)", group);
-
- if (group == nullptr) {
- JNI_TRACE("EC_POINT_get_generator(%p) => group == null", group);
- return 0;
+ if (RSA_get0_d(rsa.get()) != nullptr) {
+ jbyteArray d = bignumToArray(env, RSA_get0_d(rsa.get()), "d");
+ if (env->ExceptionCheck()) {
+ return nullptr;
+ }
+ env->SetObjectArrayElement(joa, 2, d);
}
- const EC_POINT* generator = EC_GROUP_get0_generator(group);
-
- bssl::UniquePtr dup(EC_POINT_dup(generator, group));
- if (dup.get() == nullptr) {
- JNI_TRACE("EC_GROUP_get_generator(%p) => oom error", group);
- conscrypt::jniutil::throwOutOfMemory(env, "unable to dupe generator");
- return 0;
+ if (RSA_get0_p(rsa.get()) != nullptr) {
+ jbyteArray p = bignumToArray(env, RSA_get0_p(rsa.get()), "p");
+ if (env->ExceptionCheck()) {
+ return nullptr;
+ }
+ env->SetObjectArrayElement(joa, 3, p);
}
- JNI_TRACE("EC_GROUP_get_generator(%p) => %p", group, dup.get());
- return reinterpret_cast(dup.release());
-}
-
-static jlong NativeCrypto_EC_POINT_new(JNIEnv* env, jclass, jobject groupRef) {
- CHECK_ERROR_QUEUE_ON_RETURN;
- const EC_GROUP* group = fromContextObject(env, groupRef);
- JNI_TRACE("EC_POINT_new(%p)", group);
-
- if (group == nullptr) {
- JNI_TRACE("EC_POINT_new(%p) => group == null", group);
- return 0;
+ if (RSA_get0_q(rsa.get()) != nullptr) {
+ jbyteArray q = bignumToArray(env, RSA_get0_q(rsa.get()), "q");
+ if (env->ExceptionCheck()) {
+ return nullptr;
+ }
+ env->SetObjectArrayElement(joa, 4, q);
}
- EC_POINT* point = EC_POINT_new(group);
- if (point == nullptr) {
- conscrypt::jniutil::throwOutOfMemory(env, "Unable create an EC_POINT");
- return 0;
+ if (RSA_get0_dmp1(rsa.get()) != nullptr) {
+ jbyteArray dmp1 = bignumToArray(env, RSA_get0_dmp1(rsa.get()), "dmp1");
+ if (env->ExceptionCheck()) {
+ return nullptr;
+ }
+ env->SetObjectArrayElement(joa, 5, dmp1);
}
- return reinterpret_cast(point);
-}
-
-static void NativeCrypto_EC_POINT_clear_free(JNIEnv* env, jclass, jlong groupRef) {
- CHECK_ERROR_QUEUE_ON_RETURN;
- EC_POINT* group = reinterpret_cast(groupRef);
- JNI_TRACE("EC_POINT_clear_free(%p)", group);
+ if (RSA_get0_dmq1(rsa.get()) != nullptr) {
+ jbyteArray dmq1 = bignumToArray(env, RSA_get0_dmq1(rsa.get()), "dmq1");
+ if (env->ExceptionCheck()) {
+ return nullptr;
+ }
+ env->SetObjectArrayElement(joa, 6, dmq1);
+ }
- if (group == nullptr) {
- JNI_TRACE("EC_POINT_clear_free => group == null");
- conscrypt::jniutil::throwNullPointerException(env, "group == null");
- return;
+ if (RSA_get0_iqmp(rsa.get()) != nullptr) {
+ jbyteArray iqmp = bignumToArray(env, RSA_get0_iqmp(rsa.get()), "iqmp");
+ if (env->ExceptionCheck()) {
+ return nullptr;
+ }
+ env->SetObjectArrayElement(joa, 7, iqmp);
}
- EC_POINT_free(group);
- JNI_TRACE("EC_POINT_clear_free(%p) => success", group);
+ return joa;
}
-static void NativeCrypto_EC_POINT_set_affine_coordinates(JNIEnv* env, jclass, jobject groupRef,
- jobject pointRef, jbyteArray xjavaBytes,
- jbyteArray yjavaBytes) {
+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) {
CHECK_ERROR_QUEUE_ON_RETURN;
- JNI_TRACE("EC_POINT_set_affine_coordinates(%p, %p, %p, %p)", groupRef, pointRef, xjavaBytes,
- yjavaBytes);
- const EC_GROUP* group = fromContextObject(env, groupRef);
- if (group == nullptr) {
+ JNI_TRACE("chacha20_encrypt_decrypt");
+ ScopedByteArrayRO in(env, inBytes);
+ if (in.get() == nullptr) {
+ JNI_TRACE(
+ "chacha20_encrypt_decrypt => threw exception: could not read input "
+ "bytes");
return;
}
- EC_POINT* point = fromContextObject(env, pointRef);
- if (point == nullptr) {
+ ScopedByteArrayRW out(env, outBytes);
+ if (out.get() == nullptr) {
+ JNI_TRACE(
+ "chacha20_encrypt_decrypt => threw exception: could not read output "
+ "bytes");
return;
}
- JNI_TRACE("EC_POINT_set_affine_coordinates(%p, %p, %p, %p) <- ptr", group, point, xjavaBytes,
- yjavaBytes);
-
- bssl::UniquePtr x = arrayToBignum(env, xjavaBytes);
- if (x == nullptr) {
+ ScopedByteArrayRO key(env, keyBytes);
+ if (key.get() == nullptr) {
+ JNI_TRACE(
+ "chacha20_encrypt_decrypt => threw exception: could not read key "
+ "bytes");
return;
}
-
- bssl::UniquePtr y = arrayToBignum(env, yjavaBytes);
- if (y == nullptr) {
- return;
- }
-
- int ret = EC_POINT_set_affine_coordinates_GFp(group, point, x.get(), y.get(), nullptr);
- if (ret != 1) {
- conscrypt::jniutil::throwExceptionFromBoringSSLError(env,
- "EC_POINT_set_affine_coordinates");
+ ScopedByteArrayRO nonce(env, nonceBytes);
+ if (nonce.get() == nullptr) {
+ JNI_TRACE(
+ "chacha20_encrypt_decrypt => threw exception: could not read nonce "
+ "bytes");
return;
}
- JNI_TRACE("EC_POINT_set_affine_coordinates(%p, %p, %p, %p) => %d", group, point, xjavaBytes,
- yjavaBytes, ret);
+ CRYPTO_chacha_20(reinterpret_cast(out.get()) + outOffset,
+ reinterpret_cast(in.get()) + inOffset, length,
+ reinterpret_cast