3 // Copyright (c) Microsoft Corporation. All rights reserved.
11 namespace System.Security.Cryptography.X509Certificates
13 using System.Runtime.CompilerServices;
14 using System.Runtime.Versioning;
15 using System.Runtime.InteropServices;
16 using Microsoft.Win32;
17 using System.Diagnostics.Contracts;
19 internal static class X509Constants {
20 internal const uint CRYPT_EXPORTABLE = 0x00000001;
21 internal const uint CRYPT_USER_PROTECTED = 0x00000002;
22 internal const uint CRYPT_MACHINE_KEYSET = 0x00000020;
23 internal const uint CRYPT_USER_KEYSET = 0x00001000;
25 internal const uint CERT_QUERY_CONTENT_CERT = 1;
26 internal const uint CERT_QUERY_CONTENT_CTL = 2;
27 internal const uint CERT_QUERY_CONTENT_CRL = 3;
28 internal const uint CERT_QUERY_CONTENT_SERIALIZED_STORE = 4;
29 internal const uint CERT_QUERY_CONTENT_SERIALIZED_CERT = 5;
30 internal const uint CERT_QUERY_CONTENT_SERIALIZED_CTL = 6;
31 internal const uint CERT_QUERY_CONTENT_SERIALIZED_CRL = 7;
32 internal const uint CERT_QUERY_CONTENT_PKCS7_SIGNED = 8;
33 internal const uint CERT_QUERY_CONTENT_PKCS7_UNSIGNED = 9;
34 internal const uint CERT_QUERY_CONTENT_PKCS7_SIGNED_EMBED = 10;
35 internal const uint CERT_QUERY_CONTENT_PKCS10 = 11;
36 internal const uint CERT_QUERY_CONTENT_PFX = 12;
37 internal const uint CERT_QUERY_CONTENT_CERT_PAIR = 13;
39 internal const uint CERT_STORE_PROV_MEMORY = 2;
40 internal const uint CERT_STORE_PROV_SYSTEM = 10;
43 internal const uint CERT_STORE_NO_CRYPT_RELEASE_FLAG = 0x00000001;
44 internal const uint CERT_STORE_SET_LOCALIZED_NAME_FLAG = 0x00000002;
45 internal const uint CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG = 0x00000004;
46 internal const uint CERT_STORE_DELETE_FLAG = 0x00000010;
47 internal const uint CERT_STORE_SHARE_STORE_FLAG = 0x00000040;
48 internal const uint CERT_STORE_SHARE_CONTEXT_FLAG = 0x00000080;
49 internal const uint CERT_STORE_MANIFOLD_FLAG = 0x00000100;
50 internal const uint CERT_STORE_ENUM_ARCHIVED_FLAG = 0x00000200;
51 internal const uint CERT_STORE_UPDATE_KEYID_FLAG = 0x00000400;
52 internal const uint CERT_STORE_BACKUP_RESTORE_FLAG = 0x00000800;
53 internal const uint CERT_STORE_READONLY_FLAG = 0x00008000;
54 internal const uint CERT_STORE_OPEN_EXISTING_FLAG = 0x00004000;
55 internal const uint CERT_STORE_CREATE_NEW_FLAG = 0x00002000;
56 internal const uint CERT_STORE_MAXIMUM_ALLOWED_FLAG = 0x00001000;
58 internal const uint CERT_NAME_EMAIL_TYPE = 1;
59 internal const uint CERT_NAME_RDN_TYPE = 2;
60 internal const uint CERT_NAME_SIMPLE_DISPLAY_TYPE = 4;
61 internal const uint CERT_NAME_FRIENDLY_DISPLAY_TYPE = 5;
62 internal const uint CERT_NAME_DNS_TYPE = 6;
63 internal const uint CERT_NAME_URL_TYPE = 7;
64 internal const uint CERT_NAME_UPN_TYPE = 8;
68 /// Groups of OIDs supported by CryptFindOIDInfo
70 internal enum OidGroup {
72 HashAlgorithm = 1, // CRYPT_HASH_ALG_OID_GROUP_ID
73 EncryptionAlgorithm = 2, // CRYPT_ENCRYPT_ALG_OID_GROUP_ID
74 PublicKeyAlgorithm = 3, // CRYPT_PUBKEY_ALG_OID_GROUP_ID
75 SignatureAlgorithm = 4, // CRYPT_SIGN_ALG_OID_GROUP_ID
76 Attribute = 5, // CRYPT_RDN_ATTR_OID_GROUP_ID
77 ExtensionOrAttribute = 6, // CRYPT_EXT_OR_ATTR_OID_GROUP_ID
78 EnhancedKeyUsage = 7, // CRYPT_ENHKEY_USAGE_OID_GROUP_ID
79 Policy = 8, // CRYPT_POLICY_OID_GROUP_ID
80 Template = 9, // CRYPT_TEMPLATE_OID_GROUP_ID
81 KeyDerivationFunction = 10, // CRYPT_KDF_OID_GROUP_ID
83 // This can be ORed into the above groups to turn off an AD search
84 DisableSearchDS = unchecked((int)0x80000000) // CRYPT_OID_DISABLE_SEARCH_DS_FLAG
88 /// Keys that can be used to query information on via CryptFindOIDInfo
90 internal enum OidKeyType {
91 Oid = 1, // CRYPT_OID_INFO_OID_KEY
92 Name = 2, // CRYPT_OID_INFO_NAME_KEY
93 AlgorithmID = 3, // CRYPT_OID_INFO_ALGID_KEY
94 SignatureID = 4, // CRYPT_OID_INFO_SIGN_KEY
95 CngAlgorithmID = 5, // CRYPT_OID_INFO_CNG_ALGID_KEY
96 CngSignatureID = 6, // CRYPT_OID_INFO_CNG_SIGN_KEY
99 [StructLayout(LayoutKind.Sequential)]
100 internal struct CRYPT_OID_INFO {
102 [MarshalAs(UnmanagedType.LPStr)]
103 internal string pszOID;
104 [MarshalAs(UnmanagedType.LPWStr)]
105 internal string pwszName;
106 internal OidGroup dwGroupId;
109 internal IntPtr pbData;
112 internal static class X509Utils
114 #if FEATURE_CRYPTO || FEATURE_LEGACYNETCFCRYPTO
115 private static bool OidGroupWillNotUseActiveDirectory(OidGroup group) {
116 // These groups will never cause an Active Directory query
117 return group == OidGroup.HashAlgorithm ||
118 group == OidGroup.EncryptionAlgorithm ||
119 group == OidGroup.PublicKeyAlgorithm ||
120 group == OidGroup.SignatureAlgorithm ||
121 group == OidGroup.Attribute ||
122 group == OidGroup.ExtensionOrAttribute ||
123 group == OidGroup.KeyDerivationFunction;
127 private static CRYPT_OID_INFO FindOidInfo(OidKeyType keyType, string key, OidGroup group) {
128 Contract.Requires(key != null);
130 IntPtr rawKey = IntPtr.Zero;
132 RuntimeHelpers.PrepareConstrainedRegions();
134 if (keyType == OidKeyType.Oid) {
135 rawKey = Marshal.StringToCoTaskMemAnsi(key);
138 rawKey = Marshal.StringToCoTaskMemUni(key);
141 // If the group alone isn't sufficient to suppress an active directory lookup, then our
142 // first attempt should also include the suppression flag
143 if (!OidGroupWillNotUseActiveDirectory(group)) {
144 OidGroup localGroup = group | OidGroup.DisableSearchDS;
145 IntPtr localOidInfo = CryptFindOIDInfo(keyType, rawKey, localGroup);
146 if (localOidInfo != IntPtr.Zero) {
147 return (CRYPT_OID_INFO)Marshal.PtrToStructure(localOidInfo, typeof(CRYPT_OID_INFO));
151 // Attempt to query with a specific group, to make try to avoid an AD lookup if possible
152 IntPtr fullOidInfo = CryptFindOIDInfo(keyType, rawKey, group);
153 if (fullOidInfo != IntPtr.Zero) {
154 return (CRYPT_OID_INFO)Marshal.PtrToStructure(fullOidInfo, typeof(CRYPT_OID_INFO));
157 // Finally, for compatibility with previous runtimes, if we have a group specified retry the
158 // query with no group
159 if (group != OidGroup.AllGroups) {
160 IntPtr allGroupOidInfo = CryptFindOIDInfo(keyType, rawKey, OidGroup.AllGroups);
161 if (allGroupOidInfo != IntPtr.Zero) {
162 return (CRYPT_OID_INFO)Marshal.PtrToStructure(fullOidInfo, typeof(CRYPT_OID_INFO));
166 // Otherwise the lookup failed
167 return new CRYPT_OID_INFO();
170 if (rawKey != IntPtr.Zero) {
171 Marshal.FreeCoTaskMem(rawKey);
176 [SecuritySafeCritical]
177 internal static int GetAlgIdFromOid(string oid, OidGroup oidGroup) {
178 Contract.Requires(oid != null);
180 // CAPI does not have ALGID mappings for all of the hash algorithms - see if we know the mapping
181 // first to avoid doing an AD lookup on these values
182 if (String.Equals(oid, Constants.OID_OIWSEC_SHA256, StringComparison.Ordinal)) {
183 return Constants.CALG_SHA_256;
185 else if (String.Equals(oid, Constants.OID_OIWSEC_SHA384, StringComparison.Ordinal)) {
186 return Constants.CALG_SHA_384;
188 else if (String.Equals(oid, Constants.OID_OIWSEC_SHA512, StringComparison.Ordinal)) {
189 return Constants.CALG_SHA_512;
192 return FindOidInfo(OidKeyType.Oid, oid, oidGroup).AlgId;
196 [SecuritySafeCritical]
197 internal static string GetFriendlyNameFromOid(string oid, OidGroup oidGroup) {
198 Contract.Requires(oid != null);
199 CRYPT_OID_INFO oidInfo = FindOidInfo(OidKeyType.Oid, oid, oidGroup);
200 return oidInfo.pwszName;
203 [SecuritySafeCritical]
204 internal static string GetOidFromFriendlyName(string friendlyName, OidGroup oidGroup) {
205 Contract.Requires(friendlyName != null);
206 CRYPT_OID_INFO oidInfo = FindOidInfo(OidKeyType.Name, friendlyName, oidGroup);
207 return oidInfo.pszOID;
210 internal static int NameOrOidToAlgId (string oid, OidGroup oidGroup) {
211 // Default Algorithm Id is CALG_SHA1
213 return Constants.CALG_SHA1;
214 string oidValue = CryptoConfig.MapNameToOID(oid, oidGroup);
215 if (oidValue == null)
216 oidValue = oid; // we were probably passed an OID value directly
218 int algId = GetAlgIdFromOid(oidValue, oidGroup);
219 if (algId == 0 || algId == -1) {
220 throw new CryptographicException(Environment.GetResourceString("Cryptography_InvalidOID"));
224 #endif // FEATURE_CRYPTO
226 // this method maps a cert content type returned from CryptQueryObject
227 // to a value in the managed X509ContentType enum
228 internal static X509ContentType MapContentType (uint contentType) {
229 switch (contentType) {
230 case X509Constants.CERT_QUERY_CONTENT_CERT:
231 return X509ContentType.Cert;
233 case X509Constants.CERT_QUERY_CONTENT_SERIALIZED_STORE:
234 return X509ContentType.SerializedStore;
235 case X509Constants.CERT_QUERY_CONTENT_SERIALIZED_CERT:
236 return X509ContentType.SerializedCert;
237 case X509Constants.CERT_QUERY_CONTENT_PKCS7_SIGNED:
238 case X509Constants.CERT_QUERY_CONTENT_PKCS7_UNSIGNED:
239 return X509ContentType.Pkcs7;
240 case X509Constants.CERT_QUERY_CONTENT_PKCS7_SIGNED_EMBED:
241 return X509ContentType.Authenticode;
243 case X509Constants.CERT_QUERY_CONTENT_PFX:
244 return X509ContentType.Pkcs12;
245 #endif // !FEATURE_PAL
246 #endif // !FEATURE_CORECLR
248 return X509ContentType.Unknown;
252 // this method maps a X509KeyStorageFlags enum to a combination of crypto API flags
253 internal static uint MapKeyStorageFlags(X509KeyStorageFlags keyStorageFlags) {
254 #if FEATURE_LEGACYNETCF
255 if (CompatibilitySwitches.IsAppEarlierThanWindowsPhone8) {
256 if (keyStorageFlags != X509KeyStorageFlags.DefaultKeySet)
257 throw new NotSupportedException(Environment.GetResourceString("Argument_InvalidFlag"),
258 new ArgumentException(Environment.GetResourceString("Argument_InvalidFlag"), "keyStorageFlags"));
261 if ((keyStorageFlags & (X509KeyStorageFlags) ~0x1F) != 0)
262 throw new ArgumentException(Environment.GetResourceString("Argument_InvalidFlag"), "keyStorageFlags");
264 #if !FEATURE_LEGACYNETCF // CompatibilitySwitches causes problems with CCRewrite
265 Contract.EndContractBlock();
270 if (keyStorageFlags != X509KeyStorageFlags.DefaultKeySet) {
271 throw new ArgumentException(Environment.GetResourceString("Argument_InvalidFlag"), "keyStorageFlags",
272 new NotSupportedException());
274 #else // FEATURE_CORECLR
275 if ((keyStorageFlags & X509KeyStorageFlags.UserKeySet) == X509KeyStorageFlags.UserKeySet)
276 dwFlags |= X509Constants.CRYPT_USER_KEYSET;
277 else if ((keyStorageFlags & X509KeyStorageFlags.MachineKeySet) == X509KeyStorageFlags.MachineKeySet)
278 dwFlags |= X509Constants.CRYPT_MACHINE_KEYSET;
280 if ((keyStorageFlags & X509KeyStorageFlags.Exportable) == X509KeyStorageFlags.Exportable)
281 dwFlags |= X509Constants.CRYPT_EXPORTABLE;
282 if ((keyStorageFlags & X509KeyStorageFlags.UserProtected) == X509KeyStorageFlags.UserProtected)
283 dwFlags |= X509Constants.CRYPT_USER_PROTECTED;
284 #endif // FEATURE_CORECLR else
290 // this method creates a memory store from a certificate
291 [System.Security.SecurityCritical] // auto-generated
292 internal static SafeCertStoreHandle ExportCertToMemoryStore (X509Certificate certificate) {
293 SafeCertStoreHandle safeCertStoreHandle = SafeCertStoreHandle.InvalidHandle;
294 X509Utils._OpenX509Store(X509Constants.CERT_STORE_PROV_MEMORY,
295 X509Constants.CERT_STORE_ENUM_ARCHIVED_FLAG | X509Constants.CERT_STORE_CREATE_NEW_FLAG,
297 ref safeCertStoreHandle);
298 X509Utils._AddCertificateToStore(safeCertStoreHandle, certificate.CertContext);
299 return safeCertStoreHandle;
301 #endif // !FEATURE_CORECLR
303 [System.Security.SecurityCritical] // auto-generated
304 internal static IntPtr PasswordToHGlobalUni (object password) {
305 if (password != null) {
306 string pwd = password as string;
308 return Marshal.StringToHGlobalUni(pwd);
309 #if FEATURE_X509_SECURESTRINGS
310 SecureString securePwd = password as SecureString;
311 if (securePwd != null)
312 return Marshal.SecureStringToGlobalAllocUnicode(securePwd);
313 #endif // FEATURE_X509_SECURESTRINGS
318 #if FEATURE_CRYPTO || FEATURE_LEGACYNETCFCRYPTO
320 [SuppressUnmanagedCodeSecurity]
321 [DllImport("crypt32")]
322 private static extern IntPtr CryptFindOIDInfo(OidKeyType dwKeyType, IntPtr pvKey, OidGroup dwGroupId);
323 #endif // FEATURE_CRYPTO
326 [System.Security.SecurityCritical] // auto-generated
327 [ResourceExposure(ResourceScope.None)]
328 [MethodImplAttribute(MethodImplOptions.InternalCall)]
329 internal static extern void _AddCertificateToStore(SafeCertStoreHandle safeCertStoreHandle, SafeCertContextHandle safeCertContext);
330 #endif // !FEATURE_CORECLR
331 [System.Security.SecurityCritical] // auto-generated
332 [ResourceExposure(ResourceScope.None)]
333 [MethodImplAttribute(MethodImplOptions.InternalCall)]
334 internal static extern void _DuplicateCertContext(IntPtr handle, ref SafeCertContextHandle safeCertContext);
336 [System.Security.SecurityCritical] // auto-generated
337 [ResourceExposure(ResourceScope.None)]
338 [MethodImplAttribute(MethodImplOptions.InternalCall)]
339 internal static extern byte[] _ExportCertificatesToBlob(SafeCertStoreHandle safeCertStoreHandle, X509ContentType contentType, IntPtr password);
340 #endif // !FEATURE_CORECLR
341 [System.Security.SecurityCritical] // auto-generated
342 [ResourceExposure(ResourceScope.None)]
343 [MethodImplAttribute(MethodImplOptions.InternalCall)]
344 internal static extern byte[] _GetCertRawData(SafeCertContextHandle safeCertContext);
345 [System.Security.SecurityCritical] // auto-generated
346 [ResourceExposure(ResourceScope.None)]
347 [MethodImplAttribute(MethodImplOptions.InternalCall)]
348 internal static extern void _GetDateNotAfter(SafeCertContextHandle safeCertContext, ref Win32Native.FILE_TIME fileTime);
349 [System.Security.SecurityCritical] // auto-generated
350 [ResourceExposure(ResourceScope.None)]
351 [MethodImplAttribute(MethodImplOptions.InternalCall)]
352 internal static extern void _GetDateNotBefore(SafeCertContextHandle safeCertContext, ref Win32Native.FILE_TIME fileTime);
353 [System.Security.SecurityCritical] // auto-generated
354 [ResourceExposure(ResourceScope.None)]
355 [MethodImplAttribute(MethodImplOptions.InternalCall)]
356 internal static extern string _GetIssuerName(SafeCertContextHandle safeCertContext, bool legacyV1Mode);
357 [System.Security.SecurityCritical] // auto-generated
358 [ResourceExposure(ResourceScope.None)]
359 [MethodImplAttribute(MethodImplOptions.InternalCall)]
360 internal static extern string _GetPublicKeyOid(SafeCertContextHandle safeCertContext);
361 [System.Security.SecurityCritical] // auto-generated
362 [ResourceExposure(ResourceScope.None)]
363 [MethodImplAttribute(MethodImplOptions.InternalCall)]
364 internal static extern byte[] _GetPublicKeyParameters(SafeCertContextHandle safeCertContext);
365 [System.Security.SecurityCritical] // auto-generated
366 [ResourceExposure(ResourceScope.None)]
367 [MethodImplAttribute(MethodImplOptions.InternalCall)]
368 internal static extern byte[] _GetPublicKeyValue(SafeCertContextHandle safeCertContext);
369 [System.Security.SecurityCritical] // auto-generated
370 [ResourceExposure(ResourceScope.None)]
371 [MethodImplAttribute(MethodImplOptions.InternalCall)]
372 internal static extern string _GetSubjectInfo(SafeCertContextHandle safeCertContext, uint displayType, bool legacyV1Mode);
373 [System.Security.SecurityCritical] // auto-generated
374 [ResourceExposure(ResourceScope.None)]
375 [MethodImplAttribute(MethodImplOptions.InternalCall)]
376 internal static extern byte[] _GetSerialNumber(SafeCertContextHandle safeCertContext);
377 [System.Security.SecurityCritical] // auto-generated
378 [ResourceExposure(ResourceScope.None)]
379 [MethodImplAttribute(MethodImplOptions.InternalCall)]
380 internal static extern byte[] _GetThumbprint(SafeCertContextHandle safeCertContext);
381 [System.Security.SecurityCritical] // auto-generated
382 [ResourceExposure(ResourceScope.None)]
383 [MethodImplAttribute(MethodImplOptions.InternalCall)]
384 internal static extern void _LoadCertFromBlob(byte[] rawData, IntPtr password, uint dwFlags, bool persistKeySet, ref SafeCertContextHandle pCertCtx);
385 [System.Security.SecurityCritical] // auto-generated
386 [ResourceExposure(ResourceScope.Machine)]
387 [MethodImplAttribute(MethodImplOptions.InternalCall)]
388 internal static extern void _LoadCertFromFile(string fileName, IntPtr password, uint dwFlags, bool persistKeySet, ref SafeCertContextHandle pCertCtx);
390 [System.Security.SecurityCritical] // auto-generated
391 [ResourceExposure(ResourceScope.None)]
392 [MethodImplAttribute(MethodImplOptions.InternalCall)]
393 internal static extern void _OpenX509Store(uint storeType, uint flags, string storeName, ref SafeCertStoreHandle safeCertStoreHandle);
394 #endif // !FEATURE_CORECLR
395 [System.Security.SecurityCritical] // auto-generated
396 [ResourceExposure(ResourceScope.None)]
397 [MethodImplAttribute(MethodImplOptions.InternalCall)]
398 internal static extern uint _QueryCertBlobType(byte[] rawData);
399 [System.Security.SecurityCritical] // auto-generated
400 [ResourceExposure(ResourceScope.Machine)]
401 [MethodImplAttribute(MethodImplOptions.InternalCall)]
402 internal static extern uint _QueryCertFileType(string fileName);