Skip to content

Commit d7953f6

Browse files
committed
setup for tls clinet hello exposure
1 parent 46312f3 commit d7953f6

File tree

18 files changed

+559
-18
lines changed

18 files changed

+559
-18
lines changed

AspNetCore.sln

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1772,6 +1772,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNetCore.Http.R
17721772
EndProject
17731773
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNetCore.Http.ValidationsGenerator", "src\Http\Http.Extensions\gen\Microsoft.AspNetCore.Http.ValidationsGenerator\Microsoft.AspNetCore.Http.ValidationsGenerator.csproj", "{7899F5DD-AA7C-4561-BAC4-E2EC78B7D157}"
17741774
EndProject
1775+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TlsFeaturesObserve", "src\Servers\HttpSys\samples\TlsFeaturesObserve\TlsFeaturesObserve.csproj", "{98C71EC8-1303-F55D-4032-E6728971770E}"
1776+
EndProject
17751777
Global
17761778
GlobalSection(SolutionConfigurationPlatforms) = preSolution
17771779
Debug|Any CPU = Debug|Any CPU
@@ -10983,6 +10985,22 @@ Global
1098310985
{7899F5DD-AA7C-4561-BAC4-E2EC78B7D157}.Release|x64.Build.0 = Release|Any CPU
1098410986
{7899F5DD-AA7C-4561-BAC4-E2EC78B7D157}.Release|x86.ActiveCfg = Release|Any CPU
1098510987
{7899F5DD-AA7C-4561-BAC4-E2EC78B7D157}.Release|x86.Build.0 = Release|Any CPU
10988+
{98C71EC8-1303-F55D-4032-E6728971770E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
10989+
{98C71EC8-1303-F55D-4032-E6728971770E}.Debug|Any CPU.Build.0 = Debug|Any CPU
10990+
{98C71EC8-1303-F55D-4032-E6728971770E}.Debug|arm64.ActiveCfg = Debug|Any CPU
10991+
{98C71EC8-1303-F55D-4032-E6728971770E}.Debug|arm64.Build.0 = Debug|Any CPU
10992+
{98C71EC8-1303-F55D-4032-E6728971770E}.Debug|x64.ActiveCfg = Debug|Any CPU
10993+
{98C71EC8-1303-F55D-4032-E6728971770E}.Debug|x64.Build.0 = Debug|Any CPU
10994+
{98C71EC8-1303-F55D-4032-E6728971770E}.Debug|x86.ActiveCfg = Debug|Any CPU
10995+
{98C71EC8-1303-F55D-4032-E6728971770E}.Debug|x86.Build.0 = Debug|Any CPU
10996+
{98C71EC8-1303-F55D-4032-E6728971770E}.Release|Any CPU.ActiveCfg = Release|Any CPU
10997+
{98C71EC8-1303-F55D-4032-E6728971770E}.Release|Any CPU.Build.0 = Release|Any CPU
10998+
{98C71EC8-1303-F55D-4032-E6728971770E}.Release|arm64.ActiveCfg = Release|Any CPU
10999+
{98C71EC8-1303-F55D-4032-E6728971770E}.Release|arm64.Build.0 = Release|Any CPU
11000+
{98C71EC8-1303-F55D-4032-E6728971770E}.Release|x64.ActiveCfg = Release|Any CPU
11001+
{98C71EC8-1303-F55D-4032-E6728971770E}.Release|x64.Build.0 = Release|Any CPU
11002+
{98C71EC8-1303-F55D-4032-E6728971770E}.Release|x86.ActiveCfg = Release|Any CPU
11003+
{98C71EC8-1303-F55D-4032-E6728971770E}.Release|x86.Build.0 = Release|Any CPU
1098611004
EndGlobalSection
1098711005
GlobalSection(SolutionProperties) = preSolution
1098811006
HideSolutionNode = FALSE
@@ -11777,6 +11795,7 @@ Global
1177711795
{01A75167-DF5A-AF38-8700-C3FBB2C2CFF5} = {225AEDCF-7162-4A86-AC74-06B84660B379}
1177811796
{E6D564C0-4CA5-411C-BF40-9802AF7900CB} = {01A75167-DF5A-AF38-8700-C3FBB2C2CFF5}
1177911797
{7899F5DD-AA7C-4561-BAC4-E2EC78B7D157} = {01A75167-DF5A-AF38-8700-C3FBB2C2CFF5}
11798+
{98C71EC8-1303-F55D-4032-E6728971770E} = {49016328-4D32-46E4-A4D2-94686ED38EA2}
1178011799
EndGlobalSection
1178111800
GlobalSection(ExtensibilityGlobals) = postSolution
1178211801
SolutionGuid = {3E8720B3-DBDD-498C-B383-2CC32A054E8F}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System;
5+
using System.Collections.Generic;
6+
using System.Linq;
7+
using System.Security.Cryptography.X509Certificates;
8+
using System.Text;
9+
using System.Threading;
10+
using System.Threading.Tasks;
11+
using Microsoft.AspNetCore.Connections.Abstractions.TLS;
12+
13+
namespace Microsoft.AspNetCore.Connections.Features;
14+
15+
/// <summary>
16+
/// Represents the details about the TLS fingerprinting.
17+
/// </summary>
18+
public interface ITlsFingerprintingFeature
19+
{
20+
/// <summary>
21+
/// Returns the TLS client hello details, if any.
22+
/// </summary>
23+
TLS_CLIENT_HELLO GetTlsClientHello();
24+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System;
5+
using System.Collections.Generic;
6+
using System.Linq;
7+
using System.Runtime.InteropServices;
8+
using System.Security.Authentication;
9+
using System.Text;
10+
using System.Threading.Tasks;
11+
12+
namespace Microsoft.AspNetCore.Connections.Abstractions.TLS;
13+
14+
public struct TLS_CLIENT_HELLO
15+
{
16+
public SslProtocols ProtocolVersion; // Version of the TLS protocol
17+
18+
public override string ToString()
19+
{
20+
return $"""
21+
TLS CLIENT HELLO MESSAGE:
22+
- ProtocolVersion: {ProtocolVersion}
23+
""";
24+
}
25+
}

src/Servers/HttpSys/HttpSysServer.slnf

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
"src\\Servers\\HttpSys\\samples\\QueueSharing\\QueueSharing.csproj",
3939
"src\\Servers\\HttpSys\\samples\\SelfHostServer\\SelfHostServer.csproj",
4040
"src\\Servers\\HttpSys\\samples\\TestClient\\TestClient.csproj",
41+
"src\\Servers\\HttpSys\\samples\\TlsFeaturesObserve\\TlsFeaturesObserve.csproj",
4142
"src\\Servers\\HttpSys\\src\\Microsoft.AspNetCore.Server.HttpSys.csproj",
4243
"src\\Servers\\HttpSys\\test\\FunctionalTests\\Microsoft.AspNetCore.Server.HttpSys.FunctionalTests.csproj",
4344
"src\\Servers\\HttpSys\\test\\NonHelixTests\\Microsoft.AspNetCore.Server.HttpSys.NonHelixTests.csproj",
@@ -54,4 +55,4 @@
5455
"src\\WebEncoders\\src\\Microsoft.Extensions.WebEncoders.csproj"
5556
]
5657
}
57-
}
58+
}
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System;
5+
using System.Net;
6+
using System.Net.Sockets;
7+
using System.Runtime.InteropServices;
8+
using System.Text;
9+
using Microsoft.AspNetCore.Http;
10+
11+
namespace TlsFeaturesObserve.HttpSys;
12+
13+
internal static class HttpSysConfigurator
14+
{
15+
const uint HTTP_INITIALIZE_CONFIG = 0x00000002;
16+
const uint ERROR_ALREADY_EXISTS = 183;
17+
18+
static readonly HTTPAPI_VERSION HttpApiVersion = new HTTPAPI_VERSION(1, 0);
19+
20+
internal static void ConfigureCacheTlsClientHello()
21+
{
22+
IPEndPoint ipPort = new IPEndPoint(new IPAddress([0, 0, 0, 0]), 6000);
23+
string certThumbprint = "" /* your cert thumbprint here */;
24+
Guid appId = Guid.NewGuid();
25+
string sslCertStoreName = "My";
26+
27+
CallHttpApi(() => SetConfiguration(ipPort, certThumbprint, appId, sslCertStoreName));
28+
}
29+
30+
static void SetConfiguration(IPEndPoint ipPort, string certThumbprint, Guid appId, string sslCertStoreName)
31+
{
32+
GCHandle sockAddrHandle = CreateSockaddrStructure(ipPort);
33+
var pIpPort = sockAddrHandle.AddrOfPinnedObject();
34+
var httpServiceConfigSslKey = new HTTP_SERVICE_CONFIG_SSL_KEY(pIpPort);
35+
36+
byte[] hash = GetHash(certThumbprint);
37+
var handleHash = GCHandle.Alloc(hash, GCHandleType.Pinned);
38+
var configSslParam = new HTTP_SERVICE_CONFIG_SSL_PARAM
39+
{
40+
AppId = appId,
41+
DefaultFlags = 0x00008000 /* HTTP_SERVICE_CONFIG_SSL_FLAG_ENABLE_CACHE_CLIENT_HELLO */,
42+
DefaultRevocationFreshnessTime = 0,
43+
DefaultRevocationUrlRetrievalTimeout = 15,
44+
pSslCertStoreName = sslCertStoreName,
45+
pSslHash = handleHash.AddrOfPinnedObject(),
46+
SslHashLength = hash.Length,
47+
pDefaultSslCtlIdentifier = null,
48+
pDefaultSslCtlStoreName = sslCertStoreName
49+
};
50+
51+
var configSslSet = new HTTP_SERVICE_CONFIG_SSL_SET
52+
{
53+
ParamDesc = configSslParam,
54+
KeyDesc = httpServiceConfigSslKey
55+
};
56+
57+
var pInputConfigInfo = Marshal.AllocCoTaskMem(
58+
Marshal.SizeOf(typeof(HTTP_SERVICE_CONFIG_SSL_SET)));
59+
Marshal.StructureToPtr(configSslSet, pInputConfigInfo, false);
60+
61+
uint status = HttpSetServiceConfiguration(nint.Zero,
62+
HTTP_SERVICE_CONFIG_ID.HttpServiceConfigSSLCertInfo,
63+
pInputConfigInfo,
64+
Marshal.SizeOf(configSslSet),
65+
nint.Zero);
66+
67+
if (status == ERROR_ALREADY_EXISTS || status == 0) // already present or success
68+
{
69+
Console.WriteLine("HttpServiceConfiguration is correct");
70+
}
71+
else
72+
{
73+
Console.WriteLine("Failed to HttpSetServiceConfiguration: " + status);
74+
}
75+
}
76+
77+
static byte[] GetHash(string thumbprint)
78+
{
79+
int length = thumbprint.Length;
80+
byte[] bytes = new byte[length / 2];
81+
for (int i = 0; i < length; i += 2)
82+
bytes[i / 2] = Convert.ToByte(thumbprint.Substring(i, 2), 16);
83+
return bytes;
84+
}
85+
86+
static GCHandle CreateSockaddrStructure(IPEndPoint ipEndPoint)
87+
{
88+
SocketAddress socketAddress = ipEndPoint.Serialize();
89+
90+
// use an array of bytes instead of the sockaddr structure
91+
byte[] sockAddrStructureBytes = new byte[socketAddress.Size];
92+
GCHandle sockAddrHandle = GCHandle.Alloc(sockAddrStructureBytes, GCHandleType.Pinned);
93+
for (int i = 0; i < socketAddress.Size; ++i)
94+
{
95+
sockAddrStructureBytes[i] = socketAddress[i];
96+
}
97+
return sockAddrHandle;
98+
}
99+
100+
static void CallHttpApi(Action body)
101+
{
102+
const uint flags = HTTP_INITIALIZE_CONFIG;
103+
uint retVal = HttpInitialize(HttpApiVersion, flags, IntPtr.Zero);
104+
body();
105+
}
106+
107+
[DllImport("httpapi.dll", SetLastError = true)]
108+
private static extern uint HttpInitialize(
109+
HTTPAPI_VERSION version,
110+
uint flags,
111+
IntPtr pReserved);
112+
113+
[DllImport("httpapi.dll", SetLastError = true)]
114+
public static extern uint HttpSetServiceConfiguration(
115+
nint serviceIntPtr,
116+
HTTP_SERVICE_CONFIG_ID configId,
117+
nint pConfigInformation,
118+
int configInformationLength,
119+
nint pOverlapped);
120+
}
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System;
5+
using System.Collections.Generic;
6+
using System.Runtime.InteropServices;
7+
using System.Text;
8+
9+
namespace TlsFeaturesObserve.HttpSys;
10+
11+
[StructLayout(LayoutKind.Sequential, Pack = 2)]
12+
public struct HTTPAPI_VERSION
13+
{
14+
public ushort HttpApiMajorVersion;
15+
public ushort HttpApiMinorVersion;
16+
17+
public HTTPAPI_VERSION(ushort majorVersion, ushort minorVersion)
18+
{
19+
HttpApiMajorVersion = majorVersion;
20+
HttpApiMinorVersion = minorVersion;
21+
}
22+
}
23+
24+
public enum HTTP_SERVICE_CONFIG_ID
25+
{
26+
HttpServiceConfigIPListenList = 0,
27+
HttpServiceConfigSSLCertInfo,
28+
HttpServiceConfigUrlAclInfo,
29+
HttpServiceConfigMax
30+
}
31+
32+
[StructLayout(LayoutKind.Sequential)]
33+
public struct HTTP_SERVICE_CONFIG_SSL_SET
34+
{
35+
public HTTP_SERVICE_CONFIG_SSL_KEY KeyDesc;
36+
public HTTP_SERVICE_CONFIG_SSL_PARAM ParamDesc;
37+
}
38+
39+
[StructLayout(LayoutKind.Sequential)]
40+
public struct HTTP_SERVICE_CONFIG_SSL_KEY
41+
{
42+
public IntPtr pIpPort;
43+
44+
public HTTP_SERVICE_CONFIG_SSL_KEY(IntPtr pIpPort)
45+
{
46+
this.pIpPort = pIpPort;
47+
}
48+
}
49+
50+
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
51+
public struct HTTP_SERVICE_CONFIG_SSL_PARAM
52+
{
53+
public int SslHashLength;
54+
public IntPtr pSslHash;
55+
public Guid AppId;
56+
[MarshalAs(UnmanagedType.LPWStr)]
57+
public string pSslCertStoreName;
58+
public CertCheckModes DefaultCertCheckMode;
59+
public int DefaultRevocationFreshnessTime;
60+
public int DefaultRevocationUrlRetrievalTimeout;
61+
[MarshalAs(UnmanagedType.LPWStr)]
62+
public string pDefaultSslCtlIdentifier;
63+
[MarshalAs(UnmanagedType.LPWStr)]
64+
public string pDefaultSslCtlStoreName;
65+
public uint DefaultFlags; // HTTP_SERVICE_CONFIG_SSL_FLAG
66+
}
67+
68+
[Flags]
69+
public enum CertCheckModes : uint
70+
{
71+
/// <summary>
72+
/// Enables the client certificate revocation check.
73+
/// </summary>
74+
None = 0,
75+
76+
/// <summary>
77+
/// Client certificate is not to be verified for revocation.
78+
/// </summary>
79+
DoNotVerifyCertificateRevocation = 1,
80+
81+
/// <summary>
82+
/// Only cached certificate is to be used the revocation check.
83+
/// </summary>
84+
VerifyRevocationWithCachedCertificateOnly = 2,
85+
86+
/// <summary>
87+
/// The RevocationFreshnessTime setting is enabled.
88+
/// </summary>
89+
EnableRevocationFreshnessTime = 4,
90+
91+
/// <summary>
92+
/// No usage check is to be performed.
93+
/// </summary>
94+
NoUsageCheck = 0x10000
95+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System.Reflection;
5+
using System.Runtime.InteropServices;
6+
using Microsoft.AspNetCore.Hosting;
7+
using Microsoft.AspNetCore.Server.HttpSys;
8+
using Microsoft.Extensions.Hosting;
9+
using TlsFeaturesObserve.HttpSys;
10+
11+
namespace TlsFeatureObserve;
12+
13+
public static class Program
14+
{
15+
public static void Main(string[] args)
16+
{
17+
HttpSysConfigurator.ConfigureCacheTlsClientHello();
18+
CreateHostBuilder(args).Build().Run();
19+
}
20+
21+
public static IHostBuilder CreateHostBuilder(string[] args) =>
22+
Host.CreateDefaultBuilder(args)
23+
.ConfigureWebHost(webBuilder =>
24+
{
25+
webBuilder.UseStartup<Startup>()
26+
.UseHttpSys(options =>
27+
{
28+
// If you want to use https locally: https://stackoverflow.com/a/51841893
29+
options.UrlPrefixes.Add("https://*:6000"); // HTTPS
30+
31+
options.Authentication.Schemes = AuthenticationSchemes.None;
32+
options.Authentication.AllowAnonymous = true;
33+
});
34+
});
35+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"profiles": {
3+
"TlsFeaturesObserve": {
4+
"commandName": "Project",
5+
"launchBrowser": true,
6+
"applicationUrl": "http://localhost:5000",
7+
"nativeDebugging": true
8+
}
9+
}
10+
}

0 commit comments

Comments
 (0)