[Android] Fix crash in startup when running below API Level 24 (#54231)
authorSteve Pfister <steveisok@users.noreply.github.com>
Tue, 15 Jun 2021 20:38:44 +0000 (16:38 -0400)
committerGitHub <noreply@github.com>
Tue, 15 Jun 2021 20:38:44 +0000 (16:38 -0400)
This change fixes a crash when running below API Level 24 due to SNIHostName and SSLParameters.setServerNames not being available. We will now throw a PlatformNotSupportedException to make things a little more apparent.

Fixes #54182

src/libraries/Common/src/Interop/Android/System.Security.Cryptography.Native.Android/Interop.Ssl.cs
src/libraries/Native/Unix/System.Security.Cryptography.Native.Android/pal_jni.c
src/libraries/Native/Unix/System.Security.Cryptography.Native.Android/pal_jni.h
src/libraries/Native/Unix/System.Security.Cryptography.Native.Android/pal_sslstream.c
src/libraries/System.Net.Security/src/Resources/Strings.resx

index bf558da..762d352 100644 (file)
@@ -17,6 +17,8 @@ internal static partial class Interop
 {
     internal static partial class AndroidCrypto
     {
+        private const int UNSUPPORTED_API_LEVEL = 2;
+
         internal unsafe delegate PAL_SSLStreamStatus SSLReadCallback(byte* data, int* length);
         internal unsafe delegate void SSLWriteCallback(byte* data, int length);
 
@@ -77,7 +79,9 @@ internal static partial class Interop
             string targetHost)
         {
             int ret = SSLStreamSetTargetHostImpl(sslHandle, targetHost);
-            if (ret != SUCCESS)
+            if (ret == UNSUPPORTED_API_LEVEL)
+                throw new PlatformNotSupportedException(SR.net_android_ssl_api_level_unsupported);
+            else if (ret != SUCCESS)
                 throw new SslException();
         }
 
index 1140d47..fe92ce9 100644 (file)
@@ -705,7 +705,6 @@ JNI_OnLoad(JavaVM *vm, void *reserved)
     g_SSLParametersClass =                      GetClassGRef(env, "javax/net/ssl/SSLParameters");
     g_SSLParametersGetProtocols =               GetMethod(env, false,  g_SSLParametersClass, "getProtocols", "()[Ljava/lang/String;");
     g_SSLParametersSetApplicationProtocols =    GetOptionalMethod(env, false,  g_SSLParametersClass, "setApplicationProtocols", "([Ljava/lang/String;)V");
-    g_SSLParametersSetServerNames =             GetMethod(env, false,  g_SSLParametersClass, "setServerNames", "(Ljava/util/List;)V");
 
     g_sslCtxClass =                     GetClassGRef(env, "javax/net/ssl/SSLContext");
     g_sslCtxGetDefaultMethod =          GetMethod(env, true,  g_sslCtxClass, "getDefault", "()Ljavax/net/ssl/SSLContext;");
@@ -957,8 +956,13 @@ JNI_OnLoad(JavaVM *vm, void *reserved)
     g_KeyManagerFactoryInit =           GetMethod(env, false, g_KeyManagerFactory, "init", "(Ljava/security/KeyStore;[C)V");
     g_KeyManagerFactoryGetKeyManagers = GetMethod(env, false, g_KeyManagerFactory, "getKeyManagers", "()[Ljavax/net/ssl/KeyManager;");
 
-    g_SNIHostName =     GetClassGRef(env, "javax/net/ssl/SNIHostName");
-    g_SNIHostNameCtor = GetMethod(env, false, g_SNIHostName, "<init>", "(Ljava/lang/String;)V");
+    // Supported on API Level 24 and above
+    g_SNIHostName = GetOptionalClassGRef(env, "javax/net/ssl/SNIHostName");
+    if (g_SNIHostName != NULL)
+    {
+        g_SNIHostNameCtor =                 GetMethod(env, false, g_SNIHostName, "<init>", "(Ljava/lang/String;)V");
+        g_SSLParametersSetServerNames =     GetOptionalMethod(env, false,  g_SSLParametersClass, "setServerNames", "(Ljava/util/List;)V");
+    }
 
     g_SSLEngine =                       GetClassGRef(env, "javax/net/ssl/SSLEngine");
     g_SSLEngineBeginHandshake =         GetMethod(env, false, g_SSLEngine, "beginHandshake", "()V");
index 0a458ea..4b95faf 100644 (file)
@@ -479,6 +479,12 @@ int32_t AndroidCryptoNative_SSLStreamSetTargetHost(SSLStream* sslStream, char* t
     abort_if_invalid_pointer_argument (sslStream);
     abort_if_invalid_pointer_argument (targetHost);
 
+    if (g_SNIHostName == NULL || g_SSLParametersSetServerNames == NULL)
+    {
+        // SSL not supported below API Level 24
+        return UNSUPPORTED_API_LEVEL;
+    }
+
     JNIEnv* env = GetJNIEnv();
 
     int32_t ret = FAIL;
index c002340..8181afe 100644 (file)
   <data name="net_ssl_renegotiate_data" xml:space="preserve">
     <value>Received data during renegotiation.</value>
   </data>
+  <data name="net_android_ssl_api_level_unsupported" xml:space="preserve">
+    <value>Setting an SNI hostname is not supported on this API level.</value>
+  </data>
 </root>