diff --git a/scenarios/tls.benchmarks.yml b/scenarios/tls.benchmarks.yml index 276976b14..e8219b8e3 100644 --- a/scenarios/tls.benchmarks.yml +++ b/scenarios/tls.benchmarks.yml @@ -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: @@ -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: @@ -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: @@ -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: @@ -87,6 +96,7 @@ scenarios: serverScheme: https certPath: https://raw.githubusercontent.com/aspnet/Benchmarks/refs/heads/main/src/BenchmarksApps/TLS/HttpSys/testCert.pfx certPwd: testPassword + sslProtocol: tls12 # Kestrel @@ -94,12 +104,13 @@ scenarios: application: job: kestrelServer load: - job: wrk + job: httpclient variables: path: /hello-world presetHeaders: connectionclose connections: 32 serverScheme: https + sslProtocol: tls12 mTls-handshakes-kestrel: application: @@ -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: @@ -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 \ No newline at end of file + certPwd: testPassword + sslProtocol: tls12 \ No newline at end of file diff --git a/src/BenchmarksApps/TLS/HttpSys/Program.cs b/src/BenchmarksApps/TLS/HttpSys/Program.cs index 2ab338cb1..56e170b31 100644 --- a/src/BenchmarksApps/TLS/HttpSys/Program.cs +++ b/src/BenchmarksApps/TLS/HttpSys/Program.cs @@ -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 => { @@ -30,6 +36,28 @@ var connectionIds = new HashSet(); 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(); + + Console.WriteLine("Request details:"); + Console.WriteLine("-----"); + Console.WriteLine("TLS: " + tlsHandshakeFeature.Protocol); + Console.WriteLine("-----"); + } + + await next(context); + }); +} + if (statsEnabled) { Console.WriteLine("Registered stats middleware"); @@ -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); }); } @@ -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); }); } diff --git a/src/BenchmarksApps/TLS/Kestrel/Program.cs b/src/BenchmarksApps/TLS/Kestrel/Program.cs index 9fa7b8dc9..4d218dede 100644 --- a/src/BenchmarksApps/TLS/Kestrel/Program.cs +++ b/src/BenchmarksApps/TLS/Kestrel/Program.cs @@ -1,7 +1,10 @@ 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; @@ -9,11 +12,16 @@ 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) { @@ -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; @@ -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(); + + Console.WriteLine("Request details:"); + Console.WriteLine("-----"); + Console.WriteLine("TLS: " + tlsHandshakeFeature.Protocol); + Console.WriteLine("-----"); + } + + await next(context); + }); +} + if (statsEnabled) { Console.WriteLine("Registered stats middleware"); @@ -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); }); } @@ -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); }); } @@ -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("--------------------------------"); @@ -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; } \ No newline at end of file