Skip to content

Commit

Permalink
[AndroidCrypto] Handle setting non-default application protocols (#51187
Browse files Browse the repository at this point in the history
)
  • Loading branch information
elinor-fung authored Apr 16, 2021
1 parent 189829c commit 237d863
Show file tree
Hide file tree
Showing 12 changed files with 253 additions and 55 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,9 @@ internal static partial class AndroidCrypto
{
[DllImport(Interop.Libraries.CryptoNative, EntryPoint = "AndroidCryptoNative_SSLGetSupportedProtocols")]
internal static extern SslProtocols SSLGetSupportedProtocols();

[DllImport(Libraries.CryptoNative, EntryPoint = "AndroidCryptoNative_SSLSupportsApplicationProtocolsConfiguration")]
[return:MarshalAs(UnmanagedType.U1)]
internal static extern bool SSLSupportsApplicationProtocolsConfiguration();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

using System;
using System.Buffers;
using System.Collections.Generic;
using System.Net.Security;
using System.Runtime.InteropServices;
using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates;
Expand Down Expand Up @@ -66,19 +68,63 @@ internal static void SSLStreamInitialize(
throw new SslException();
}

[DllImport(Interop.Libraries.CryptoNative, EntryPoint = "AndroidCryptoNative_SSLStreamConfigureParameters")]
private static extern int SSLStreamConfigureParametersImpl(
[DllImport(Interop.Libraries.CryptoNative, EntryPoint = "AndroidCryptoNative_SSLStreamSetTargetHost")]
private static extern int SSLStreamSetTargetHostImpl(
SafeSslHandle sslHandle,
[MarshalAs(UnmanagedType.LPUTF8Str)] string targetHost);
internal static void SSLStreamConfigureParameters(
internal static void SSLStreamSetTargetHost(
SafeSslHandle sslHandle,
string targetHost)
{
int ret = SSLStreamConfigureParametersImpl(sslHandle, targetHost);
int ret = SSLStreamSetTargetHostImpl(sslHandle, targetHost);
if (ret != SUCCESS)
throw new SslException();
}

[DllImport(Interop.Libraries.CryptoNative, EntryPoint = "AndroidCryptoNative_SSLStreamRequestClientAuthentication")]
internal static extern void SSLStreamRequestClientAuthentication(SafeSslHandle sslHandle);

[StructLayout(LayoutKind.Sequential)]
private unsafe struct ApplicationProtocolData
{
public byte* Data;
public int Length;
}

[DllImport(Interop.Libraries.CryptoNative, EntryPoint = "AndroidCryptoNative_SSLStreamSetApplicationProtocols")]
private static unsafe extern int SSLStreamSetApplicationProtocols(SafeSslHandle sslHandle, ApplicationProtocolData[] protocolData, int count);
internal static unsafe void SSLStreamSetApplicationProtocols(SafeSslHandle sslHandle, List<SslApplicationProtocol> protocols)
{
int count = protocols.Count;
MemoryHandle[] memHandles = new MemoryHandle[count];
ApplicationProtocolData[] protocolData = new ApplicationProtocolData[count];
try
{
for (int i = 0; i < count; i++)
{
ReadOnlyMemory<byte> protocol = protocols[i].Protocol;
memHandles[i] = protocol.Pin();
protocolData[i] = new ApplicationProtocolData
{
Data = (byte*)memHandles[i].Pointer,
Length = protocol.Length
};
}
int ret = SSLStreamSetApplicationProtocols(sslHandle, protocolData, count);
if (ret != SUCCESS)
{
throw new SslException();
}
}
finally
{
foreach (MemoryHandle memHandle in memHandles)
{
memHandle.Dispose();
}
}
}

[DllImport(Interop.Libraries.CryptoNative, EntryPoint = "AndroidCryptoNative_SSLStreamSetEnabledProtocols")]
private static extern int SSLStreamSetEnabledProtocols(SafeSslHandle sslHandle, ref SslProtocols protocols, int length);
internal static void SSLStreamSetEnabledProtocols(SafeSslHandle sslHandle, ReadOnlySpan<SslProtocols> protocols)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,14 @@ await TestHelper.WhenAllCompletedOrAnyFailed(

string GetTestSNIName()
{
return $"{nameof(GetAsync_AllowedSSLVersion_Succeeds)}_{acceptedProtocol}_{requestOnlyThisProtocol}";
string name = $"{nameof(GetAsync_AllowedSSLVersion_Succeeds)}_{acceptedProtocol}_{requestOnlyThisProtocol}";
if (PlatformDetection.IsAndroid)
{
// Android does not support underscores in host names
name = name.Replace("_", string.Empty);
}

return name;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,15 +134,34 @@ public static bool IsNonZeroLowerBoundArraySupported
public static bool IsDomainJoinedMachine => !Environment.MachineName.Equals(Environment.UserDomainName, StringComparison.OrdinalIgnoreCase);
public static bool IsNotDomainJoinedMachine => !IsDomainJoinedMachine;

public static bool IsOpenSslSupported => IsLinux || IsFreeBSD || Isillumos || IsSolaris;

// Windows - Schannel supports alpn from win8.1/2012 R2 and higher.
// Linux - OpenSsl supports alpn from openssl 1.0.2 and higher.
// OSX - SecureTransport doesn't expose alpn APIs. TODO https://github.com/dotnet/runtime/issues/27727
public static bool IsOpenSslSupported => IsLinux || IsFreeBSD || Isillumos || IsSolaris;
// Android - Platform supports alpn from API level 29 and higher
private static Lazy<bool> s_supportsAlpn = new Lazy<bool>(GetAlpnSupport);
private static bool GetAlpnSupport()
{
if (IsWindows && !IsWindows7 && !IsNetFramework)
{
return true;
}

public static bool SupportsAlpn => (IsWindows && !IsWindows7 && !IsNetFramework) ||
(IsOpenSslSupported &&
(OpenSslVersion.Major >= 1 && (OpenSslVersion.Minor >= 1 || OpenSslVersion.Build >= 2)));
if (IsOpenSslSupported)
{
return OpenSslVersion.Major >= 1 && (OpenSslVersion.Minor >= 1 || OpenSslVersion.Build >= 2);
}

if (IsAndroid)
{
return Interop.AndroidCrypto.SSLSupportsApplicationProtocolsConfiguration();
}

return false;
}

public static bool SupportsAlpn => s_supportsAlpn.Value;
public static bool SupportsClientAlpn => SupportsAlpn || IsOSX || IsMacCatalyst || IsiOS || IstvOS;

private static Lazy<bool> s_supportsTls10 = new Lazy<bool>(GetTls10Support);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,8 @@ jmethodID g_sigNumMethod;

// javax/net/ssl/SSLParameters
jclass g_SSLParametersClass;
jmethodID g_SSLParametersCtor;
jmethodID g_SSLParametersGetProtocols;
jmethodID g_SSLParametersSetApplicationProtocols;
jmethodID g_SSLParametersSetServerNames;

// javax/net/ssl/SSLContext
Expand Down Expand Up @@ -397,17 +397,19 @@ jmethodID g_SNIHostNameCtor;

// javax/net/ssl/SSLEngine
jclass g_SSLEngine;
jmethodID g_SSLEngineGetApplicationProtocol;
jmethodID g_SSLEngineSetUseClientMode;
jmethodID g_SSLEngineGetSession;
jmethodID g_SSLEngineBeginHandshake;
jmethodID g_SSLEngineWrap;
jmethodID g_SSLEngineUnwrap;
jmethodID g_SSLEngineCloseOutbound;
jmethodID g_SSLEngineGetApplicationProtocol;
jmethodID g_SSLEngineGetHandshakeStatus;
jmethodID g_SSLEngineGetSession;
jmethodID g_SSLEngineGetSSLParameters;
jmethodID g_SSLEngineGetSupportedProtocols;
jmethodID g_SSLEngineSetEnabledProtocols;
jmethodID g_SSLEngineSetSSLParameters;
jmethodID g_SSLEngineSetUseClientMode;
jmethodID g_SSLEngineSetWantClientAuth;
jmethodID g_SSLEngineUnwrap;
jmethodID g_SSLEngineWrap;

// java/nio/ByteBuffer
jclass g_ByteBuffer;
Expand Down Expand Up @@ -711,10 +713,10 @@ JNI_OnLoad(JavaVM *vm, void *reserved)
g_bitLengthMethod = GetMethod(env, false, g_bigNumClass, "bitLength", "()I");
g_sigNumMethod = GetMethod(env, false, g_bigNumClass, "signum", "()I");

g_SSLParametersClass = GetClassGRef(env, "javax/net/ssl/SSLParameters");
g_SSLParametersCtor = GetMethod(env, false, g_SSLParametersClass, "<init>", "()V");
g_SSLParametersGetProtocols = GetMethod(env, false, g_SSLParametersClass, "getProtocols", "()[Ljava/lang/String;");
g_SSLParametersSetServerNames = GetMethod(env, false, g_SSLParametersClass, "setServerNames", "(Ljava/util/List;)V");
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;");
Expand Down Expand Up @@ -970,17 +972,19 @@ JNI_OnLoad(JavaVM *vm, void *reserved)
g_SNIHostNameCtor = GetMethod(env, false, g_SNIHostName, "<init>", "(Ljava/lang/String;)V");

g_SSLEngine = GetClassGRef(env, "javax/net/ssl/SSLEngine");
g_SSLEngineGetApplicationProtocol = GetMethod(env, false, g_SSLEngine, "getApplicationProtocol", "()Ljava/lang/String;");
g_SSLEngineSetUseClientMode = GetMethod(env, false, g_SSLEngine, "setUseClientMode", "(Z)V");
g_SSLEngineGetSession = GetMethod(env, false, g_SSLEngine, "getSession", "()Ljavax/net/ssl/SSLSession;");
g_SSLEngineBeginHandshake = GetMethod(env, false, g_SSLEngine, "beginHandshake", "()V");
g_SSLEngineWrap = GetMethod(env, false, g_SSLEngine, "wrap", "(Ljava/nio/ByteBuffer;Ljava/nio/ByteBuffer;)Ljavax/net/ssl/SSLEngineResult;");
g_SSLEngineUnwrap = GetMethod(env, false, g_SSLEngine, "unwrap", "(Ljava/nio/ByteBuffer;Ljava/nio/ByteBuffer;)Ljavax/net/ssl/SSLEngineResult;");
g_SSLEngineGetHandshakeStatus = GetMethod(env, false, g_SSLEngine, "getHandshakeStatus", "()Ljavax/net/ssl/SSLEngineResult$HandshakeStatus;");
g_SSLEngineCloseOutbound = GetMethod(env, false, g_SSLEngine, "closeOutbound", "()V");
g_SSLEngineGetApplicationProtocol = GetMethod(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_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");
g_SSLEngineSetSSLParameters = GetMethod(env, false, g_SSLEngine, "setSSLParameters", "(Ljavax/net/ssl/SSLParameters;)V");
g_SSLEngineSetUseClientMode = GetMethod(env, false, g_SSLEngine, "setUseClientMode", "(Z)V");
g_SSLEngineSetWantClientAuth = GetMethod(env, false, g_SSLEngine, "setWantClientAuth", "(Z)V");
g_SSLEngineUnwrap = GetMethod(env, false, g_SSLEngine, "unwrap", "(Ljava/nio/ByteBuffer;Ljava/nio/ByteBuffer;)Ljavax/net/ssl/SSLEngineResult;");
g_SSLEngineWrap = GetMethod(env, false, g_SSLEngine, "wrap", "(Ljava/nio/ByteBuffer;Ljava/nio/ByteBuffer;)Ljavax/net/ssl/SSLEngineResult;");

g_ByteBuffer = GetClassGRef(env, "java/nio/ByteBuffer");
g_ByteBufferAllocate = GetMethod(env, true, g_ByteBuffer, "allocate", "(I)Ljava/nio/ByteBuffer;");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,8 @@ extern jmethodID g_sigNumMethod;

// javax/net/ssl/SSLParameters
extern jclass g_SSLParametersClass;
extern jmethodID g_SSLParametersCtor;
extern jmethodID g_SSLParametersGetProtocols;
extern jmethodID g_SSLParametersSetApplicationProtocols;
extern jmethodID g_SSLParametersSetServerNames;

// javax/net/ssl/SSLContext
Expand Down Expand Up @@ -411,17 +411,19 @@ extern jmethodID g_SNIHostNameCtor;

// javax/net/ssl/SSLEngine
extern jclass g_SSLEngine;
extern jmethodID g_SSLEngineGetApplicationProtocol;
extern jmethodID g_SSLEngineSetUseClientMode;
extern jmethodID g_SSLEngineGetSession;
extern jmethodID g_SSLEngineBeginHandshake;
extern jmethodID g_SSLEngineWrap;
extern jmethodID g_SSLEngineUnwrap;
extern jmethodID g_SSLEngineCloseOutbound;
extern jmethodID g_SSLEngineGetApplicationProtocol;
extern jmethodID g_SSLEngineGetHandshakeStatus;
extern jmethodID g_SSLEngineGetSession;
extern jmethodID g_SSLEngineGetSSLParameters;
extern jmethodID g_SSLEngineGetSupportedProtocols;
extern jmethodID g_SSLEngineSetEnabledProtocols;
extern jmethodID g_SSLEngineSetSSLParameters;
extern jmethodID g_SSLEngineSetUseClientMode;
extern jmethodID g_SSLEngineSetWantClientAuth;
extern jmethodID g_SSLEngineUnwrap;
extern jmethodID g_SSLEngineWrap;

// java/nio/ByteBuffer
extern jclass g_ByteBuffer;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,8 @@ PAL_SslProtocol AndroidCryptoNative_SSLGetSupportedProtocols(void)
RELEASE_LOCALS(loc, env);
return supported;
}

bool AndroidCryptoNative_SSLSupportsApplicationProtocolsConfiguration(void)
{
return g_SSLParametersSetApplicationProtocols != NULL;
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,8 @@
Get the supported protocols
*/
PALEXPORT PAL_SslProtocol AndroidCryptoNative_SSLGetSupportedProtocols(void);

/*
Returns whether or not configuration of application protocols is supported
*/
PALEXPORT bool AndroidCryptoNative_SSLSupportsApplicationProtocolsConfiguration(void);
Loading

0 comments on commit 237d863

Please sign in to comment.