- Notifications
You must be signed in to change notification settings - Fork10.5k
fetch TLS client hello message from HTTP.SYS#61494
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
Merged
Uh oh!
There was an error while loading.Please reload this page.
Merged
Changes from23 commits
Commits
Show all changes
24 commits Select commitHold shift + click to select a range
757457a setup for tls clinet hello exposure
DeagleGrossa376c94 correctly retry access
DeagleGross9c5fc17 last minute changes
DeagleGrosse8834a2 fix warnings
DeagleGrossc953a21 hook up tls client hello callback
DeagleGross6c5239d fix warnings & publish API
DeagleGrossff9518c minimal
DeagleGrossde70b16 only go via callback if options has callback set; remove unused
DeagleGross1441e30 PR review
DeagleGross56704ef address PR comments x1
DeagleGrossd43b424 TTL & evict approach
DeagleGross6275c30 address comments 1
DeagleGrossc58805b periodic timer
DeagleGross25d4955 address comments x3
DeagleGrossb12f515 TryAdd
DeagleGross7a39916 make a static field (just in case)
DeagleGross4f85d5f Cache updates
BrennanConroy53721d7 test
BrennanConroy9b012c3 whitespace
BrennanConroya801563 clear array
BrennanConroy03c0cfb appcontext
BrennanConroy370d39c fb
BrennanConroyabd38ff bp changes
BrennanConroy909128b Update src/Servers/HttpSys/src/RequestProcessing/RequestContext.cs
BrennanConroyFile filter
Filter by extension
Conversations
Failed to load comments.
Loading
Uh oh!
There was an error while loading.Please reload this page.
Jump to
Jump to file
Failed to load files.
Loading
Uh oh!
There was an error while loading.Please reload this page.
Diff view
Diff view
There are no files selected for viewing
19 changes: 19 additions & 0 deletionsAspNetCore.sln
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.Learn more about bidirectional Unicode characters
123 changes: 123 additions & 0 deletionssrc/Servers/HttpSys/samples/TlsFeaturesObserve/HttpSys/HttpSysConfigurator.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,123 @@ | ||
| // Licensed to the .NET Foundation under one or more agreements. | ||
| // The .NET Foundation licenses this file to you under the MIT license. | ||
| using System.Net; | ||
| using System.Runtime.InteropServices; | ||
| namespace TlsFeaturesObserve.HttpSys; | ||
| internal static class HttpSysConfigurator | ||
| { | ||
| const uint HTTP_INITIALIZE_CONFIG = 0x00000002; | ||
| const uint ERROR_ALREADY_EXISTS = 183; | ||
| static readonly HTTPAPI_VERSION HttpApiVersion = new HTTPAPI_VERSION(1, 0); | ||
| internal static void ConfigureCacheTlsClientHello() | ||
| { | ||
| // Arbitrarily chosen port, but must match the port used in the web server. Via UrlPrefixes or launchsettings. | ||
| var ipPort = new IPEndPoint(new IPAddress([0, 0, 0, 0]), 6000); | ||
| var certThumbprint = "" /* your cert thumbprint here */; | ||
| var appId = Guid.NewGuid(); | ||
| var sslCertStoreName = "My"; | ||
| CallHttpApi(() => SetConfiguration(ipPort, certThumbprint, appId, sslCertStoreName)); | ||
| } | ||
| static void SetConfiguration(IPEndPoint ipPort, string certThumbprint, Guid appId, string sslCertStoreName) | ||
| { | ||
| var sockAddrHandle = CreateSockaddrStructure(ipPort); | ||
| var pIpPort = sockAddrHandle.AddrOfPinnedObject(); | ||
| var httpServiceConfigSslKey = new HTTP_SERVICE_CONFIG_SSL_KEY(pIpPort); | ||
| var hash = GetHash(certThumbprint); | ||
| var handleHash = GCHandle.Alloc(hash, GCHandleType.Pinned); | ||
| var configSslParam = new HTTP_SERVICE_CONFIG_SSL_PARAM | ||
| { | ||
| AppId = appId, | ||
| DefaultFlags = 0x00008000 /* HTTP_SERVICE_CONFIG_SSL_FLAG_ENABLE_CACHE_CLIENT_HELLO */, | ||
| DefaultRevocationFreshnessTime = 0, | ||
| DefaultRevocationUrlRetrievalTimeout = 15, | ||
| pSslCertStoreName = sslCertStoreName, | ||
| pSslHash = handleHash.AddrOfPinnedObject(), | ||
| SslHashLength = hash.Length, | ||
| pDefaultSslCtlIdentifier = null, | ||
| pDefaultSslCtlStoreName = sslCertStoreName | ||
| }; | ||
| var configSslSet = new HTTP_SERVICE_CONFIG_SSL_SET | ||
| { | ||
| ParamDesc = configSslParam, | ||
| KeyDesc = httpServiceConfigSslKey | ||
| }; | ||
| var pInputConfigInfo = Marshal.AllocCoTaskMem( | ||
| Marshal.SizeOf(typeof(HTTP_SERVICE_CONFIG_SSL_SET))); | ||
| Marshal.StructureToPtr(configSslSet, pInputConfigInfo, false); | ||
| var status = HttpSetServiceConfiguration(nint.Zero, | ||
| HTTP_SERVICE_CONFIG_ID.HttpServiceConfigSSLCertInfo, | ||
| pInputConfigInfo, | ||
| Marshal.SizeOf(configSslSet), | ||
| nint.Zero); | ||
| if (status == ERROR_ALREADY_EXISTS || status == 0) // already present or success | ||
| { | ||
| Console.WriteLine($"HttpServiceConfiguration is correct"); | ||
| } | ||
| else | ||
| { | ||
| Console.WriteLine("Failed to HttpSetServiceConfiguration: " + status); | ||
| } | ||
| } | ||
| static byte[] GetHash(string thumbprint) | ||
| { | ||
| var length = thumbprint.Length; | ||
| var bytes = new byte[length / 2]; | ||
| for (var i = 0; i < length; i += 2) | ||
| { | ||
| bytes[i / 2] = Convert.ToByte(thumbprint.Substring(i, 2), 16); | ||
| } | ||
| return bytes; | ||
| } | ||
| static GCHandle CreateSockaddrStructure(IPEndPoint ipEndPoint) | ||
| { | ||
| var socketAddress = ipEndPoint.Serialize(); | ||
| // use an array of bytes instead of the sockaddr structure | ||
| var sockAddrStructureBytes = new byte[socketAddress.Size]; | ||
| var sockAddrHandle = GCHandle.Alloc(sockAddrStructureBytes, GCHandleType.Pinned); | ||
| for (var i = 0; i < socketAddress.Size; ++i) | ||
| { | ||
| sockAddrStructureBytes[i] = socketAddress[i]; | ||
| } | ||
| return sockAddrHandle; | ||
| } | ||
| static void CallHttpApi(Action body) | ||
| { | ||
| const uint flags = HTTP_INITIALIZE_CONFIG; | ||
| var retVal = HttpInitialize(HttpApiVersion, flags, IntPtr.Zero); | ||
| body(); | ||
| } | ||
| // disabled warning since it is just a sample | ||
| #pragma warning disable SYSLIB1054 // Use 'LibraryImportAttribute' instead of 'DllImportAttribute' to generate P/Invoke marshalling code at compile time | ||
| [DllImport("httpapi.dll", SetLastError = true)] | ||
| private static extern uint HttpInitialize( | ||
| HTTPAPI_VERSION version, | ||
| uint flags, | ||
| IntPtr pReserved); | ||
| [DllImport("httpapi.dll", SetLastError = true)] | ||
| public static extern uint HttpSetServiceConfiguration( | ||
| nint serviceIntPtr, | ||
| HTTP_SERVICE_CONFIG_ID configId, | ||
| nint pConfigInformation, | ||
| int configInformationLength, | ||
| nint pOverlapped); | ||
| #pragma warning restore SYSLIB1054 // Use 'LibraryImportAttribute' instead of 'DllImportAttribute' to generate P/Invoke marshalling code at compile time | ||
| } |
97 changes: 97 additions & 0 deletionssrc/Servers/HttpSys/samples/TlsFeaturesObserve/HttpSys/Native.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,97 @@ | ||
| // Licensed to the .NET Foundation under one or more agreements. | ||
| // The .NET Foundation licenses this file to you under the MIT license. | ||
| using System; | ||
| using System.Collections.Generic; | ||
| using System.Runtime.InteropServices; | ||
| using System.Text; | ||
| namespace TlsFeaturesObserve.HttpSys; | ||
| // Http.Sys types from https://learn.microsoft.com/windows/win32/api/http/ | ||
| [StructLayout(LayoutKind.Sequential, Pack = 2)] | ||
| public struct HTTPAPI_VERSION | ||
| { | ||
| public ushort HttpApiMajorVersion; | ||
| public ushort HttpApiMinorVersion; | ||
| public HTTPAPI_VERSION(ushort majorVersion, ushort minorVersion) | ||
| { | ||
| HttpApiMajorVersion = majorVersion; | ||
| HttpApiMinorVersion = minorVersion; | ||
| } | ||
| } | ||
| public enum HTTP_SERVICE_CONFIG_ID | ||
| { | ||
| HttpServiceConfigIPListenList = 0, | ||
| HttpServiceConfigSSLCertInfo, | ||
| HttpServiceConfigUrlAclInfo, | ||
| HttpServiceConfigMax | ||
| } | ||
| [StructLayout(LayoutKind.Sequential)] | ||
| public struct HTTP_SERVICE_CONFIG_SSL_SET | ||
| { | ||
| public HTTP_SERVICE_CONFIG_SSL_KEY KeyDesc; | ||
| public HTTP_SERVICE_CONFIG_SSL_PARAM ParamDesc; | ||
| } | ||
| [StructLayout(LayoutKind.Sequential)] | ||
| public struct HTTP_SERVICE_CONFIG_SSL_KEY | ||
| { | ||
| public IntPtr pIpPort; | ||
| public HTTP_SERVICE_CONFIG_SSL_KEY(IntPtr pIpPort) | ||
| { | ||
| this.pIpPort = pIpPort; | ||
| } | ||
| } | ||
| [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] | ||
| public struct HTTP_SERVICE_CONFIG_SSL_PARAM | ||
| { | ||
| public int SslHashLength; | ||
| public IntPtr pSslHash; | ||
| public Guid AppId; | ||
| [MarshalAs(UnmanagedType.LPWStr)] | ||
| public string pSslCertStoreName; | ||
| public CertCheckModes DefaultCertCheckMode; | ||
| public int DefaultRevocationFreshnessTime; | ||
| public int DefaultRevocationUrlRetrievalTimeout; | ||
| [MarshalAs(UnmanagedType.LPWStr)] | ||
| public string pDefaultSslCtlIdentifier; | ||
| [MarshalAs(UnmanagedType.LPWStr)] | ||
| public string pDefaultSslCtlStoreName; | ||
| public uint DefaultFlags; // HTTP_SERVICE_CONFIG_SSL_FLAG | ||
| } | ||
| [Flags] | ||
| public enum CertCheckModes : uint | ||
| { | ||
| /// <summary> | ||
| /// Enables the client certificate revocation check. | ||
| /// </summary> | ||
| None = 0, | ||
| /// <summary> | ||
| /// Client certificate is not to be verified for revocation. | ||
| /// </summary> | ||
| DoNotVerifyCertificateRevocation = 1, | ||
| /// <summary> | ||
| /// Only cached certificate is to be used the revocation check. | ||
| /// </summary> | ||
| VerifyRevocationWithCachedCertificateOnly = 2, | ||
| /// <summary> | ||
| /// The RevocationFreshnessTime setting is enabled. | ||
| /// </summary> | ||
| EnableRevocationFreshnessTime = 4, | ||
| /// <summary> | ||
| /// No usage check is to be performed. | ||
| /// </summary> | ||
| NoUsageCheck = 0x10000 | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,69 @@ | ||
| // Licensed to the .NET Foundation under one or more agreements. | ||
| // The .NET Foundation licenses this file to you under the MIT license. | ||
| using System.Reflection; | ||
| using System.Runtime.InteropServices; | ||
| using Microsoft.AspNetCore.Hosting; | ||
| using Microsoft.AspNetCore.Http.Features; | ||
| using Microsoft.AspNetCore.Server.HttpSys; | ||
| using Microsoft.Extensions.Hosting; | ||
| using TlsFeatureObserve; | ||
| using TlsFeaturesObserve.HttpSys; | ||
| HttpSysConfigurator.ConfigureCacheTlsClientHello(); | ||
| CreateHostBuilder(args).Build().Run(); | ||
| static IHostBuilder CreateHostBuilder(string[] args) => | ||
| Host.CreateDefaultBuilder(args) | ||
| .ConfigureWebHost(webBuilder => | ||
| { | ||
| webBuilder.UseStartup<Startup>() | ||
| .UseHttpSys(options => | ||
| { | ||
| // If you want to use https locally: https://stackoverflow.com/a/51841893 | ||
| options.UrlPrefixes.Add("https://*:6000"); // HTTPS | ||
| options.Authentication.Schemes = AuthenticationSchemes.None; | ||
| options.Authentication.AllowAnonymous = true; | ||
| var property = typeof(HttpSysOptions).GetProperty("TlsClientHelloBytesCallback", BindingFlags.NonPublic | BindingFlags.Instance); | ||
| var delegateType = property.PropertyType; // Get the exact delegate type | ||
| // Create a delegate of the correct type | ||
| var callbackDelegate = Delegate.CreateDelegate(delegateType, typeof(Holder).GetMethod(nameof(Holder.ProcessTlsClientHello), BindingFlags.Static | BindingFlags.Public)); | ||
| property?.SetValue(options, callbackDelegate); | ||
| }); | ||
| }); | ||
| public static class Holder | ||
| { | ||
| public static void ProcessTlsClientHello(IFeatureCollection features, ReadOnlySpan<byte> tlsClientHelloBytes) | ||
| { | ||
| var httpConnectionFeature = features.Get<IHttpConnectionFeature>(); | ||
| var myTlsFeature = new MyTlsFeature( | ||
| connectionId: httpConnectionFeature.ConnectionId, | ||
| tlsClientHelloLength: tlsClientHelloBytes.Length); | ||
| features.Set<IMyTlsFeature>(myTlsFeature); | ||
| } | ||
| } | ||
| public interface IMyTlsFeature | ||
| { | ||
| string ConnectionId { get; } | ||
| int TlsClientHelloLength { get; } | ||
| } | ||
| public class MyTlsFeature : IMyTlsFeature | ||
| { | ||
| public string ConnectionId { get; } | ||
| public int TlsClientHelloLength { get; } | ||
| public MyTlsFeature(string connectionId, int tlsClientHelloLength) | ||
| { | ||
| ConnectionId = connectionId; | ||
| TlsClientHelloLength = tlsClientHelloLength; | ||
| } | ||
| } |
10 changes: 10 additions & 0 deletionssrc/Servers/HttpSys/samples/TlsFeaturesObserve/Properties/launchSettings.json
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| { | ||
| "profiles": { | ||
| "TlsFeaturesObserve": { | ||
| "commandName": "Project", | ||
| "launchBrowser": true, | ||
| "applicationUrl": "http://localhost:5000", | ||
| "nativeDebugging": true | ||
| } | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| // Licensed to the .NET Foundation under one or more agreements. | ||
| // The .NET Foundation licenses this file to you under the MIT license. | ||
| using System; | ||
| using Microsoft.AspNetCore.Builder; | ||
| using Microsoft.AspNetCore.Connections.Features; | ||
| using Microsoft.AspNetCore.Hosting; | ||
| using Microsoft.AspNetCore.Http; | ||
| using Microsoft.AspNetCore.Http.Features; | ||
| using Microsoft.AspNetCore.Server.HttpSys; | ||
| using Microsoft.Extensions.DependencyInjection; | ||
| using Microsoft.Extensions.Logging; | ||
| namespace TlsFeatureObserve; | ||
| public class Startup | ||
| { | ||
| public void Configure(IApplicationBuilder app) | ||
| { | ||
| app.Run(async (HttpContext context) => | ||
| { | ||
| context.Response.ContentType = "text/plain"; | ||
| var tlsFeature = context.Features.Get<IMyTlsFeature>(); | ||
| await context.Response.WriteAsync("TlsClientHello data: " + $"connectionId={tlsFeature?.ConnectionId}; length={tlsFeature?.TlsClientHelloLength}"); | ||
| }); | ||
| } | ||
| } |
Oops, something went wrong.
Uh oh!
There was an error while loading.Please reload this page.
Oops, something went wrong.
Uh oh!
There was an error while loading.Please reload this page.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.