Skip to content

Commit 84a9d29

Browse files
authored
Merge branch 'aspnet:main' into main
2 parents 85c1c9d + ed94252 commit 84a9d29

File tree

10 files changed

+181
-26
lines changed

10 files changed

+181
-26
lines changed

build/trend-scenarios.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,9 @@ parameters:
108108
- displayName: "HttpSys Windows: mTLS Handshakes"
109109
arguments: --scenario mTls-handshakes-httpsys $(tlsJobs) --property scenario=HttpSysMutualTLSHandshakes --application.options.requiredOperatingSystem windows
110110

111+
- displayName: "HttpSys Windows: TLS Renegotiation"
112+
arguments: --scenario tls-renegotiation-httpsys $(tlsJobs) --property scenario=HttpSysTLSRenegotiation --application.options.requiredOperatingSystem windows
113+
111114
- displayName: "Kestrel Linux: TLS Handshakes"
112115
arguments: --scenario tls-handshakes-kestrel $(tlsJobs) --property scenario=KestrelTLSHandshakes --application.options.requiredOperatingSystem linux
113116

scenarios/tls.benchmarks.yml

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,12 @@ jobs:
1515
project: src/BenchmarksApps/TLS/HttpSys/HttpSys.csproj
1616
readyStateText: Application started.
1717
variables:
18-
mTLS: false
18+
mTLS: false # enables settings on http.sys to negotiate client cert on connections
19+
tlsRenegotiation: false # enables client cert validation
1920
certValidationConsoleEnabled: false
21+
httpSysLogs: false
2022
statsEnabled: false
21-
arguments: "--urls https://{{serverAddress}}:{{serverPort}} --mTLS {{mTLS}} --certValidationConsoleEnabled {{certValidationConsoleEnabled}} --statsEnabled {{statsEnabled}}"
23+
arguments: "--urls https://{{serverAddress}}:{{serverPort}} --mTLS {{mTLS}} --certValidationConsoleEnabled {{certValidationConsoleEnabled}} --statsEnabled {{statsEnabled}} --tlsRenegotiation {{tlsRenegotiation}} --httpSysLogs {{httpSysLogs}}"
2224

2325
kestrelServer:
2426
source:
@@ -52,7 +54,29 @@ scenarios:
5254
application:
5355
job: httpSysServer
5456
variables:
55-
mTLS: true
57+
mTLS: true # enables settings on http.sys to negotiate client cert on connections
58+
tlsRenegotiation: true # enables client cert validation
59+
httpSysLogs: false # only for debug purposes
60+
certValidationConsoleEnabled: false # only for debug purposes
61+
serverPort: 8080 # IMPORTANT: not to intersect with other tests in case http.sys configuration impacts other benchmarks
62+
load:
63+
job: httpclient
64+
variables:
65+
serverPort: 8080 # in sync with server
66+
path: /hello-world
67+
presetHeaders: connectionclose
68+
connections: 32
69+
serverScheme: https
70+
certPath: https://raw.githubusercontent.com/aspnet/Benchmarks/refs/heads/main/src/BenchmarksApps/TLS/HttpSys/testCert.pfx
71+
certPwd: testPassword
72+
73+
tls-renegotiation-httpsys:
74+
application:
75+
job: httpSysServer
76+
variables:
77+
mTLS: false
78+
tlsRenegotiation: true
79+
httpSysLogs: false # only for debug purposes
5680
certValidationConsoleEnabled: false # only for debug purposes
5781
load:
5882
job: httpclient

src/BenchmarksApps/Grpc/BasicGoServer/go.mod

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,7 @@ require (
88
)
99

1010
require (
11-
golang.org/x/crypto v0.31.0 // indirect
12-
golang.org/x/net v0.26.0 // indirect
11+
golang.org/x/net v0.33.0 // indirect
1312
golang.org/x/sys v0.28.0 // indirect
1413
golang.org/x/text v0.21.0 // indirect
1514
google.golang.org/genproto/googleapis/rpc v0.0.0-20240521202816-d264139d666e // indirect

src/BenchmarksApps/Grpc/BasicGoServer/go.sum

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,10 @@
11
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
22
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
3-
golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
4-
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
5-
golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ=
6-
golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
7-
golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
8-
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
3+
golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
4+
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
5+
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
96
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
10-
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
11-
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
7+
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
128
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
139
google.golang.org/genproto/googleapis/rpc v0.0.0-20240521202816-d264139d666e h1:Elxv5MwEkCI9f5SkoL6afed6NTdxaGoAo39eANBwHL8=
1410
google.golang.org/genproto/googleapis/rpc v0.0.0-20240521202816-d264139d666e/go.mod h1:EfXuqaE1J41VCDicxHzUDm+8rk+7ZdXzHV0IhO/I6s0=

src/BenchmarksApps/Grpc/GoClient/go.mod

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,7 @@ require (
88
)
99

1010
require (
11-
golang.org/x/crypto v0.31.0 // indirect
12-
golang.org/x/net v0.27.0 // indirect
11+
golang.org/x/net v0.33.0 // indirect
1312
golang.org/x/sys v0.28.0 // indirect
1413
golang.org/x/text v0.21.0 // indirect
1514
google.golang.org/genproto/googleapis/rpc v0.0.0-20240711142825-46eb208f015d // indirect

src/BenchmarksApps/Grpc/GoClient/go.sum

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,9 @@
11
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
22
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
3-
golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
4-
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
5-
golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys=
6-
golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE=
7-
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
8-
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
3+
golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
4+
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
95
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
106
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
11-
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
12-
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
137
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
148
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
159
google.golang.org/genproto/googleapis/rpc v0.0.0-20240711142825-46eb208f015d h1:JU0iKnSg02Gmb5ZdV8nYsKEKsP6o/FGVWTrw4i1DA9A=

src/BenchmarksApps/TLS/HttpSys/HttpSys.csproj

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,10 @@
66
<ImplicitUsings>enable</ImplicitUsings>
77
</PropertyGroup>
88

9+
<ItemGroup>
10+
<None Update="testCert.pfx">
11+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
12+
</None>
13+
</ItemGroup>
14+
915
</Project>
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
using System.Diagnostics;
2+
using System.Security.Cryptography.X509Certificates;
3+
4+
namespace HttpSys
5+
{
6+
public static class NetShWrapper
7+
{
8+
public static void DisableHttpSysMutualTlsIfExists(string ipPort)
9+
{
10+
try
11+
{
12+
DisableHttpSysMutualTls(ipPort);
13+
}
14+
catch
15+
{
16+
// ignore
17+
}
18+
}
19+
20+
public static void DisableHttpSysMutualTls(string ipPort)
21+
{
22+
Console.WriteLine("Disabling mTLS for http.sys");
23+
24+
string command = $"http delete sslcert ipport={ipPort}";
25+
ExecuteNetShCommand(command);
26+
27+
Console.WriteLine("Disabled http.sys settings for mTLS");
28+
}
29+
30+
public static void Show()
31+
{
32+
ExecuteNetShCommand("http show sslcert", alwaysLogOutput: true);
33+
}
34+
35+
public static void EnableHttpSysMutualTls(string ipPort)
36+
{
37+
Console.WriteLine("Setting up mTLS for http.sys");
38+
39+
var certificate = LoadCertificate();
40+
Console.WriteLine("Loaded `testCert.pfx` from local file system");
41+
using (var store = new X509Store(StoreName.My, StoreLocation.LocalMachine))
42+
{
43+
store.Open(OpenFlags.ReadWrite);
44+
store.Add(certificate);
45+
Console.WriteLine("Added `testCert.pfx` to localMachine cert store");
46+
store.Close();
47+
}
48+
49+
string certThumbprint = certificate.Thumbprint;
50+
string appId = Guid.NewGuid().ToString();
51+
52+
string command = $"http add sslcert ipport={ipPort} certstorename=MY certhash={certThumbprint} appid={{{appId}}} clientcertnegotiation=enable";
53+
ExecuteNetShCommand(command);
54+
55+
Console.WriteLine("Configured http.sys settings for mTLS");
56+
}
57+
58+
private static void ExecuteNetShCommand(string command, bool alwaysLogOutput = false)
59+
{
60+
ProcessStartInfo processInfo = new ProcessStartInfo("netsh", command)
61+
{
62+
RedirectStandardOutput = true,
63+
RedirectStandardError = true,
64+
UseShellExecute = false,
65+
CreateNoWindow = true
66+
};
67+
68+
Console.WriteLine($"Executing command: `netsh {command}`");
69+
using Process process = Process.Start(processInfo)!;
70+
string output = process.StandardOutput.ReadToEnd();
71+
process.WaitForExit();
72+
73+
if (alwaysLogOutput)
74+
{
75+
Console.WriteLine(output);
76+
}
77+
78+
if (process.ExitCode != 0)
79+
{
80+
throw new InvalidOperationException($"netsh command execution failure: {output}");
81+
}
82+
}
83+
84+
private static X509Certificate2 LoadCertificate()
85+
=> File.Exists("testCert.pfx")
86+
? X509CertificateLoader.LoadPkcs12FromFile("testCert.pfx", "testPassword", X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.Exportable)
87+
: X509CertificateLoader.LoadPkcs12FromFile("../testCert.pfx", "testPassword", X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.Exportable);
88+
}
89+
}

src/BenchmarksApps/TLS/HttpSys/Program.cs

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
1-
using Microsoft.AspNetCore.Mvc;
1+
using HttpSys;
22
using Microsoft.AspNetCore.Server.HttpSys;
33

44
var builder = WebApplication.CreateBuilder(args);
55
builder.Logging.ClearProviders();
66

77
var writeCertValidationEventsToConsole = bool.TryParse(builder.Configuration["certValidationConsoleEnabled"], out var certValidationConsoleEnabled) && certValidationConsoleEnabled;
8+
var httpSysLoggingEnabled = bool.TryParse(builder.Configuration["httpSysLogs"], out var httpSysLogsEnabled) && httpSysLogsEnabled;
89
var statsEnabled = bool.TryParse(builder.Configuration["statsEnabled"], out var connectionStatsEnabledConfig) && connectionStatsEnabledConfig;
910
var mTlsEnabled = bool.TryParse(builder.Configuration["mTLS"], out var mTlsEnabledConfig) && mTlsEnabledConfig;
11+
var tlsRenegotiationEnabled = bool.TryParse(builder.Configuration["tlsRenegotiation"], out var tlsRenegotiationEnabledConfig) && tlsRenegotiationEnabledConfig;
1012
var listeningEndpoints = builder.Configuration["urls"] ?? "https://localhost:5000/";
13+
var httpsIpPort = listeningEndpoints.Split(";").First(x => x.Contains("https")).Replace("https://", "");
1114

1215
#pragma warning disable CA1416 // Can be launched only on Windows (HttpSys)
1316
builder.WebHost.UseHttpSys(options =>
@@ -17,7 +20,7 @@
1720
});
1821
#pragma warning restore CA1416 // Can be launched only on Windows (HttpSys)
1922

20-
var app = builder.Build();
23+
var app = builder.Build();
2124

2225
app.MapGet("/hello-world", () =>
2326
{
@@ -40,6 +43,40 @@
4043
}
4144

4245
if (mTlsEnabled)
46+
{
47+
var hostAppLifetime = app.Services.GetRequiredService<IHostApplicationLifetime>();
48+
hostAppLifetime!.ApplicationStopping.Register(OnShutdown);
49+
50+
void OnShutdown()
51+
{
52+
Console.WriteLine("Application shutdown started.");
53+
54+
try
55+
{
56+
NetShWrapper.DisableHttpSysMutualTls(ipPort: httpsIpPort);
57+
}
58+
catch
59+
{
60+
Console.WriteLine("Failed to disable HTTP.SYS mTLS settings");
61+
throw;
62+
}
63+
}
64+
65+
try
66+
{
67+
// if not executed, following command (enable http.sys mutual tls) will fail because binding exists
68+
NetShWrapper.DisableHttpSysMutualTlsIfExists(ipPort: httpsIpPort);
69+
70+
NetShWrapper.EnableHttpSysMutualTls(ipPort: httpsIpPort);
71+
}
72+
catch
73+
{
74+
Console.WriteLine($"Http.Sys configuration for mTLS failed");
75+
throw;
76+
}
77+
}
78+
79+
if (tlsRenegotiationEnabled)
4380
{
4481
// this is an http.sys middleware to get a cert
4582
Console.WriteLine("Registered client cert validation middleware");
@@ -72,6 +109,12 @@
72109
}
73110

74111
await app.StartAsync();
112+
113+
if (httpSysLoggingEnabled)
114+
{
115+
NetShWrapper.Show();
116+
}
117+
75118
Console.WriteLine("Application Info:");
76119
if (mTlsEnabled)
77120
{

src/BenchmarksApps/TLS/HttpSys/appsettings.Development.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
"Microsoft.AspNetCore": "Warning"
66
}
77
},
8-
"mTLS": "true",
8+
"mTLS": "false",
9+
"httpSysLogs": "true",
10+
"tlsRenegotiation": "true",
911
"certValidationConsoleEnabled": "true"
1012
}

0 commit comments

Comments
 (0)