-
Notifications
You must be signed in to change notification settings - Fork 1.3k
/
Copy pathHttpClientCertificate.cs
311 lines (248 loc) · 12.1 KB
/
HttpClientCertificate.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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
//------------------------------------------------------------------------------
// <copyright file="HttpClientCertificate.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
/*
* Client Certificate
*
* Copyright (c) 2000 Microsoft Corporation
*/
namespace System.Web {
using System.Collections;
using System.Collections.Specialized;
using System.Globalization;
using System.Security.Permissions;
using System.Web.Util;
/// <devdoc>
/// <para>The HttpClientCertificate collection retrieves the certification fields
/// (specified in the X.509 standard) from a request issued by the Web browser.</para>
/// <para>If a Web browser uses the SSL3.0/PCT1 protocol (in other words, it uses a URL
/// starting with https:// instead of http://) to connect to a server and the server
/// requests certification, the browser sends the certification fields.</para>
/// </devdoc>
public class HttpClientCertificate : NameValueCollection {
/////////////////////////////////////////////////////////////////////////////
// Properties
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public String Cookie { get { return _Cookie;}}
/// <devdoc>
/// A string containing the binary stream of the entire certificate content in ASN.1 format.
/// </devdoc>
public byte [] Certificate { get { return _Certificate;}}
/// <devdoc>
/// <para>A set of flags that provide additional client certificate information. </para>
/// </devdoc>
public int Flags { get { return _Flags;}}
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public int KeySize { get { return _KeySize;}}
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public int SecretKeySize { get { return _SecretKeySize;}}
/// <devdoc>
/// <para>A string that contains a list of subfield values containing information about
/// the issuer of the certificate.</para>
/// </devdoc>
public String Issuer { get { return _Issuer;}}
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public String ServerIssuer { get { return _ServerIssuer;}}
/// <devdoc>
/// <para>A string that contains a list of subfield values. The subfield values contain
/// information about the subject of the certificate. If this value is specified
/// without a <paramref name="SubField"/>, the ClientCertificate collection returns a
/// comma-separated list of subfields. For example, C=US, O=Msft, and so on.</para>
/// </devdoc>
public String Subject { get { return _Subject;}}
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public String ServerSubject { get { return _ServerSubject;}}
/// <devdoc>
/// <para>A string that contains the certification serial number as an ASCII
/// representation of hexadecimal bytes separated by hyphens (-). For example,
/// 04-67-F3-02.</para>
/// </devdoc>
public String SerialNumber { get { return _SerialNumber;}}
/// <devdoc>
/// <para>A date specifying when the certificate becomes valid. This date varies with
/// international settings. </para>
/// </devdoc>
public DateTime ValidFrom { get { return _ValidFrom;}}
/// <devdoc>
/// <para>A date specifying when the certificate expires. The year value is displayed
/// as a four-digit number.</para>
/// </devdoc>
public DateTime ValidUntil { get { return _ValidUntil;}}
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public int CertEncoding { get { return _CertEncoding;}}
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public byte [] PublicKey { get { return _PublicKey;}}
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public byte [] BinaryIssuer { get { return _BinaryIssuer;}}
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public bool IsPresent { get { return((_Flags & 0x1) == 1);}}
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public bool IsValid { get { return((_Flags & 0x2) == 0);}}
/////////////////////////////////////////////////////////////////////////////
// Ctor
internal HttpClientCertificate(HttpContext context) {
String flags = context.Request.ServerVariables["CERT_FLAGS"];
if (!String.IsNullOrEmpty(flags))
_Flags = Int32.Parse(flags, CultureInfo.InvariantCulture);
else
_Flags = 0;
if (IsPresent == false)
return;
_Cookie = context.Request.ServerVariables["CERT_COOKIE"];
_Issuer = context.Request.ServerVariables["CERT_ISSUER"];
_ServerIssuer = context.Request.ServerVariables["CERT_SERVER_ISSUER"];
_Subject = context.Request.ServerVariables["CERT_SUBJECT"];
_ServerSubject = context.Request.ServerVariables["CERT_SERVER_SUBJECT"];
_SerialNumber = context.Request.ServerVariables["CERT_SERIALNUMBER"];
_Certificate = context.WorkerRequest.GetClientCertificate();
_ValidFrom = context.WorkerRequest.GetClientCertificateValidFrom();
_ValidUntil = context.WorkerRequest.GetClientCertificateValidUntil();
_BinaryIssuer = context.WorkerRequest.GetClientCertificateBinaryIssuer();
_PublicKey = context.WorkerRequest.GetClientCertificatePublicKey();
_CertEncoding = context.WorkerRequest.GetClientCertificateEncoding();
String keySize = context.Request.ServerVariables["CERT_KEYSIZE"];
String skeySize = context.Request.ServerVariables["CERT_SECRETKEYSIZE"];
if (!String.IsNullOrEmpty(keySize))
_KeySize = Int32.Parse(keySize, CultureInfo.InvariantCulture);
if (!String.IsNullOrEmpty(skeySize))
_SecretKeySize = Int32.Parse(skeySize, CultureInfo.InvariantCulture);
base.Add("ISSUER", null);
base.Add("SUBJECTEMAIL", null);
base.Add("BINARYISSUER", null);
base.Add("FLAGS", null);
base.Add("ISSUERO", null);
base.Add("PUBLICKEY", null);
base.Add("ISSUEROU", null);
base.Add("ENCODING", null);
base.Add("ISSUERCN", null);
base.Add("SERIALNUMBER", null);
base.Add("SUBJECT", null);
base.Add("SUBJECTCN", null);
base.Add("CERTIFICATE", null);
base.Add("SUBJECTO", null);
base.Add("SUBJECTOU", null);
base.Add("VALIDUNTIL", null);
base.Add("VALIDFROM", null);
}
/// <devdoc>
/// <para>Allows access to individual items in the collection by name.</para>
/// </devdoc>
public override String Get(String field)
{
if (field == null)
return String.Empty;
field = field.ToLower(CultureInfo.InvariantCulture);
switch (field) {
case "cookie":
return Cookie;
case "flags":
return Flags.ToString("G", CultureInfo.InvariantCulture);
case "keysize":
return KeySize.ToString("G", CultureInfo.InvariantCulture);
case "secretkeysize":
return SecretKeySize.ToString(CultureInfo.InvariantCulture);
case "issuer":
return Issuer;
case "serverissuer":
return ServerIssuer;
case "subject":
return Subject;
case "serversubject":
return ServerSubject;
case "serialnumber":
return SerialNumber;
case "certificate":
return System.Text.Encoding.Default.GetString(Certificate);
case "binaryissuer":
return System.Text.Encoding.Default.GetString(BinaryIssuer);
case "publickey":
return System.Text.Encoding.Default.GetString(PublicKey);
case "encoding":
return CertEncoding.ToString("G", CultureInfo.InvariantCulture);
case "validfrom":
return HttpUtility.FormatHttpDateTime(ValidFrom);
case "validuntil":
return HttpUtility.FormatHttpDateTime(ValidUntil);
}
if (StringUtil.StringStartsWith(field, "issuer"))
return ExtractString(Issuer, field.Substring(6));
if (StringUtil.StringStartsWith(field, "subject")) {
if (field.Equals("subjectemail"))
return ExtractString(Subject, "e");
else
return ExtractString(Subject, field.Substring(7));
}
if (StringUtil.StringStartsWith(field, "serversubject"))
return ExtractString(ServerSubject, field.Substring(13));
if (StringUtil.StringStartsWith(field, "serverissuer"))
return ExtractString(ServerIssuer, field.Substring(12));
return String.Empty;
}
/////////////////////////////////////////////////////////////////////////////
// Private data
private String _Cookie = String.Empty;
private byte [] _Certificate = new byte[0];
private int _Flags;
private int _KeySize;
private int _SecretKeySize;
private String _Issuer = String.Empty;
private String _ServerIssuer = String.Empty;
private String _Subject = String.Empty;
private String _ServerSubject = String.Empty;
private String _SerialNumber = String.Empty;
private DateTime _ValidFrom = DateTime.Now;
private DateTime _ValidUntil = DateTime.Now;
private int _CertEncoding;
private byte [] _PublicKey = new byte[0];
private byte [] _BinaryIssuer = new byte[0];
private String ExtractString(String strAll, String strSubject) {
if (strAll == null || strSubject == null)
return String.Empty;
String strReturn = String.Empty;
int iStart = 0;
String strAllL = strAll.ToLower(CultureInfo.InvariantCulture);
while (iStart < strAllL.Length) {
iStart = strAllL.IndexOf(strSubject + "=", iStart, StringComparison.Ordinal);
if (iStart < 0)
return strReturn;
if (strReturn.Length > 0)
strReturn += ";";
iStart += strSubject.Length + 1;
int iEnd = 0;
if (strAll[iStart]=='"') {
iStart++;
iEnd = strAll.IndexOf('"' , iStart);
}
else
iEnd = strAll.IndexOf(',' , iStart);
if (iEnd < 0)
iEnd = strAll.Length;
strReturn += strAll.Substring(iStart, iEnd - iStart);
iStart = iEnd + 1;
}
return strReturn;
}
}
}