Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Spake #1278

Closed
wants to merge 5 commits into from
Closed

Spake #1278

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* Copyright (C) 2024 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 android.net.ssl;

public class SpakeKeyManagerParameters {

private SpakeKeyManagerParameters() {}

public byte[] getPassword() {
return null;
}

public byte[] getIdProver() {
return null;
}

public byte[] getIdVerifier() {
return null;
}

public byte[] getContext() {
return null;
}
}

4 changes: 4 additions & 0 deletions android/src/main/java/org/conscrypt/Platform.java
Original file line number Diff line number Diff line change
Expand Up @@ -965,4 +965,8 @@ public static boolean isTlsV1Filtered() {
public static boolean isTlsV1Supported() {
return false;
}

public static boolean isSpake2Supported() {
return false;
}
}
38 changes: 27 additions & 11 deletions common/src/jni/main/cpp/conscrypt/native_crypto.cc
Original file line number Diff line number Diff line change
Expand Up @@ -530,8 +530,7 @@ static jbyteArray ecSignDigestWithPrivateKey(JNIEnv* env, jobject privateKey, co

return reinterpret_cast<jbyteArray>(env->CallStaticObjectMethod(
conscrypt::jniutil::cryptoUpcallsClass,
conscrypt::jniutil::cryptoUpcallsClass_rawSignMethod,
privateKey, messageArray.get()));
conscrypt::jniutil::cryptoUpcallsClass_rawSignMethod, privateKey, messageArray.get()));
}

static jbyteArray rsaSignDigestWithPrivateKey(JNIEnv* env, jobject privateKey, jint padding,
Expand All @@ -558,10 +557,9 @@ static jbyteArray rsaSignDigestWithPrivateKey(JNIEnv* env, jobject privateKey, j
}

return reinterpret_cast<jbyteArray>(
env->CallStaticObjectMethod(
conscrypt::jniutil::cryptoUpcallsClass,
conscrypt::jniutil::cryptoUpcallsClass_rsaSignMethod,
privateKey, padding, messageArray.get()));
env->CallStaticObjectMethod(conscrypt::jniutil::cryptoUpcallsClass,
conscrypt::jniutil::cryptoUpcallsClass_rsaSignMethod,
privateKey, padding, messageArray.get()));
}

// rsaDecryptWithPrivateKey uses privateKey to decrypt |ciphertext_len| bytes
Expand Down Expand Up @@ -592,10 +590,9 @@ static jbyteArray rsaDecryptWithPrivateKey(JNIEnv* env, jobject privateKey, jint
}

return reinterpret_cast<jbyteArray>(
env->CallStaticObjectMethod(
conscrypt::jniutil::cryptoUpcallsClass,
conscrypt::jniutil::cryptoUpcallsClass_rsaDecryptMethod,
privateKey, padding, ciphertextArray.get()));
env->CallStaticObjectMethod(conscrypt::jniutil::cryptoUpcallsClass,
conscrypt::jniutil::cryptoUpcallsClass_rsaDecryptMethod,
privateKey, padding, ciphertextArray.get()));
}

// *********************************************
Expand Down Expand Up @@ -7266,7 +7263,7 @@ static void info_callback(const SSL* ssl, int type, int value) {

JNI_TRACE("ssl=%p info_callback calling onSSLStateChange", ssl);
env->CallVoidMethod(sslHandshakeCallbacks,
conscrypt::jniutil::sslHandshakeCallbacks_onSSLStateChange, type, value);
conscrypt::jniutil::sslHandshakeCallbacks_onSSLStateChange, type, value);

if (env->ExceptionCheck()) {
JNI_TRACE("ssl=%p info_callback exception", ssl);
Expand Down Expand Up @@ -10891,6 +10888,24 @@ static jbyteArray NativeCrypto_Scrypt_generate_key(JNIEnv* env, jclass, jbyteArr
return key_bytes;
}


#define SPAKE2PLUS_PW_VERIFIER_SIZE 32
#define SPAKE2PLUS_REGISTRATION_RECORD_SIZE 65

static void NativeCrypto_SSL_CTX_set_spake_credential(
JNIEnv* env, jclass, jobject sslCtx, jbyteArray context, jint contextLen,
jbyteArray pwArray, jint pwLen, jbyteArray idProverArray, jint idProverLen,
jbyteArray idVerifierArray, jint idVerifierLen, jboolean isClient) {
CHECK_ERROR_QUEUE_ON_RETURN;
JNI_TRACE(
"SSL_CTX_set_spake_credential(%p, %p, %d, %p, %d, %p, %d, %p, "
"%d, %d)",
sslCtx, context, contextLen, pwArray, pwLen, idProverArray, idProverLen,
idVerifierArray, idVerifierLen, isClient);

return;
}

// TESTING METHODS BEGIN

static int NativeCrypto_BIO_read(JNIEnv* env, jclass, jlong bioRef, jbyteArray outputJavaBytes) {
Expand Down Expand Up @@ -11369,6 +11384,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, "(J[BI[BI[BI[BIZ)V"),

// Used for testing only.
CONSCRYPT_NATIVE_METHOD(BIO_read, "(J[B)I"),
Expand Down
12 changes: 12 additions & 0 deletions common/src/main/java/org/conscrypt/NativeCrypto.java
Original file line number Diff line number Diff line change
Expand Up @@ -639,6 +639,13 @@ static native long X509_CRL_get_nextUpdate(long x509CrlCtx, OpenSSLX509CRL holde

static native int X509_supported_extension(long x509ExtensionRef);

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

static native void SSL_CTX_set_spake_credential(
Object sslCtx, byte[] context, int contextLen,
byte[] pwArray, int pwLen, byte[] idProverArray, int idProverLen,
byte[] idVerifierArray, int idVerifierLen, boolean isClient);

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

static native void ASN1_TIME_to_Calendar(long asn1TimeCtx, Calendar cal) throws ParsingException;
Expand Down Expand Up @@ -963,6 +970,11 @@ static String cipherSuiteFromJava(String javaCipherSuite) {
"TLS_PSK_WITH_AES_256_CBC_SHA",
};

/** TLS-SPAKE */
static final String[] DEFAULT_SPAKE_CIPHER_SUITES = new String[] {
"TLS1_3_NAMED_PAKE_SPAKE2PLUSV1",
};

static String[] getSupportedCipherSuites() {
return SSLUtils.concat(SUPPORTED_TLS_1_3_CIPHER_SUITES, SUPPORTED_TLS_1_2_CIPHER_SUITES.clone());
}
Expand Down
23 changes: 22 additions & 1 deletion common/src/main/java/org/conscrypt/NativeSsl.java
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ final class NativeSsl {
private X509Certificate[] localCertificates;
private final ReadWriteLock lock = new ReentrantReadWriteLock();
private volatile long ssl;
private final boolean isSpake;

private NativeSsl(long ssl, SSLParametersImpl parameters,
SSLHandshakeCallbacks handshakeCallbacks, AliasChooser aliasChooser,
Expand All @@ -86,6 +87,19 @@ BioWrapper newBio() {
}
}

void initSpake() {
SpakeKeyManager spakeKeyManager = parameters.getSpakeKeyManager();
byte[] context = spakeKeyManager.getContext();
byte[] pwArray = spakeKeyManager.getPassword();
byte[] idProverArray = spakeKeyManager.getIdProver();
byte[] idVerifierArray = spakeKeyManager.getIdVerifier();

long sslCtx = NativeCrypto.SSL_CTX_new();
NativeCrypto.SSL_CTX_set_spake_credential(
sslCtx, context, context.length, pwArray, pwArray.length, idProverArray,
idProverArray.length, idVerifierArray, idVerifierArray.length, isClient());
}

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

void initialize(String hostname, OpenSSLKey channelIdPrivateKey) throws IOException {
this.isSpake = parameters.isSpake();
if (this.isSpake) {
initSpake();
}

boolean enableSessionCreation = parameters.getEnableSessionCreation();
if (!enableSessionCreation) {
NativeCrypto.SSL_set_session_creation_enabled(ssl, this, false);
Expand Down Expand Up @@ -349,7 +368,9 @@ void initialize(String hostname, OpenSSLKey channelIdPrivateKey) throws IOExcept
// with TLSv1 and SSLv3).
NativeCrypto.SSL_set_mode(ssl, this, SSL_MODE_CBC_RECORD_SPLITTING);

setCertificateValidation();
if (!isSpake) {
setCertificateValidation();
}
setTlsChannelId(channelIdPrivateKey);
}

Expand Down
6 changes: 6 additions & 0 deletions common/src/main/java/org/conscrypt/OpenSSLProvider.java
Original file line number Diff line number Diff line change
Expand Up @@ -535,6 +535,12 @@ public OpenSSLProvider(String providerName) {
baseClass + "$X25519_CHACHA20");
put("Alg.Alias.ConscryptHpke.DHKEM_X25519_HKDF_SHA256_HKDF_SHA256_GhpkeCHACHA20POLY1305",
"DHKEM_X25519_HKDF_SHA256/HKDF_SHA256/CHACHA20POLY1305");

/* === SPAKE2+ - Conscrypt internal only === */
if (Platform.isSpake2Supported()) {
put("TrustManagerFactory.SPAKE2+", "SpakeTrustManagerFactory");
put("KeyManagerFactory.SPAKE2+", "SpakeKeyManagerFactory");
}
}

private boolean classExists(String classname) {
Expand Down
65 changes: 63 additions & 2 deletions common/src/main/java/org/conscrypt/SSLParametersImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,10 @@ final class SSLParametersImpl implements Cloneable {
private final PSKKeyManager pskKeyManager;
// source of X.509 certificate based authentication trust decisions or null if not provided
private final X509TrustManager x509TrustManager;
// source of Spake trust or null if not provided
private final SpakeTrustManager spakeTrustManager;
// source of Spake authentication or null if not provided
private final SpakeKeyManager spakeKeyManager;

// protocols enabled for SSL connection
String[] enabledProtocols;
Expand Down Expand Up @@ -126,6 +130,20 @@ final class SSLParametersImpl implements Cloneable {
this.serverSessionContext = serverSessionContext;
this.clientSessionContext = clientSessionContext;

spakeKeyManager = findFirstSpakeKeyManager(kms);
spakeTrustManager = findFirstSpakeTrustManager(tms);
if (spakeKeyManager != null ^ spakeTrustManager != null) {
throw new IllegalArgumentException("SpakeKeyManager and SpakeTrustManager must be set together");
}
if (spakeKeyManager != null) {
x509KeyManager = findFirstX509KeyManager(kms);
pskKeyManager = findFirstPSKKeyManager(kms);
x509TrustManager = findFirstX509TrustManager(tms);
if (x509KeyManager != null || pskKeyManager != null || x509TrustManager != null) {
throw new IllegalArgumentException("SpakeManagers should not be set with X509KeyManager, x509TrustManager or PSKKeyManager");
}
}

// initialize key managers
if (kms == null) {
x509KeyManager = getDefaultX509KeyManager();
Expand Down Expand Up @@ -161,7 +179,8 @@ final class SSLParametersImpl implements Cloneable {
boolean x509CipherSuitesNeeded = (x509KeyManager != null) || (x509TrustManager != null);
boolean pskCipherSuitesNeeded = pskKeyManager != null;
enabledCipherSuites = getDefaultCipherSuites(
x509CipherSuitesNeeded, pskCipherSuitesNeeded);
x509CipherSuitesNeeded, pskCipherSuitesNeeded, isSpake());


// We ignore the SecureRandom passed in by the caller. The native code below
// directly accesses /dev/urandom, which makes it irrelevant.
Expand All @@ -180,6 +199,8 @@ private SSLParametersImpl(ClientSessionContext clientSessionContext,
this.x509KeyManager = x509KeyManager;
this.pskKeyManager = pskKeyManager;
this.x509TrustManager = x509TrustManager;
this.spakeKeyManager = null;
this.spakeTrustManager = null;

this.enabledProtocols =
(sslParams.enabledProtocols == null) ? null : sslParams.enabledProtocols.clone();
Expand Down Expand Up @@ -248,6 +269,14 @@ PSKKeyManager getPSKKeyManager() {
return pskKeyManager;
}

/*
* Returns Spake key manager or null for none.
*/
SpakeKeyManager getSpakeKeyManager() {
return spakeKeyManager;
}


/*
* Returns X.509 trust manager or null for none.
*/
Expand Down Expand Up @@ -596,6 +625,18 @@ private static PSKKeyManager findFirstPSKKeyManager(KeyManager[] kms) {
return null;
}

/*
* Returns the first SpakeKeyManager element in the provided array.
*/
private static SpakeKeyManager findFirstSpakeKeyManager(KeyManager[] kms) {
for (KeyManager km : kms) {
if (km instanceof SpakeKeyManager) {
return (SpakeKeyManager)km;
}
}
return null;
}

/*
* Returns the default X.509 trust manager.
*/
Expand Down Expand Up @@ -642,6 +683,18 @@ private static X509TrustManager findFirstX509TrustManager(TrustManager[] tms) {
return null;
}

/*
* Returns the first SpakeTrustManager element in the provided array.
*/
private static SpakeTrustManager findFirstSpakeTrustManager(TrustManager[] tms) {
for (TrustManager tm : tms) {
if (tm instanceof SpakeTrustManager) {
return (SpakeTrustManager) tm;
}
}
return null;
}

String getEndpointIdentificationAlgorithm() {
return endpointIdentificationAlgorithm;
}
Expand Down Expand Up @@ -679,7 +732,11 @@ void setUseCipherSuitesOrder(boolean useCipherSuitesOrder) {

private static String[] getDefaultCipherSuites(
boolean x509CipherSuitesNeeded,
boolean pskCipherSuitesNeeded) {
boolean pskCipherSuitesNeeded,
boolean spakeCipherSuitesNeeded) {
if (spakeCipherSuitesNeeded) {
return NativeCrypto.DEFAULT_SPAKE_CIPHER_SUITES;
}
if (x509CipherSuitesNeeded) {
// X.509 based cipher suites need to be listed.
if (pskCipherSuitesNeeded) {
Expand Down Expand Up @@ -724,4 +781,8 @@ boolean isCTVerificationEnabled(String hostname) {
}
return Platform.isCTVerificationRequired(hostname);
}

boolean isSpake() {
return spakeKeyManager != null;
}
}
Loading
Loading