Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: control tls protocol version for TLS-related benchmark jobs #2048

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 12 additions & 4 deletions scenarios/tls.benchmarks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,17 @@ 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
tlsProtocols: "tls12"
# debug purpose settings
certValidationConsoleEnabled: false
httpSysLogs: false
tlsRegistryLogs: false
statsEnabled: false
arguments: "--urls https://{{serverAddress}}:{{serverPort}} --mTLS {{mTLS}} --certValidationConsoleEnabled {{certValidationConsoleEnabled}} --statsEnabled {{statsEnabled}} --tlsRenegotiation {{tlsRenegotiation}} --httpSysLogs {{httpSysLogs}}"
logRequestInfo: false
arguments: "--urls https://{{serverAddress}}:{{serverPort}} --mTLS {{mTLS}} --certValidationConsoleEnabled {{certValidationConsoleEnabled}} --statsEnabled {{statsEnabled}} --tlsRenegotiation {{tlsRenegotiation}} --httpSysLogs {{httpSysLogs}} --tlsProtocols {{tlsProtocols}} --logRequestInfo {{logRequestInfo}} --tlsRegistryLogs {{tlsRegistryLogs}}"

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

scenarios:

Expand All @@ -43,7 +51,7 @@ scenarios:
application:
job: httpSysServer
load:
job: wrk
job: httpclient
variables:
path: /hello-world
presetHeaders: connectionclose
Expand Down Expand Up @@ -94,7 +102,7 @@ scenarios:
application:
job: kestrelServer
load:
job: wrk
job: httpclient
variables:
path: /hello-world
presetHeaders: connectionclose
Expand Down
40 changes: 40 additions & 0 deletions src/BenchmarksApps/TLS/HttpSys/ConfigurationHelpers.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
using System.Security.Authentication;

namespace HttpSys
{
internal static class ConfigurationHelpers
{
public static SslProtocols ParseSslProtocols(string? supportedTlsVersions)
{
var protocols = SslProtocols.None;
if (string.IsNullOrEmpty(supportedTlsVersions))
{
return protocols;
}

foreach (var version in supportedTlsVersions.Split(','))
{
switch (version.Trim().ToLower())
{
#pragma warning disable SYSLIB0039 // Type or member is obsolete
case "tls11":
protocols |= SslProtocols.Tls11;
break;
#pragma warning restore SYSLIB0039 // Type or member is obsolete
case "tls12":
protocols |= SslProtocols.Tls12;
break;
case "tls13":
protocols |= SslProtocols.Tls13;
break;
case "any":
return SslProtocols.None;
default:
throw new ArgumentException($"Unsupported TLS version: {version}");
}
}

return protocols;
}
}
}
2 changes: 1 addition & 1 deletion src/BenchmarksApps/TLS/HttpSys/HttpSys.csproj
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
Expand Down
37 changes: 33 additions & 4 deletions src/BenchmarksApps/TLS/HttpSys/Program.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
using HttpSys;
using Microsoft.AspNetCore.Connections.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;
var httpSysLoggingEnabled = bool.TryParse(builder.Configuration["httpSysLogs"], out var httpSysLogsEnabled) && httpSysLogsEnabled;
var httpSysLogsEnabled = bool.TryParse(builder.Configuration["httpSysLogs"], out var httpSysLogsConfig) && httpSysLogsConfig;
var tlsRegistryLogsEnabled = bool.TryParse(builder.Configuration["tlsRegistryLogs"], out var tlsRegistryLogsConfig) && tlsRegistryLogsConfig;
var logRequestInfo = bool.TryParse(builder.Configuration["logRequestInfo"], out var logRequestInfoConfig) && logRequestInfoConfig;
var statsEnabled = bool.TryParse(builder.Configuration["statsEnabled"], out var connectionStatsEnabledConfig) && connectionStatsEnabledConfig;
var supportedTlsVersions = ConfigurationHelpers.ParseSslProtocols(builder.Configuration["tlsProtocols"]);

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/";
Expand Down Expand Up @@ -76,6 +81,25 @@ void OnShutdown()
}
}

if (logRequestInfo)
{
Console.WriteLine("Registered request logging middleware");
var logged = false;

app.Use(async (context, next) =>
{
if (!logged)
{
logged = true;
Console.WriteLine("[RequestInfo]");
Console.WriteLine("TLS Protocol: " + context.Features.Get<ITlsHandshakeFeature>()?.Protocol);
Console.WriteLine("---");
}

await next();
});
}

if (tlsRenegotiationEnabled)
{
// this is an http.sys middleware to get a cert
Expand Down Expand Up @@ -108,9 +132,12 @@ void OnShutdown()
});
}

await app.StartAsync();

if (httpSysLoggingEnabled)
RegistryController.EnableTls(supportedTlsVersions);
if (tlsRegistryLogsEnabled)
{
RegistryController.ShowRegistryKeys();
}
if (httpSysLogsEnabled)
{
NetShWrapper.Show();
}
Expand All @@ -131,5 +158,7 @@ void OnShutdown()
Console.WriteLine($"\tlistening endpoints: {listeningEndpoints}");
Console.WriteLine("--------------------------------");

await app.StartAsync();

Console.WriteLine("Application started.");
await app.WaitForShutdownAsync();
140 changes: 140 additions & 0 deletions src/BenchmarksApps/TLS/HttpSys/RegistryController.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
using System.Security.Authentication;
using System.Text;
using Microsoft.Win32;

namespace HttpSys;

[System.Diagnostics.CodeAnalysis.SuppressMessage("Interoperability", "CA1416:Validate platform compatibility", Justification = "benchmark only runs on windows")]
public static class RegistryController
{
// see https://learn.microsoft.com/en-us/windows-server/security/tls/tls-registry-settings?tabs=diffie-hellman
private const string TLS12SubKey = @"SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.2\Server";
private const string TLS13SubKey = @"SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.3\Server";

private static RegistryKey RootRegistryKey => Environment.Is64BitOperatingSystem
? RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64)
: RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32);

public static void ShowRegistryKeys()
{
var tls12DisabledByDefault = GetRegistryValue(TLS12SubKey, "DisabledByDefault");
var tls12Enabled = GetRegistryValue(TLS12SubKey, "Enabled");

var tls13DisabledByDefault = GetRegistryValue(TLS13SubKey, "DisabledByDefault");
var tls13Enabled = GetRegistryValue(TLS13SubKey, "Enabled");

var strBuilder = new StringBuilder("Registry TLS settings: \n");
strBuilder.AppendLine($"\tTLS 1.2: DisabledByDefault='{tls12DisabledByDefault}', Enabled='{tls12Enabled}'");
strBuilder.AppendLine($"\tTLS 1.3: DisabledByDefault='{tls13DisabledByDefault}', Enabled='{tls13Enabled}'");
strBuilder.AppendLine("\t------");

Console.WriteLine(strBuilder.ToString());
}

public static void EnableTls(SslProtocols sslProtocols)
{
Console.WriteLine($"Configuring tls to match {sslProtocols}");

if (sslProtocols.HasFlag(SslProtocols.Tls12))
{
EnableTls12();
return;
}
if (sslProtocols.HasFlag(SslProtocols.Tls13))
{
EnableTls13();
return;
}

Console.WriteLine("Enabling all TLS - no option specified");
EnableAll();
}

private static void EnableAll()
{
// Enable TLS1.2
SetRegistryValue(TLS12SubKey, "DisabledByDefault", value: 0, valueToOverride: 1);
SetRegistryValue(TLS12SubKey, "Enabled", value: 1, valueToOverride: 0);

// Enable TLS1.3
SetRegistryValue(TLS13SubKey, "DisabledByDefault", value: 0, valueToOverride: 1);
SetRegistryValue(TLS13SubKey, "Enabled", value: 1, valueToOverride: 0);
}

private static void EnableTls12()
{
// Enable TLS1.2
SetRegistryValue(TLS12SubKey, "DisabledByDefault", value: 0, valueToOverride: 1);
SetRegistryValue(TLS12SubKey, "Enabled", value: 1, valueToOverride: 0);

// and disable TLS1.3
SetRegistryValue(TLS13SubKey, "DisabledByDefault", value: 0, valueToOverride: 1);
SetRegistryValue(TLS13SubKey, "Enabled", value: 0, valueToOverride: 1);
}

private static void EnableTls13()
{
// Enable TLS1.3
SetRegistryValue(TLS13SubKey, "DisabledByDefault", value: 0, valueToOverride: 1);
SetRegistryValue(TLS13SubKey, "Enabled", value: 1, valueToOverride: 0);

// and disable TLS1.2
SetRegistryValue(TLS12SubKey, "DisabledByDefault", value: 0, valueToOverride: 1);
SetRegistryValue(TLS12SubKey, "Enabled", value: 0, valueToOverride: 1);
}

private static void SetRegistryValue(string subKey, string name, int value, int valueToOverride)
{
var registrySubKey = GetAndCreateSubKey(subKey);

var registryValue = registrySubKey.GetValue(name) as int?;
if (registryValue is null || registryValue == valueToOverride)
{
Console.WriteLine($"Setting value '{value}' on {subKey}\\{name}");
registrySubKey.SetValue(name, value);
Console.WriteLine($"Successfully set value '{value}' on {subKey}\\{name}");
}
}

private static int? GetRegistryValue(string path, string name)
{
var localKey = RootRegistryKey;

var registrySubKey = localKey.OpenSubKey(path);
if (registrySubKey is not null)
{
var value = registrySubKey.GetValue(name);
return value as int?;
}

return null;
}

private static RegistryKey GetAndCreateSubKey(string path)
{
var parts = path.Split(@"\");
var localKey = RootRegistryKey;

RegistryKey? registrySubKey = null;
var currentPath = parts[0] + @"\" + parts[1];
var i = 1;
while (i <= parts.Length)
{
registrySubKey = localKey.OpenSubKey(currentPath, writable: true);
if (registrySubKey is null)
{
Console.WriteLine($"Registry subKey `{currentPath}` does not exist. Creating one...");
registrySubKey = localKey.CreateSubKey(currentPath, writable: true);
Console.WriteLine($"Created Registry subKey `{currentPath}`");
}
currentPath = string.Join(@"\", parts.Take(i++ + 1));
}

if (registrySubKey is null || registrySubKey.Name.Substring(localKey.Name.Length + 1) != path)
{
throw new ArgumentException($"failed to create registry subKey {path}");
}

return registrySubKey;
}
}
5 changes: 4 additions & 1 deletion src/BenchmarksApps/TLS/HttpSys/appsettings.Development.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
},
"mTLS": "false",
"httpSysLogs": "true",
"tlsRegistryLogs": "true",
"tlsRenegotiation": "true",
"certValidationConsoleEnabled": "true"
"certValidationConsoleEnabled": "true",

"tlsProtocols": "tls12"
}
39 changes: 39 additions & 0 deletions src/BenchmarksApps/TLS/Kestrel/ConfigurationHelpers.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
using System.Security.Authentication;

namespace Kestrel
{
internal static class ConfigurationHelpers
{
public static SslProtocols ParseSslProtocols(string? supportedTlsVersions)
{
var protocols = SslProtocols.Tls12; // default it TLS 1.2
if (string.IsNullOrEmpty(supportedTlsVersions))
{
return protocols;
}

protocols = SslProtocols.None;
foreach (var version in supportedTlsVersions.Split(','))
{
switch (version.Trim().ToLower())
{
#pragma warning disable SYSLIB0039 // Type or member is obsolete
case "tls11":
protocols |= SslProtocols.Tls11;
break;
#pragma warning restore SYSLIB0039 // Type or member is obsolete
case "tls12":
protocols |= SslProtocols.Tls12;
break;
case "tls13":
protocols |= SslProtocols.Tls13;
break;
default:
throw new ArgumentException($"Unsupported TLS version: {version}");
}
}

return protocols;
}
}
}
7 changes: 6 additions & 1 deletion src/BenchmarksApps/TLS/Kestrel/Program.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
using System.Net;
using System.Net.Security;
using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates;
using Microsoft.AspNetCore.Authentication.Certificate;
using Kestrel;
using Microsoft.AspNetCore.Server.HttpSys;
using Microsoft.AspNetCore.Server.Kestrel.Core;
using Microsoft.AspNetCore.Server.Kestrel.Https;
Expand All @@ -14,6 +15,7 @@
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 = ConfigurationHelpers.ParseSslProtocols(builder.Configuration["tlsProtocols"]);

if (mTlsEnabled && tlsRenegotiationEnabled)
{
Expand All @@ -40,6 +42,8 @@
// [SuppressMessage("Microsoft.Security", "CSCAN0220.DefaultPasswordContexts", Justification="Benchmark code, not a secret")]
listenOptions.UseHttps("testCert.pfx", "testPassword", options =>
{
options.SslProtocols = supportedTlsVersions;

if (mTlsEnabled)
{
options.ClientCertificateMode = ClientCertificateMode.RequireCertificate;
Expand Down Expand Up @@ -137,6 +141,7 @@
{
Console.WriteLine($"\tenabled logging stats to console");
}
Console.WriteLine($"\tsupported TLS versions: {supportedTlsVersions}");
Console.WriteLine($"\tlistening endpoints: {listeningEndpoints}");
Console.WriteLine("--------------------------------");

Expand All @@ -151,7 +156,7 @@
{
ip = IPAddress.Loopback;
}
else if (!IPAddress.TryParse(urlPrefix.Host, out ip))

Check warning on line 159 in src/BenchmarksApps/TLS/Kestrel/Program.cs

View workflow job for this annotation

GitHub Actions / Build & Test (ubuntu-latest)

Converting null literal or possible null value to non-nullable type.
{
ip = IPAddress.IPv6Any;
}
Expand Down
Loading