Skip to content

Commit ed5aa3d

Browse files
rzikmManickaP
andauthored
[QUIC] Support for OpenSSL build of MsQuic on Windows (Attempt 2) (#72609)
* Initial OpenSSL MsQuic support * Don't check Windows version when OpenSSL is used * Update src/libraries/System.Net.Quic/src/System/Net/Quic/Internal/MsQuicApi.cs Co-authored-by: Marie Píchová <11718369+ManickaP@users.noreply.github.com> * Gracefully close the API handle before unloading the library * Minor formatting change * Update src/libraries/System.Net.Quic/src/System/Net/Quic/Internal/MsQuicApi.cs Co-authored-by: Marie Píchová <11718369+ManickaP@users.noreply.github.com> Co-authored-by: Marie Píchová <11718369+ManickaP@users.noreply.github.com>
1 parent cbe29e8 commit ed5aa3d

File tree

4 files changed

+70
-42
lines changed

4 files changed

+70
-42
lines changed

src/libraries/System.Net.Quic/src/System/Net/Quic/Internal/MsQuicApi.cs

Lines changed: 65 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -51,68 +51,96 @@ private MsQuicApi(QUIC_API_TABLE* apiTable)
5151

5252
internal static bool IsQuicSupported { get; }
5353

54+
internal static bool UsesSChannelBackend { get; }
55+
5456
internal static bool Tls13ServerMayBeDisabled { get; }
5557
internal static bool Tls13ClientMayBeDisabled { get; }
5658

5759
static MsQuicApi()
5860
{
59-
if (OperatingSystem.IsWindows())
61+
IntPtr msQuicHandle;
62+
if (!NativeLibrary.TryLoad($"{Interop.Libraries.MsQuic}.{MsQuicVersion.Major}", typeof(MsQuicApi).Assembly, DllImportSearchPath.AssemblyDirectory, out msQuicHandle) &&
63+
!NativeLibrary.TryLoad(Interop.Libraries.MsQuic, typeof(MsQuicApi).Assembly, DllImportSearchPath.AssemblyDirectory, out msQuicHandle))
6064
{
61-
if (!IsWindowsVersionSupported())
62-
{
63-
if (NetEventSource.Log.IsEnabled())
64-
{
65-
NetEventSource.Info(null, $"Current Windows version ({Environment.OSVersion}) is not supported by QUIC. Minimal supported version is {MinWindowsVersion}");
66-
}
65+
return;
66+
}
6767

68+
try
69+
{
70+
if (!NativeLibrary.TryGetExport(msQuicHandle, "MsQuicOpenVersion", out IntPtr msQuicOpenVersionAddress))
71+
{
6872
return;
6973
}
7074

71-
Tls13ServerMayBeDisabled = IsTls13Disabled(true);
72-
Tls13ClientMayBeDisabled = IsTls13Disabled(false);
73-
}
75+
QUIC_API_TABLE* apiTable = null;
76+
delegate* unmanaged[Cdecl]<uint, QUIC_API_TABLE**, int> msQuicOpenVersion = (delegate* unmanaged[Cdecl]<uint, QUIC_API_TABLE**, int>)msQuicOpenVersionAddress;
77+
if (StatusFailed(msQuicOpenVersion((uint)MsQuicVersion.Major, &apiTable)))
78+
{
79+
return;
80+
}
7481

75-
IntPtr msQuicHandle;
76-
if (NativeLibrary.TryLoad($"{Interop.Libraries.MsQuic}.{MsQuicVersion.Major}", typeof(MsQuicApi).Assembly, DllImportSearchPath.AssemblyDirectory, out msQuicHandle) ||
77-
NativeLibrary.TryLoad(Interop.Libraries.MsQuic, typeof(MsQuicApi).Assembly, DllImportSearchPath.AssemblyDirectory, out msQuicHandle))
78-
{
7982
try
8083
{
81-
if (NativeLibrary.TryGetExport(msQuicHandle, "MsQuicOpenVersion", out IntPtr msQuicOpenVersionAddress))
84+
int arraySize = 4;
85+
uint* libVersion = stackalloc uint[arraySize];
86+
uint size = (uint)arraySize * sizeof(uint);
87+
if (StatusFailed(apiTable->GetParam(null, QUIC_PARAM_GLOBAL_LIBRARY_VERSION, &size, libVersion)))
8288
{
83-
QUIC_API_TABLE* apiTable;
84-
delegate* unmanaged[Cdecl]<uint, QUIC_API_TABLE**, int> msQuicOpenVersion = (delegate* unmanaged[Cdecl]<uint, QUIC_API_TABLE**, int>)msQuicOpenVersionAddress;
85-
if (StatusSucceeded(msQuicOpenVersion((uint)MsQuicVersion.Major, &apiTable)))
89+
return;
90+
}
91+
92+
var version = new Version((int)libVersion[0], (int)libVersion[1], (int)libVersion[2], (int)libVersion[3]);
93+
if (version < MsQuicVersion)
94+
{
95+
if (NetEventSource.Log.IsEnabled())
96+
{
97+
NetEventSource.Info(null, $"Incompatible MsQuic library version '{version}', expecting '{MsQuicVersion}'");
98+
}
99+
return;
100+
}
101+
102+
// Assume SChannel is being used on windows and query for the actual provider from the library
103+
QUIC_TLS_PROVIDER provider = OperatingSystem.IsWindows() ? QUIC_TLS_PROVIDER.SCHANNEL : QUIC_TLS_PROVIDER.OPENSSL;
104+
size = sizeof(QUIC_TLS_PROVIDER);
105+
apiTable->GetParam(null, QUIC_PARAM_GLOBAL_TLS_PROVIDER, &size, &provider);
106+
UsesSChannelBackend = provider == QUIC_TLS_PROVIDER.SCHANNEL;
107+
108+
if (UsesSChannelBackend)
109+
{
110+
// Implies windows platform, check TLS1.3 availability
111+
if (!IsWindowsVersionSupported())
86112
{
87-
int arraySize = 4;
88-
uint* libVersion = stackalloc uint[arraySize];
89-
uint size = (uint)arraySize * sizeof(uint);
90-
if (StatusSucceeded(apiTable->GetParam(null, QUIC_PARAM_GLOBAL_LIBRARY_VERSION, &size, libVersion)))
113+
if (NetEventSource.Log.IsEnabled())
91114
{
92-
var version = new Version((int)libVersion[0], (int)libVersion[1], (int)libVersion[2], (int)libVersion[3]);
93-
if (version >= MsQuicVersion)
94-
{
95-
Api = new MsQuicApi(apiTable);
96-
IsQuicSupported = true;
97-
}
98-
else
99-
{
100-
if (NetEventSource.Log.IsEnabled())
101-
{
102-
NetEventSource.Info(null, $"Incompatible MsQuic library version '{version}', expecting '{MsQuicVersion}'");
103-
}
104-
}
115+
NetEventSource.Info(null, $"Current Windows version ({Environment.OSVersion}) is not supported by QUIC. Minimal supported version is {MinWindowsVersion}");
105116
}
117+
118+
return;
106119
}
120+
121+
Tls13ServerMayBeDisabled = IsTls13Disabled(isServer: true);
122+
Tls13ClientMayBeDisabled = IsTls13Disabled(isServer: false);
107123
}
124+
125+
Api = new MsQuicApi(apiTable);
126+
IsQuicSupported = true;
108127
}
109128
finally
110129
{
111-
if (!IsQuicSupported)
130+
if (!IsQuicSupported && NativeLibrary.TryGetExport(msQuicHandle, "MsQuicClose", out IntPtr msQuicClose))
112131
{
113-
NativeLibrary.Free(msQuicHandle);
132+
// Gracefully close the API table
133+
((delegate* unmanaged[Cdecl]<QUIC_API_TABLE*, void>)msQuicClose)(apiTable);
114134
}
115135
}
136+
137+
}
138+
finally
139+
{
140+
if (!IsQuicSupported)
141+
{
142+
NativeLibrary.Free(msQuicHandle);
143+
}
116144
}
117145
}
118146

src/libraries/System.Net.Quic/src/System/Net/Quic/Internal/MsQuicConfiguration.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ public static MsQuicSafeHandle Create(QuicClientConnectionOptions options)
2323
flags |= QUIC_CREDENTIAL_FLAGS.CLIENT;
2424
flags |= QUIC_CREDENTIAL_FLAGS.INDICATE_CERTIFICATE_RECEIVED;
2525
flags |= QUIC_CREDENTIAL_FLAGS.NO_CERTIFICATE_VALIDATION;
26-
if (OperatingSystem.IsWindows())
26+
if (MsQuicApi.UsesSChannelBackend)
2727
{
2828
flags |= QUIC_CREDENTIAL_FLAGS.USE_SUPPLIED_CREDENTIALS;
2929
}
@@ -145,7 +145,7 @@ private static unsafe MsQuicSafeHandle Create(QuicConnectionOptions options, QUI
145145
try
146146
{
147147
QUIC_CREDENTIAL_CONFIG config = new QUIC_CREDENTIAL_CONFIG { Flags = flags };
148-
config.Flags |= (OperatingSystem.IsWindows() ? QUIC_CREDENTIAL_FLAGS.NONE : QUIC_CREDENTIAL_FLAGS.USE_PORTABLE_CERTIFICATES);
148+
config.Flags |= (MsQuicApi.UsesSChannelBackend ? QUIC_CREDENTIAL_FLAGS.NONE : QUIC_CREDENTIAL_FLAGS.USE_PORTABLE_CERTIFICATES);
149149

150150
if (cipherSuitesPolicy != null)
151151
{
@@ -159,7 +159,7 @@ private static unsafe MsQuicSafeHandle Create(QuicConnectionOptions options, QUI
159159
config.Type = QUIC_CREDENTIAL_TYPE.NONE;
160160
status = MsQuicApi.Api.ApiTable->ConfigurationLoadCredential(configurationHandle.QuicHandle, &config);
161161
}
162-
else if (OperatingSystem.IsWindows())
162+
else if (MsQuicApi.UsesSChannelBackend)
163163
{
164164
config.Type = QUIC_CREDENTIAL_TYPE.CERTIFICATE_CONTEXT;
165165
config.CertificateContext = (void*)certificate.Handle;

src/libraries/System.Net.Quic/src/System/Net/Quic/QuicConnection.SslConnectionOptions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ public unsafe int ValidateCertificate(QUIC_BUFFER* certificatePtr, QUIC_BUFFER*
6969
chain.ChainPolicy.RevocationFlag = X509RevocationFlag.ExcludeRoot;
7070
chain.ChainPolicy.ApplicationPolicy.Add(_isClient ? s_serverAuthOid : s_clientAuthOid);
7171

72-
if (OperatingSystem.IsWindows())
72+
if (MsQuicApi.UsesSChannelBackend)
7373
{
7474
result = new X509Certificate2((IntPtr)certificatePtr);
7575
}

src/libraries/System.Net.Security/tests/FunctionalTests/TestHelper.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ internal static (X509Certificate2 certificate, X509Certificate2Collection) Gener
206206
if (PlatformDetection.IsWindows)
207207
{
208208
X509Certificate2 ephemeral = endEntity;
209-
endEntity = new X509Certificate2(endEntity.Export(X509ContentType.Pfx));
209+
endEntity = new X509Certificate2(endEntity.Export(X509ContentType.Pfx), (string?)null, X509KeyStorageFlags.Exportable);
210210
ephemeral.Dispose();
211211
}
212212

0 commit comments

Comments
 (0)