1
1
using System . Diagnostics ;
2
2
using System . Security . Cryptography . X509Certificates ;
3
+ using System . Text . RegularExpressions ;
3
4
4
5
namespace HttpSys
5
6
{
6
7
public static class NetShWrapper
7
8
{
8
- public static void DisableHttpSysMutualTlsIfExists ( string ipPort )
9
+ public static void DeleteBindingIfExists ( string ipPort )
9
10
{
10
11
try
11
12
{
12
- DisableHttpSysMutualTls ( ipPort ) ;
13
+ DeleteBinding ( ipPort ) ;
13
14
}
14
15
catch
15
16
{
16
17
// ignore
17
18
}
18
19
}
19
20
20
- public static void DisableHttpSysMutualTls ( string ipPort )
21
+ public static void DeleteBinding ( string ipPort )
21
22
{
22
23
Console . WriteLine ( "Disabling mTLS for http.sys" ) ;
23
24
@@ -27,14 +28,42 @@ public static void DisableHttpSysMutualTls(string ipPort)
27
28
Console . WriteLine ( "Disabled http.sys settings for mTLS" ) ;
28
29
}
29
30
31
+ public static bool BindingExists ( string ipPort , out string certThumbprint , out string appId )
32
+ {
33
+ certThumbprint = string . Empty ;
34
+ appId = string . Empty ;
35
+
36
+ var bindings = ExecuteNetShCommand ( "http show sslcert" ) ;
37
+ if ( string . IsNullOrEmpty ( bindings ) || ! bindings . Contains ( ipPort ) )
38
+ {
39
+ return false ;
40
+ }
41
+
42
+ // Extract the certificate thumbprint
43
+ var thumbprintMatch = Regex . Match ( bindings , @"Certificate Hash\s+:\s+([a-fA-F0-9]+)" ) ;
44
+ if ( thumbprintMatch . Success )
45
+ {
46
+ certThumbprint = thumbprintMatch . Groups [ 1 ] . Value ;
47
+ }
48
+
49
+ // Extract the application ID
50
+ var appIdMatch = Regex . Match ( bindings , @"Application ID\s+:\s+{([a-fA-F0-9-]+)}" ) ;
51
+ if ( appIdMatch . Success )
52
+ {
53
+ appId = appIdMatch . Groups [ 1 ] . Value ;
54
+ }
55
+
56
+ return true ;
57
+ }
58
+
30
59
public static void Show ( )
31
60
{
32
61
ExecuteNetShCommand ( "http show sslcert" , alwaysLogOutput : true ) ;
33
62
}
34
63
35
- public static void EnableHttpSysMutualTls ( string ipPort )
64
+ public static void SetTestCertBinding ( string ipPort , bool enableClientCertNegotiation )
36
65
{
37
- Console . WriteLine ( "Setting up mTLS for http.sys" ) ;
66
+ Console . WriteLine ( "Setting up binding for testCert for http.sys" ) ;
38
67
39
68
var certificate = LoadCertificate ( ) ;
40
69
Console . WriteLine ( "Loaded `testCert.pfx` from local file system" ) ;
@@ -47,25 +76,67 @@ public static void EnableHttpSysMutualTls(string ipPort)
47
76
}
48
77
49
78
string certThumbprint = certificate . Thumbprint ;
50
- string appId = Guid . NewGuid ( ) . ToString ( ) ;
79
+ SetCertBinding ( ipPort , certThumbprint , enableClientCertNegotiation : enableClientCertNegotiation ) ;
51
80
52
- string command = $ "http add sslcert ipport= { ipPort } certstorename=MY certhash= { certThumbprint } appid={{{appId}}} clientcertnegotiation=enable" ;
53
- ExecuteNetShCommand ( command ) ;
81
+ Console . WriteLine ( "Configured binding for testCert for http.sys" ) ;
82
+ }
54
83
55
- Console . WriteLine ( "Configured http.sys settings for mTLS" ) ;
84
+ public static bool TrySelfSignCertificate ( string ipPort , out string certThumbprint )
85
+ {
86
+ certThumbprint = string . Empty ;
87
+ try
88
+ {
89
+ // Extract the IP address from ipPort
90
+ string ipAddress = ipPort . Split ( ':' ) [ 0 ] ;
91
+
92
+ // Generate a self-signed certificate using PowerShell
93
+ string command = $ "New-SelfSignedCertificate -CertStoreLocation cert:\\ LocalMachine\\ My -DnsName { ipAddress } ";
94
+ string output = ExecutePowershellCommand ( command ) ;
95
+
96
+ // Extract the thumbprint from the output
97
+ var lines = output . Split ( "\r \n " , StringSplitOptions . RemoveEmptyEntries ) ;
98
+ var lastLine = lines [ ^ 1 ] ;
99
+ certThumbprint = lastLine . Split ( " " , StringSplitOptions . RemoveEmptyEntries ) [ 0 ] ;
100
+
101
+ Console . WriteLine ( $ "Self-signed certificate for { ipAddress } ") ;
102
+ return true ;
103
+ }
104
+ catch ( Exception ex )
105
+ {
106
+ Console . WriteLine ( "Failed to self-sign the certificate: " + ex . Message ) ;
107
+ return false ;
108
+ }
109
+ }
110
+
111
+ public static void SetCertBinding ( string ipPort , string certThumbprint , string appId = null , bool enableClientCertNegotiation = false )
112
+ {
113
+ var negotiateClientCert = enableClientCertNegotiation ? "enable" : "disable" ;
114
+ if ( string . IsNullOrEmpty ( appId ) )
115
+ {
116
+ appId = "00000000-0000-0000-0000-000000000000" ;
117
+ }
118
+ string command = $ "http add sslcert ipport={ ipPort } certstorename=MY certhash={ certThumbprint } appid={{{appId}}} clientcertnegotiation={ negotiateClientCert } ";
119
+ ExecuteNetShCommand ( command ) ;
120
+ Console . WriteLine ( $ "Performed cert bindign for { ipPort } ") ;
56
121
}
57
122
58
- private static void ExecuteNetShCommand ( string command , bool alwaysLogOutput = false )
123
+ private static string ExecutePowershellCommand ( string command , bool alwaysLogOutput = false )
124
+ => ExecuteCommand ( "powershell.exe" , command , alwaysLogOutput ) ;
125
+
126
+ private static string ExecuteNetShCommand ( string command , bool alwaysLogOutput = false )
127
+ => ExecuteCommand ( "netsh" , command , alwaysLogOutput ) ;
128
+
129
+ private static string ExecuteCommand ( string fileName , string command , bool alwaysLogOutput = false )
59
130
{
60
- ProcessStartInfo processInfo = new ProcessStartInfo ( "netsh" , command )
131
+ ProcessStartInfo processInfo = new ProcessStartInfo ( fileName , command )
61
132
{
62
133
RedirectStandardOutput = true ,
63
134
RedirectStandardError = true ,
64
135
UseShellExecute = false ,
65
136
CreateNoWindow = true
66
137
} ;
67
138
68
- Console . WriteLine ( $ "Executing command: `netsh { command } `") ;
139
+ Console . WriteLine ( $ "Executing command: `{ fileName } { command } `") ;
69
140
using Process process = Process . Start ( processInfo ) ! ;
70
141
string output = process . StandardOutput . ReadToEnd ( ) ;
71
142
process . WaitForExit ( ) ;
@@ -77,8 +148,10 @@ private static void ExecuteNetShCommand(string command, bool alwaysLogOutput = f
77
148
78
149
if ( process . ExitCode != 0 )
79
150
{
80
- throw new InvalidOperationException ( $ "netsh command execution failure: { output } ") ;
151
+ throw new InvalidOperationException ( $ "{ fileName } command execution failure: { output } ") ;
81
152
}
153
+
154
+ return output ;
82
155
}
83
156
84
157
private static X509Certificate2 LoadCertificate ( )
0 commit comments