Skip to content

Commit

Permalink
Merge branch 'master' into ckozak/gh1170_reentrant_locks
Browse files Browse the repository at this point in the history
  • Loading branch information
prbprbprb committed Oct 26, 2023
2 parents 3dde52e + bc1a34b commit b14310d
Show file tree
Hide file tree
Showing 29 changed files with 1,670 additions and 858 deletions.
11 changes: 11 additions & 0 deletions common/src/jni/main/cpp/conscrypt/jniutil.cc
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,12 @@ int throwInvalidKeyException(JNIEnv* env, const char* message) {
return conscrypt::jniutil::throwException(env, "java/security/InvalidKeyException", message);
}

int throwIllegalArgumentException(JNIEnv* env, const char* message) {
JNI_TRACE("throwIllegalArgumentException %s", message);
return conscrypt::jniutil::throwException(
env, "java/lang/IllegalArgumentException", message);
}

int throwIllegalBlockSizeException(JNIEnv* env, const char* message) {
JNI_TRACE("throwIllegalBlockSizeException %s", message);
return conscrypt::jniutil::throwException(
Expand Down Expand Up @@ -344,11 +350,16 @@ int throwForEvpError(JNIEnv* env, int reason, const char* message,
int (*defaultThrow)(JNIEnv*, const char*)) {
switch (reason) {
case EVP_R_MISSING_PARAMETERS:
case EVP_R_INVALID_PEER_KEY:
case EVP_R_DECODE_ERROR:
return throwInvalidKeyException(env, message);
break;
case EVP_R_UNSUPPORTED_ALGORITHM:
return throwNoSuchAlgorithmException(env, message);
break;
case EVP_R_INVALID_BUFFER_SIZE:
return throwIllegalArgumentException(env, message);
break;
default:
return defaultThrow(env, message);
break;
Expand Down
110 changes: 34 additions & 76 deletions common/src/jni/main/cpp/conscrypt/native_crypto.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4007,11 +4007,12 @@ const EVP_HPKE_KEM* getHpkeKem(JNIEnv* env, jint kemValue) {
}
}

static jobject NativeCrypto_EVP_HPKE_CTX_setup_recipient(JNIEnv* env, jclass, jint kemValue,
jint kdfValue, jint aeadValue,
jbyteArray privateKeyArray,
jbyteArray encArray,
jbyteArray infoArray) {
static jobject NativeCrypto_EVP_HPKE_CTX_setup_base_mode_recipient(JNIEnv* env, jclass,
jint kemValue,jint kdfValue,
jint aeadValue,
jbyteArray privateKeyArray,
jbyteArray encArray,
jbyteArray infoArray) {
CHECK_ERROR_QUEUE_ON_RETURN;
JNI_TRACE("EVP_HPKE_CTX_setup_recipient(%d, %d, %d, %p, %p, %p)", kemValue, kdfValue, aeadValue,
privateKeyArray, encArray, infoArray);
Expand Down Expand Up @@ -4082,10 +4083,11 @@ static jobject NativeCrypto_EVP_HPKE_CTX_setup_recipient(JNIEnv* env, jclass, ji
return ctxObject.release();
}

static jobjectArray NativeCrypto_EVP_HPKE_CTX_setup_sender(JNIEnv* env, jclass, jint kemValue,
jint kdfValue, jint aeadValue,
jbyteArray publicKeyArray,
jbyteArray infoArray) {
static jobjectArray NativeCrypto_EVP_HPKE_CTX_setup_base_mode_sender(JNIEnv* env, jclass,
jint kemValue,jint kdfValue,
jint aeadValue,
jbyteArray publicKeyArray,
jbyteArray infoArray) {
CHECK_ERROR_QUEUE_ON_RETURN;
JNI_TRACE("EVP_HPKE_CTX_setup_sender(%d, %d, %d, %p, %p)", kemValue, kdfValue, aeadValue,
publicKeyArray, infoArray);
Expand Down Expand Up @@ -4165,7 +4167,7 @@ static jobjectArray NativeCrypto_EVP_HPKE_CTX_setup_sender(JNIEnv* env, jclass,
return result.release();
}

static jobjectArray NativeCrypto_EVP_HPKE_CTX_setup_sender_with_seed_for_testing(
static jobjectArray NativeCrypto_EVP_HPKE_CTX_setup_base_mode_sender_with_seed_for_testing(
JNIEnv* env, jclass, jint kemValue, jint kdfValue, jint aeadValue,
jbyteArray publicKeyArray, jbyteArray infoArray, jbyteArray seedArray) {
CHECK_ERROR_QUEUE_ON_RETURN;
Expand Down Expand Up @@ -4861,6 +4863,20 @@ static jobjectArray NativeCrypto_get_X509_GENERAL_NAME_stack(JNIEnv* env, jclass
return joa.release();
}

/*
* Converts an ASN1_TIME to epoch time in milliseconds.
*/
static jlong ASN1_TIME_convert_to_posix(JNIEnv* env, const ASN1_TIME* time) {
int64_t retval;
if (!ASN1_TIME_to_posix(time, &retval)) {
JNI_TRACE("ASN1_TIME_convert_to_posix(%p) => Invalid date value", time);
conscrypt::jniutil::throwParsingException(env, "Invalid date value");
return 0;
}
// ASN1_TIME_to_posix can only return years from 0000 to 9999, so this won't overflow.
return static_cast<jlong>(retval * 1000);
}

static jlong NativeCrypto_X509_get_notBefore(JNIEnv* env, jclass, jlong x509Ref,
CONSCRYPT_UNUSED jobject holder) {
CHECK_ERROR_QUEUE_ON_RETURN;
Expand All @@ -4875,7 +4891,7 @@ static jlong NativeCrypto_X509_get_notBefore(JNIEnv* env, jclass, jlong x509Ref,

ASN1_TIME* notBefore = X509_get_notBefore(x509);
JNI_TRACE("X509_get_notBefore(%p) => %p", x509, notBefore);
return reinterpret_cast<uintptr_t>(notBefore);
return ASN1_TIME_convert_to_posix(env, notBefore);
}

static jlong NativeCrypto_X509_get_notAfter(JNIEnv* env, jclass, jlong x509Ref,
Expand All @@ -4892,7 +4908,7 @@ static jlong NativeCrypto_X509_get_notAfter(JNIEnv* env, jclass, jlong x509Ref,

ASN1_TIME* notAfter = X509_get_notAfter(x509);
JNI_TRACE("X509_get_notAfter(%p) => %p", x509, notAfter);
return reinterpret_cast<uintptr_t>(notAfter);
return ASN1_TIME_convert_to_posix(env, notAfter);
}

// NOLINTNEXTLINE(runtime/int)
Expand Down Expand Up @@ -5528,7 +5544,7 @@ static jlong NativeCrypto_get_X509_REVOKED_revocationDate(JNIEnv* env, jclass,

JNI_TRACE("get_X509_REVOKED_revocationDate(%p) => %p", revoked,
X509_REVOKED_get0_revocationDate(revoked));
return reinterpret_cast<uintptr_t>(X509_REVOKED_get0_revocationDate(revoked));
return ASN1_TIME_convert_to_posix(env, X509_REVOKED_get0_revocationDate(revoked));
}

#ifdef __GNUC__
Expand Down Expand Up @@ -5622,7 +5638,7 @@ static jlong NativeCrypto_X509_CRL_get_lastUpdate(JNIEnv* env, jclass, jlong x50

ASN1_TIME* lastUpdate = X509_CRL_get_lastUpdate(crl);
JNI_TRACE("X509_CRL_get_lastUpdate(%p) => %p", crl, lastUpdate);
return reinterpret_cast<uintptr_t>(lastUpdate);
return ASN1_TIME_convert_to_posix(env, lastUpdate);
}

static jlong NativeCrypto_X509_CRL_get_nextUpdate(JNIEnv* env, jclass, jlong x509CrlRef,
Expand All @@ -5639,7 +5655,7 @@ static jlong NativeCrypto_X509_CRL_get_nextUpdate(JNIEnv* env, jclass, jlong x50

ASN1_TIME* nextUpdate = X509_CRL_get_nextUpdate(crl);
JNI_TRACE("X509_CRL_get_nextUpdate(%p) => %p", crl, nextUpdate);
return reinterpret_cast<uintptr_t>(nextUpdate);
return ASN1_TIME_convert_to_posix(env, nextUpdate);
}

static jbyteArray NativeCrypto_i2d_X509_REVOKED(JNIEnv* env, jclass, jlong x509RevokedRef) {
Expand All @@ -5663,63 +5679,6 @@ static jint NativeCrypto_X509_supported_extension(JNIEnv* env, jclass, jlong x50
return X509_supported_extension(ext);
}

static inline bool decimal_to_integer(const char* data, size_t len, int* out) {
int ret = 0;
for (size_t i = 0; i < len; i++) {
ret *= 10;
if (data[i] < '0' || data[i] > '9') {
return false;
}
ret += data[i] - '0';
}
*out = ret;
return true;
}

static void NativeCrypto_ASN1_TIME_to_Calendar(JNIEnv* env, jclass, jlong asn1TimeRef,
jobject calendar) {
CHECK_ERROR_QUEUE_ON_RETURN;
ASN1_TIME* asn1Time = reinterpret_cast<ASN1_TIME*>(static_cast<uintptr_t>(asn1TimeRef));
JNI_TRACE("ASN1_TIME_to_Calendar(%p, %p)", asn1Time, calendar);

if (asn1Time == nullptr) {
conscrypt::jniutil::throwNullPointerException(env, "asn1Time == null");
return;
}

if (!ASN1_TIME_check(asn1Time)) {
conscrypt::jniutil::throwParsingException(env, "Invalid date format");
return;
}

bssl::UniquePtr<ASN1_GENERALIZEDTIME> gen(ASN1_TIME_to_generalizedtime(asn1Time, nullptr));
if (gen.get() == nullptr) {
conscrypt::jniutil::throwParsingException(env,
"ASN1_TIME_to_generalizedtime returned null");
return;
}

if (ASN1_STRING_length(gen.get()) < 14 || ASN1_STRING_get0_data(gen.get()) == nullptr) {
conscrypt::jniutil::throwNullPointerException(env, "gen->length < 14 || gen->data == null");
return;
}

int year, mon, mday, hour, min, sec;
const char* data = reinterpret_cast<const char*>(ASN1_STRING_get0_data(gen.get()));
if (!decimal_to_integer(data, 4, &year) ||
!decimal_to_integer(data + 4, 2, &mon) ||
!decimal_to_integer(data + 6, 2, &mday) ||
!decimal_to_integer(data + 8, 2, &hour) ||
!decimal_to_integer(data + 10, 2, &min) ||
!decimal_to_integer(data + 12, 2, &sec)) {
conscrypt::jniutil::throwParsingException(env, "Invalid date format");
return;
}

env->CallVoidMethod(calendar, conscrypt::jniutil::calendar_setMethod, year, mon - 1, mday, hour,
min, sec);
}

// A CbsHandle is a structure used to manage resources allocated by asn1_read-*
// functions so that they can be freed properly when finished. This struct owns
// all objects pointed to by its members.
Expand Down Expand Up @@ -11135,9 +11094,9 @@ static JNINativeMethod sNativeCryptoMethods[] = {
CONSCRYPT_NATIVE_METHOD(EVP_HPKE_CTX_free, "(J)V"),
CONSCRYPT_NATIVE_METHOD(EVP_HPKE_CTX_open, "(" REF_EVP_HPKE_CTX "[B[B)[B"),
CONSCRYPT_NATIVE_METHOD(EVP_HPKE_CTX_seal, "(" REF_EVP_HPKE_CTX "[B[B)[B"),
CONSCRYPT_NATIVE_METHOD(EVP_HPKE_CTX_setup_recipient, "(III[B[B[B)Ljava/lang/Object;"),
CONSCRYPT_NATIVE_METHOD(EVP_HPKE_CTX_setup_sender, "(III[B[B)[Ljava/lang/Object;"),
CONSCRYPT_NATIVE_METHOD(EVP_HPKE_CTX_setup_sender_with_seed_for_testing,
CONSCRYPT_NATIVE_METHOD(EVP_HPKE_CTX_setup_base_mode_recipient, "(III[B[B[B)Ljava/lang/Object;"),
CONSCRYPT_NATIVE_METHOD(EVP_HPKE_CTX_setup_base_mode_sender, "(III[B[B)[Ljava/lang/Object;"),
CONSCRYPT_NATIVE_METHOD(EVP_HPKE_CTX_setup_base_mode_sender_with_seed_for_testing,
"(III[B[B[B)[Ljava/lang/Object;"),
CONSCRYPT_NATIVE_METHOD(HMAC_CTX_new, "()J"),
CONSCRYPT_NATIVE_METHOD(HMAC_CTX_free, "(J)V"),
Expand Down Expand Up @@ -11218,7 +11177,6 @@ static JNINativeMethod sNativeCryptoMethods[] = {
CONSCRYPT_NATIVE_METHOD(X509_REVOKED_dup, "(J)J"),
CONSCRYPT_NATIVE_METHOD(i2d_X509_REVOKED, "(J)[B"),
CONSCRYPT_NATIVE_METHOD(X509_supported_extension, "(J)I"),
CONSCRYPT_NATIVE_METHOD(ASN1_TIME_to_Calendar, "(JLjava/util/Calendar;)V"),
CONSCRYPT_NATIVE_METHOD(asn1_read_init, "([B)J"),
CONSCRYPT_NATIVE_METHOD(asn1_read_sequence, "(J)J"),
CONSCRYPT_NATIVE_METHOD(asn1_read_next_tag_is, "(JI)Z"),
Expand Down
125 changes: 125 additions & 0 deletions common/src/main/java/org/conscrypt/DuckTypedHpkeSpi.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/

package org.conscrypt;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.security.GeneralSecurityException;
import java.security.InvalidKeyException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.HashMap;
import java.util.Map;

/**
* Duck typed implementation of {@link HpkeSpi}.
* <p>
* Will wrap any Object which implements all of the methods in HpkeSpi and delegate to them
* by reflection.
*/
@Internal
public class DuckTypedHpkeSpi implements HpkeSpi {
private final Object delegate;
private final Map<String, Method> methods = new HashMap<>();

private DuckTypedHpkeSpi(Object delegate) throws NoSuchMethodException {
this.delegate = delegate;

Class<?> sourceClass = delegate.getClass();
for (Method targetMethod : HpkeSpi.class.getMethods()) {
if (targetMethod.isSynthetic()) {
continue;
}

Method sourceMethod =
sourceClass.getMethod(targetMethod.getName(), targetMethod.getParameterTypes());
// Check that the return types match too.
Class<?> sourceReturnType = sourceMethod.getReturnType();
Class<?> targetReturnType = targetMethod.getReturnType();
if (!targetReturnType.isAssignableFrom(sourceReturnType)) {
throw new NoSuchMethodException(sourceMethod + " return value (" + sourceReturnType
+ ") incompatible with target return value (" + targetReturnType + ")");
}
methods.put(sourceMethod.getName(), sourceMethod);
}
}

public static DuckTypedHpkeSpi newInstance(Object delegate) {
try {
return new DuckTypedHpkeSpi(delegate);
} catch (Exception ignored) {
return null;
}
}

private Object invoke(String methodName, Object... args) {
Method method = methods.get(methodName);
if (method == null) {
throw new IllegalStateException("DuckTypedHpkSpi internal error");
}
try {
return method.invoke(delegate, args);
} catch (InvocationTargetException | IllegalAccessException e) {
throw new IllegalStateException("DuckTypedHpkSpi internal error", e);
}
}

// Visible for testing
public Object getDelegate() {
return delegate;
}

@Override
public void engineInitSender(
PublicKey recipientKey, byte[] info, PrivateKey senderKey, byte[] psk, byte[] psk_id)
throws InvalidKeyException {
invoke("engineInitSender", recipientKey, info, senderKey, psk, psk_id);
}

@Override
public void engineInitSenderForTesting(PublicKey recipientKey, byte[] info, PrivateKey senderKey,
byte[] psk, byte[] psk_id, byte[] sKe) throws InvalidKeyException {
invoke("engineInitSenderForTesting",
recipientKey, info, senderKey, psk, psk_id, sKe);
}

@Override
public void engineInitRecipient(byte[] encapsulated, PrivateKey key, byte[] info,
PublicKey senderKey, byte[] psk, byte[] psk_id) throws InvalidKeyException {
invoke("engineInitRecipient", encapsulated, key, info, senderKey, psk, psk_id);
}

@Override
public byte[] engineSeal(byte[] plaintext, byte[] aad) {
return (byte[]) invoke("engineSeal", plaintext, aad);
}

@Override
public byte[] engineExport(int length, byte[] exporterContext) {
return (byte[]) invoke("engineExport", length, exporterContext);
}

@Override
public byte[] engineOpen(byte[] ciphertext, byte[] aad) throws GeneralSecurityException {
return (byte[]) invoke("engineOpen", ciphertext, aad);
}

@Override
public byte[] getEncapsulated() {
return (byte[]) invoke("getEncapsulated");
}
}
Loading

0 comments on commit b14310d

Please sign in to comment.