diff --git a/src/libraries/Common/src/Interop/Android/System.Security.Cryptography.Native.Android/Interop.Ssl.cs b/src/libraries/Common/src/Interop/Android/System.Security.Cryptography.Native.Android/Interop.Ssl.cs index ba9fbd297c93b5..addb8d540e43c1 100644 --- a/src/libraries/Common/src/Interop/Android/System.Security.Cryptography.Native.Android/Interop.Ssl.cs +++ b/src/libraries/Common/src/Interop/Android/System.Security.Cryptography.Native.Android/Interop.Ssl.cs @@ -55,16 +55,18 @@ private static unsafe partial int SSLStreamInitializeImpl( IntPtr managedContextHandle, delegate* unmanaged streamRead, delegate* unmanaged streamWrite, - int appBufferSize); + int appBufferSize, + [MarshalAs(UnmanagedType.LPUTF8Str)] string? peerHost); internal static unsafe void SSLStreamInitialize( SafeSslHandle sslHandle, bool isServer, IntPtr managedContextHandle, delegate* unmanaged streamRead, delegate* unmanaged streamWrite, - int appBufferSize) + int appBufferSize, + string? peerHost) { - int ret = SSLStreamInitializeImpl(sslHandle, isServer, managedContextHandle, streamRead, streamWrite, appBufferSize); + int ret = SSLStreamInitializeImpl(sslHandle, isServer, managedContextHandle, streamRead, streamWrite, appBufferSize, peerHost); if (ret != SUCCESS) throw new SslException(); } diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/Pal.Android/SafeDeleteSslContext.cs b/src/libraries/System.Net.Security/src/System/Net/Security/Pal.Android/SafeDeleteSslContext.cs index e4a2ee35c53d85..a07f84a1440e01 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/Pal.Android/SafeDeleteSslContext.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/Pal.Android/SafeDeleteSslContext.cs @@ -221,7 +221,8 @@ private unsafe void InitializeSslContext( // Make sure the class instance is associated to the session and is provided // in the Read/Write callback connection parameter IntPtr managedContextHandle = GCHandle.ToIntPtr(GCHandle.Alloc(this, GCHandleType.Weak)); - Interop.AndroidCrypto.SSLStreamInitialize(handle, isServer, managedContextHandle, &ReadFromConnection, &WriteToConnection, InitialBufferSize); + string? peerHost = !isServer && !string.IsNullOrEmpty(authOptions.TargetHost) ? authOptions.TargetHost : null; + Interop.AndroidCrypto.SSLStreamInitialize(handle, isServer, managedContextHandle, &ReadFromConnection, &WriteToConnection, InitialBufferSize, peerHost); if (authOptions.EnabledSslProtocols != SslProtocols.None) { diff --git a/src/native/libs/System.Security.Cryptography.Native.Android/pal_jni.c b/src/native/libs/System.Security.Cryptography.Native.Android/pal_jni.c index 7aa8b45768be96..40de62da26c45b 100644 --- a/src/native/libs/System.Security.Cryptography.Native.Android/pal_jni.c +++ b/src/native/libs/System.Security.Cryptography.Native.Android/pal_jni.c @@ -83,6 +83,14 @@ jmethodID g_SSLParametersGetProtocols; jmethodID g_SSLParametersSetApplicationProtocols; jmethodID g_SSLParametersSetServerNames; +// com/android/org/conscrypt/OpenSSLEngineImpl +jclass g_ConscryptOpenSSLEngineImplClass; +jfieldID g_ConscryptOpenSSLEngineImplSslParametersField; + +// com/android/org/conscrypt/SSLParametersImpl +jclass g_ConscryptSSLParametersImplClass; +jmethodID g_ConscryptSSLParametersImplSetUseSni; + // javax/net/ssl/SSLContext jclass g_sslCtxClass; jmethodID g_sslCtxGetDefaultMethod; @@ -416,6 +424,7 @@ jmethodID g_SSLEngineBeginHandshake; jmethodID g_SSLEngineCloseOutbound; jmethodID g_SSLEngineGetApplicationProtocol; jmethodID g_SSLEngineGetHandshakeStatus; +jmethodID g_SSLEngineGetHandshakeSession; jmethodID g_SSLEngineGetSession; jmethodID g_SSLEngineGetSSLParameters; jmethodID g_SSLEngineGetSupportedProtocols; @@ -445,6 +454,7 @@ jmethodID g_SSLContextGetDefault; jmethodID g_SSLContextGetInstanceMethod; jmethodID g_SSLContextInitMethod; jmethodID g_SSLContextCreateSSLEngineMethod; +jmethodID g_SSLContextCreateSSLEngineMethodWithHostAndPort; // javax/net/ssl/SSLSession jclass g_SSLSession; @@ -458,6 +468,7 @@ jmethodID g_SSLSessionGetProtocol; jclass g_SSLEngineResult; jmethodID g_SSLEngineResultGetStatus; jmethodID g_SSLEngineResultGetHandshakeStatus; +bool g_SSLEngineResultStatusLegacyOrder; // javax/crypto/KeyAgreement jclass g_KeyAgreementClass; @@ -733,6 +744,15 @@ JNI_OnLoad(JavaVM *vm, void *reserved) g_SSLParametersGetProtocols = GetMethod(env, false, g_SSLParametersClass, "getProtocols", "()[Ljava/lang/String;"); g_SSLParametersSetApplicationProtocols = GetOptionalMethod(env, false, g_SSLParametersClass, "setApplicationProtocols", "([Ljava/lang/String;)V"); + g_ConscryptOpenSSLEngineImplClass = GetOptionalClassGRef(env, "com/android/org/conscrypt/OpenSSLEngineImpl"); + if (g_ConscryptOpenSSLEngineImplClass != NULL) + { + g_ConscryptOpenSSLEngineImplSslParametersField = GetField(env, false, g_ConscryptOpenSSLEngineImplClass, "sslParameters", "Lcom/android/org/conscrypt/SSLParametersImpl;"); + + g_ConscryptSSLParametersImplClass = GetClassGRef(env, "com/android/org/conscrypt/SSLParametersImpl"); + g_ConscryptSSLParametersImplSetUseSni = GetMethod(env, false, g_ConscryptSSLParametersImplClass, "setUseSni", "(Z)V"); + } + g_sslCtxClass = GetClassGRef(env, "javax/net/ssl/SSLContext"); g_sslCtxGetDefaultMethod = GetMethod(env, true, g_sslCtxClass, "getDefault", "()Ljavax/net/ssl/SSLContext;"); g_sslCtxGetDefaultSslParamsMethod = GetMethod(env, false, g_sslCtxClass, "getDefaultSSLParameters", "()Ljavax/net/ssl/SSLParameters;"); @@ -997,6 +1017,7 @@ JNI_OnLoad(JavaVM *vm, void *reserved) g_SSLEngineGetApplicationProtocol = GetOptionalMethod(env, false, g_SSLEngine, "getApplicationProtocol", "()Ljava/lang/String;"); g_SSLEngineGetHandshakeStatus = GetMethod(env, false, g_SSLEngine, "getHandshakeStatus", "()Ljavax/net/ssl/SSLEngineResult$HandshakeStatus;"); g_SSLEngineGetSession = GetMethod(env, false, g_SSLEngine, "getSession", "()Ljavax/net/ssl/SSLSession;"); + g_SSLEngineGetHandshakeSession = GetOptionalMethod(env, false, g_SSLEngine, "getHandshakeSession", "()Ljavax/net/ssl/SSLSession;"); g_SSLEngineGetSSLParameters = GetMethod(env, false, g_SSLEngine, "getSSLParameters", "()Ljavax/net/ssl/SSLParameters;"); g_SSLEngineGetSupportedProtocols = GetMethod(env, false, g_SSLEngine, "getSupportedProtocols", "()[Ljava/lang/String;"); g_SSLEngineSetEnabledProtocols = GetMethod(env, false, g_SSLEngine, "setEnabledProtocols", "([Ljava/lang/String;)V"); @@ -1023,6 +1044,7 @@ JNI_OnLoad(JavaVM *vm, void *reserved) g_SSLContextGetInstanceMethod = GetMethod(env, true, g_SSLContext, "getInstance", "(Ljava/lang/String;)Ljavax/net/ssl/SSLContext;"); g_SSLContextInitMethod = GetMethod(env, false, g_SSLContext, "init", "([Ljavax/net/ssl/KeyManager;[Ljavax/net/ssl/TrustManager;Ljava/security/SecureRandom;)V"); g_SSLContextCreateSSLEngineMethod = GetMethod(env, false, g_SSLContext, "createSSLEngine", "()Ljavax/net/ssl/SSLEngine;"); + g_SSLContextCreateSSLEngineMethodWithHostAndPort = GetMethod(env, false, g_SSLContext, "createSSLEngine", "(Ljava/lang/String;I)Ljavax/net/ssl/SSLEngine;"); g_SSLSession = GetClassGRef(env, "javax/net/ssl/SSLSession"); g_SSLSessionGetApplicationBufferSize = GetMethod(env, false, g_SSLSession, "getApplicationBufferSize", "()I"); @@ -1034,6 +1056,7 @@ JNI_OnLoad(JavaVM *vm, void *reserved) g_SSLEngineResult = GetClassGRef(env, "javax/net/ssl/SSLEngineResult"); g_SSLEngineResultGetStatus = GetMethod(env, false, g_SSLEngineResult, "getStatus", "()Ljavax/net/ssl/SSLEngineResult$Status;"); g_SSLEngineResultGetHandshakeStatus = GetMethod(env, false, g_SSLEngineResult, "getHandshakeStatus", "()Ljavax/net/ssl/SSLEngineResult$HandshakeStatus;"); + g_SSLEngineResultStatusLegacyOrder = android_get_device_api_level() < 24; g_KeyAgreementClass = GetClassGRef(env, "javax/crypto/KeyAgreement"); g_KeyAgreementGetInstance = GetMethod(env, true, g_KeyAgreementClass, "getInstance", "(Ljava/lang/String;)Ljavax/crypto/KeyAgreement;"); diff --git a/src/native/libs/System.Security.Cryptography.Native.Android/pal_jni.h b/src/native/libs/System.Security.Cryptography.Native.Android/pal_jni.h index f8d89e2513115c..639a4bf68b73ca 100644 --- a/src/native/libs/System.Security.Cryptography.Native.Android/pal_jni.h +++ b/src/native/libs/System.Security.Cryptography.Native.Android/pal_jni.h @@ -92,6 +92,14 @@ extern jmethodID g_SSLParametersGetProtocols; extern jmethodID g_SSLParametersSetApplicationProtocols; extern jmethodID g_SSLParametersSetServerNames; +// com/android/org/conscrypt/OpenSSLEngineImpl +extern jclass g_ConscryptOpenSSLEngineImplClass; +extern jfieldID g_ConscryptOpenSSLEngineImplSslParametersField; + +// com/android/org/conscrypt/SSLParametersImpl +extern jclass g_ConscryptSSLParametersImplClass; +extern jmethodID g_ConscryptSSLParametersImplSetUseSni; + // javax/net/ssl/SSLContext extern jclass g_sslCtxClass; extern jmethodID g_sslCtxGetDefaultMethod; @@ -430,6 +438,7 @@ extern jmethodID g_SSLEngineBeginHandshake; extern jmethodID g_SSLEngineCloseOutbound; extern jmethodID g_SSLEngineGetApplicationProtocol; extern jmethodID g_SSLEngineGetHandshakeStatus; +extern jmethodID g_SSLEngineGetHandshakeSession; extern jmethodID g_SSLEngineGetSession; extern jmethodID g_SSLEngineGetSSLParameters; extern jmethodID g_SSLEngineGetSupportedProtocols; @@ -459,7 +468,7 @@ extern jmethodID g_SSLContextGetDefault; extern jmethodID g_SSLContextGetInstanceMethod; extern jmethodID g_SSLContextInitMethod; extern jmethodID g_SSLContextCreateSSLEngineMethod; -extern jmethodID g_SSLContextCreateSSLEngineWithPeer; +extern jmethodID g_SSLContextCreateSSLEngineMethodWithHostAndPort; // javax/net/ssl/SSLSession extern jclass g_SSLSession; @@ -473,6 +482,7 @@ extern jmethodID g_SSLSessionGetProtocol; extern jclass g_SSLEngineResult; extern jmethodID g_SSLEngineResultGetStatus; extern jmethodID g_SSLEngineResultGetHandshakeStatus; +extern bool g_SSLEngineResultStatusLegacyOrder; // javax/crypto/KeyAgreement extern jclass g_KeyAgreementClass; diff --git a/src/native/libs/System.Security.Cryptography.Native.Android/pal_sslstream.c b/src/native/libs/System.Security.Cryptography.Native.Android/pal_sslstream.c index 430edc20edf28c..b73e2c75fac1e3 100644 --- a/src/native/libs/System.Security.Cryptography.Native.Android/pal_sslstream.c +++ b/src/native/libs/System.Security.Cryptography.Native.Android/pal_sslstream.c @@ -15,6 +15,7 @@ enum }; // javax/net/ssl/SSLEngineResult$Status +// Android API 24+ enum { STATUS__BUFFER_UNDERFLOW = 0, @@ -23,6 +24,16 @@ enum STATUS__CLOSED = 3, }; +// javax/net/ssl/SSLEngineResult$Status +// Android API 21-23 +enum +{ + LEGACY__STATUS__BUFFER_OVERFLOW = 0, + LEGACY__STATUS__BUFFER_UNDERFLOW = 1, + LEGACY__STATUS__OK = 3, + LEGACY__STATUS__CLOSED = 2, +}; + struct ApplicationProtocolData_t { uint8_t* data; @@ -40,6 +51,27 @@ static bool IsHandshaking(int handshakeStatus) return handshakeStatus != HANDSHAKE_STATUS__NOT_HANDSHAKING && handshakeStatus != HANDSHAKE_STATUS__FINISHED; } +static jobject GetSslSessionForHandshakeStatus(JNIEnv* env, SSLStream* sslStream, int handshakeStatus) +{ + // SSLEngine.getHandshakeSession() is available since API 24 + jobject sslSession = IsHandshaking(handshakeStatus) && g_SSLEngineGetHandshakeSession != NULL + ? (*env)->CallObjectMethod(env, sslStream->sslEngine, g_SSLEngineGetHandshakeSession) + : (*env)->CallObjectMethod(env, sslStream->sslEngine, g_SSLEngineGetSession); + if (CheckJNIExceptions(env)) + return NULL; + + return sslSession; +} + +static jobject GetCurrentSslSession(JNIEnv* env, SSLStream* sslStream) +{ + int handshakeStatus = GetEnumAsInt(env, (*env)->CallObjectMethod(env, sslStream->sslEngine, g_SSLEngineGetHandshakeStatus)); + if (CheckJNIExceptions(env)) + return NULL; + + return GetSslSessionForHandshakeStatus(env, sslStream, handshakeStatus); +} + ARGS_NON_NULL_ALL static PAL_SSLStreamStatus Close(JNIEnv* env, SSLStream* sslStream) { // Call wrap to clear any remaining data before closing @@ -115,6 +147,25 @@ ARGS_NON_NULL_ALL static jobject EnsureRemaining(JNIEnv* env, jobject oldBuffer, } } +// There has been a change in the SSLEngineResult.Status enum between API 23 and 24 that changed +// the order/interger values of the enum options. +static int MapLegacySSLEngineResultStatus(int legacyStatus) { + switch (legacyStatus) { + case LEGACY__STATUS__BUFFER_OVERFLOW: + return STATUS__BUFFER_OVERFLOW; + case LEGACY__STATUS__BUFFER_UNDERFLOW: + return STATUS__BUFFER_UNDERFLOW; + case LEGACY__STATUS__CLOSED: + return STATUS__CLOSED; + case LEGACY__STATUS__OK: + return STATUS__OK; + default: + LOG_ERROR("Unknown legacy SSLEngineResult status: %d", legacyStatus); + assert(false && "Unknown SSLEngineResult status"); + return -1; + } +} + ARGS_NON_NULL_ALL static PAL_SSLStreamStatus DoWrap(JNIEnv* env, SSLStream* sslStream, int* handshakeStatus) { // appOutBuffer.flip(); @@ -134,6 +185,10 @@ ARGS_NON_NULL_ALL static PAL_SSLStreamStatus DoWrap(JNIEnv* env, SSLStream* sslS int status = GetEnumAsInt(env, (*env)->CallObjectMethod(env, result, g_SSLEngineResultGetStatus)); (*env)->DeleteLocalRef(env, result); + if (g_SSLEngineResultStatusLegacyOrder) { + status = MapLegacySSLEngineResultStatus(status); + } + switch (status) { case STATUS__OK: @@ -208,6 +263,11 @@ ARGS_NON_NULL_ALL static PAL_SSLStreamStatus DoUnwrap(JNIEnv* env, SSLStream* ss *handshakeStatus = GetEnumAsInt(env, (*env)->CallObjectMethod(env, result, g_SSLEngineResultGetHandshakeStatus)); int status = GetEnumAsInt(env, (*env)->CallObjectMethod(env, result, g_SSLEngineResultGetStatus)); (*env)->DeleteLocalRef(env, result); + + if (g_SSLEngineResultStatusLegacyOrder) { + status = MapLegacySSLEngineResultStatus(status); + } + switch (status) { case STATUS__OK: @@ -425,7 +485,7 @@ SSLStream* AndroidCryptoNative_SSLStreamCreateWithCertificates(uint8_t* pkcs8Pri } int32_t AndroidCryptoNative_SSLStreamInitialize( - SSLStream* sslStream, bool isServer, ManagedContextHandle managedContextHandle, STREAM_READER streamReader, STREAM_WRITER streamWriter, int32_t appBufferSize) + SSLStream* sslStream, bool isServer, ManagedContextHandle managedContextHandle, STREAM_READER streamReader, STREAM_WRITER streamWriter, int32_t appBufferSize, char* peerHost) { abort_if_invalid_pointer_argument (sslStream); abort_unless(sslStream->sslContext != NULL, "sslContext is NULL in SSL stream"); @@ -435,10 +495,23 @@ int32_t AndroidCryptoNative_SSLStreamInitialize( int32_t ret = FAIL; JNIEnv* env = GetJNIEnv(); - // SSLEngine sslEngine = sslContext.createSSLEngine(); + jobject sslEngine = NULL; + if (peerHost) + { + // SSLEngine sslEngine = sslContext.createSSLEngine(peerHost, -1); + jstring peerHostStr = make_java_string(env, peerHost); + sslEngine = (*env)->CallObjectMethod(env, sslStream->sslContext, g_SSLContextCreateSSLEngineMethodWithHostAndPort, peerHostStr, -1); + ReleaseLRef(env, peerHostStr); + ON_EXCEPTION_PRINT_AND_GOTO(exit); + } + else + { + // SSLEngine sslEngine = sslContext.createSSLEngine(); + sslEngine = (*env)->CallObjectMethod(env, sslStream->sslContext, g_SSLContextCreateSSLEngineMethod); + ON_EXCEPTION_PRINT_AND_GOTO(exit); + } + // sslEngine.setUseClientMode(!isServer); - jobject sslEngine = (*env)->CallObjectMethod(env, sslStream->sslContext, g_SSLContextCreateSSLEngineMethod); - ON_EXCEPTION_PRINT_AND_GOTO(exit); sslStream->sslEngine = ToGRef(env, sslEngine); (*env)->CallVoidMethod(env, sslStream->sslEngine, g_SSLEngineSetUseClientMode, !isServer); ON_EXCEPTION_PRINT_AND_GOTO(exit); @@ -476,19 +549,48 @@ int32_t AndroidCryptoNative_SSLStreamInitialize( return ret; } +// This method calls internal Android APIs that are specific to Android API 21-23 and it won't work +// on newer API levels. By calling the sslEngine.sslParameters.useSni(true) method, the SSLEngine +// will include the peerHost that was passed in to the SSLEngine factory method in the client hello +// message. +ARGS_NON_NULL_ALL static int32_t ApplyLegacyAndroidSNIWorkaround(JNIEnv* env, SSLStream* sslStream) +{ + if (g_ConscryptOpenSSLEngineImplClass == NULL || !(*env)->IsInstanceOf(env, sslStream->sslEngine, g_ConscryptOpenSSLEngineImplClass)) + return FAIL; + + int32_t ret = FAIL; + INIT_LOCALS(loc, sslParameters); + + loc[sslParameters] = (*env)->GetObjectField(env, sslStream->sslEngine, g_ConscryptOpenSSLEngineImplSslParametersField); + ON_EXCEPTION_PRINT_AND_GOTO(cleanup); + + if (!loc[sslParameters]) + goto cleanup; + + (*env)->CallVoidMethod(env, loc[sslParameters], g_ConscryptSSLParametersImplSetUseSni, true); + ON_EXCEPTION_PRINT_AND_GOTO(cleanup); + + ret = SUCCESS; + +cleanup: + RELEASE_LOCALS(loc, env); + return ret; +} + int32_t AndroidCryptoNative_SSLStreamSetTargetHost(SSLStream* sslStream, char* targetHost) { abort_if_invalid_pointer_argument (sslStream); abort_if_invalid_pointer_argument (targetHost); + JNIEnv* env = GetJNIEnv(); + if (g_SNIHostName == NULL || g_SSLParametersSetServerNames == NULL) { - // SSL not supported below API Level 24 - return UNSUPPORTED_API_LEVEL; + // SNIHostName is only available since API 24 + // on APIs 21-23 we use a workaround to force the SSLEngine to use SNI + return ApplyLegacyAndroidSNIWorkaround(env, sslStream); } - JNIEnv* env = GetJNIEnv(); - int32_t ret = FAIL; INIT_LOCALS(loc, hostStr, nameList, hostName, params); @@ -523,10 +625,13 @@ PAL_SSLStreamStatus AndroidCryptoNative_SSLStreamHandshake(SSLStream* sslStream) abort_if_invalid_pointer_argument (sslStream); JNIEnv* env = GetJNIEnv(); - // sslEngine.beginHandshake(); - (*env)->CallVoidMethod(env, sslStream->sslEngine, g_SSLEngineBeginHandshake); - if (CheckJNIExceptions(env)) - return SSLStreamStatus_Error; + int handshakeStatus = GetEnumAsInt(env, (*env)->CallObjectMethod(env, sslStream->sslEngine, g_SSLEngineGetHandshakeStatus)); + if (!IsHandshaking(handshakeStatus)) { + // sslEngine.beginHandshake(); + (*env)->CallVoidMethod(env, sslStream->sslEngine, g_SSLEngineBeginHandshake); + if (CheckJNIExceptions(env)) + return SSLStreamStatus_Error; + } return DoHandshake(env, sslStream); } @@ -705,14 +810,16 @@ int32_t AndroidCryptoNative_SSLStreamGetCipherSuite(SSLStream* sslStream, uint16 *out = NULL; // String cipherSuite = sslSession.getCipherSuite(); - jstring cipherSuite = (*env)->CallObjectMethod(env, sslStream->sslSession, g_SSLSessionGetCipherSuite); + jobject sslSession = GetCurrentSslSession(env, sslStream); + jstring cipherSuite = (*env)->CallObjectMethod(env, sslSession, g_SSLSessionGetCipherSuite); ON_EXCEPTION_PRINT_AND_GOTO(cleanup); *out = AllocateString(env, cipherSuite); ret = SUCCESS; cleanup: - (*env)->DeleteLocalRef(env, cipherSuite); + ReleaseLRef(env, sslSession); + ReleaseLRef(env, cipherSuite); return ret; } @@ -726,14 +833,16 @@ int32_t AndroidCryptoNative_SSLStreamGetProtocol(SSLStream* sslStream, uint16_t* *out = NULL; // String protocol = sslSession.getProtocol(); - jstring protocol = (*env)->CallObjectMethod(env, sslStream->sslSession, g_SSLSessionGetProtocol); + jobject sslSession = GetCurrentSslSession(env, sslStream); + jstring protocol = (*env)->CallObjectMethod(env, sslSession, g_SSLSessionGetProtocol); ON_EXCEPTION_PRINT_AND_GOTO(cleanup); *out = AllocateString(env, protocol); ret = SUCCESS; cleanup: - (*env)->DeleteLocalRef(env, protocol); + ReleaseLRef(env, sslSession); + ReleaseLRef(env, protocol); return ret; } @@ -746,7 +855,8 @@ jobject /*X509Certificate*/ AndroidCryptoNative_SSLStreamGetPeerCertificate(SSLS // Certificate[] certs = sslSession.getPeerCertificates(); // out = certs[0]; - jobjectArray certs = (*env)->CallObjectMethod(env, sslStream->sslSession, g_SSLSessionGetPeerCertificates); + jobject sslSession = GetCurrentSslSession(env, sslStream); + jobjectArray certs = (*env)->CallObjectMethod(env, sslSession, g_SSLSessionGetPeerCertificates); // If there are no peer certificates, getPeerCertificates will throw. Return null to indicate no certificate. if (TryClearJNIExceptions(env)) @@ -761,7 +871,8 @@ jobject /*X509Certificate*/ AndroidCryptoNative_SSLStreamGetPeerCertificate(SSLS } cleanup: - (*env)->DeleteLocalRef(env, certs); + ReleaseLRef(env, sslSession); + ReleaseLRef(env, certs); return ret; } @@ -779,7 +890,8 @@ void AndroidCryptoNative_SSLStreamGetPeerCertificates(SSLStream* sslStream, jobj // for (int i = 0; i < certs.length; i++) { // out[i] = certs[i]; // } - jobjectArray certs = (*env)->CallObjectMethod(env, sslStream->sslSession, g_SSLSessionGetPeerCertificates); + jobject sslSession = GetCurrentSslSession(env, sslStream); + jobjectArray certs = (*env)->CallObjectMethod(env, sslSession, g_SSLSessionGetPeerCertificates); // If there are no peer certificates, getPeerCertificates will throw. Return null and length of zero to indicate no certificates. if (TryClearJNIExceptions(env)) @@ -798,7 +910,8 @@ void AndroidCryptoNative_SSLStreamGetPeerCertificates(SSLStream* sslStream, jobj } cleanup: - (*env)->DeleteLocalRef(env, certs); + ReleaseLRef(env, sslSession); + ReleaseLRef(env, certs); } void AndroidCryptoNative_SSLStreamRequestClientAuthentication(SSLStream* sslStream) @@ -912,14 +1025,15 @@ bool AndroidCryptoNative_SSLStreamVerifyHostname(SSLStream* sslStream, char* hos JNIEnv* env = GetJNIEnv(); bool ret = false; - INIT_LOCALS(loc, name, verifier); + INIT_LOCALS(loc, name, verifier, sslSession); // HostnameVerifier verifier = HttpsURLConnection.getDefaultHostnameVerifier(); // return verifier.verify(hostname, sslSession); loc[name] = make_java_string(env, hostname); + loc[sslSession] = GetCurrentSslSession(env, sslStream); loc[verifier] = (*env)->CallStaticObjectMethod(env, g_HttpsURLConnection, g_HttpsURLConnectionGetDefaultHostnameVerifier); - ret = (*env)->CallBooleanMethod(env, loc[verifier], g_HostnameVerifierVerify, loc[name], sslStream->sslSession); + ret = (*env)->CallBooleanMethod(env, loc[verifier], g_HostnameVerifierVerify, loc[name], loc[sslSession]); RELEASE_LOCALS(loc, env); return ret; diff --git a/src/native/libs/System.Security.Cryptography.Native.Android/pal_sslstream.h b/src/native/libs/System.Security.Cryptography.Native.Android/pal_sslstream.h index cc7a7b52b6f253..db20069eb843cc 100644 --- a/src/native/libs/System.Security.Cryptography.Native.Android/pal_sslstream.h +++ b/src/native/libs/System.Security.Cryptography.Native.Android/pal_sslstream.h @@ -67,7 +67,7 @@ Initialize an SSL context Returns 1 on success, 0 otherwise */ PALEXPORT int32_t AndroidCryptoNative_SSLStreamInitialize( - SSLStream* sslStream, bool isServer, ManagedContextHandle managedContextHandle, STREAM_READER streamReader, STREAM_WRITER streamWriter, int32_t appBufferSize); + SSLStream* sslStream, bool isServer, ManagedContextHandle managedContextHandle, STREAM_READER streamReader, STREAM_WRITER streamWriter, int32_t appBufferSize, char* peerHost); /* Set target host