Skip to content

Commit 3f44486

Browse files
committed
try with httpsys api
1 parent 0f1cd4a commit 3f44486

File tree

4 files changed

+73
-56
lines changed

4 files changed

+73
-56
lines changed

scenarios/tls.benchmarks.yml

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,6 @@
77
variables:
88
serverPort: 5000
99

10-
# these scripts allow to disable (or rollback changes) to the SChannel registry
11-
# this allows to disable TLS resumption on windows level
12-
disableTlsResumptionScript: powershell -Command "New-ItemProperty 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\' -Name MaximumCacheSize -PropertyType DWord -Value 0 -ErrorAction Ignore; New-ItemProperty 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\' -Name ServerCacheTime -PropertyType DWord -Value 0 -ErrorAction Ignore; Restart-Service -Name Http -Force;"
13-
rollbackTlsResumptionScript: powershell -Command "Remove-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL' -Name MaximumCacheSize -ErrorAction Ignore; Remove-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL' -Name ServerCacheTime -ErrorAction Ignore; Restart-Service -Name Http -Force;"
14-
1510
jobs:
1611
httpSysServer:
1712
source:
@@ -70,8 +65,6 @@ scenarios:
7065
tls-handshakes-httpsys:
7166
application:
7267
job: httpSysServer
73-
beforeScript: "{{disableTlsResumptionScript}}"
74-
afterScript: "{{rollbackTlsResumptionScript}}"
7568
load:
7669
job: httpclient
7770
variables:
@@ -84,8 +77,6 @@ scenarios:
8477
mTls-handshakes-httpsys:
8578
application:
8679
job: httpSysServer
87-
beforeScript: "{{disableTlsResumptionScript}}"
88-
afterScript: "{{rollbackTlsResumptionScript}}"
8980
variables:
9081
mTLS: true # enables settings on http.sys to negotiate client cert on connections
9182
tlsRenegotiation: true # enables client cert validation
@@ -106,8 +97,6 @@ scenarios:
10697
tls-renegotiation-httpsys:
10798
application:
10899
job: httpSysServer
109-
beforeScript: "{{disableTlsResumptionScript}}"
110-
afterScript: "{{rollbackTlsResumptionScript}}"
111100
variables:
112101
mTLS: false
113102
tlsRenegotiation: true

src/BenchmarksApps/TLS/HttpSys/NetSh/SslCertBinding.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,12 @@ public override string ToString() => $"""
2424
""";
2525
}
2626

27+
[Flags]
2728
public enum NetShFlag
2829
{
29-
NotSet = 0,
30+
NotSet = 0,
3031

31-
Disabled = 1,
32-
Enable = 2
32+
Disabled = 1,
33+
Enable = 2,
3334
}
3435
}

src/BenchmarksApps/TLS/HttpSys/NetShWrapper.cs

Lines changed: 55 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,37 @@
55

66
namespace HttpSys
77
{
8-
public static class NetShWrapper
8+
public class NetShWrapper
99
{
10-
public static void DeleteBindingIfExists(string ipPort)
10+
public bool SupportsDisableSessionId { get; }
11+
public bool SupportsEnableSessionTicket { get; }
12+
13+
public NetShWrapper()
14+
{
15+
var sslCertCapabilitiesText = ExecuteNetShCommand($"http add sslcert help");
16+
if (string.IsNullOrEmpty(sslCertCapabilitiesText))
17+
{
18+
throw new InvalidOperationException("Failed to determine http.sys capabilities");
19+
}
20+
21+
if (sslCertCapabilitiesText.Contains("disablesessionid"))
22+
{
23+
SupportsDisableSessionId = true;
24+
}
25+
26+
if (sslCertCapabilitiesText.Contains("enablesessionticket"))
27+
{
28+
SupportsEnableSessionTicket = true;
29+
}
30+
31+
Console.WriteLine($"""
32+
Http.SYS Capabilities:
33+
- SupportsDisableSessionId: {SupportsDisableSessionId} (if not supported, renegotiation will most likely be enabled by default)
34+
- SupportsEnableSessionTicket: {SupportsEnableSessionTicket}
35+
""");
36+
}
37+
38+
public void DeleteBindingIfExists(string ipPort)
1139
{
1240
try
1341
{
@@ -19,7 +47,7 @@ public static void DeleteBindingIfExists(string ipPort)
1947
}
2048
}
2149

22-
public static void DeleteBinding(string ipPort)
50+
public void DeleteBinding(string ipPort)
2351
{
2452
Console.WriteLine("Disabling mTLS for http.sys");
2553

@@ -29,9 +57,7 @@ public static void DeleteBinding(string ipPort)
2957
Console.WriteLine("Disabled http.sys settings for mTLS");
3058
}
3159

32-
33-
34-
public static bool TryGetSslCertBinding(string ipPort, out SslCertBinding result)
60+
public bool TryGetSslCertBinding(string ipPort, out SslCertBinding result)
3561
{
3662
result = new SslCertBinding();
3763

@@ -71,7 +97,7 @@ public static bool TryGetSslCertBinding(string ipPort, out SslCertBinding result
7197
Max Settings Per Frame : 2796202
7298
Max Settings Per Minute : 4294967295
7399
*/
74-
var bindings = ExecuteNetShCommand($"http show sslcert ipport={ipPort}");
100+
var bindings = ExecuteNetShCommand($"http show sslcert ipport={ipPort}", ignoreErrorExit: true);
75101
if (string.IsNullOrEmpty(bindings) || !bindings.Contains(ipPort))
76102
{
77103
return false;
@@ -123,12 +149,12 @@ public static bool TryGetSslCertBinding(string ipPort, out SslCertBinding result
123149
};
124150
}
125151

126-
public static void LogSslCertBinding(string ipPort)
152+
public void LogSslCertBinding(string ipPort)
127153
{
128154
ExecuteNetShCommand($"http show sslcert ipport={ipPort}", alwaysLogOutput: true);
129155
}
130156

131-
public static void SetTestCertBinding(string ipPort, bool enableClientCertNegotiation)
157+
public void SetTestCertBinding(string ipPort, bool enableClientCertNegotiation)
132158
{
133159
Console.WriteLine("Setting up binding for testCert for http.sys");
134160

@@ -148,7 +174,7 @@ public static void SetTestCertBinding(string ipPort, bool enableClientCertNegoti
148174
Console.WriteLine("Configured binding for testCert for http.sys");
149175
}
150176

151-
public static bool TrySelfSignCertificate(string ipPort, out string certThumbprint)
177+
public bool TrySelfSignCertificate(string ipPort, out string certThumbprint)
152178
{
153179
certThumbprint = string.Empty;
154180
try
@@ -175,31 +201,31 @@ public static bool TrySelfSignCertificate(string ipPort, out string certThumbpri
175201
}
176202
}
177203

178-
public static void AddCertBinding(
204+
public void AddCertBinding(
179205
string ipPort, string certThumbprint,
180206
string? appId = null,
181207
NetShFlag clientCertNegotiation = NetShFlag.Disabled,
182208
NetShFlag disablesessionid = NetShFlag.Enable,
183209
NetShFlag enablesessionticket = NetShFlag.Disabled)
184210
=> CertBindingCore("add", ipPort, certThumbprint, appId, clientCertNegotiation, disablesessionid, enablesessionticket);
185211

186-
public static void UpdateCertBinding(string ipPort, SslCertBinding binding) => UpdateCertBinding(
212+
public void UpdateCertBinding(string ipPort, SslCertBinding binding) => UpdateCertBinding(
187213
ipPort,
188214
binding.CertificateThumbprint,
189215
binding.ApplicationId,
190216
binding.NegotiateClientCertificate ,
191217
binding.DisableSessionIdTlsResumption,
192218
binding.EnableSessionTicketTlsResumption);
193219

194-
public static void UpdateCertBinding(
220+
public void UpdateCertBinding(
195221
string ipPort, string certThumbprint,
196222
string? appId = null,
197223
NetShFlag clientCertNegotiation = NetShFlag.Disabled,
198224
NetShFlag disablesessionid = NetShFlag.Enable,
199225
NetShFlag enablesessionticket = NetShFlag.Disabled)
200226
=> CertBindingCore("update", ipPort, certThumbprint, appId, clientCertNegotiation, disablesessionid, enablesessionticket);
201227

202-
private static void CertBindingCore(
228+
private void CertBindingCore(
203229
string httpOperation,
204230
string ipPort, string certThumbprint,
205231
string? appId = null,
@@ -224,17 +250,15 @@ private static void CertBindingCore(
224250

225251
// below options are supported only in later versions of HTTP.SYS
226252
// you can identify if it is available by running `netsh http add sslcert help`
227-
// ---
228-
// workaround is to control SChannel settings via registry
229-
230-
//if (disablesessionidFlag != null)
231-
//{
232-
// command += $" disablesessionid={disablesessionidFlag}";
233-
//}
234-
//if (enablesessionticketFlag != null)
235-
//{
236-
// command += $" enablesessionticket={enablesessionticketFlag}";
237-
//}
253+
254+
if (SupportsDisableSessionId && disablesessionidFlag != null)
255+
{
256+
command += $" disablesessionid={disablesessionidFlag}";
257+
}
258+
if (SupportsEnableSessionTicket && enablesessionticketFlag != null)
259+
{
260+
command += $" enablesessionticket={enablesessionticketFlag}";
261+
}
238262

239263
ExecuteNetShCommand(command, alwaysLogOutput: true);
240264
Console.WriteLine($"Performed cert binding for {ipPort}");
@@ -248,13 +272,13 @@ private static void CertBindingCore(
248272
};
249273
}
250274

251-
private static string ExecutePowershellCommand(string command, bool alwaysLogOutput = false)
252-
=> ExecuteCommand("powershell.exe", command, alwaysLogOutput);
275+
private static string ExecutePowershellCommand(string command, bool ignoreErrorExit = false, bool alwaysLogOutput = false)
276+
=> ExecuteCommand("powershell.exe", command, ignoreErrorExit, alwaysLogOutput);
253277

254-
private static string ExecuteNetShCommand(string command, bool alwaysLogOutput = false)
255-
=> ExecuteCommand("netsh", command, alwaysLogOutput);
278+
private static string ExecuteNetShCommand(string command, bool ignoreErrorExit = false, bool alwaysLogOutput = false)
279+
=> ExecuteCommand("netsh", command, ignoreErrorExit, alwaysLogOutput);
256280

257-
private static string ExecuteCommand(string fileName, string command, bool logOutput = false)
281+
private static string ExecuteCommand(string fileName, string command, bool ignoreErrorExit = false, bool logOutput = false)
258282
{
259283
ProcessStartInfo processInfo = new ProcessStartInfo(fileName, command)
260284
{
@@ -274,7 +298,7 @@ private static string ExecuteCommand(string fileName, string command, bool logOu
274298
Console.WriteLine(output);
275299
}
276300

277-
if (process.ExitCode != 0)
301+
if (!ignoreErrorExit && process.ExitCode != 0)
278302
{
279303
throw new InvalidOperationException($"{fileName} command execution failure: {output}");
280304
}

src/BenchmarksApps/TLS/HttpSys/Program.cs

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -20,33 +20,36 @@
2020

2121
var mTLSNetShFlag = mTlsEnabled ? NetShFlag.Enable : NetShFlag.Disabled;
2222

23+
var netshWrapper = new NetShWrapper();
24+
2325
// verify there is an netsh http sslcert binding for specified ip:port
24-
if (!NetShWrapper.TryGetSslCertBinding(httpsIpPort, out var sslCertBinding))
26+
if (!netshWrapper.TryGetSslCertBinding(httpsIpPort, out var sslCertBinding))
2527
{
2628
Console.WriteLine($"No binding existed. Need to self-sign it and bind to '{httpsIpPort}'");
27-
if (!NetShWrapper.TrySelfSignCertificate(httpsIpPort, out var originalCertThumbprint))
29+
if (!netshWrapper.TrySelfSignCertificate(httpsIpPort, out var originalCertThumbprint))
2830
{
2931
throw new ApplicationException($"Failed to setup ssl binding for '{httpsIpPort}'. Please unblock the VM.");
3032
}
31-
NetShWrapper.AddCertBinding(
33+
netshWrapper.AddCertBinding(
3234
httpsIpPort,
3335
originalCertThumbprint,
3436
disablesessionid: NetShFlag.Enable,
3537
enablesessionticket: NetShFlag.Disabled,
3638
clientCertNegotiation: mTLSNetShFlag);
3739
}
3840

39-
Console.WriteLine("Current netsh ssl certificate binding: " + sslCertBinding);
41+
Console.WriteLine("Current netsh ssl certificate binding: \n" + sslCertBinding);
4042

4143
if (
4244
// those flags can be set only on later versions of HTTP.SYS; so only considering mTLS here
43-
// sslCertBinding.DisableSessionIdTlsResumption != NetShFlag.Enable || sslCertBinding.EnableSessionTicketTlsResumption != NetShFlag.Disabled ||
44-
sslCertBinding.NegotiateClientCertificate != mTLSNetShFlag)
45+
(netshWrapper.SupportsDisableSessionId && sslCertBinding.DisableSessionIdTlsResumption != NetShFlag.Enable)
46+
|| (netshWrapper.SupportsEnableSessionTicket && (sslCertBinding.EnableSessionTicketTlsResumption == NetShFlag.Enable))
47+
|| sslCertBinding.NegotiateClientCertificate != mTLSNetShFlag)
4548
{
4649
Console.WriteLine($"Need to prepare ssl-cert binding for the run.");
47-
Console.WriteLine($"Expected configuration: mTLS={mTLSNetShFlag}");
50+
Console.WriteLine($"Expected configuration: mTLS={mTLSNetShFlag}; disableSessionId={NetShFlag.Enable}; enableSessionTicket={NetShFlag.Disabled}");
4851

49-
NetShWrapper.UpdateCertBinding(
52+
netshWrapper.UpdateCertBinding(
5053
httpsIpPort,
5154
sslCertBinding.CertificateThumbprint,
5255
appId: sslCertBinding.ApplicationId,
@@ -140,7 +143,7 @@
140143

141144
await app.StartAsync();
142145

143-
NetShWrapper.LogSslCertBinding(httpsIpPort);
146+
netshWrapper.LogSslCertBinding(httpsIpPort);
144147

145148
Console.WriteLine("Application Info:");
146149
if (mTlsEnabled)
@@ -162,11 +165,11 @@
162165
await app.WaitForShutdownAsync();
163166
Console.WriteLine("Application stopped.");
164167

165-
if (NetShWrapper.TryGetSslCertBinding(httpsIpPort, out sslCertBinding) && mTLSNetShFlag == NetShFlag.Enable)
168+
if (netshWrapper.TryGetSslCertBinding(httpsIpPort, out sslCertBinding) && mTLSNetShFlag == NetShFlag.Enable)
166169
{
167170
// update the sslCert binding to disable "negotiate client cert" (aka mTLS) to not break other tests.
168171
Console.WriteLine($"Rolling back mTLS setting for sslCert binding at '{httpsIpPort}'");
169172

170173
sslCertBinding.NegotiateClientCertificate = NetShFlag.Disabled;
171-
NetShWrapper.UpdateCertBinding(httpsIpPort, sslCertBinding);
174+
netshWrapper.UpdateCertBinding(httpsIpPort, sslCertBinding);
172175
}

0 commit comments

Comments
 (0)