-
Notifications
You must be signed in to change notification settings - Fork 0
/
WebClient.cs
130 lines (104 loc) · 4.58 KB
/
WebClient.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
using Microsoft.Win32;
using System.Diagnostics;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
bool IsClientAuthCertificate(X509Certificate2 cert) {
// based on sample code on https://docs.microsoft.com/en-us/dotnet/api/system.security.cryptography.x509certificates.x509enhancedkeyusageextension
foreach (X509Extension ext in cert.Extensions) {
if (ext.Oid == null)
continue;
if (ext.Oid.FriendlyName == "Enhanced Key Usage") {
var ext2 = (X509EnhancedKeyUsageExtension)ext;
foreach (Oid oid in ext2.EnhancedKeyUsages) {
if (oid.Value == "1.3.6.1.5.5.7.3.2") // clientAuth OID
return true;
}
}
}
return false;
}
string GetCertHash(CertType type) {
if (type == CertType.ActiveDirectory) {
// Get long-lived 10-year "MS-Organization-Access" clientAuth certificate associated with a Active-Directory joined machine
using RegistryKey key = Registry.LocalMachine.OpenSubKey("SYSTEM\\CurrentControlSet\\Control\\CloudDomainJoin\\JoinInfo")!;
var names = key.GetSubKeyNames();
if (names.Length == 0)
throw new ApplicationException("no AD clientAuth cert found");
return names[0]; // use first AD connection
} else if (type == CertType.InTune) {
// Get short-lived 1-year "Microsoft Intune MDM Device CA" certificate
using RegistryKey key = Registry.LocalMachine.OpenSubKey("SOFTWARE\\Microsoft\\Provisioning\\OMADM\\Accounts")!;
var names = key.GetSubKeyNames();
if (names.Length == 0)
throw new ApplicationException("no InTune clientAuth cert found");
using RegistryKey subkey = key.OpenSubKey(names[0])!;
var cert_ref = (string)subkey.GetValue("SslClientCertReference")!;
var tokens = cert_ref.Split(";");
Debug.Assert(tokens[0] == "MY");
Debug.Assert(tokens[1] == "System");
return tokens[2];
}
throw new ApplicationException("Unsupported CertType");
}
X509Certificate2 GetMachineCertificateFromHash (string cert_hash) {
using X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadOnly);
// expired certs. are included in the enumeration
foreach (X509Certificate2 cert in store.Certificates) {
if (cert.GetCertHashString() != cert_hash)
continue;
// sanity checks
Debug.Assert(cert.HasPrivateKey);
Debug.Assert(IsClientAuthCertificate(cert));
Console.WriteLine("Client certificate: " + cert.Subject);
return cert;
}
throw new ApplicationException("no cert found");
}
/** Returns the first clientAuth certificate with private key found in the Windows cert. store. */
X509Certificate2 GetFirstClientAuthCert() {
// open personal certificate store
using X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadOnly);
// expired certs. are included in the enumeration
foreach (X509Certificate2 cert in store.Certificates) {
if (!cert.HasPrivateKey)
continue;
if (IsClientAuthCertificate(cert)) {
Console.WriteLine("Client certificate: " + cert.Subject);
return cert;
}
}
throw new ApplicationException("no clientAuth cert found");
}
string hostname = "localhost:443"; // default
if (args.Length > 0)
hostname = args[0];
using HttpClientHandler handler = new HttpClientHandler();
{
// client cert. selection
if (args.Length > 1) {
if (args[1] == "ad")
handler.ClientCertificates.Add(GetMachineCertificateFromHash(GetCertHash(CertType.ActiveDirectory)));
else if (args[1] == "intune")
handler.ClientCertificates.Add(GetMachineCertificateFromHash(GetCertHash(CertType.InTune)));
}
if (handler.ClientCertificates.Count == 0)
handler.ClientCertificates.Add(GetFirstClientAuthCert());
}
{
// perform HTTP request with client authentication
using HttpClient client = new HttpClient(handler);
try {
HttpResponseMessage response = await client.GetAsync("https://"+hostname);
response.EnsureSuccessStatusCode();
string responseBody = await response.Content.ReadAsStringAsync();
Console.WriteLine(responseBody);
} catch (Exception e) {
Console.WriteLine("ERROR:{0} ", e.Message);
}
}
enum CertType {
ActiveDirectory, /// long-lived 10 year "MS-Organization-Access"
InTune, /// short-lived 1-year "Microsoft Intune MDM Device CA" certificate
};