From f5fb78d5d857a4378f18b66c30cdd55f34f5fad7 Mon Sep 17 00:00:00 2001 From: Radek Zikmund Date: Fri, 15 Jul 2022 15:16:57 +0200 Subject: [PATCH 1/6] Initial OpenSSL MsQuic support --- .../src/System/Net/Quic/Internal/MsQuicApi.cs | 8 ++++++++ .../src/System/Net/Quic/Internal/MsQuicConfiguration.cs | 6 +++--- .../Net/Quic/QuicConnection.SslConnectionOptions.cs | 2 +- .../tests/FunctionalTests/TestHelper.cs | 2 +- 4 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/libraries/System.Net.Quic/src/System/Net/Quic/Internal/MsQuicApi.cs b/src/libraries/System.Net.Quic/src/System/Net/Quic/Internal/MsQuicApi.cs index c4b1e00ada347..3a4b4d22a0600 100644 --- a/src/libraries/System.Net.Quic/src/System/Net/Quic/Internal/MsQuicApi.cs +++ b/src/libraries/System.Net.Quic/src/System/Net/Quic/Internal/MsQuicApi.cs @@ -51,6 +51,8 @@ private MsQuicApi(QUIC_API_TABLE* apiTable) internal static bool IsQuicSupported { get; } + internal static bool UsesSChannelBackend { get; } + internal static bool Tls13ServerMayBeDisabled { get; } internal static bool Tls13ClientMayBeDisabled { get; } @@ -102,6 +104,12 @@ static MsQuicApi() NetEventSource.Info(null, $"Incompatible MsQuic library version '{version}', expecting '{MsQuicVersion}'"); } } + + // Assume SChanel is being used on windows and query for the actual provider from the library + QUIC_TLS_PROVIDER provider = OperatingSystem.IsWindows() ? QUIC_TLS_PROVIDER.SCHANNEL : QUIC_TLS_PROVIDER.OPENSSL; + size = sizeof(QUIC_TLS_PROVIDER); + apiTable->GetParam(null, QUIC_PARAM_GLOBAL_TLS_PROVIDER, &size, &provider); + UsesSChannelBackend = provider == QUIC_TLS_PROVIDER.SCHANNEL; } } } diff --git a/src/libraries/System.Net.Quic/src/System/Net/Quic/Internal/MsQuicConfiguration.cs b/src/libraries/System.Net.Quic/src/System/Net/Quic/Internal/MsQuicConfiguration.cs index 67a72e453ab72..50c00ae379e3c 100644 --- a/src/libraries/System.Net.Quic/src/System/Net/Quic/Internal/MsQuicConfiguration.cs +++ b/src/libraries/System.Net.Quic/src/System/Net/Quic/Internal/MsQuicConfiguration.cs @@ -23,7 +23,7 @@ public static MsQuicSafeHandle Create(QuicClientConnectionOptions options) flags |= QUIC_CREDENTIAL_FLAGS.CLIENT; flags |= QUIC_CREDENTIAL_FLAGS.INDICATE_CERTIFICATE_RECEIVED; flags |= QUIC_CREDENTIAL_FLAGS.NO_CERTIFICATE_VALIDATION; - if (OperatingSystem.IsWindows()) + if (MsQuicApi.UsesSChannelBackend) { flags |= QUIC_CREDENTIAL_FLAGS.USE_SUPPLIED_CREDENTIALS; } @@ -131,7 +131,7 @@ private static unsafe MsQuicSafeHandle Create(QuicConnectionOptions options, QUI try { QUIC_CREDENTIAL_CONFIG config = new QUIC_CREDENTIAL_CONFIG { Flags = flags }; - config.Flags |= (OperatingSystem.IsWindows() ? QUIC_CREDENTIAL_FLAGS.NONE : QUIC_CREDENTIAL_FLAGS.USE_PORTABLE_CERTIFICATES); + config.Flags |= (MsQuicApi.UsesSChannelBackend ? QUIC_CREDENTIAL_FLAGS.NONE : QUIC_CREDENTIAL_FLAGS.USE_PORTABLE_CERTIFICATES); if (cipherSuitesPolicy != null) { @@ -145,7 +145,7 @@ private static unsafe MsQuicSafeHandle Create(QuicConnectionOptions options, QUI config.Type = QUIC_CREDENTIAL_TYPE.NONE; status = MsQuicApi.Api.ApiTable->ConfigurationLoadCredential(configurationHandle.QuicHandle, &config); } - else if (OperatingSystem.IsWindows()) + else if (MsQuicApi.UsesSChannelBackend) { config.Type = QUIC_CREDENTIAL_TYPE.CERTIFICATE_CONTEXT; config.CertificateContext = (void*)certificate.Handle; diff --git a/src/libraries/System.Net.Quic/src/System/Net/Quic/QuicConnection.SslConnectionOptions.cs b/src/libraries/System.Net.Quic/src/System/Net/Quic/QuicConnection.SslConnectionOptions.cs index 0b9e13fb022ab..e8b05c52db396 100644 --- a/src/libraries/System.Net.Quic/src/System/Net/Quic/QuicConnection.SslConnectionOptions.cs +++ b/src/libraries/System.Net.Quic/src/System/Net/Quic/QuicConnection.SslConnectionOptions.cs @@ -68,7 +68,7 @@ public unsafe int ValidateCertificate(QUIC_BUFFER* certificatePtr, QUIC_BUFFER* chain.ChainPolicy.RevocationFlag = X509RevocationFlag.ExcludeRoot; chain.ChainPolicy.ApplicationPolicy.Add(_isClient ? s_serverAuthOid : s_clientAuthOid); - if (OperatingSystem.IsWindows()) + if (MsQuicApi.UsesSChannelBackend) { certificate = new X509Certificate2((IntPtr)certificatePtr); } diff --git a/src/libraries/System.Net.Security/tests/FunctionalTests/TestHelper.cs b/src/libraries/System.Net.Security/tests/FunctionalTests/TestHelper.cs index 62383aa16337a..45f6f53cf2209 100644 --- a/src/libraries/System.Net.Security/tests/FunctionalTests/TestHelper.cs +++ b/src/libraries/System.Net.Security/tests/FunctionalTests/TestHelper.cs @@ -204,7 +204,7 @@ internal static (X509Certificate2 certificate, X509Certificate2Collection) Gener if (PlatformDetection.IsWindows) { X509Certificate2 ephemeral = endEntity; - endEntity = new X509Certificate2(endEntity.Export(X509ContentType.Pfx)); + endEntity = new X509Certificate2(endEntity.Export(X509ContentType.Pfx), (string?)null, X509KeyStorageFlags.Exportable); ephemeral.Dispose(); } From 903652804024d3f7f4c4ae5b02af3239c37d1fa4 Mon Sep 17 00:00:00 2001 From: Radek Zikmund Date: Fri, 15 Jul 2022 15:22:56 +0200 Subject: [PATCH 2/6] Don't check Windows version when OpenSSL is used --- .../src/System/Net/Quic/Internal/MsQuicApi.cs | 43 +++++++++---------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/src/libraries/System.Net.Quic/src/System/Net/Quic/Internal/MsQuicApi.cs b/src/libraries/System.Net.Quic/src/System/Net/Quic/Internal/MsQuicApi.cs index 3a4b4d22a0600..518c85f79e190 100644 --- a/src/libraries/System.Net.Quic/src/System/Net/Quic/Internal/MsQuicApi.cs +++ b/src/libraries/System.Net.Quic/src/System/Net/Quic/Internal/MsQuicApi.cs @@ -58,22 +58,6 @@ private MsQuicApi(QUIC_API_TABLE* apiTable) static MsQuicApi() { - if (OperatingSystem.IsWindows()) - { - if (!IsWindowsVersionSupported()) - { - if (NetEventSource.Log.IsEnabled()) - { - NetEventSource.Info(null, $"Current Windows version ({Environment.OSVersion}) is not supported by QUIC. Minimal supported version is {MinWindowsVersion}"); - } - - return; - } - - Tls13ServerMayBeDisabled = IsTls13Disabled(true); - Tls13ClientMayBeDisabled = IsTls13Disabled(false); - } - IntPtr msQuicHandle; if (NativeLibrary.TryLoad($"{Interop.Libraries.MsQuic}.{MsQuicVersion.Major}", typeof(MsQuicApi).Assembly, DllImportSearchPath.AssemblyDirectory, out msQuicHandle) || NativeLibrary.TryLoad(Interop.Libraries.MsQuic, typeof(MsQuicApi).Assembly, DllImportSearchPath.AssemblyDirectory, out msQuicHandle)) @@ -92,17 +76,13 @@ static MsQuicApi() if (StatusSucceeded(apiTable->GetParam(null, QUIC_PARAM_GLOBAL_LIBRARY_VERSION, &size, libVersion))) { var version = new Version((int)libVersion[0], (int)libVersion[1], (int)libVersion[2], (int)libVersion[3]); - if (version >= MsQuicVersion) - { - Api = new MsQuicApi(apiTable); - IsQuicSupported = true; - } - else + if (version < MsQuicVersion) { if (NetEventSource.Log.IsEnabled()) { NetEventSource.Info(null, $"Incompatible MsQuic library version '{version}', expecting '{MsQuicVersion}'"); } + return; } // Assume SChanel is being used on windows and query for the actual provider from the library @@ -110,6 +90,25 @@ static MsQuicApi() size = sizeof(QUIC_TLS_PROVIDER); apiTable->GetParam(null, QUIC_PARAM_GLOBAL_TLS_PROVIDER, &size, &provider); UsesSChannelBackend = provider == QUIC_TLS_PROVIDER.SCHANNEL; + + if (UsesSChannelBackend) + { + if (!IsWindowsVersionSupported()) + { + if (NetEventSource.Log.IsEnabled()) + { + NetEventSource.Info(null, $"Current Windows version ({Environment.OSVersion}) is not supported by QUIC. Minimal supported version is {MinWindowsVersion}"); + } + + return; + } + + Tls13ServerMayBeDisabled = IsTls13Disabled(true); + Tls13ClientMayBeDisabled = IsTls13Disabled(false); + } + + Api = new MsQuicApi(apiTable); + IsQuicSupported = true; } } } From 1bc405a2616f2e861366f34d968ad92717caad27 Mon Sep 17 00:00:00 2001 From: Radek Zikmund <32671551+rzikm@users.noreply.github.com> Date: Fri, 15 Jul 2022 17:18:52 +0200 Subject: [PATCH 3/6] Update src/libraries/System.Net.Quic/src/System/Net/Quic/Internal/MsQuicApi.cs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Marie Píchová <11718369+ManickaP@users.noreply.github.com> --- .../System.Net.Quic/src/System/Net/Quic/Internal/MsQuicApi.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libraries/System.Net.Quic/src/System/Net/Quic/Internal/MsQuicApi.cs b/src/libraries/System.Net.Quic/src/System/Net/Quic/Internal/MsQuicApi.cs index 518c85f79e190..20807cc2598d0 100644 --- a/src/libraries/System.Net.Quic/src/System/Net/Quic/Internal/MsQuicApi.cs +++ b/src/libraries/System.Net.Quic/src/System/Net/Quic/Internal/MsQuicApi.cs @@ -103,8 +103,8 @@ static MsQuicApi() return; } - Tls13ServerMayBeDisabled = IsTls13Disabled(true); - Tls13ClientMayBeDisabled = IsTls13Disabled(false); + Tls13ServerMayBeDisabled = IsTls13Disabled(isServer: true); + Tls13ClientMayBeDisabled = IsTls13Disabled(isServer: false); } Api = new MsQuicApi(apiTable); From 1f7e57a5fd7b7148818ee592b4c1c20985390541 Mon Sep 17 00:00:00 2001 From: Radek Zikmund Date: Thu, 21 Jul 2022 16:15:32 +0200 Subject: [PATCH 4/6] Gracefully close the API handle before unloading the library --- .../src/System/Net/Quic/Internal/MsQuicApi.cs | 117 +++++++++++------- 1 file changed, 69 insertions(+), 48 deletions(-) diff --git a/src/libraries/System.Net.Quic/src/System/Net/Quic/Internal/MsQuicApi.cs b/src/libraries/System.Net.Quic/src/System/Net/Quic/Internal/MsQuicApi.cs index 20807cc2598d0..342979388f65f 100644 --- a/src/libraries/System.Net.Quic/src/System/Net/Quic/Internal/MsQuicApi.cs +++ b/src/libraries/System.Net.Quic/src/System/Net/Quic/Internal/MsQuicApi.cs @@ -59,67 +59,88 @@ private MsQuicApi(QUIC_API_TABLE* apiTable) static MsQuicApi() { IntPtr msQuicHandle; - if (NativeLibrary.TryLoad($"{Interop.Libraries.MsQuic}.{MsQuicVersion.Major}", typeof(MsQuicApi).Assembly, DllImportSearchPath.AssemblyDirectory, out msQuicHandle) || - NativeLibrary.TryLoad(Interop.Libraries.MsQuic, typeof(MsQuicApi).Assembly, DllImportSearchPath.AssemblyDirectory, out msQuicHandle)) + if (!NativeLibrary.TryLoad($"{Interop.Libraries.MsQuic}.{MsQuicVersion.Major}", typeof(MsQuicApi).Assembly, DllImportSearchPath.AssemblyDirectory, out msQuicHandle) && + !NativeLibrary.TryLoad(Interop.Libraries.MsQuic, typeof(MsQuicApi).Assembly, DllImportSearchPath.AssemblyDirectory, out msQuicHandle)) { + return; + } + + try + { + if (!NativeLibrary.TryGetExport(msQuicHandle, "MsQuicOpenVersion", out IntPtr msQuicOpenVersionAddress)) + { + return; + } + + QUIC_API_TABLE* apiTable = null; + delegate* unmanaged[Cdecl] msQuicOpenVersion = (delegate* unmanaged[Cdecl])msQuicOpenVersionAddress; + if (StatusFailed(msQuicOpenVersion((uint)MsQuicVersion.Major, &apiTable))) + { + return; + } + try { - if (NativeLibrary.TryGetExport(msQuicHandle, "MsQuicOpenVersion", out IntPtr msQuicOpenVersionAddress)) + int arraySize = 4; + uint* libVersion = stackalloc uint[arraySize]; + uint size = (uint)arraySize * sizeof(uint); + if (StatusFailed(apiTable->GetParam(null, QUIC_PARAM_GLOBAL_LIBRARY_VERSION, &size, libVersion))) + { + return; + } + + var version = new Version((int)libVersion[0], (int)libVersion[1], (int)libVersion[2], (int)libVersion[3]); + if (version < MsQuicVersion) + { + if (NetEventSource.Log.IsEnabled()) + { + NetEventSource.Info(null, $"Incompatible MsQuic library version '{version}', expecting '{MsQuicVersion}'"); + } + return; + } + + // Assume SChanel is being used on windows and query for the actual provider from the library + QUIC_TLS_PROVIDER provider = OperatingSystem.IsWindows() ? QUIC_TLS_PROVIDER.SCHANNEL : QUIC_TLS_PROVIDER.OPENSSL; + size = sizeof(QUIC_TLS_PROVIDER); + apiTable->GetParam(null, QUIC_PARAM_GLOBAL_TLS_PROVIDER, &size, &provider); + UsesSChannelBackend = provider == QUIC_TLS_PROVIDER.SCHANNEL; + + if (UsesSChannelBackend) { - QUIC_API_TABLE* apiTable; - delegate* unmanaged[Cdecl] msQuicOpenVersion = (delegate* unmanaged[Cdecl])msQuicOpenVersionAddress; - if (StatusSucceeded(msQuicOpenVersion((uint)MsQuicVersion.Major, &apiTable))) + // Implies windows platform, check TLS1.3 availability + if (!IsWindowsVersionSupported()) { - int arraySize = 4; - uint* libVersion = stackalloc uint[arraySize]; - uint size = (uint)arraySize * sizeof(uint); - if (StatusSucceeded(apiTable->GetParam(null, QUIC_PARAM_GLOBAL_LIBRARY_VERSION, &size, libVersion))) + if (NetEventSource.Log.IsEnabled()) { - var version = new Version((int)libVersion[0], (int)libVersion[1], (int)libVersion[2], (int)libVersion[3]); - if (version < MsQuicVersion) - { - if (NetEventSource.Log.IsEnabled()) - { - NetEventSource.Info(null, $"Incompatible MsQuic library version '{version}', expecting '{MsQuicVersion}'"); - } - return; - } - - // Assume SChanel is being used on windows and query for the actual provider from the library - QUIC_TLS_PROVIDER provider = OperatingSystem.IsWindows() ? QUIC_TLS_PROVIDER.SCHANNEL : QUIC_TLS_PROVIDER.OPENSSL; - size = sizeof(QUIC_TLS_PROVIDER); - apiTable->GetParam(null, QUIC_PARAM_GLOBAL_TLS_PROVIDER, &size, &provider); - UsesSChannelBackend = provider == QUIC_TLS_PROVIDER.SCHANNEL; - - if (UsesSChannelBackend) - { - if (!IsWindowsVersionSupported()) - { - if (NetEventSource.Log.IsEnabled()) - { - NetEventSource.Info(null, $"Current Windows version ({Environment.OSVersion}) is not supported by QUIC. Minimal supported version is {MinWindowsVersion}"); - } - - return; - } - - Tls13ServerMayBeDisabled = IsTls13Disabled(isServer: true); - Tls13ClientMayBeDisabled = IsTls13Disabled(isServer: false); - } - - Api = new MsQuicApi(apiTable); - IsQuicSupported = true; + NetEventSource.Info(null, $"Current Windows version ({Environment.OSVersion}) is not supported by QUIC. Minimal supported version is {MinWindowsVersion}"); } + + return; } + + Tls13ServerMayBeDisabled = IsTls13Disabled(isServer: true); + Tls13ClientMayBeDisabled = IsTls13Disabled(isServer: false); } + + Api = new MsQuicApi(apiTable); + IsQuicSupported = true; } finally { - if (!IsQuicSupported) + if (!IsQuicSupported && NativeLibrary.TryGetExport(msQuicHandle, "MsQuicClose", out IntPtr msQuicClose)) { - NativeLibrary.Free(msQuicHandle); + // Gracefully close the API table + ((delegate*unmanaged[Cdecl])msQuicClose)(apiTable); } } + + } + finally + { + if (!IsQuicSupported) + { + NativeLibrary.Free(msQuicHandle); + } } } @@ -128,7 +149,7 @@ private static bool IsWindowsVersionSupported() => OperatingSystem.IsWindowsVers private static bool IsTls13Disabled(bool isServer) { -#if TARGET_WINDOWS + #if TARGET_WINDOWS string SChannelTls13RegistryKey = isServer ? @"SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.3\Server" : @"SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.3\Client"; @@ -149,7 +170,7 @@ private static bool IsTls13Disabled(bool isServer) { return true; } -#endif + #endif return false; } } From 4fe8cb4b00a1cd78c74e6ab3dbc2ca711b89d245 Mon Sep 17 00:00:00 2001 From: Radek Zikmund Date: Thu, 21 Jul 2022 16:25:06 +0200 Subject: [PATCH 5/6] Minor formatting change --- .../src/System/Net/Quic/Internal/MsQuicApi.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libraries/System.Net.Quic/src/System/Net/Quic/Internal/MsQuicApi.cs b/src/libraries/System.Net.Quic/src/System/Net/Quic/Internal/MsQuicApi.cs index 342979388f65f..537ab5a1b2e97 100644 --- a/src/libraries/System.Net.Quic/src/System/Net/Quic/Internal/MsQuicApi.cs +++ b/src/libraries/System.Net.Quic/src/System/Net/Quic/Internal/MsQuicApi.cs @@ -130,7 +130,7 @@ static MsQuicApi() if (!IsQuicSupported && NativeLibrary.TryGetExport(msQuicHandle, "MsQuicClose", out IntPtr msQuicClose)) { // Gracefully close the API table - ((delegate*unmanaged[Cdecl])msQuicClose)(apiTable); + ((delegate* unmanaged[Cdecl])msQuicClose)(apiTable); } } @@ -149,7 +149,7 @@ private static bool IsWindowsVersionSupported() => OperatingSystem.IsWindowsVers private static bool IsTls13Disabled(bool isServer) { - #if TARGET_WINDOWS +#if TARGET_WINDOWS string SChannelTls13RegistryKey = isServer ? @"SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.3\Server" : @"SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.3\Client"; @@ -170,7 +170,7 @@ private static bool IsTls13Disabled(bool isServer) { return true; } - #endif +#endif return false; } } From 5a7d74390539f37198054c2da7cb1f8ac52bb8e7 Mon Sep 17 00:00:00 2001 From: Radek Zikmund <32671551+rzikm@users.noreply.github.com> Date: Thu, 21 Jul 2022 16:56:55 +0200 Subject: [PATCH 6/6] Update src/libraries/System.Net.Quic/src/System/Net/Quic/Internal/MsQuicApi.cs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Marie Píchová <11718369+ManickaP@users.noreply.github.com> --- .../System.Net.Quic/src/System/Net/Quic/Internal/MsQuicApi.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Net.Quic/src/System/Net/Quic/Internal/MsQuicApi.cs b/src/libraries/System.Net.Quic/src/System/Net/Quic/Internal/MsQuicApi.cs index 537ab5a1b2e97..2a6ceac8cacf1 100644 --- a/src/libraries/System.Net.Quic/src/System/Net/Quic/Internal/MsQuicApi.cs +++ b/src/libraries/System.Net.Quic/src/System/Net/Quic/Internal/MsQuicApi.cs @@ -99,7 +99,7 @@ static MsQuicApi() return; } - // Assume SChanel is being used on windows and query for the actual provider from the library + // Assume SChannel is being used on windows and query for the actual provider from the library QUIC_TLS_PROVIDER provider = OperatingSystem.IsWindows() ? QUIC_TLS_PROVIDER.SCHANNEL : QUIC_TLS_PROVIDER.OPENSSL; size = sizeof(QUIC_TLS_PROVIDER); apiTable->GetParam(null, QUIC_PARAM_GLOBAL_TLS_PROVIDER, &size, &provider);