diff --git a/src/Servers/HttpSys/src/RequestProcessing/Request.cs b/src/Servers/HttpSys/src/RequestProcessing/Request.cs index 9b1095515e93..0b9418cbcac6 100644 --- a/src/Servers/HttpSys/src/RequestProcessing/Request.cs +++ b/src/Servers/HttpSys/src/RequestProcessing/Request.cs @@ -343,41 +343,7 @@ private AspNetCore.HttpSys.Internal.SocketAddress LocalEndPoint private void GetTlsHandshakeResults() { var handshake = RequestContext.GetTlsHandshake(); - Protocol = handshake.Protocol; - // The OS considers client and server TLS as different enum values. SslProtocols choose to combine those for some reason. - // We need to fill in the client bits so the enum shows the expected protocol. - // https://learn.microsoft.com/windows/desktop/api/schannel/ns-schannel-_secpkgcontext_connectioninfo - // Compare to https://referencesource.microsoft.com/#System/net/System/Net/SecureProtocols/_SslState.cs,8905d1bf17729de3 -#pragma warning disable CS0618 // Type or member is obsolete - if ((Protocol & SslProtocols.Ssl2) != 0) - { - Protocol |= SslProtocols.Ssl2; - } - if ((Protocol & SslProtocols.Ssl3) != 0) - { - Protocol |= SslProtocols.Ssl3; - } -#pragma warning restore CS0618 // Type or Prmember is obsolete -#pragma warning disable SYSLIB0039 // TLS 1.0 and 1.1 are obsolete - if ((Protocol & SslProtocols.Tls) != 0) - { - Protocol |= SslProtocols.Tls; - } - if ((Protocol & SslProtocols.Tls11) != 0) - { - Protocol |= SslProtocols.Tls11; - } -#pragma warning restore SYSLIB0039 - if ((Protocol & SslProtocols.Tls12) != 0) - { - Protocol |= SslProtocols.Tls12; - } - if ((Protocol & SslProtocols.Tls13) != 0) - { - Protocol |= SslProtocols.Tls13; - } - CipherAlgorithm = handshake.CipherType; CipherStrength = (int)handshake.CipherStrength; HashAlgorithm = handshake.HashType; diff --git a/src/Servers/IIS/AspNetCoreModuleV2/InProcessRequestHandler/managedexports.cpp b/src/Servers/IIS/AspNetCoreModuleV2/InProcessRequestHandler/managedexports.cpp index b2a907be48a3..23639860527a 100644 --- a/src/Servers/IIS/AspNetCoreModuleV2/InProcessRequestHandler/managedexports.cpp +++ b/src/Servers/IIS/AspNetCoreModuleV2/InProcessRequestHandler/managedexports.cpp @@ -611,4 +611,35 @@ http_response_set_need_goaway( pHttpResponse->SetNeedGoAway(); return 0; } + +EXTERN_C __declspec(dllexport) +HRESULT +http_query_request_property( + _In_ HTTP_OPAQUE_ID requestId, + _In_ HTTP_REQUEST_PROPERTY propertyId, + _In_reads_bytes_opt_(qualifierSize) PVOID pQualifier, + _In_ ULONG qualifierSize, + _Out_writes_bytes_to_opt_(outputBufferSize, *pcbBytesReturned) PVOID pOutput, + _In_ ULONG outputBufferSize, + _Out_opt_ PULONG pcbBytesReturned, + _In_ LPOVERLAPPED pOverlapped +) +{ + IHttpServer3* httpServer3; + HRESULT hr = HttpGetExtendedInterface(g_pHttpServer, g_pHttpServer, &httpServer3); + if (FAILED(hr)) + { + return hr; + } + + return httpServer3->QueryRequestProperty( + requestId, + propertyId, + pQualifier, + qualifierSize, + pOutput, + outputBufferSize, + pcbBytesReturned, + pOverlapped); +} // End of export diff --git a/src/Servers/IIS/IIS/src/Core/IISHttpContext.FeatureCollection.cs b/src/Servers/IIS/IIS/src/Core/IISHttpContext.FeatureCollection.cs index 73541e57ac2e..de2244c7176f 100644 --- a/src/Servers/IIS/IIS/src/Core/IISHttpContext.FeatureCollection.cs +++ b/src/Servers/IIS/IIS/src/Core/IISHttpContext.FeatureCollection.cs @@ -4,7 +4,9 @@ using System.Collections; using System.Diagnostics; using System.IO.Pipelines; +using System.Net.Security; using System.Runtime.InteropServices; +using System.Security.Authentication; using System.Security.Claims; using System.Security.Cryptography.X509Certificates; using Microsoft.AspNetCore.Connections.Features; @@ -28,6 +30,7 @@ internal partial class IISHttpContext : IFeatureCollection, IHttpAuthenticationFeature, IServerVariablesFeature, ITlsConnectionFeature, + ITlsHandshakeFeature, IHttpBodyControlFeature, IHttpMaxRequestBodySizeFeature, IHttpResponseTrailersFeature, @@ -406,6 +409,24 @@ unsafe X509Certificate2? ITlsConnectionFeature.ClientCertificate } } + SslProtocols ITlsHandshakeFeature.Protocol => Protocol; + + TlsCipherSuite? ITlsHandshakeFeature.NegotiatedCipherSuite => NegotiatedCipherSuite; + + string ITlsHandshakeFeature.HostName => SniHostName; + + CipherAlgorithmType ITlsHandshakeFeature.CipherAlgorithm => CipherAlgorithm; + + int ITlsHandshakeFeature.CipherStrength => CipherStrength; + + HashAlgorithmType ITlsHandshakeFeature.HashAlgorithm => HashAlgorithm; + + int ITlsHandshakeFeature.HashStrength => HashStrength; + + ExchangeAlgorithmType ITlsHandshakeFeature.KeyExchangeAlgorithm => KeyExchangeAlgorithm; + + int ITlsHandshakeFeature.KeyExchangeStrength => KeyExchangeStrength; + IEnumerator> IEnumerable>.GetEnumerator() => FastEnumerable().GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => FastEnumerable().GetEnumerator(); @@ -446,6 +467,11 @@ unsafe X509Certificate2? ITlsConnectionFeature.ClientCertificate return AdvancedHttp2FeaturesSupported() ? this : null; } + internal ITlsHandshakeFeature? GetTlsHandshakeFeature() + { + return IsHttps ? this : null; + } + IHeaderDictionary IHttpResponseTrailersFeature.Trailers { get => ResponseTrailers ??= HttpResponseTrailers; diff --git a/src/Servers/IIS/IIS/src/Core/IISHttpContext.Features.cs b/src/Servers/IIS/IIS/src/Core/IISHttpContext.Features.cs index 4d6623126ca8..6bce10267386 100644 --- a/src/Servers/IIS/IIS/src/Core/IISHttpContext.Features.cs +++ b/src/Servers/IIS/IIS/src/Core/IISHttpContext.Features.cs @@ -20,6 +20,7 @@ internal partial class IISHttpContext private static readonly Type IResponseCookiesFeatureType = typeof(global::Microsoft.AspNetCore.Http.Features.IResponseCookiesFeature); private static readonly Type IItemsFeatureType = typeof(global::Microsoft.AspNetCore.Http.Features.IItemsFeature); private static readonly Type ITlsConnectionFeatureType = typeof(global::Microsoft.AspNetCore.Http.Features.ITlsConnectionFeature); + private static readonly Type ITlsHandshakeFeatureType = typeof(global::Microsoft.AspNetCore.Connections.Features.ITlsHandshakeFeature); private static readonly Type IHttpWebSocketFeatureType = typeof(global::Microsoft.AspNetCore.Http.Features.IHttpWebSocketFeature); private static readonly Type ISessionFeatureType = typeof(global::Microsoft.AspNetCore.Http.Features.ISessionFeature); private static readonly Type IHttpBodyControlFeatureType = typeof(global::Microsoft.AspNetCore.Http.Features.IHttpBodyControlFeature); @@ -48,6 +49,7 @@ internal partial class IISHttpContext private object? _currentIResponseCookiesFeature; private object? _currentIItemsFeature; private object? _currentITlsConnectionFeature; + private object? _currentITlsHandshakeFeature; private object? _currentIHttpWebSocketFeature; private object? _currentISessionFeature; private object? _currentIHttpBodyControlFeature; @@ -75,6 +77,7 @@ private void Initialize() _currentIServerVariablesFeature = this; _currentIHttpMaxRequestBodySizeFeature = this; _currentITlsConnectionFeature = this; + _currentITlsHandshakeFeature = GetTlsHandshakeFeature(); _currentIHttpResponseTrailersFeature = GetResponseTrailersFeature(); _currentIHttpResetFeature = GetResetFeature(); _currentIConnectionLifetimeNotificationFeature = this; @@ -146,6 +149,10 @@ private void Initialize() { return _currentITlsConnectionFeature; } + if (key == ITlsHandshakeFeatureType) + { + return _currentITlsHandshakeFeature; + } if (key == IHttpWebSocketFeatureType) { return _currentIHttpWebSocketFeature; @@ -277,6 +284,11 @@ internal void FastFeatureSet(Type key, object? feature) _currentITlsConnectionFeature = feature; return; } + if (key == ITlsHandshakeFeatureType) + { + _currentITlsHandshakeFeature = feature; + return; + } if (key == IHttpWebSocketFeatureType) { _currentIHttpWebSocketFeature = feature; @@ -400,6 +412,10 @@ private IEnumerable> FastEnumerable() { yield return new KeyValuePair(ITlsConnectionFeatureType, _currentITlsConnectionFeature); } + if (_currentITlsHandshakeFeature != null) + { + yield return new KeyValuePair(ITlsHandshakeFeatureType, _currentITlsHandshakeFeature); + } if (_currentIHttpWebSocketFeature != null) { yield return new KeyValuePair(IHttpWebSocketFeatureType, _currentIHttpWebSocketFeature); diff --git a/src/Servers/IIS/IIS/src/Core/IISHttpContext.cs b/src/Servers/IIS/IIS/src/Core/IISHttpContext.cs index a8a7c034d5c0..5eff74efd87c 100644 --- a/src/Servers/IIS/IIS/src/Core/IISHttpContext.cs +++ b/src/Servers/IIS/IIS/src/Core/IISHttpContext.cs @@ -6,7 +6,9 @@ using System.Diagnostics.CodeAnalysis; using System.IO.Pipelines; using System.Net; +using System.Net.Security; using System.Runtime.InteropServices; +using System.Security.Authentication; using System.Security.Claims; using System.Security.Principal; using System.Text; @@ -88,6 +90,7 @@ internal unsafe IISHttpContext( private int PauseWriterThreshold => _options.MaxRequestBodyBufferSize; private int ResumeWriterTheshold => PauseWriterThreshold / 2; + private bool IsHttps => SslStatus != SslStatus.Insecure; public Version HttpVersion { get; set; } = default!; public string Scheme { get; set; } = default!; @@ -111,6 +114,16 @@ internal unsafe IISHttpContext( public Stream ResponseBody { get; set; } = default!; public PipeWriter? ResponsePipeWrapper { get; set; } + public SslProtocols Protocol { get; private set; } + public TlsCipherSuite? NegotiatedCipherSuite { get; private set; } + public string SniHostName { get; private set; } = default!; + public CipherAlgorithmType CipherAlgorithm { get; private set; } + public int CipherStrength { get; private set; } + public HashAlgorithmType HashAlgorithm { get; private set; } + public int HashStrength { get; private set; } + public ExchangeAlgorithmType KeyExchangeAlgorithm { get; private set; } + public int KeyExchangeStrength { get; private set; } + protected IAsyncIOEngine? AsyncIO { get; set; } public IHeaderDictionary RequestHeaders { get; set; } = default!; @@ -139,7 +152,7 @@ protected void InitializeContext() RawTarget = GetRawUrl() ?? string.Empty; // TODO version is slow. HttpVersion = GetVersion(); - Scheme = SslStatus != SslStatus.Insecure ? Constants.HttpsScheme : Constants.HttpScheme; + Scheme = IsHttps ? Constants.HttpsScheme : Constants.HttpScheme; KnownMethod = VerbId; StatusCode = 200; @@ -253,6 +266,12 @@ protected void InitializeContext() // Request headers can be modified by the app, read these first. RequestCanHaveBody = CheckRequestCanHaveBody(); + SniHostName = string.Empty; + if (IsHttps) + { + GetTlsHandshakeResults(); + } + if (_options.ForwardWindowsAuthentication) { WindowsUser = GetWindowsPrincipal(); @@ -371,6 +390,40 @@ private bool CheckRequestCanHaveBody() return RequestHeaders.ContentLength.GetValueOrDefault() > 0; } + private void GetTlsHandshakeResults() + { + var handshake = this.GetTlsHandshake(); + Protocol = handshake.Protocol; + CipherAlgorithm = handshake.CipherType; + CipherStrength = (int)handshake.CipherStrength; + HashAlgorithm = handshake.HashType; + HashStrength = (int)handshake.HashStrength; + KeyExchangeAlgorithm = handshake.KeyExchangeType; + KeyExchangeStrength = (int)handshake.KeyExchangeStrength; + + var sni = GetClientSni(); + SniHostName = sni.Hostname; + } + + private unsafe HttpApiTypes.HTTP_REQUEST_PROPERTY_SNI GetClientSni() + { + var buffer = new byte[HttpApiTypes.SniPropertySizeInBytes]; + fixed (byte* pBuffer = buffer) + { + var statusCode = NativeMethods.HttpQueryRequestProperty( + RequestId, + HttpApiTypes.HTTP_REQUEST_PROPERTY.HttpRequestPropertySni, + qualifier: null, + qualifierSize: 0, + (void*)pBuffer, + (uint)buffer.Length, + bytesReturned: null, + IntPtr.Zero); + + return statusCode == NativeMethods.HR_OK ? Marshal.PtrToStructure((IntPtr)pBuffer) : default; + } + } + private async Task InitializeResponse(bool flushHeaders) { await FireOnStarting(); diff --git a/src/Servers/IIS/IIS/src/NativeMethods.cs b/src/Servers/IIS/IIS/src/NativeMethods.cs index 79ed2bf696a2..9d25ce793c03 100644 --- a/src/Servers/IIS/IIS/src/NativeMethods.cs +++ b/src/Servers/IIS/IIS/src/NativeMethods.cs @@ -90,6 +90,17 @@ private static unsafe partial int register_callbacks(NativeSafeHandle pInProcess [LibraryImport(AspNetCoreModuleDll)] private static partial int http_get_application_properties(out IISConfigurationData iiConfigData); + [LibraryImport(AspNetCoreModuleDll)] + private static unsafe partial int http_query_request_property( + ulong requestId, + HttpApiTypes.HTTP_REQUEST_PROPERTY propertyId, + void* qualifier, + uint qualifierSize, + void* output, + uint outputSize, + uint* bytesReturned, + IntPtr overlapped); + [LibraryImport(AspNetCoreModuleDll)] private static partial int http_get_server_variable( NativeSafeHandle pInProcessHandler, @@ -231,6 +242,11 @@ internal static IISConfigurationData HttpGetApplicationProperties() return iisConfigurationData; } + public static unsafe int HttpQueryRequestProperty(ulong requestId, HttpApiTypes.HTTP_REQUEST_PROPERTY propertyId, void* qualifier, uint qualifierSize, void* output, uint outputSize, uint* bytesReturned, IntPtr overlapped) + { + return http_query_request_property(requestId, propertyId, qualifier, qualifierSize, output, outputSize, bytesReturned, overlapped); + } + public static bool HttpTryGetServerVariable(NativeSafeHandle pInProcessHandler, string variableName, out string value) { return http_get_server_variable(pInProcessHandler, variableName, out value) == 0; diff --git a/src/Servers/IIS/IIS/test/IIS.Tests/TlsHandshakeFeatureTests.cs b/src/Servers/IIS/IIS/test/IIS.Tests/TlsHandshakeFeatureTests.cs new file mode 100644 index 000000000000..c3a2077ea59a --- /dev/null +++ b/src/Servers/IIS/IIS/test/IIS.Tests/TlsHandshakeFeatureTests.cs @@ -0,0 +1,75 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Security.Authentication; +using Microsoft.AspNetCore.Connections.Features; +using Microsoft.AspNetCore.Testing; +using Xunit; + +namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests; + +[SkipIfHostableWebCoreNotAvailable] +[MinimumOSVersion(OperatingSystems.Windows, WindowsVersions.Win8, SkipReason = "https://github.com/aspnet/IISIntegration/issues/866")] +[SkipOnHelix("Unsupported queue", Queues = "Windows.Amd64.VS2022.Pre.Open;")] +public class TlsHandshakeFeatureTests : StrictTestServerTests +{ + [ConditionalFact] + public async Task SetsTlsHandshakeFeatureForHttps() + { + ITlsHandshakeFeature tlsHandshakeFeature = null; + using (var testServer = await TestServer.CreateHttps(ctx => + { + tlsHandshakeFeature = ctx.Features.Get(); + return Task.CompletedTask; + }, LoggerFactory)) + { + await testServer.HttpClient.GetStringAsync("/"); + } + + Assert.NotNull(tlsHandshakeFeature); + + var protocol = tlsHandshakeFeature.Protocol; + Assert.True(protocol > SslProtocols.None, "Protocol: " + protocol); + Assert.True(Enum.IsDefined(typeof(SslProtocols), protocol), "Defined: " + protocol); // Mapping is required, make sure it's current + + var cipherAlgorithm = tlsHandshakeFeature.CipherAlgorithm; + Assert.True(cipherAlgorithm > CipherAlgorithmType.Null, "Cipher: " + cipherAlgorithm); + + var cipherStrength = tlsHandshakeFeature.CipherStrength; + Assert.True(cipherStrength > 0, "CipherStrength: " + cipherStrength); + + var hashAlgorithm = tlsHandshakeFeature.HashAlgorithm; + Assert.True(hashAlgorithm >= HashAlgorithmType.None, "HashAlgorithm: " + hashAlgorithm); + + var hashStrength = tlsHandshakeFeature.HashStrength; + Assert.True(hashStrength >= 0, "HashStrength: " + hashStrength); // May be 0 for some algorithms + + var keyExchangeAlgorithm = tlsHandshakeFeature.KeyExchangeAlgorithm; + Assert.True(keyExchangeAlgorithm >= ExchangeAlgorithmType.None, "KeyExchangeAlgorithm: " + keyExchangeAlgorithm); + + var keyExchangeStrength = tlsHandshakeFeature.KeyExchangeStrength; + Assert.True(keyExchangeStrength >= 0, "KeyExchangeStrength: " + keyExchangeStrength); + + if (Environment.OSVersion.Version > new Version(10, 0, 19043, 0)) + { + var hostName = tlsHandshakeFeature.HostName; + Assert.Equal("localhost", hostName); + } + } + + [ConditionalFact] + public async Task DoesNotSetTlsHandshakeFeatureForHttp() + { + ITlsHandshakeFeature tlsHandshakeFeature = null; + using (var testServer = await TestServer.Create(ctx => + { + tlsHandshakeFeature = ctx.Features.Get(); + return Task.CompletedTask; + }, LoggerFactory)) + { + await testServer.HttpClient.GetStringAsync("/"); + } + + Assert.Null(tlsHandshakeFeature); + } +} diff --git a/src/Servers/IIS/IIS/test/IIS.Tests/Utilities/TestServer.cs b/src/Servers/IIS/IIS/test/IIS.Tests/Utilities/TestServer.cs index 1d3be52275cd..f5d42a0013ce 100644 --- a/src/Servers/IIS/IIS/test/IIS.Tests/Utilities/TestServer.cs +++ b/src/Servers/IIS/IIS/test/IIS.Tests/Utilities/TestServer.cs @@ -45,8 +45,10 @@ public partial class TestServer : IDisposable private readonly Action _appBuilder; private readonly ILoggerFactory _loggerFactory; private readonly hostfxr_main_fn _hostfxrMainFn; + private readonly bool _isHttps; + private readonly string _protocol; - private Uri BaseUri => new Uri("http://localhost:" + _currentPort); + private Uri BaseUri => new Uri(_protocol + "://localhost:" + _currentPort); public HttpClient HttpClient { get; private set; } public TestConnection CreateConnection() => new TestConnection(_currentPort); @@ -56,18 +58,20 @@ public partial class TestServer : IDisposable private string _appHostConfigPath; private int _currentPort; - private TestServer(Action appBuilder, ILoggerFactory loggerFactory) + private TestServer(Action appBuilder, ILoggerFactory loggerFactory, bool isHttps) { _hostfxrMainFn = Main; _appBuilder = appBuilder; _loggerFactory = loggerFactory; + _isHttps = isHttps; + _protocol = isHttps ? "https" : "http"; } - public static async Task Create(Action appBuilder, ILoggerFactory loggerFactory, IISServerOptions options) + public static async Task Create(Action appBuilder, ILoggerFactory loggerFactory, IISServerOptions options, bool isHttps = false) { await WebCoreLock.WaitAsync(); _options = options; - var server = new TestServer(appBuilder, loggerFactory); + var server = new TestServer(appBuilder, loggerFactory, isHttps); server.Start(); (await server.HttpClient.GetAsync("/start")).EnsureSuccessStatusCode(); await server._startedTaskCompletionSource.Task; @@ -84,6 +88,11 @@ public static Task Create(RequestDelegate app, ILoggerFactory logger return Create(builder => builder.Run(app), loggerFactory, options); } + public static Task CreateHttps(RequestDelegate app, ILoggerFactory loggerFactory) + { + return Create(builder => builder.Run(app), loggerFactory, new IISServerOptions(), isHttps: true); + } + private void Start() { LoadLibrary(HostableWebCoreLocation); @@ -93,7 +102,7 @@ private void Start() Retry(() => { - _currentPort = TestPortHelper.GetNextPort(); + _currentPort = _isHttps ? TestPortHelper.GetNextSSLPort() : TestPortHelper.GetNextPort(); InitializeConfig(_currentPort); @@ -122,10 +131,12 @@ private void InitializeConfig(int port) .RequiredElement("sites") .RequiredElement("site"); - siteElement + var binding = siteElement .RequiredElement("bindings") - .RequiredElement("binding") - .SetAttributeValue("bindingInformation", $":{port}:localhost"); + .RequiredElement("binding"); + + binding.SetAttributeValue("protocol", _protocol); + binding.SetAttributeValue("bindingInformation", $":{port}:localhost"); webHostConfig.Save(_appHostConfigPath); } diff --git a/src/Shared/HttpSys/RequestProcessing/NativeRequestContext.cs b/src/Shared/HttpSys/RequestProcessing/NativeRequestContext.cs index e6741aea8926..dc78c7ee5cc0 100644 --- a/src/Shared/HttpSys/RequestProcessing/NativeRequestContext.cs +++ b/src/Shared/HttpSys/RequestProcessing/NativeRequestContext.cs @@ -10,6 +10,7 @@ using System.Net.Sockets; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using System.Security.Authentication; using System.Security.Cryptography.X509Certificates; using System.Security.Principal; using Microsoft.AspNetCore.Server.HttpSys; @@ -340,14 +341,54 @@ internal HttpApiTypes.HTTP_SSL_PROTOCOL_INFO GetTlsHandshake() if (info != null && info->InfoType == HttpApiTypes.HTTP_REQUEST_INFO_TYPE.HttpRequestInfoTypeSslProtocol) { - var authInfo = (HttpApiTypes.HTTP_SSL_PROTOCOL_INFO*)info->pInfo; - return *authInfo; + var authInfo = *((HttpApiTypes.HTTP_SSL_PROTOCOL_INFO*)info->pInfo); + SetSslProtocol(&authInfo); + return authInfo; } } return default; } + private static void SetSslProtocol(HttpApiTypes.HTTP_SSL_PROTOCOL_INFO* protocolInfo) + { + var protocol = protocolInfo->Protocol; + // The OS considers client and server TLS as different enum values. SslProtocols choose to combine those for some reason. + // We need to fill in the client bits so the enum shows the expected protocol. + // https://learn.microsoft.com/windows/desktop/api/schannel/ns-schannel-_secpkgcontext_connectioninfo + // Compare to https://referencesource.microsoft.com/#System/net/System/Net/SecureProtocols/_SslState.cs,8905d1bf17729de3 +#pragma warning disable CS0618 // Type or member is obsolete + if ((protocol & SslProtocols.Ssl2) != 0) + { + protocol |= SslProtocols.Ssl2; + } + if ((protocol & SslProtocols.Ssl3) != 0) + { + protocol |= SslProtocols.Ssl3; + } +#pragma warning restore CS0618 // Type or Prmember is obsolete +#pragma warning disable SYSLIB0039 // TLS 1.0 and 1.1 are obsolete + if ((protocol & SslProtocols.Tls) != 0) + { + protocol |= SslProtocols.Tls; + } + if ((protocol & SslProtocols.Tls11) != 0) + { + protocol |= SslProtocols.Tls11; + } +#pragma warning restore SYSLIB0039 + if ((protocol & SslProtocols.Tls12) != 0) + { + protocol |= SslProtocols.Tls12; + } + if ((protocol & SslProtocols.Tls13) != 0) + { + protocol |= SslProtocols.Tls13; + } + + protocolInfo->Protocol = protocol; + } + private static string GetAuthTypeFromRequest(HttpApiTypes.HTTP_REQUEST_AUTH_TYPE input) { switch (input)