Skip to content

Commit

Permalink
feat: control SSL protocol version on tls jobs (#2049)
Browse files Browse the repository at this point in the history
  • Loading branch information
DeagleGross authored Jan 22, 2025
1 parent ed94252 commit e8d6427
Show file tree
Hide file tree
Showing 3 changed files with 116 additions and 13 deletions.
23 changes: 18 additions & 5 deletions scenarios/tls.benchmarks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,15 @@ jobs:
project: src/BenchmarksApps/TLS/HttpSys/HttpSys.csproj
readyStateText: Application started.
variables:
# behavioral settings
mTLS: false # enables settings on http.sys to negotiate client cert on connections
tlsRenegotiation: false # enables client cert validation
# debug settings
certValidationConsoleEnabled: false
httpSysLogs: false
statsEnabled: false
arguments: "--urls https://{{serverAddress}}:{{serverPort}} --mTLS {{mTLS}} --certValidationConsoleEnabled {{certValidationConsoleEnabled}} --statsEnabled {{statsEnabled}} --tlsRenegotiation {{tlsRenegotiation}} --httpSysLogs {{httpSysLogs}}"
logRequestDetails: false
arguments: "--urls https://{{serverAddress}}:{{serverPort}} --mTLS {{mTLS}} --certValidationConsoleEnabled {{certValidationConsoleEnabled}} --statsEnabled {{statsEnabled}} --tlsRenegotiation {{tlsRenegotiation}} --httpSysLogs {{httpSysLogs}} --logRequestDetails {{logRequestDetails}}"

kestrelServer:
source:
Expand All @@ -29,11 +32,15 @@ jobs:
project: src/BenchmarksApps/TLS/Kestrel/Kestrel.csproj
readyStateText: Application started.
variables:
# behavioral settings
mTLS: false
tlsRenegotiation: false
tlsProtocols: "tls12,tls13"
# debug settings
certValidationConsoleEnabled: false
statsEnabled: false
arguments: "--urls https://{{serverAddress}}:{{serverPort}} --mTLS {{mTLS}} --certValidationConsoleEnabled {{certValidationConsoleEnabled}} --statsEnabled {{statsEnabled}} --tlsRenegotiation {{tlsRenegotiation}}"
logRequestDetails: false
arguments: "--urls https://{{serverAddress}}:{{serverPort}} --mTLS {{mTLS}} --certValidationConsoleEnabled {{certValidationConsoleEnabled}} --tlsProtocols {{tlsProtocols}} --statsEnabled {{statsEnabled}} --tlsRenegotiation {{tlsRenegotiation}} --logRequestDetails {{logRequestDetails}}"

scenarios:

Expand All @@ -43,12 +50,13 @@ scenarios:
application:
job: httpSysServer
load:
job: wrk
job: httpclient
variables:
path: /hello-world
presetHeaders: connectionclose
connections: 32
serverScheme: https
sslProtocol: tls12

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

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

# Kestrel

tls-handshakes-kestrel:
application:
job: kestrelServer
load:
job: wrk
job: httpclient
variables:
path: /hello-world
presetHeaders: connectionclose
connections: 32
serverScheme: https
sslProtocol: tls12

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

tls-renegotiation-kestrel:
application:
Expand All @@ -132,4 +144,5 @@ scenarios:
connections: 32
serverScheme: https
certPath: https://raw.githubusercontent.com/aspnet/Benchmarks/refs/heads/main/src/BenchmarksApps/TLS/Kestrel/testCert.pfx
certPwd: testPassword
certPwd: testPassword
sslProtocol: tls12
36 changes: 32 additions & 4 deletions src/BenchmarksApps/TLS/HttpSys/Program.cs
Original file line number Diff line number Diff line change
@@ -1,17 +1,23 @@
using HttpSys;
using Microsoft.AspNetCore.Connections.Features;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Server.HttpSys;

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

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

// debug
var writeCertValidationEventsToConsole = bool.TryParse(builder.Configuration["certValidationConsoleEnabled"], out var certValidationConsoleEnabled) && certValidationConsoleEnabled;
var statsEnabled = bool.TryParse(builder.Configuration["statsEnabled"], out var connectionStatsEnabledConfig) && connectionStatsEnabledConfig;
var logRequestDetails = bool.TryParse(builder.Configuration["logRequestDetails"], out var logRequestDetailsConfig) && logRequestDetailsConfig;

#pragma warning disable CA1416 // Can be launched only on Windows (HttpSys)
builder.WebHost.UseHttpSys(options =>
{
Expand All @@ -30,6 +36,28 @@
var connectionIds = new HashSet<string>();
var fetchedCertsCounter = 0;

if (logRequestDetails)
{
var logged = false;
Console.WriteLine("Registered request details logging middleware");
app.Use(async (context, next) =>
{
if (!logged)
{
logged = true;

var tlsHandshakeFeature = context.Features.GetRequiredFeature<ITlsHandshakeFeature>();

Console.WriteLine("Request details:");
Console.WriteLine("-----");
Console.WriteLine("TLS: " + tlsHandshakeFeature.Protocol);
Console.WriteLine("-----");
}

await next(context);
});
}

if (statsEnabled)
{
Console.WriteLine("Registered stats middleware");
Expand All @@ -38,7 +66,7 @@
connectionIds.Add(context.Connection.Id);
Console.WriteLine($"[stats] unique connections established: {connectionIds.Count}; fetched certificates: {fetchedCertsCounter}");

await next();
await next(context);
});
}

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

await next();
await next(context);
});
}

Expand Down
70 changes: 66 additions & 4 deletions src/BenchmarksApps/TLS/Kestrel/Program.cs
Original file line number Diff line number Diff line change
@@ -1,19 +1,27 @@
using System.Net;
using System.Net.Security;
using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates;
using Microsoft.AspNetCore.Authentication.Certificate;
using Microsoft.AspNetCore.Connections.Features;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Server.HttpSys;
using Microsoft.AspNetCore.Server.Kestrel.Core;
using Microsoft.AspNetCore.Server.Kestrel.Https;

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

var writeCertValidationEventsToConsole = bool.TryParse(builder.Configuration["certValidationConsoleEnabled"], out var certValidationConsoleEnabled) && certValidationConsoleEnabled;
// behavioral
var mTlsEnabled = bool.TryParse(builder.Configuration["mTLS"], out var mTlsEnabledConfig) && mTlsEnabledConfig;
var tlsRenegotiationEnabled = bool.TryParse(builder.Configuration["tlsRenegotiation"], out var tlsRenegotiationEnabledConfig) && tlsRenegotiationEnabledConfig;
var statsEnabled = bool.TryParse(builder.Configuration["statsEnabled"], out var connectionStatsEnabledConfig) && connectionStatsEnabledConfig;
var listeningEndpoints = builder.Configuration["urls"] ?? "https://localhost:5000/";
var supportedTlsVersions = ParseSslProtocols(builder.Configuration["tlsProtocols"]);

// debug
var writeCertValidationEventsToConsole = bool.TryParse(builder.Configuration["certValidationConsoleEnabled"], out var certValidationConsoleEnabled) && certValidationConsoleEnabled;
var statsEnabled = bool.TryParse(builder.Configuration["statsEnabled"], out var connectionStatsEnabledConfig) && connectionStatsEnabledConfig;
var logRequestDetails = bool.TryParse(builder.Configuration["logRequestDetails"], out var logRequestDetailsConfig) && logRequestDetailsConfig;

if (mTlsEnabled && tlsRenegotiationEnabled)
{
Expand All @@ -40,6 +48,11 @@ void ConfigureListen(KestrelServerOptions serverOptions, IConfigurationRoot conf
// [SuppressMessage("Microsoft.Security", "CSCAN0220.DefaultPasswordContexts", Justification="Benchmark code, not a secret")]
listenOptions.UseHttps("testCert.pfx", "testPassword", options =>
{
if (supportedTlsVersions is not null)
{
options.SslProtocols = supportedTlsVersions.Value;
}

if (mTlsEnabled)
{
options.ClientCertificateMode = ClientCertificateMode.RequireCertificate;
Expand Down Expand Up @@ -81,6 +94,28 @@ bool AllowAnyCertificateValidationWithLogging(X509Certificate2 certificate, X509
return true;
}

if (logRequestDetails)
{
var logged = false;
Console.WriteLine("Registered request details logging middleware");
app.Use(async (context, next) =>
{
if (!logged)
{
logged = true;

var tlsHandshakeFeature = context.Features.GetRequiredFeature<ITlsHandshakeFeature>();

Console.WriteLine("Request details:");
Console.WriteLine("-----");
Console.WriteLine("TLS: " + tlsHandshakeFeature.Protocol);
Console.WriteLine("-----");
}

await next(context);
});
}

if (statsEnabled)
{
Console.WriteLine("Registered stats middleware");
Expand All @@ -89,7 +124,7 @@ bool AllowAnyCertificateValidationWithLogging(X509Certificate2 certificate, X509
connectionIds.Add(context.Connection.Id);
Console.WriteLine($"[stats] unique connections established: {connectionIds.Count}; fetched certificates: {fetchedCertsCounter}");

await next();
await next(context);
});
}

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

await next();
await next(context);
});
}

Expand Down Expand Up @@ -137,6 +172,7 @@ bool AllowAnyCertificateValidationWithLogging(X509Certificate2 certificate, X509
{
Console.WriteLine($"\tenabled logging stats to console");
}
Console.WriteLine($"\tsupported TLS versions: {supportedTlsVersions}");
Console.WriteLine($"\tlistening endpoints: {listeningEndpoints}");
Console.WriteLine("--------------------------------");

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

return new IPEndPoint(ip, urlPrefix.PortValue);
}

static SslProtocols? ParseSslProtocols(string? supportedTlsVersions)
{
var protocols = SslProtocols.None;
if (string.IsNullOrEmpty(supportedTlsVersions) || supportedTlsVersions == "any")
{
return null;
}

foreach (var version in supportedTlsVersions.Split(','))
{
switch (version.Trim().ToLower())
{
case "tls12":
protocols |= SslProtocols.Tls12;
break;
case "tls13":
protocols |= SslProtocols.Tls13;
break;
default:
throw new ArgumentException($"Unsupported TLS version: {version}");
}
}

return protocols;
}

0 comments on commit e8d6427

Please sign in to comment.