Skip to content

Commit

Permalink
[QUIC] Support for OpenSSL build of MsQuic on Windows (Attempt 2) (#7…
Browse files Browse the repository at this point in the history
…2609)

* 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>
  • Loading branch information
rzikm and ManickaP committed Jul 22, 2022
1 parent cbe29e8 commit ed5aa3d
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 42 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -51,68 +51,96 @@ 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; }

static MsQuicApi()
{
if (OperatingSystem.IsWindows())
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 (!IsWindowsVersionSupported())
{
if (NetEventSource.Log.IsEnabled())
{
NetEventSource.Info(null, $"Current Windows version ({Environment.OSVersion}) is not supported by QUIC. Minimal supported version is {MinWindowsVersion}");
}
return;
}

try
{
if (!NativeLibrary.TryGetExport(msQuicHandle, "MsQuicOpenVersion", out IntPtr msQuicOpenVersionAddress))
{
return;
}

Tls13ServerMayBeDisabled = IsTls13Disabled(true);
Tls13ClientMayBeDisabled = IsTls13Disabled(false);
}
QUIC_API_TABLE* apiTable = null;
delegate* unmanaged[Cdecl]<uint, QUIC_API_TABLE**, int> msQuicOpenVersion = (delegate* unmanaged[Cdecl]<uint, QUIC_API_TABLE**, int>)msQuicOpenVersionAddress;
if (StatusFailed(msQuicOpenVersion((uint)MsQuicVersion.Major, &apiTable)))
{
return;
}

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))
{
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)))
{
QUIC_API_TABLE* apiTable;
delegate* unmanaged[Cdecl]<uint, QUIC_API_TABLE**, int> msQuicOpenVersion = (delegate* unmanaged[Cdecl]<uint, QUIC_API_TABLE**, int>)msQuicOpenVersionAddress;
if (StatusSucceeded(msQuicOpenVersion((uint)MsQuicVersion.Major, &apiTable)))
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 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);
UsesSChannelBackend = provider == QUIC_TLS_PROVIDER.SCHANNEL;

if (UsesSChannelBackend)
{
// 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)
{
Api = new MsQuicApi(apiTable);
IsQuicSupported = true;
}
else
{
if (NetEventSource.Log.IsEnabled())
{
NetEventSource.Info(null, $"Incompatible MsQuic library version '{version}', expecting '{MsQuicVersion}'");
}
}
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]<QUIC_API_TABLE*, void>)msQuicClose)(apiTable);
}
}

}
finally
{
if (!IsQuicSupported)
{
NativeLibrary.Free(msQuicHandle);
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down Expand Up @@ -145,7 +145,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)
{
Expand All @@ -159,7 +159,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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,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)
{
result = new X509Certificate2((IntPtr)certificatePtr);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,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();
}

Expand Down

0 comments on commit ed5aa3d

Please sign in to comment.