Skip to content

Commit e8d6427

Browse files
authored
feat: control SSL protocol version on tls jobs (#2049)
1 parent ed94252 commit e8d6427

File tree

3 files changed

+116
-13
lines changed

3 files changed

+116
-13
lines changed

scenarios/tls.benchmarks.yml

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

2528
kestrelServer:
2629
source:
@@ -29,11 +32,15 @@ jobs:
2932
project: src/BenchmarksApps/TLS/Kestrel/Kestrel.csproj
3033
readyStateText: Application started.
3134
variables:
35+
# behavioral settings
3236
mTLS: false
3337
tlsRenegotiation: false
38+
tlsProtocols: "tls12,tls13"
39+
# debug settings
3440
certValidationConsoleEnabled: false
3541
statsEnabled: false
36-
arguments: "--urls https://{{serverAddress}}:{{serverPort}} --mTLS {{mTLS}} --certValidationConsoleEnabled {{certValidationConsoleEnabled}} --statsEnabled {{statsEnabled}} --tlsRenegotiation {{tlsRenegotiation}}"
42+
logRequestDetails: false
43+
arguments: "--urls https://{{serverAddress}}:{{serverPort}} --mTLS {{mTLS}} --certValidationConsoleEnabled {{certValidationConsoleEnabled}} --tlsProtocols {{tlsProtocols}} --statsEnabled {{statsEnabled}} --tlsRenegotiation {{tlsRenegotiation}} --logRequestDetails {{logRequestDetails}}"
3744

3845
scenarios:
3946

@@ -43,12 +50,13 @@ scenarios:
4350
application:
4451
job: httpSysServer
4552
load:
46-
job: wrk
53+
job: httpclient
4754
variables:
4855
path: /hello-world
4956
presetHeaders: connectionclose
5057
connections: 32
5158
serverScheme: https
59+
sslProtocol: tls12
5260

5361
mTls-handshakes-httpsys:
5462
application:
@@ -69,6 +77,7 @@ scenarios:
6977
serverScheme: https
7078
certPath: https://raw.githubusercontent.com/aspnet/Benchmarks/refs/heads/main/src/BenchmarksApps/TLS/HttpSys/testCert.pfx
7179
certPwd: testPassword
80+
sslProtocol: tls12
7281

7382
tls-renegotiation-httpsys:
7483
application:
@@ -87,19 +96,21 @@ scenarios:
8796
serverScheme: https
8897
certPath: https://raw.githubusercontent.com/aspnet/Benchmarks/refs/heads/main/src/BenchmarksApps/TLS/HttpSys/testCert.pfx
8998
certPwd: testPassword
99+
sslProtocol: tls12
90100

91101
# Kestrel
92102

93103
tls-handshakes-kestrel:
94104
application:
95105
job: kestrelServer
96106
load:
97-
job: wrk
107+
job: httpclient
98108
variables:
99109
path: /hello-world
100110
presetHeaders: connectionclose
101111
connections: 32
102112
serverScheme: https
113+
sslProtocol: tls12
103114

104115
mTls-handshakes-kestrel:
105116
application:
@@ -116,6 +127,7 @@ scenarios:
116127
serverScheme: https
117128
certPath: https://raw.githubusercontent.com/aspnet/Benchmarks/refs/heads/main/src/BenchmarksApps/TLS/Kestrel/testCert.pfx
118129
certPwd: testPassword
130+
sslProtocol: tls12
119131

120132
tls-renegotiation-kestrel:
121133
application:
@@ -132,4 +144,5 @@ scenarios:
132144
connections: 32
133145
serverScheme: https
134146
certPath: https://raw.githubusercontent.com/aspnet/Benchmarks/refs/heads/main/src/BenchmarksApps/TLS/Kestrel/testCert.pfx
135-
certPwd: testPassword
147+
certPwd: testPassword
148+
sslProtocol: tls12

src/BenchmarksApps/TLS/HttpSys/Program.cs

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,23 @@
11
using HttpSys;
2+
using Microsoft.AspNetCore.Connections.Features;
3+
using Microsoft.AspNetCore.Http.Features;
24
using Microsoft.AspNetCore.Server.HttpSys;
35

46
var builder = WebApplication.CreateBuilder(args);
57
builder.Logging.ClearProviders();
68

7-
var writeCertValidationEventsToConsole = bool.TryParse(builder.Configuration["certValidationConsoleEnabled"], out var certValidationConsoleEnabled) && certValidationConsoleEnabled;
9+
// behavioral
810
var httpSysLoggingEnabled = bool.TryParse(builder.Configuration["httpSysLogs"], out var httpSysLogsEnabled) && httpSysLogsEnabled;
9-
var statsEnabled = bool.TryParse(builder.Configuration["statsEnabled"], out var connectionStatsEnabledConfig) && connectionStatsEnabledConfig;
1011
var mTlsEnabled = bool.TryParse(builder.Configuration["mTLS"], out var mTlsEnabledConfig) && mTlsEnabledConfig;
1112
var tlsRenegotiationEnabled = bool.TryParse(builder.Configuration["tlsRenegotiation"], out var tlsRenegotiationEnabledConfig) && tlsRenegotiationEnabledConfig;
1213
var listeningEndpoints = builder.Configuration["urls"] ?? "https://localhost:5000/";
1314
var httpsIpPort = listeningEndpoints.Split(";").First(x => x.Contains("https")).Replace("https://", "");
1415

16+
// debug
17+
var writeCertValidationEventsToConsole = bool.TryParse(builder.Configuration["certValidationConsoleEnabled"], out var certValidationConsoleEnabled) && certValidationConsoleEnabled;
18+
var statsEnabled = bool.TryParse(builder.Configuration["statsEnabled"], out var connectionStatsEnabledConfig) && connectionStatsEnabledConfig;
19+
var logRequestDetails = bool.TryParse(builder.Configuration["logRequestDetails"], out var logRequestDetailsConfig) && logRequestDetailsConfig;
20+
1521
#pragma warning disable CA1416 // Can be launched only on Windows (HttpSys)
1622
builder.WebHost.UseHttpSys(options =>
1723
{
@@ -30,6 +36,28 @@
3036
var connectionIds = new HashSet<string>();
3137
var fetchedCertsCounter = 0;
3238

39+
if (logRequestDetails)
40+
{
41+
var logged = false;
42+
Console.WriteLine("Registered request details logging middleware");
43+
app.Use(async (context, next) =>
44+
{
45+
if (!logged)
46+
{
47+
logged = true;
48+
49+
var tlsHandshakeFeature = context.Features.GetRequiredFeature<ITlsHandshakeFeature>();
50+
51+
Console.WriteLine("Request details:");
52+
Console.WriteLine("-----");
53+
Console.WriteLine("TLS: " + tlsHandshakeFeature.Protocol);
54+
Console.WriteLine("-----");
55+
}
56+
57+
await next(context);
58+
});
59+
}
60+
3361
if (statsEnabled)
3462
{
3563
Console.WriteLine("Registered stats middleware");
@@ -38,7 +66,7 @@
3866
connectionIds.Add(context.Connection.Id);
3967
Console.WriteLine($"[stats] unique connections established: {connectionIds.Count}; fetched certificates: {fetchedCertsCounter}");
4068

41-
await next();
69+
await next(context);
4270
});
4371
}
4472

@@ -104,7 +132,7 @@ void OnShutdown()
104132
// we have a client cert here, and lets imagine we do the validation here
105133
// if (clientCert.Thumbprint != "1234567890") throw new NotImplementedException();
106134

107-
await next();
135+
await next(context);
108136
});
109137
}
110138

src/BenchmarksApps/TLS/Kestrel/Program.cs

Lines changed: 66 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,27 @@
11
using System.Net;
22
using System.Net.Security;
3+
using System.Security.Authentication;
34
using System.Security.Cryptography.X509Certificates;
45
using Microsoft.AspNetCore.Authentication.Certificate;
6+
using Microsoft.AspNetCore.Connections.Features;
7+
using Microsoft.AspNetCore.Http.Features;
58
using Microsoft.AspNetCore.Server.HttpSys;
69
using Microsoft.AspNetCore.Server.Kestrel.Core;
710
using Microsoft.AspNetCore.Server.Kestrel.Https;
811

912
var builder = WebApplication.CreateBuilder(args);
1013
builder.Logging.ClearProviders();
1114

12-
var writeCertValidationEventsToConsole = bool.TryParse(builder.Configuration["certValidationConsoleEnabled"], out var certValidationConsoleEnabled) && certValidationConsoleEnabled;
15+
// behavioral
1316
var mTlsEnabled = bool.TryParse(builder.Configuration["mTLS"], out var mTlsEnabledConfig) && mTlsEnabledConfig;
1417
var tlsRenegotiationEnabled = bool.TryParse(builder.Configuration["tlsRenegotiation"], out var tlsRenegotiationEnabledConfig) && tlsRenegotiationEnabledConfig;
15-
var statsEnabled = bool.TryParse(builder.Configuration["statsEnabled"], out var connectionStatsEnabledConfig) && connectionStatsEnabledConfig;
1618
var listeningEndpoints = builder.Configuration["urls"] ?? "https://localhost:5000/";
19+
var supportedTlsVersions = ParseSslProtocols(builder.Configuration["tlsProtocols"]);
20+
21+
// debug
22+
var writeCertValidationEventsToConsole = bool.TryParse(builder.Configuration["certValidationConsoleEnabled"], out var certValidationConsoleEnabled) && certValidationConsoleEnabled;
23+
var statsEnabled = bool.TryParse(builder.Configuration["statsEnabled"], out var connectionStatsEnabledConfig) && connectionStatsEnabledConfig;
24+
var logRequestDetails = bool.TryParse(builder.Configuration["logRequestDetails"], out var logRequestDetailsConfig) && logRequestDetailsConfig;
1725

1826
if (mTlsEnabled && tlsRenegotiationEnabled)
1927
{
@@ -40,6 +48,11 @@ void ConfigureListen(KestrelServerOptions serverOptions, IConfigurationRoot conf
4048
// [SuppressMessage("Microsoft.Security", "CSCAN0220.DefaultPasswordContexts", Justification="Benchmark code, not a secret")]
4149
listenOptions.UseHttps("testCert.pfx", "testPassword", options =>
4250
{
51+
if (supportedTlsVersions is not null)
52+
{
53+
options.SslProtocols = supportedTlsVersions.Value;
54+
}
55+
4356
if (mTlsEnabled)
4457
{
4558
options.ClientCertificateMode = ClientCertificateMode.RequireCertificate;
@@ -81,6 +94,28 @@ bool AllowAnyCertificateValidationWithLogging(X509Certificate2 certificate, X509
8194
return true;
8295
}
8396

97+
if (logRequestDetails)
98+
{
99+
var logged = false;
100+
Console.WriteLine("Registered request details logging middleware");
101+
app.Use(async (context, next) =>
102+
{
103+
if (!logged)
104+
{
105+
logged = true;
106+
107+
var tlsHandshakeFeature = context.Features.GetRequiredFeature<ITlsHandshakeFeature>();
108+
109+
Console.WriteLine("Request details:");
110+
Console.WriteLine("-----");
111+
Console.WriteLine("TLS: " + tlsHandshakeFeature.Protocol);
112+
Console.WriteLine("-----");
113+
}
114+
115+
await next(context);
116+
});
117+
}
118+
84119
if (statsEnabled)
85120
{
86121
Console.WriteLine("Registered stats middleware");
@@ -89,7 +124,7 @@ bool AllowAnyCertificateValidationWithLogging(X509Certificate2 certificate, X509
89124
connectionIds.Add(context.Connection.Id);
90125
Console.WriteLine($"[stats] unique connections established: {connectionIds.Count}; fetched certificates: {fetchedCertsCounter}");
91126

92-
await next();
127+
await next(context);
93128
});
94129
}
95130

@@ -109,7 +144,7 @@ bool AllowAnyCertificateValidationWithLogging(X509Certificate2 certificate, X509
109144
Console.WriteLine($"client certificate ({clientCert.Thumbprint}) already exists on the connection {context.Connection.Id}");
110145
}
111146

112-
await next();
147+
await next(context);
113148
});
114149
}
115150

@@ -137,6 +172,7 @@ bool AllowAnyCertificateValidationWithLogging(X509Certificate2 certificate, X509
137172
{
138173
Console.WriteLine($"\tenabled logging stats to console");
139174
}
175+
Console.WriteLine($"\tsupported TLS versions: {supportedTlsVersions}");
140176
Console.WriteLine($"\tlistening endpoints: {listeningEndpoints}");
141177
Console.WriteLine("--------------------------------");
142178

@@ -157,4 +193,30 @@ static IPEndPoint CreateIPEndPoint(UrlPrefix urlPrefix)
157193
}
158194

159195
return new IPEndPoint(ip, urlPrefix.PortValue);
196+
}
197+
198+
static SslProtocols? ParseSslProtocols(string? supportedTlsVersions)
199+
{
200+
var protocols = SslProtocols.None;
201+
if (string.IsNullOrEmpty(supportedTlsVersions) || supportedTlsVersions == "any")
202+
{
203+
return null;
204+
}
205+
206+
foreach (var version in supportedTlsVersions.Split(','))
207+
{
208+
switch (version.Trim().ToLower())
209+
{
210+
case "tls12":
211+
protocols |= SslProtocols.Tls12;
212+
break;
213+
case "tls13":
214+
protocols |= SslProtocols.Tls13;
215+
break;
216+
default:
217+
throw new ArgumentException($"Unsupported TLS version: {version}");
218+
}
219+
}
220+
221+
return protocols;
160222
}

0 commit comments

Comments
 (0)