Skip to content

Commit 369ee94

Browse files
committed
pre-configure properly!
1 parent 37c7b5c commit 369ee94

File tree

4 files changed

+101
-62
lines changed

4 files changed

+101
-62
lines changed

src/BenchmarksApps/TLS/HttpSys/NetShWrapper.cs renamed to src/BenchmarksApps/TLS/HttpSys/NetSh/NetShWrapper.cs

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
using System.Diagnostics;
22
using System.Security.Cryptography.X509Certificates;
33
using System.Text.RegularExpressions;
4-
using HttpSys.NetSh;
54

6-
namespace HttpSys
5+
namespace HttpSys.NetSh
76
{
87
public class NetShWrapper
98
{
@@ -41,17 +40,17 @@ public void DeleteBindingIfExists(string ipPort)
4140
{
4241
DeleteBinding(ipPort);
4342
}
44-
catch
43+
catch (Exception ex)
4544
{
46-
// ignore
45+
Console.WriteLine($"Failed to delete binding on port {ipPort}: " + ex);
4746
}
4847
}
4948

5049
public void DeleteBinding(string ipPort)
5150
{
5251
Console.WriteLine("Disabling mTLS for http.sys");
5352

54-
string command = $"http delete sslcert ipport={ipPort}";
53+
var command = $"http delete sslcert ipport={ipPort}";
5554
ExecuteNetShCommand(command);
5655

5756
Console.WriteLine("Disabled http.sys settings for mTLS");
@@ -168,23 +167,23 @@ public void SetTestCertBinding(string ipPort, bool enableClientCertNegotiation)
168167
store.Close();
169168
}
170169

171-
string certThumbprint = certificate.Thumbprint;
170+
var certThumbprint = certificate.Thumbprint;
172171
AddCertBinding(ipPort, certThumbprint, clientCertNegotiation: enableClientCertNegotiation ? NetShFlag.Enable : NetShFlag.Disabled);
173172

174173
Console.WriteLine("Configured binding for testCert for http.sys");
175174
}
176175

177-
public bool TrySelfSignCertificate(string ipPort, out string certThumbprint)
176+
public bool TrySelfSignCertificate(string ipPort, int certPublicKeyLength, out string certThumbprint)
178177
{
179178
certThumbprint = string.Empty;
180179
try
181180
{
182181
// Extract the IP address from ipPort
183-
string ipAddress = ipPort.Split(':')[0];
182+
var ipAddress = ipPort.Split(':')[0];
184183

185184
// Generate a self-signed certificate using PowerShell
186-
string command = $"New-SelfSignedCertificate -CertStoreLocation cert:\\LocalMachine\\My -DnsName {ipAddress}";
187-
string output = ExecutePowershellCommand(command);
185+
var command = $"New-SelfSignedCertificate -CertStoreLocation cert:\\LocalMachine\\My -DnsName {ipAddress} -KeyAlgorithm RSA -KeyLength {certPublicKeyLength}";
186+
var output = ExecutePowershellCommand(command);
188187

189188
// Extract the thumbprint from the output
190189
var lines = output.Split("\r\n", StringSplitOptions.RemoveEmptyEntries);
@@ -241,7 +240,7 @@ private void CertBindingCore(
241240
var clientcertnegotiationFlag = GetFlagValue(clientcertnegotiation);
242241
var disablesessionidFlag = GetFlagValue(disablesessionid);
243242
var enablesessionticketFlag = GetFlagValue(enablesessionticket);
244-
string command = $"http {httpOperation} sslcert ipport={ipPort} certstorename=MY certhash={certThumbprint} appid={{{appId}}}";
243+
var command = $"http {httpOperation} sslcert ipport={ipPort} certstorename=MY certhash={certThumbprint} appid={{{appId}}}";
245244

246245
if (clientcertnegotiationFlag != null)
247246
{
@@ -280,7 +279,7 @@ private static string ExecuteNetShCommand(string command, bool ignoreErrorExit =
280279

281280
private static string ExecuteCommand(string fileName, string command, bool ignoreErrorExit = false, bool logOutput = false)
282281
{
283-
ProcessStartInfo processInfo = new ProcessStartInfo(fileName, command)
282+
var processInfo = new ProcessStartInfo(fileName, command)
284283
{
285284
RedirectStandardOutput = true,
286285
RedirectStandardError = true,
@@ -289,8 +288,8 @@ private static string ExecuteCommand(string fileName, string command, bool ignor
289288
};
290289

291290
Console.WriteLine($"Executing command: `{fileName} {command}`");
292-
using Process process = Process.Start(processInfo)!;
293-
string output = process.StandardOutput.ReadToEnd();
291+
using var process = Process.Start(processInfo)!;
292+
var output = process.StandardOutput.ReadToEnd();
294293
process.WaitForExit();
295294

296295
if (logOutput)
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
namespace HttpSys.NetSh
2+
{
3+
public static class NetshConfigurator
4+
{
5+
private static readonly NetShWrapper _netshWrapper = new();
6+
private static string _certThumbprint;
7+
8+
public static SslCertBinding PreConfigureNetsh(
9+
string httpsIpPort,
10+
int certPublicKeyLength = 2048,
11+
NetShFlag clientCertNegotiation = NetShFlag.Disabled,
12+
NetShFlag disablesessionid = NetShFlag.Enable,
13+
NetShFlag enableSessionTicket = NetShFlag.Disabled)
14+
{
15+
// we will anyway reconfigure the netsh certificate binding, so we can delete it firstly
16+
_netshWrapper.DeleteBindingIfExists(httpsIpPort);
17+
18+
if (_netshWrapper.TryGetSslCertBinding(httpsIpPort, out var sslCertBinding))
19+
{
20+
throw new NetshException($"Binding already exists ({httpsIpPort}). It was unable to be deleted, and run can not proceed without proper configuration. SslCertBinding: " + sslCertBinding);
21+
}
22+
23+
if (!_netshWrapper.TrySelfSignCertificate(httpsIpPort, certPublicKeyLength, out _certThumbprint))
24+
{
25+
throw new ApplicationException($"Failed to setup ssl binding for '{httpsIpPort}'. Please unblock the VM.");
26+
}
27+
28+
_netshWrapper.AddCertBinding(
29+
httpsIpPort,
30+
_certThumbprint,
31+
disablesessionid: disablesessionid,
32+
enablesessionticket: enableSessionTicket,
33+
clientCertNegotiation: clientCertNegotiation);
34+
35+
if (!_netshWrapper.TryGetSslCertBinding(httpsIpPort, out sslCertBinding))
36+
{
37+
throw new NetshException($"Failed to setup ssl binding for '{httpsIpPort}'. Please unblock the VM.");
38+
}
39+
40+
return sslCertBinding;
41+
}
42+
43+
public static void LogCurrentSslCertBinding(string httpsIpPort) => _netshWrapper.LogSslCertBinding(httpsIpPort);
44+
45+
public static void ResetNetshConfiguration(
46+
string httpsIpPort,
47+
int certPublicKeyLength = 4096)
48+
{
49+
_netshWrapper.DeleteBindingIfExists(httpsIpPort);
50+
_netshWrapper.AddCertBinding(
51+
httpsIpPort,
52+
_certThumbprint,
53+
disablesessionid: NetShFlag.NotSet,
54+
enablesessionticket: NetShFlag.NotSet,
55+
clientCertNegotiation: NetShFlag.NotSet);
56+
}
57+
}
58+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
namespace HttpSys.NetSh
2+
{
3+
public class NetshException : Exception
4+
{
5+
public NetshException(string message) : base(message)
6+
{
7+
}
8+
public NetshException(string message, Exception innerException) : base(message, innerException)
9+
{
10+
}
11+
public NetshException(string message, string command) : base($"{message} Command: {command}")
12+
{
13+
}
14+
public NetshException(string message, string command, Exception innerException) : base($"{message} Command: {command}", innerException)
15+
{
16+
}
17+
}
18+
}

src/BenchmarksApps/TLS/HttpSys/Program.cs

Lines changed: 12 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
// behavioral
1111
var mTlsEnabled = bool.TryParse(builder.Configuration["mTLS"], out var mTlsEnabledConfig) && mTlsEnabledConfig;
1212
var tlsRenegotiationEnabled = bool.TryParse(builder.Configuration["tlsRenegotiation"], out var tlsRenegotiationEnabledConfig) && tlsRenegotiationEnabledConfig;
13+
var certPublicKeySpecified = int.TryParse(builder.Configuration["certPublicKeyLength"], out var certPublicKeyConfig);
14+
var certPublicKeyLength = certPublicKeySpecified ? certPublicKeyConfig : 2048;
1315
var listeningEndpoints = builder.Configuration["urls"] ?? "https://localhost:5000/";
1416
var httpsIpPort = listeningEndpoints.Split(";").First(x => x.Contains("https")).Replace("https://", "");
1517

@@ -18,45 +20,12 @@
1820
var statsEnabled = bool.TryParse(builder.Configuration["statsEnabled"], out var connectionStatsEnabledConfig) && connectionStatsEnabledConfig;
1921
var logRequestDetails = bool.TryParse(builder.Configuration["logRequestDetails"], out var logRequestDetailsConfig) && logRequestDetailsConfig;
2022

21-
var mTLSNetShFlag = mTlsEnabled ? NetShFlag.Enable : NetShFlag.Disabled;
22-
23-
var netshWrapper = new NetShWrapper();
24-
25-
// verify there is an netsh http sslcert binding for specified ip:port
26-
if (!netshWrapper.TryGetSslCertBinding(httpsIpPort, out var sslCertBinding))
27-
{
28-
Console.WriteLine($"No binding existed. Need to self-sign it and bind to '{httpsIpPort}'");
29-
if (!netshWrapper.TrySelfSignCertificate(httpsIpPort, out var originalCertThumbprint))
30-
{
31-
throw new ApplicationException($"Failed to setup ssl binding for '{httpsIpPort}'. Please unblock the VM.");
32-
}
33-
netshWrapper.AddCertBinding(
34-
httpsIpPort,
35-
originalCertThumbprint,
36-
disablesessionid: NetShFlag.Enable,
37-
enablesessionticket: NetShFlag.Disabled,
38-
clientCertNegotiation: mTLSNetShFlag);
39-
}
40-
41-
Console.WriteLine("Current netsh ssl certificate binding: \n" + sslCertBinding);
42-
43-
if (
44-
// those flags can be set only on later versions of HTTP.SYS; so only considering mTLS here
45-
(netshWrapper.SupportsDisableSessionId && sslCertBinding.DisableSessionIdTlsResumption != NetShFlag.Enable)
46-
|| (netshWrapper.SupportsEnableSessionTicket && (sslCertBinding.EnableSessionTicketTlsResumption == NetShFlag.Enable))
47-
|| sslCertBinding.NegotiateClientCertificate != mTLSNetShFlag)
48-
{
49-
Console.WriteLine($"Need to prepare ssl-cert binding for the run.");
50-
Console.WriteLine($"Expected configuration: mTLS={mTLSNetShFlag}; disableSessionId={NetShFlag.Enable}; enableSessionTicket={NetShFlag.Disabled}");
51-
52-
netshWrapper.UpdateCertBinding(
53-
httpsIpPort,
54-
sslCertBinding.CertificateThumbprint,
55-
appId: sslCertBinding.ApplicationId,
56-
disablesessionid: NetShFlag.Enable,
57-
enablesessionticket: NetShFlag.Disabled,
58-
clientCertNegotiation: mTLSNetShFlag);
59-
}
23+
var sslCertConfiguration = NetshConfigurator.PreConfigureNetsh(
24+
httpsIpPort,
25+
certPublicKeyLength: certPublicKeyLength,
26+
clientCertNegotiation: mTlsEnabled ? NetShFlag.Enable : NetShFlag.Disabled,
27+
disablesessionid: NetShFlag.Enable,
28+
enableSessionTicket: NetShFlag.Disabled);
6029

6130
#pragma warning disable CA1416 // Can be launched only on Windows (HttpSys)
6231
builder.WebHost.UseHttpSys(options =>
@@ -143,7 +112,7 @@
143112

144113
await app.StartAsync();
145114

146-
netshWrapper.LogSslCertBinding(httpsIpPort);
115+
NetshConfigurator.LogCurrentSslCertBinding(httpsIpPort);
147116

148117
Console.WriteLine("Application Info:");
149118
if (mTlsEnabled)
@@ -165,11 +134,6 @@
165134
await app.WaitForShutdownAsync();
166135
Console.WriteLine("Application stopped.");
167136

168-
if (netshWrapper.TryGetSslCertBinding(httpsIpPort, out sslCertBinding) && mTLSNetShFlag == NetShFlag.Enable)
169-
{
170-
// update the sslCert binding to disable "negotiate client cert" (aka mTLS) to not break other tests.
171-
Console.WriteLine($"Rolling back mTLS setting for sslCert binding at '{httpsIpPort}'");
172-
173-
sslCertBinding.NegotiateClientCertificate = NetShFlag.Disabled;
174-
netshWrapper.UpdateCertBinding(httpsIpPort, sslCertBinding);
175-
}
137+
Console.WriteLine("Starting netsh rollback configuration...");
138+
NetshConfigurator.ResetNetshConfiguration(httpsIpPort, certPublicKeyLength: 4096); // a default value
139+
Console.WriteLine($"Reset netsh (ipport={httpsIpPort}) completed.");

0 commit comments

Comments
 (0)