Skip to content

Commit

Permalink
Merge branch 'google:master' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
juergw authored Feb 21, 2025
2 parents 1cd3ebe + 8c5c75b commit 5fccae4
Show file tree
Hide file tree
Showing 15 changed files with 454 additions and 162 deletions.
5 changes: 4 additions & 1 deletion android/src/main/java/org/conscrypt/Platform.java
Original file line number Diff line number Diff line change
Expand Up @@ -977,8 +977,11 @@ public static boolean isTlsV1Filtered() {
public static boolean isTlsV1Supported() {
return ENABLED_TLS_V1;
}

public static boolean isPakeSupported() {
return false;
}

public static boolean isSdkGreater(int sdk) {
return Build.VERSION.SDK_INT > sdk;
}
}
35 changes: 35 additions & 0 deletions common/src/jni/main/cpp/conscrypt/jniutil.cc
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,11 @@ int throwIllegalBlockSizeException(JNIEnv* env, const char* message) {
env, "javax/crypto/IllegalBlockSizeException", message);
}

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

int throwShortBufferException(JNIEnv* env, const char* message) {
JNI_TRACE("throwShortBufferException %s", message);
return conscrypt::jniutil::throwException(
Expand Down Expand Up @@ -408,6 +413,30 @@ int throwForX509Error(JNIEnv* env, int reason, const char* message,
}
}

int throwForCryptoError(JNIEnv* env, int reason, const char* message,
int (*defaultThrow)(JNIEnv*, const char*)) {
switch (reason) {
case ERR_R_INTERNAL_ERROR:
return throwIOException(env, message);
break;
default:
return defaultThrow(env, message);
break;
}
}

int throwForSslError(JNIEnv* env, int reason, const char* message,
int (*defaultThrow)(JNIEnv*, const char*)) {
switch (reason) {
case ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED:
return throwIllegalStateException(env, message);
break;
default:
return defaultThrow(env, message);
break;
}
}

void throwExceptionFromBoringSSLError(JNIEnv* env, CONSCRYPT_UNUSED const char* location,
int (*defaultThrow)(JNIEnv*, const char*)) {
const char* file;
Expand Down Expand Up @@ -451,6 +480,12 @@ void throwExceptionFromBoringSSLError(JNIEnv* env, CONSCRYPT_UNUSED const char*
case ERR_LIB_DSA:
throwInvalidKeyException(env, message);
break;
case ERR_LIB_CRYPTO:
throwForCryptoError(env, reason, message, defaultThrow);
break;
case ERR_LIB_SSL:
throwForSslError(env, reason, message, defaultThrow);
break;
default:
defaultThrow(env, message);
break;
Expand Down
121 changes: 121 additions & 0 deletions common/src/jni/main/cpp/conscrypt/native_crypto.cc
Original file line number Diff line number Diff line change
Expand Up @@ -11193,6 +11193,126 @@ static jbyteArray NativeCrypto_Scrypt_generate_key(JNIEnv* env, jclass, jbyteArr
return key_bytes;
}

/**
* SPAKE2+ support
*/

#define SPAKE2PLUS_PW_VERIFIER_SIZE 32
#define SPAKE2PLUS_REGISTRATION_RECORD_SIZE 65

static void NativeCrypto_SSL_CTX_set_spake_credential(JNIEnv* env, jclass, jbyteArray context,
jbyteArray pw_array,
jbyteArray id_prover_array,
jbyteArray id_verifier_array,
jboolean is_client, jlong ssl_ctx_address,
CONSCRYPT_UNUSED jobject holder) {
CHECK_ERROR_QUEUE_ON_RETURN;
JNI_TRACE("SSL_CTX_set_spake_credential(%p, %p, %p, %p, %d, %ld)", context, pw_array,
id_prover_array, id_verifier_array, is_client, ssl_ctx_address);

SSL_CTX* ssl_ctx = to_SSL_CTX(env, ssl_ctx_address, true);

JNI_TRACE("SSL_CTX_set_spake_credential(%p, %p, %p, %p, %d, %p)", context, pw_array,
id_prover_array, id_verifier_array, is_client, ssl_ctx);

if (context == nullptr || pw_array == nullptr || id_prover_array == nullptr ||
id_verifier_array == nullptr) {
conscrypt::jniutil::throwNullPointerException(env, "Input parameters cannot be null");
return;
}

ScopedByteArrayRO context_bytes(env, context);
if (context_bytes.get() == nullptr) {
JNI_TRACE("ctx=%p SSL_CTX_set_spake_credential => threw exception", ssl_ctx);
conscrypt::jniutil::throwOutOfMemory(env, "Unable to allocate buffer for context");
return;
}

ScopedByteArrayRO pw_bytes(env, pw_array);
if (pw_bytes.get() == nullptr) {
JNI_TRACE("ctx=%p SSL_CTX_set_spake_credential => threw exception", ssl_ctx);
conscrypt::jniutil::throwOutOfMemory(env, "Unable to allocate buffer for pw_array");
return;
}

ScopedByteArrayRO id_prover_bytes(env, id_prover_array);
if (id_prover_bytes.get() == nullptr) {
JNI_TRACE("ctx=%p SSL_CTX_set_spake_credential => threw exception", ssl_ctx);
conscrypt::jniutil::throwOutOfMemory(env, "Unable to allocate buffer for id_prover_array");
return;
}

ScopedByteArrayRO id_verifier_bytes(env, id_verifier_array);
if (id_verifier_bytes.get() == nullptr) {
JNI_TRACE("ctx=%p SSL_CTX_set_spake_credential => threw exception", ssl_ctx);
conscrypt::jniutil::throwOutOfMemory(env,
"Unable to allocate buffer for id_verifier_array");
return;
}

uint8_t pw_verifier_w0[SPAKE2PLUS_PW_VERIFIER_SIZE];
uint8_t pw_verifier_w1[SPAKE2PLUS_PW_VERIFIER_SIZE];
uint8_t registration_record[SPAKE2PLUS_REGISTRATION_RECORD_SIZE];
int ret = SSL_spake2plusv1_register(
/* out_pw_verifier_w0= */ pw_verifier_w0,
/* out_pw_verifier_w1= */ pw_verifier_w1,
/* out_registration_record= */ registration_record,
/* pw= */ reinterpret_cast<const uint8_t*>(pw_bytes.get()),
/* pw_len= */ pw_bytes.size(),
/* id_prover= */ reinterpret_cast<const uint8_t*>(id_prover_bytes.get()),
/* id_prover_len= */ id_prover_bytes.size(),
/* id_verifier= */ reinterpret_cast<const uint8_t*>(id_verifier_bytes.get()),
/* id_verifier_len= */ id_verifier_bytes.size());
if (ret != 1) {
conscrypt::jniutil::throwExceptionFromBoringSSLError(env,
"SSL_spake2plusv1_register failed");
return;
}

bssl::UniquePtr<SSL_CREDENTIAL> creds;
if (is_client) {
bssl::UniquePtr<SSL_CREDENTIAL> creds_client(SSL_CREDENTIAL_new_spake2plusv1_client(
/* context= */ reinterpret_cast<const uint8_t*>(context_bytes.get()),
/* context_len= */ context_bytes.size(),
/* client_identity= */ reinterpret_cast<const uint8_t*>(id_prover_bytes.get()),
/* client_identity_len= */ id_prover_bytes.size(),
/* server_identity= */ reinterpret_cast<const uint8_t*>(id_verifier_bytes.get()),
/* server_identity_len= */ id_verifier_bytes.size(),
/* attempts= */ 1,
/* w0= */ pw_verifier_w0,
/* w0_len= */ sizeof(pw_verifier_w0),
/* w1= */ pw_verifier_w1,
/* w1_len= */ sizeof(pw_verifier_w1)));
creds = std::move(creds_client);
} else {
bssl::UniquePtr<SSL_CREDENTIAL> creds_server(SSL_CREDENTIAL_new_spake2plusv1_server(
/* context= */ reinterpret_cast<const uint8_t*>(context_bytes.get()),
/* context_len= */ context_bytes.size(),
/* client_identity= */ reinterpret_cast<const uint8_t*>(id_prover_bytes.get()),
/* client_identity_len= */ id_prover_bytes.size(),
/* server_identity= */ reinterpret_cast<const uint8_t*>(id_verifier_bytes.get()),
/* server_identity_len= */ id_verifier_bytes.size(),
/* attempts= */ 1,
/* w0= */ pw_verifier_w0,
/* w0_len= */ sizeof(pw_verifier_w0),
/* registration_record= */ registration_record,
/* registration_record_len= */ sizeof(registration_record)));
creds = std::move(creds_server);
}
if (creds == nullptr) {
conscrypt::jniutil::throwSSLExceptionStr(env, "SSL_CREDENTIAL_new_spake2plusv1 failed");
return;
}
ret = SSL_CTX_add1_credential(ssl_ctx, creds.get());
if (ret != 1) {
conscrypt::jniutil::throwExceptionFromBoringSSLError(env, "SSL_CTX_add1_credential failed");
return;
}
JNI_TRACE("SSL_CTX_set_spake_credential (%p, %p, %p, %p, %d, %p) => %p", context, pw_array,
id_prover_array, id_verifier_array, is_client, ssl_ctx, creds.get());
return;
}

// TESTING METHODS BEGIN

static int NativeCrypto_BIO_read(JNIEnv* env, jclass, jlong bioRef, jbyteArray outputJavaBytes) {
Expand Down Expand Up @@ -11679,6 +11799,7 @@ static JNINativeMethod sNativeCryptoMethods[] = {
CONSCRYPT_NATIVE_METHOD(ENGINE_SSL_shutdown, "(J" REF_SSL SSL_CALLBACKS ")V"),
CONSCRYPT_NATIVE_METHOD(usesBoringSsl_FIPS_mode, "()Z"),
CONSCRYPT_NATIVE_METHOD(Scrypt_generate_key, "([B[BIIII)[B"),
CONSCRYPT_NATIVE_METHOD(SSL_CTX_set_spake_credential, "([B[B[B[BZJ" REF_SSL_CTX ")V"),
// Used for testing only.
CONSCRYPT_NATIVE_METHOD(BIO_read, "(J[B)I"),
Expand Down
19 changes: 18 additions & 1 deletion common/src/main/java/org/conscrypt/AbstractSessionContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ abstract class AbstractSessionContext implements SSLSessionContext {

private final ReadWriteLock lock = new ReentrantReadWriteLock();


private final Map<ByteArray, NativeSslSession> sessions =
new LinkedHashMap<ByteArray, NativeSslSession>() {
@Override
Expand Down Expand Up @@ -206,6 +205,24 @@ private boolean isValid() {
return (sslCtxNativePointer != 0);
}

void initSpake(SSLParametersImpl parameters) throws SSLException {
Spake2PlusKeyManager spakeKeyManager = parameters.getSpake2PlusKeyManager();
byte[] context = spakeKeyManager.getContext();
byte[] idProverArray = spakeKeyManager.getIdProver();
byte[] idVerifierArray = spakeKeyManager.getIdVerifier();
byte[] pwArray = spakeKeyManager.getPassword();
boolean isClient = spakeKeyManager.isClient();
lock.writeLock().lock();
try {
if (isValid()) {
NativeCrypto.SSL_CTX_set_spake_credential(context, pwArray, idProverArray,
idVerifierArray, isClient, sslCtxNativePointer, this);
}
} finally {
lock.writeLock().unlock();
}
}

/**
* Returns a native pointer to a new SSL object in this SSL_CTX.
*/
Expand Down
10 changes: 10 additions & 0 deletions common/src/main/java/org/conscrypt/NativeCrypto.java
Original file line number Diff line number Diff line change
Expand Up @@ -656,6 +656,16 @@ static native long X509_CRL_get_nextUpdate(long x509CrlCtx, OpenSSLX509CRL holde

static native int X509_supported_extension(long x509ExtensionRef);

// --- SPAKE ---------------------------------------------------------------

/**
* Sets the SPAKE credential for the given SSL context using a password.
* Used for both client and server.
*/
static native void SSL_CTX_set_spake_credential(byte[] context, byte[] pw_array,
byte[] id_prover_array, byte[] id_verifier_array, boolean is_client, long ssl_ctx,
AbstractSessionContext holder) throws SSLException;

// --- ASN1_TIME -----------------------------------------------------------

static native void ASN1_TIME_to_Calendar(long asn1TimeCtx, Calendar cal) throws ParsingException;
Expand Down
42 changes: 1 addition & 41 deletions common/src/main/java/org/conscrypt/NativeSsl.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@
import java.io.IOException;
import java.net.SocketException;
import java.nio.charset.StandardCharsets;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.PrivateKey;
import java.security.PublicKey;
Expand Down Expand Up @@ -89,36 +88,6 @@ BioWrapper newBio() {
}
}

void initSpake() throws SSLException, InvalidAlgorithmParameterException {
Spake2PlusKeyManager spakeKeyManager = parameters.getSpake2PlusKeyManager();
byte[] context = spakeKeyManager.getContext() == null ? "spake2+".getBytes()
: spakeKeyManager.getContext();
byte[] idProverArray = spakeKeyManager.getIdProver();
byte[] idVerifierArray = spakeKeyManager.getIdVerifier();
byte[] pwArray = spakeKeyManager.getPassword();
byte[] w0Array = spakeKeyManager.getW0();
byte[] w1Array = spakeKeyManager.getW1();
byte[] lArray = spakeKeyManager.getL();
boolean isClient = spakeKeyManager.isClient();

// TODO: uncomment this once the native code is ready.
/*
if (pwArray != null) {
NativeCrypto.SSL_CTX_set_spake_credential(
context, pwArray, idProverArray,
idVerifierArray, isClient, this);
} else if (isClient && w0Array != null && w1Array != null) {
NativeCrypto.SSL_CTX_set_spake_credential_client(
context, w0Array, w1Array,
idProverArray, idVerifierArray, this);
} else if (!isClient && w0Array != null && lArray != null) {
NativeCrypto.SSL_CTX_set_spake_credential_server(
context, w0Array, lArray,
idProverArray, idVerifierArray, this);
}
*/
}

void offerToResumeSession(long sslSessionNativePointer) throws SSLException {
NativeCrypto.SSL_set_session(ssl, this, sslSessionNativePointer);
}
Expand Down Expand Up @@ -306,14 +275,6 @@ byte[] getTlsChannelId() throws SSLException {
}

void initialize(String hostname, OpenSSLKey channelIdPrivateKey) throws IOException {
if (parameters.isSpake()) {
try {
initSpake();
} catch (Exception e) {
throw new SSLHandshakeException("Spake initialization failed " + e.getMessage());
}
}

boolean enableSessionCreation = parameters.getEnableSessionCreation();
if (!enableSessionCreation) {
NativeCrypto.SSL_set_session_creation_enabled(ssl, this, false);
Expand Down Expand Up @@ -349,8 +310,7 @@ void initialize(String hostname, OpenSSLKey channelIdPrivateKey) throws IOExcept
+ " are no longer supported and were filtered from the list");
}
NativeCrypto.setEnabledProtocols(ssl, this, parameters.enabledProtocols);
// Not sure if we need to do this for SPAKE, but the SPAKE cipher suite
// not registered at the moment.
// We can use default cipher suites for SPAKE.
if (!parameters.isSpake()) {
NativeCrypto.setEnabledCipherSuites(
ssl, this, parameters.enabledCipherSuites, parameters.enabledProtocols);
Expand Down
26 changes: 22 additions & 4 deletions common/src/main/java/org/conscrypt/SSLParametersImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,6 @@ final class SSLParametersImpl implements Cloneable {
throws KeyManagementException {
this.serverSessionContext = serverSessionContext;
this.clientSessionContext = clientSessionContext;

// initialize key managers
if (kms == null) {
x509KeyManager = getDefaultX509KeyManager();
Expand Down Expand Up @@ -189,6 +188,10 @@ final class SSLParametersImpl implements Cloneable {

// We ignore the SecureRandom passed in by the caller. The native code below
// directly accesses /dev/urandom, which makes it irrelevant.

if (isSpake()) {
initSpake();
}
}

// Copy constructor for the purposes of changing the final fields
Expand Down Expand Up @@ -232,6 +235,17 @@ private SSLParametersImpl(ClientSessionContext clientSessionContext,
this.channelIdEnabled = sslParams.channelIdEnabled;
}

/**
* Initializes the SSL credential for the Spake.
*/
void initSpake() throws KeyManagementException {
try {
getSessionContext().initSpake(this);
} catch (Exception e) {
throw new KeyManagementException("Spake initialization failed " + e.getMessage());
}
}

static SSLParametersImpl getDefault() throws KeyManagementException {
SSLParametersImpl result = defaultParameters;
if (result == null) {
Expand Down Expand Up @@ -260,6 +274,13 @@ ClientSessionContext getClientSessionContext() {
return clientSessionContext;
}

/*
* Returns the server session context.
*/
ServerSessionContext getServerSessionContext() {
return serverSessionContext;
}

/**
* Returns X.509 key manager or null for none.
*/
Expand Down Expand Up @@ -742,9 +763,6 @@ void setUseCipherSuitesOrder(boolean useCipherSuitesOrder) {

private static String[] getDefaultCipherSuites(boolean x509CipherSuitesNeeded,
boolean pskCipherSuitesNeeded, boolean spake2PlusCipherSuitesNeeded) {
if (spake2PlusCipherSuitesNeeded) {
return NativeCrypto.DEFAULT_SPAKE_CIPHER_SUITES;
}
if (x509CipherSuitesNeeded) {
// X.509 based cipher suites need to be listed.
if (pskCipherSuitesNeeded) {
Expand Down
Loading

0 comments on commit 5fccae4

Please sign in to comment.