1 //------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation. All rights reserved.
3 //------------------------------------------------------------
5 namespace System.IdentityModel
7 using Microsoft.Win32.SafeHandles;
8 using System.ComponentModel;
9 using System.Diagnostics;
10 using System.Runtime.InteropServices;
11 using System.Runtime.CompilerServices;
12 using System.Runtime.Versioning;
13 using System.Runtime.ConstrainedExecution;
14 using System.Security;
15 using System.Security.Cryptography;
16 using System.Security.Cryptography.X509Certificates;
18 using FILETIME = System.Runtime.InteropServices.ComTypes.FILETIME;
20 [SuppressUnmanagedCodeSecurity]
23 internal const string CRYPT32 = "crypt32.dll";
24 internal const string BCRYPT = "bcrypt.dll";
25 internal const string SubjectKeyIdentifierOid = "2.5.29.14";
27 internal const int S_OK = 0;
28 internal const int S_FALSE = 1;
30 internal const string szOID_CRL_DIST_POINTS = "2.5.29.31";
31 internal const string szOID_AUTHORITY_INFO_ACCESS = "1.3.6.1.5.5.7.1.1";
33 //internal const uint CERT_STORE_NO_CRYPT_RELEASE_FLAG = 0x00000001;
34 //internal const uint CERT_STORE_SET_LOCALIZED_NAME_FLAG = 0x00000002;
35 //internal const uint CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG = 0x00000004;
36 //internal const uint CERT_STORE_DELETE_FLAG = 0x00000010;
37 //internal const uint CERT_STORE_SHARE_STORE_FLAG = 0x00000040;
38 //internal const uint CERT_STORE_SHARE_CONTEXT_FLAG = 0x00000080;
39 //internal const uint CERT_STORE_MANIFOLD_FLAG = 0x00000100;
40 internal const uint CERT_STORE_ENUM_ARCHIVED_FLAG = 0x00000200;
41 //internal const uint CERT_STORE_UPDATE_KEYID_FLAG = 0x00000400;
42 //internal const uint CERT_STORE_BACKUP_RESTORE_FLAG = 0x00000800;
43 internal const uint CERT_STORE_READONLY_FLAG = 0x00008000;
44 internal const uint CERT_STORE_OPEN_EXISTING_FLAG = 0x00004000;
45 internal const uint CERT_STORE_CREATE_NEW_FLAG = 0x00002000;
46 internal const uint CERT_STORE_MAXIMUM_ALLOWED_FLAG = 0x00001000;
48 internal const uint CERT_STORE_ADD_ALWAYS = 4;
49 internal const uint CERT_CHAIN_POLICY_BASE = 1;
50 internal const uint CERT_CHAIN_POLICY_NT_AUTH = 6;
52 internal const uint X509_ASN_ENCODING = 0x00000001;
53 internal const uint PKCS_7_ASN_ENCODING = 0x00010000;
54 internal const uint CERT_STORE_PROV_MEMORY = 2;
55 internal const uint CERT_STORE_PROV_SYSTEM = 10;
56 internal const uint CERT_SYSTEM_STORE_CURRENT_USER_ID = 1;
57 internal const uint CERT_SYSTEM_STORE_LOCAL_MACHINE_ID = 2;
58 internal const uint CERT_SYSTEM_STORE_LOCATION_SHIFT = 16;
60 internal const uint CERT_SYSTEM_STORE_CURRENT_USER = ((int)CERT_SYSTEM_STORE_CURRENT_USER_ID << (int)CERT_SYSTEM_STORE_LOCATION_SHIFT);
61 internal const uint CERT_SYSTEM_STORE_LOCAL_MACHINE = ((int)CERT_SYSTEM_STORE_LOCAL_MACHINE_ID << (int)CERT_SYSTEM_STORE_LOCATION_SHIFT);
63 //internal const uint CERT_INFO_VERSION_FLAG = 1;
64 //internal const uint CERT_INFO_SERIAL_NUMBER_FLAG = 2;
65 //internal const uint CERT_INFO_SIGNATURE_ALGORITHM_FLAG = 3;
66 internal const uint CERT_INFO_ISSUER_FLAG = 4;
67 //internal const uint CERT_INFO_NOT_BEFORE_FLAG = 5;
68 //internal const uint CERT_INFO_NOT_AFTER_FLAG = 6;
69 internal const uint CERT_INFO_SUBJECT_FLAG = 7;
70 //internal const uint CERT_INFO_SUBJECT_PUBLIC_KEY_INFO_FLAG = 8;
71 //internal const uint CERT_INFO_ISSUER_UNIQUE_ID_FLAG = 9;
72 //internal const uint CERT_INFO_SUBJECT_UNIQUE_ID_FLAG = 10;
73 //internal const uint CERT_INFO_EXTENSION_FLAG = 11;
75 //internal const uint CERT_COMPARE_MASK = 0xFFFF;
76 internal const uint CERT_COMPARE_SHIFT = 16;
77 internal const uint CERT_COMPARE_ANY = 0;
78 internal const uint CERT_COMPARE_SHA1_HASH = 1;
79 //internal const uint CERT_COMPARE_NAME = 2;
80 //internal const uint CERT_COMPARE_ATTR = 3;
81 //internal const uint CERT_COMPARE_MD5_HASH = 4;
82 //internal const uint CERT_COMPARE_PROPERTY = 5;
83 //internal const uint CERT_COMPARE_PUBLIC_KEY = 6;
84 //internal const uint CERT_COMPARE_HASH = CERT_COMPARE_SHA1_HASH;
85 internal const uint CERT_COMPARE_NAME_STR_A = 7;
86 internal const uint CERT_COMPARE_NAME_STR_W = 8;
87 //internal const uint CERT_COMPARE_KEY_SPEC = 9;
88 //internal const uint CERT_COMPARE_ENHKEY_USAGE = 10;
89 //internal const uint CERT_COMPARE_CTL_USAGE = CERT_COMPARE_ENHKEY_USAGE;
90 //internal const uint CERT_COMPARE_SUBJECT_CERT = 11;
91 //internal const uint CERT_COMPARE_ISSUER_OF = 12;
92 //internal const uint CERT_COMPARE_EXISTING = 13;
93 //internal const uint CERT_COMPARE_SIGNATURE_HASH = 14;
94 //internal const uint CERT_COMPARE_KEY_IDENTIFIER = 15;
95 //internal const uint CERT_COMPARE_CERT_ID = 16;
96 //internal const uint CERT_COMPARE_CROSS_CERT_DIST_POINTS = 17;
97 //internal const uint CERT_COMPARE_PUBKEY_MD5_HASH = 18;
99 internal const uint CERT_FIND_ANY = ((int)CERT_COMPARE_ANY << (int)CERT_COMPARE_SHIFT);
100 internal const uint CERT_FIND_SHA1_HASH = ((int)CERT_COMPARE_SHA1_HASH << (int)CERT_COMPARE_SHIFT);
101 //internal const uint CERT_FIND_MD5_HASH = ((int)CERT_COMPARE_MD5_HASH << (int)CERT_COMPARE_SHIFT);
102 //internal const uint CERT_FIND_SIGNATURE_HASH = ((int)CERT_COMPARE_SIGNATURE_HASH << (int)CERT_COMPARE_SHIFT);
103 //internal const uint CERT_FIND_KEY_IDENTIFIER = ((int)CERT_COMPARE_KEY_IDENTIFIER << (int)CERT_COMPARE_SHIFT);
104 internal const uint CERT_FIND_HASH = CERT_FIND_SHA1_HASH;
105 //internal const uint CERT_FIND_PROPERTY = ((int)CERT_COMPARE_PROPERTY << (int)CERT_COMPARE_SHIFT);
106 //internal const uint CERT_FIND_PUBLIC_KEY = ((int)CERT_COMPARE_PUBLIC_KEY << (int)CERT_COMPARE_SHIFT);
107 //internal const uint CERT_FIND_SUBJECT_NAME = ((int)CERT_COMPARE_NAME << (int)CERT_COMPARE_SHIFT | (int)CERT_INFO_SUBJECT_FLAG);
108 //internal const uint CERT_FIND_SUBJECT_ATTR = ((int)CERT_COMPARE_ATTR << (int)CERT_COMPARE_SHIFT | (int)CERT_INFO_SUBJECT_FLAG);
109 //internal const uint CERT_FIND_ISSUER_NAME = ((int)CERT_COMPARE_NAME << (int)CERT_COMPARE_SHIFT | (int)CERT_INFO_ISSUER_FLAG);
110 //internal const uint CERT_FIND_ISSUER_ATTR = ((int)CERT_COMPARE_ATTR << (int)CERT_COMPARE_SHIFT | (int)CERT_INFO_ISSUER_FLAG);
111 internal const uint CERT_FIND_SUBJECT_STR_A = ((int)CERT_COMPARE_NAME_STR_A << (int)CERT_COMPARE_SHIFT | (int)CERT_INFO_SUBJECT_FLAG);
112 internal const uint CERT_FIND_SUBJECT_STR_W = ((int)CERT_COMPARE_NAME_STR_W << (int)CERT_COMPARE_SHIFT | (int)CERT_INFO_SUBJECT_FLAG);
113 internal const uint CERT_FIND_SUBJECT_STR = CERT_FIND_SUBJECT_STR_W;
114 internal const uint CERT_FIND_ISSUER_STR_A = ((int)CERT_COMPARE_NAME_STR_A << (int)CERT_COMPARE_SHIFT | (int)CERT_INFO_ISSUER_FLAG);
115 internal const uint CERT_FIND_ISSUER_STR_W = ((int)CERT_COMPARE_NAME_STR_W << (int)CERT_COMPARE_SHIFT | (int)CERT_INFO_ISSUER_FLAG);
116 internal const uint CERT_FIND_ISSUER_STR = CERT_FIND_ISSUER_STR_W;
117 //internal const uint CERT_FIND_KEY_SPEC = ((int)CERT_COMPARE_KEY_SPEC << (int)CERT_COMPARE_SHIFT);
118 //internal const uint CERT_FIND_ENHKEY_USAGE = ((int)CERT_COMPARE_ENHKEY_USAGE << (int)CERT_COMPARE_SHIFT);
119 //internal const uint CERT_FIND_CTL_USAGE = CERT_FIND_ENHKEY_USAGE;
120 //internal const uint CERT_FIND_SUBJECT_CERT = ((int)CERT_COMPARE_SUBJECT_CERT << (int)CERT_COMPARE_SHIFT);
121 //internal const uint CERT_FIND_ISSUER_OF = ((int)CERT_COMPARE_ISSUER_OF << (int)CERT_COMPARE_SHIFT);
122 //internal const uint CERT_FIND_EXISTING = ((int)CERT_COMPARE_EXISTING << (int)CERT_COMPARE_SHIFT);
123 //internal const uint CERT_FIND_CERT_ID = ((int)CERT_COMPARE_CERT_ID << (int)CERT_COMPARE_SHIFT);
124 //internal const uint CERT_FIND_CROSS_CERT_DIST_POINTS = ((int)CERT_COMPARE_CROSS_CERT_DIST_POINTS << (int)CERT_COMPARE_SHIFT);
125 //internal const uint CERT_FIND_PUBKEY_MD5_HASH = ((int)CERT_COMPARE_PUBKEY_MD5_HASH << (int)CERT_COMPARE_SHIFT);
127 // Common chain policy flags.
128 internal const uint CERT_CHAIN_REVOCATION_CHECK_END_CERT = 0x10000000;
129 internal const uint CERT_CHAIN_REVOCATION_CHECK_CHAIN = 0x20000000;
130 internal const uint CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT = 0x40000000;
131 internal const uint CERT_CHAIN_REVOCATION_CHECK_CACHE_ONLY = 0x80000000;
132 internal const uint CERT_CHAIN_REVOCATION_ACCUMULATIVE_TIMEOUT = 0x08000000;
134 // Chain verification flag (not available in X509VerificationFlags).
135 internal const uint CERT_CHAIN_POLICY_IGNORE_PEER_TRUST_FLAG = 0x00001000;
138 // Default usage match type is AND with value zero
139 internal const uint USAGE_MATCH_TYPE_AND = 0x00000000;
140 internal const uint USAGE_MATCH_TYPE_OR = 0x00000001;
142 // CertGetCertificateChain chain engine handles.
143 internal const uint HCCE_CURRENT_USER = 0x0;
144 internal const uint HCCE_LOCAL_MACHINE = 0x1;
147 internal const uint CERT_TRUST_IS_PEER_TRUSTED = 0x00000800;
149 [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
150 internal struct CERT_CONTEXT
152 internal uint dwCertEncodingType;
153 internal IntPtr pbCertEncoded;
154 internal uint cbCertEncoded;
155 internal IntPtr pCertInfo;
156 internal IntPtr hCertStore;
160 [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
161 internal struct CRYPTOAPI_BLOB
163 internal uint cbData;
164 internal IntPtr pbData;
166 static internal int Size = Marshal.SizeOf(typeof(CRYPTOAPI_BLOB));
169 [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
170 internal struct CERT_ENHKEY_USAGE
172 internal uint cUsageIdentifier;
173 internal IntPtr rgpszUsageIdentifier; // LPSTR*
176 [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
177 internal struct CERT_USAGE_MATCH
179 internal uint dwType;
180 internal CERT_ENHKEY_USAGE Usage;
183 [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
184 internal struct CERT_CHAIN_PARA
186 internal uint cbSize;
187 internal CERT_USAGE_MATCH RequestedUsage;
188 internal CERT_USAGE_MATCH RequestedIssuancePolicy;
189 internal uint dwUrlRetrievalTimeout; // milliseconds
190 internal bool fCheckRevocationFreshnessTime;
191 internal uint dwRevocationFreshnessTime;
194 [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
195 internal struct CERT_CHAIN_POLICY_PARA
197 internal CERT_CHAIN_POLICY_PARA(int size)
201 pvExtraPolicyPara = IntPtr.Zero;
203 internal uint cbSize;
204 internal uint dwFlags;
205 internal IntPtr pvExtraPolicyPara;
208 [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
209 internal struct CERT_CHAIN_POLICY_STATUS
211 internal CERT_CHAIN_POLICY_STATUS(int size)
215 lChainIndex = IntPtr.Zero;
216 lElementIndex = IntPtr.Zero;
217 pvExtraPolicyStatus = IntPtr.Zero;
219 internal uint cbSize;
220 internal uint dwError;
221 internal IntPtr lChainIndex;
222 internal IntPtr lElementIndex;
223 internal IntPtr pvExtraPolicyStatus;
226 [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
227 internal struct CERT_CHAIN_CONTEXT
229 internal CERT_CHAIN_CONTEXT(int size)
235 rgpChain = IntPtr.Zero;
236 cLowerQualityChainContext = 0;
237 rgpLowerQualityChainContext = IntPtr.Zero;
238 fHasRevocationFreshnessTime = 0;
239 dwRevocationFreshnessTime = 0;
241 internal uint cbSize;
242 internal uint dwErrorStatus; // serialized CERT_TRUST_STATUS
243 internal uint dwInfoStatus; // serialized CERT_TRUST_STATUS
244 internal uint cChain;
245 internal IntPtr rgpChain; // PCERT_SIMPLE_CHAIN*
246 internal uint cLowerQualityChainContext;
247 internal IntPtr rgpLowerQualityChainContext; // PCCERT_CHAIN_CONTEXT*
248 internal uint fHasRevocationFreshnessTime; // Note that we declare the field as a uint here since we are manipulating
249 // the structure manually and a bool is only 1 byte in the managed world.
250 internal uint dwRevocationFreshnessTime; // seconds
253 [DllImport(CAPI.CRYPT32, CharSet = CharSet.Unicode, SetLastError = true)]
254 internal static extern SafeCertContextHandle CertCreateCertificateContext(
255 [In] uint dwCertEncodingType,
256 [In] IntPtr pbCertEncoded,
257 [In] uint cbCertEncoded
260 // A new store is created if one did not exist. The function fails if the store already exists if dwFlags is set to CERT_STORE_CREATE_NEW_FLAG .
262 [DllImport(CAPI.CRYPT32, CharSet = CharSet.Unicode, SetLastError = true)]
263 [ResourceExposure(ResourceScope.None)]
264 internal static extern SafeCertStoreHandle CertOpenStore(
265 [In] IntPtr lpszStoreProvider,
266 [In] uint dwMsgAndCertEncodingType,
267 [In] IntPtr hCryptProv,
269 [In] string pvPara // we want this always as a Unicode string.
272 [DllImport(CAPI.CRYPT32, SetLastError = true)]
273 [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
274 [ResourceExposure(ResourceScope.None)]
275 internal static extern bool CertCloseStore(
276 [In] IntPtr hCertStore,
280 [DllImport(CAPI.CRYPT32, SetLastError = true)]
281 [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
282 [ResourceExposure( ResourceScope.None )]
283 internal static extern bool CertFreeCertificateContext(
284 [In] IntPtr pCertContext
287 [DllImport(CAPI.CRYPT32, SetLastError = true)]
288 [ResourceExposure( ResourceScope.None )]
289 [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
290 internal static extern SafeCertContextHandle CertFindCertificateInStore(
291 [In] SafeCertStoreHandle hCertStore,
292 [In] uint dwCertEncodingType,
293 [In] uint dwFindFlags,
294 [In] uint dwFindType,
295 [In] SafeHGlobalHandle pvFindPara,
296 [In] SafeCertContextHandle pPrevCertContext
299 [DllImport(CRYPT32, CharSet = CharSet.Auto, SetLastError = true)]
300 [ResourceConsumption( ResourceScope.Machine, ResourceScope.Machine)]
301 [ResourceExposure( ResourceScope.None )]
302 internal extern static bool CertAddCertificateLinkToStore(
303 [In] SafeCertStoreHandle hCertStore,
304 [In] IntPtr pCertContext,
305 [In] uint dwAddDisposition,
306 [In, Out] SafeCertContextHandle ppStoreContext
309 [DllImport(CRYPT32, CharSet = CharSet.Auto, SetLastError = true)]
310 [ResourceExposure( ResourceScope.None )]
311 [ResourceConsumption( ResourceScope.Machine, ResourceScope.Machine )]
312 internal static extern bool CertGetCertificateChain(
313 [In] IntPtr hChainEngine,
314 [In] IntPtr pCertContext,
315 [In] ref FILETIME pTime,
316 [In] SafeCertStoreHandle hAdditionalStore,
317 [In] ref CERT_CHAIN_PARA pChainPara,
319 [In] IntPtr pvReserved,
320 [Out] out SafeCertChainHandle ppChainContext
323 [DllImport(CRYPT32, CharSet = CharSet.Auto, SetLastError = true)]
324 [ResourceExposure( ResourceScope.None )]
325 internal extern static bool CertVerifyCertificateChainPolicy(
326 [In] IntPtr pszPolicyOID,
327 [In] SafeCertChainHandle pChainContext,
328 [In] ref CERT_CHAIN_POLICY_PARA pPolicyPara,
329 [In, Out] ref CERT_CHAIN_POLICY_STATUS pPolicyStatus);
331 [DllImport(CRYPT32, SetLastError = true)]
332 [ResourceExposure( ResourceScope.None )]
333 [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
334 internal extern static void CertFreeCertificateChain(IntPtr handle);
336 // On Vista and higher, check the value of the machine FIPS policy
337 [DllImport(BCRYPT, SetLastError = true)]
338 [ResourceExposure( ResourceScope.None )]
339 internal static extern int BCryptGetFipsAlgorithmMode(
340 [MarshalAs(UnmanagedType.U1), Out] out bool pfEnabled
345 #pragma warning disable 618 // have not moved to the v4 security model yet
346 [SecurityCritical(SecurityCriticalScope.Everything)]
347 #pragma warning restore 618
348 class SafeCertStoreHandle : SafeHandleZeroOrMinusOneIsInvalid
350 SafeCertStoreHandle() : base(true) { }
352 // 0 is an Invalid Handle
353 SafeCertStoreHandle(IntPtr handle)
359 public static SafeCertStoreHandle InvalidHandle
361 get { return new SafeCertStoreHandle(IntPtr.Zero); }
364 protected override bool ReleaseHandle()
366 // PreSharp Bug: Call 'Marshal.GetLastWin32Error' or 'Marshal.GetHRForLastWin32Error' before any other interop call.
367 #pragma warning suppress 56523 // We are not interested in throwing an exception here if CloseHandle fails.
368 return CAPI.CertCloseStore(handle, 0);
372 #pragma warning disable 618 // have not moved to the v4 security model yet
373 [SecurityCritical(SecurityCriticalScope.Everything)]
374 #pragma warning restore 618
375 class SafeCertContextHandle : SafeHandleZeroOrMinusOneIsInvalid
377 SafeCertContextHandle() : base(true) { }
379 // 0 is an Invalid Handle
380 SafeCertContextHandle(IntPtr handle)
386 internal static SafeCertContextHandle InvalidHandle
388 get { return new SafeCertContextHandle(IntPtr.Zero); }
391 protected override bool ReleaseHandle()
393 // PreSharp Bug: Call 'Marshal.GetLastWin32Error' or 'Marshal.GetHRForLastWin32Error' before any other interop call.
394 #pragma warning suppress 56523 // We are not interested in throwing an exception here if CloseHandle fails.
395 return CAPI.CertFreeCertificateContext(handle);
399 #pragma warning disable 618 // have not moved to the v4 security model yet
400 [SecurityCritical(SecurityCriticalScope.Everything)]
401 #pragma warning restore 618
402 class SafeCertChainHandle : SafeHandleZeroOrMinusOneIsInvalid
404 SafeCertChainHandle() : base(true) { }
406 SafeCertChainHandle(IntPtr handle)
412 internal static SafeCertChainHandle InvalidHandle
414 get { return new SafeCertChainHandle(IntPtr.Zero); }
417 protected override bool ReleaseHandle()
419 // PreSharp Bug: Call 'Marshal.GetLastWin32Error' or 'Marshal.GetHRForLastWin32Error' before any other interop call.
420 #pragma warning suppress 56523 // We are not interested in throwing an exception here if CloseHandle fails.
421 CAPI.CertFreeCertificateChain(handle);