/mcs/class/referencesource/System/security/system/security/cryptography/x509/x509certificate2collection.cs
C# | 1070 lines | 810 code | 162 blank | 98 comment | 181 complexity | 754c6d7ecaa656608e5d4649c8730003 MD5 | raw file
Possible License(s): LGPL-2.0, MPL-2.0-no-copyleft-exception, CC-BY-SA-3.0, GPL-2.0
- // ==++==
- //
- // Copyright (c) Microsoft Corporation. All rights reserved.
- //
- // ==--==
- //
- // X509Certificate2Collection.cs
- //
- namespace System.Security.Cryptography.X509Certificates {
- using System;
- using System.Collections;
- using System.Globalization;
- using System.IO;
- using System.Runtime.InteropServices;
- using System.Runtime.InteropServices.ComTypes;
- using System.Security.Cryptography;
- using System.Security.Permissions;
- using System.Text;
- using System.Runtime.Versioning;
- using _FILETIME = System.Runtime.InteropServices.ComTypes.FILETIME;
- public enum X509FindType {
- FindByThumbprint = 0,
- FindBySubjectName = 1,
- FindBySubjectDistinguishedName = 2,
- FindByIssuerName = 3,
- FindByIssuerDistinguishedName = 4,
- FindBySerialNumber = 5,
- FindByTimeValid = 6,
- FindByTimeNotYetValid = 7,
- FindByTimeExpired = 8,
- FindByTemplateName = 9,
- FindByApplicationPolicy = 10,
- FindByCertificatePolicy = 11,
- FindByExtension = 12,
- FindByKeyUsage = 13,
- FindBySubjectKeyIdentifier = 14
- }
- public class X509Certificate2Collection : X509CertificateCollection {
- public X509Certificate2Collection() {}
- public X509Certificate2Collection(X509Certificate2 certificate) {
- this.Add(certificate);
- }
- public X509Certificate2Collection(X509Certificate2Collection certificates) {
- this.AddRange(certificates);
- }
- public X509Certificate2Collection(X509Certificate2[] certificates) {
- this.AddRange(certificates);
- }
- public new X509Certificate2 this[int index] {
- get {
- return (X509Certificate2) List[index];
- }
- set {
- if (value == null)
- throw new ArgumentNullException("value");
- List[index] = value;
- }
- }
- public int Add(X509Certificate2 certificate) {
- if (certificate == null)
- throw new ArgumentNullException("certificate");
- return List.Add(certificate);
- }
- public void AddRange(X509Certificate2[] certificates) {
- if (certificates == null)
- throw new ArgumentNullException("certificates");
- int i=0;
- try {
- for (; i<certificates.Length; i++) {
- Add(certificates[i]);
- }
- } catch {
- for (int j=0; j<i; j++) {
- Remove(certificates[j]);
- }
- throw;
- }
- }
- public void AddRange(X509Certificate2Collection certificates) {
- if (certificates == null)
- throw new ArgumentNullException("certificates");
- int i = 0;
- try {
- foreach (X509Certificate2 certificate in certificates) {
- Add(certificate);
- i++;
- }
- } catch {
- for (int j=0; j<i; j++) {
- Remove(certificates[j]);
- }
- throw;
- }
- }
- public bool Contains(X509Certificate2 certificate) {
- if (certificate == null)
- throw new ArgumentNullException("certificate");
- return List.Contains(certificate);
- }
- public void Insert(int index, X509Certificate2 certificate) {
- if (certificate == null)
- throw new ArgumentNullException("certificate");
- List.Insert(index, certificate);
- }
- public new X509Certificate2Enumerator GetEnumerator() {
- return new X509Certificate2Enumerator(this);
- }
- public void Remove(X509Certificate2 certificate) {
- if (certificate == null)
- throw new ArgumentNullException("certificate");
- List.Remove(certificate);
- }
- public void RemoveRange(X509Certificate2[] certificates) {
- if (certificates == null)
- throw new ArgumentNullException("certificates");
- int i=0;
- try {
- for (; i<certificates.Length; i++) {
- Remove(certificates[i]);
- }
- } catch {
- for (int j=0; j<i; j++) {
- Add(certificates[j]);
- }
- throw;
- }
- }
- public void RemoveRange(X509Certificate2Collection certificates) {
- if (certificates == null)
- throw new ArgumentNullException("certificates");
- int i = 0;
- try {
- foreach (X509Certificate2 certificate in certificates) {
- Remove(certificate);
- i++;
- }
- } catch {
- for (int j=0; j<i; j++) {
- Add(certificates[j]);
- }
- throw;
- }
- }
- #if FEATURE_CORESYSTEM
- [SecuritySafeCritical]
- #endif
- public X509Certificate2Collection Find(X509FindType findType, Object findValue, bool validOnly) {
- #if !FEATURE_CORESYSTEM
- //
- // We need to Assert all StorePermission flags since this is a memory store and we want
- // semi-trusted code to be able to find certificates in a memory store.
- //
- StorePermission sp = new StorePermission(StorePermissionFlags.AllFlags);
- sp.Assert();
- #endif
- SafeCertStoreHandle safeSourceStoreHandle = X509Utils.ExportToMemoryStore(this);
- SafeCertStoreHandle safeTargetStoreHandle = FindCertInStore(safeSourceStoreHandle, findType, findValue, validOnly);
- X509Certificate2Collection collection = X509Utils.GetCertificates(safeTargetStoreHandle);
- safeTargetStoreHandle.Dispose();
- safeSourceStoreHandle.Dispose();
- return collection;
- }
- public void Import(byte[] rawData) {
- Import(rawData, null, X509KeyStorageFlags.DefaultKeySet);
- }
- #if FEATURE_CORESYSTEM
- [SecuritySafeCritical]
- #endif
- public void Import(byte[] rawData, string password, X509KeyStorageFlags keyStorageFlags) {
- uint dwFlags = X509Utils.MapKeyStorageFlags(keyStorageFlags);
- SafeCertStoreHandle safeCertStoreHandle = SafeCertStoreHandle.InvalidHandle;
- #if !FEATURE_CORESYSTEM
- //
- // We need to Assert all StorePermission flags since this is a memory store and we want
- // semi-trusted code to be able to import certificates to a memory store.
- //
- StorePermission sp = new StorePermission(StorePermissionFlags.AllFlags);
- sp.Assert();
- #endif
- safeCertStoreHandle = LoadStoreFromBlob(rawData, password, dwFlags, (keyStorageFlags & X509KeyStorageFlags.PersistKeySet) != 0);
- X509Certificate2Collection collection = X509Utils.GetCertificates(safeCertStoreHandle);
- safeCertStoreHandle.Dispose();
- X509Certificate2[] x509Certs = new X509Certificate2[collection.Count];
- collection.CopyTo(x509Certs, 0);
- this.AddRange(x509Certs);
- }
- [ResourceExposure(ResourceScope.Machine)]
- #if !FEATURE_CORESYSTEM
- [ResourceConsumption(ResourceScope.Machine)]
- #endif
- public void Import(string fileName) {
- Import(fileName, null, X509KeyStorageFlags.DefaultKeySet);
- }
- #if FEATURE_CORESYSTEM
- [SecuritySafeCritical]
- #endif
- [ResourceExposure(ResourceScope.Machine)]
- #if !FEATURE_CORESYSTEM
- [ResourceConsumption(ResourceScope.Machine)]
- #endif
- public void Import(string fileName, string password, X509KeyStorageFlags keyStorageFlags) {
- uint dwFlags = X509Utils.MapKeyStorageFlags(keyStorageFlags);
- SafeCertStoreHandle safeCertStoreHandle = SafeCertStoreHandle.InvalidHandle;
- #if !FEATURE_CORESYSTEM
- //
- // We need to Assert all StorePermission flags since this is a memory store and we want
- // semi-trusted code to be able to import certificates to a memory store.
- //
- StorePermission sp = new StorePermission(StorePermissionFlags.AllFlags);
- sp.Assert();
- #endif
- safeCertStoreHandle = LoadStoreFromFile(fileName, password, dwFlags, (keyStorageFlags & X509KeyStorageFlags.PersistKeySet) != 0);
- X509Certificate2Collection collection = X509Utils.GetCertificates(safeCertStoreHandle);
- safeCertStoreHandle.Dispose();
- X509Certificate2[] x509Certs = new X509Certificate2[collection.Count];
- collection.CopyTo(x509Certs, 0);
- this.AddRange(x509Certs);
- }
- #if FEATURE_CORESYSTEM
- [SecuritySafeCritical]
- #endif
- public byte[] Export(X509ContentType contentType) {
- return Export(contentType, null);
- }
- #if FEATURE_CORESYSTEM
- [SecuritySafeCritical]
- #endif
- public byte[] Export(X509ContentType contentType, string password) {
- #if !FEATURE_CORESYSTEM
- //
- // We need to Assert all StorePermission flags since this is a memory store and we want
- // semi-trusted code to be able to export certificates to a memory store.
- //
- StorePermission sp = new StorePermission(StorePermissionFlags.AllFlags);
- sp.Assert();
- #endif
- SafeCertStoreHandle safeCertStoreHandle = X509Utils.ExportToMemoryStore(this);
- byte[] result = ExportCertificatesToBlob(safeCertStoreHandle, contentType, password);
- safeCertStoreHandle.Dispose();
- return result;
- }
- #if FEATURE_CORESYSTEM
- [SecurityCritical]
- #endif
- private unsafe static byte[] ExportCertificatesToBlob(SafeCertStoreHandle safeCertStoreHandle, X509ContentType contentType, string password) {
- SafeCertContextHandle safeCertContextHandle = SafeCertContextHandle.InvalidHandle;
- uint dwSaveAs = CAPI.CERT_STORE_SAVE_AS_PKCS7;
- byte[] pbBlob = null;
- CAPI.CRYPTOAPI_BLOB DataBlob = new CAPI.CRYPTOAPI_BLOB();
- SafeLocalAllocHandle pbEncoded = SafeLocalAllocHandle.InvalidHandle;
- switch(contentType) {
- case X509ContentType.Cert:
- safeCertContextHandle = CAPI.CertEnumCertificatesInStore(safeCertStoreHandle, safeCertContextHandle);
- if (safeCertContextHandle != null && !safeCertContextHandle.IsInvalid) {
- CAPI.CERT_CONTEXT pCertContext = *((CAPI.CERT_CONTEXT*) safeCertContextHandle.DangerousGetHandle());
- pbBlob = new byte[pCertContext.cbCertEncoded];
- Marshal.Copy(pCertContext.pbCertEncoded, pbBlob, 0, pbBlob.Length);
- }
- break;
- case X509ContentType.SerializedCert:
- safeCertContextHandle = CAPI.CertEnumCertificatesInStore(safeCertStoreHandle, safeCertContextHandle);
- uint cbEncoded = 0;
- if (safeCertContextHandle != null && !safeCertContextHandle.IsInvalid) {
- if (!CAPI.CertSerializeCertificateStoreElement(safeCertContextHandle,
- 0,
- pbEncoded,
- new IntPtr(&cbEncoded)))
- throw new CryptographicException(Marshal.GetLastWin32Error());
- pbEncoded = CAPI.LocalAlloc(CAPI.LMEM_FIXED, new IntPtr(cbEncoded));
- if (!CAPI.CertSerializeCertificateStoreElement(safeCertContextHandle,
- 0,
- pbEncoded,
- new IntPtr(&cbEncoded)))
- throw new CryptographicException(Marshal.GetLastWin32Error());
- pbBlob = new byte[cbEncoded];
- Marshal.Copy(pbEncoded.DangerousGetHandle(), pbBlob, 0, pbBlob.Length);
- }
- break;
- case X509ContentType.Pkcs12:
- if (!CAPI.PFXExportCertStore(safeCertStoreHandle,
- new IntPtr(&DataBlob),
- password,
- CAPI.EXPORT_PRIVATE_KEYS | CAPI.REPORT_NOT_ABLE_TO_EXPORT_PRIVATE_KEY))
- throw new CryptographicException(Marshal.GetLastWin32Error());
- pbEncoded = CAPI.LocalAlloc(CAPI.LMEM_FIXED, new IntPtr(DataBlob.cbData));
- DataBlob.pbData = pbEncoded.DangerousGetHandle();
- if (!CAPI.PFXExportCertStore(safeCertStoreHandle,
- new IntPtr(&DataBlob),
- password,
- CAPI.EXPORT_PRIVATE_KEYS | CAPI.REPORT_NOT_ABLE_TO_EXPORT_PRIVATE_KEY))
- throw new CryptographicException(Marshal.GetLastWin32Error());
- pbBlob = new byte[DataBlob.cbData];
- Marshal.Copy(DataBlob.pbData, pbBlob, 0, pbBlob.Length);
- break;
- case X509ContentType.SerializedStore:
- // falling through
- case X509ContentType.Pkcs7:
- if (contentType == X509ContentType.SerializedStore)
- dwSaveAs = CAPI.CERT_STORE_SAVE_AS_STORE;
- // determine the required length
- if (!CAPI.CertSaveStore(safeCertStoreHandle,
- CAPI.X509_ASN_ENCODING | CAPI.PKCS_7_ASN_ENCODING,
- dwSaveAs,
- CAPI.CERT_STORE_SAVE_TO_MEMORY,
- new IntPtr(&DataBlob),
- 0))
- throw new CryptographicException(Marshal.GetLastWin32Error());
- pbEncoded = CAPI.LocalAlloc(CAPI.LMEM_FIXED, new IntPtr(DataBlob.cbData));
- DataBlob.pbData = pbEncoded.DangerousGetHandle();
- // now save the store to a memory blob
- if (!CAPI.CertSaveStore(safeCertStoreHandle,
- CAPI.X509_ASN_ENCODING | CAPI.PKCS_7_ASN_ENCODING,
- dwSaveAs,
- CAPI.CERT_STORE_SAVE_TO_MEMORY,
- new IntPtr(&DataBlob),
- 0))
- throw new CryptographicException(Marshal.GetLastWin32Error());
- pbBlob = new byte[DataBlob.cbData];
- Marshal.Copy(DataBlob.pbData, pbBlob, 0, pbBlob.Length);
- break;
- default:
- throw new CryptographicException(SR.GetString(SR.Cryptography_X509_InvalidContentType));
- }
- pbEncoded.Dispose();
- safeCertContextHandle.Dispose();
- return pbBlob;
- }
- #if FEATURE_CORESYSTEM
- [SecurityCritical]
- #endif
- internal delegate int FindProcDelegate (SafeCertContextHandle safeCertContextHandle, object pvCallbackData);
- #if FEATURE_CORESYSTEM
- [SecuritySafeCritical]
- #endif
- private unsafe static SafeCertStoreHandle FindCertInStore(SafeCertStoreHandle safeSourceStoreHandle, X509FindType findType, Object findValue, bool validOnly) {
- if (findValue == null)
- throw new ArgumentNullException("findValue");
- IntPtr pvFindPara = IntPtr.Zero;
- object pvCallbackData1 = null;
- object pvCallbackData2 = null;
- FindProcDelegate pfnCertCallback1 = null;
- FindProcDelegate pfnCertCallback2 = null;
- uint dwFindType = CAPI.CERT_FIND_ANY;
- string subject, issuer;
- CAPI.CRYPTOAPI_BLOB HashBlob = new CAPI.CRYPTOAPI_BLOB();
- SafeLocalAllocHandle pb = SafeLocalAllocHandle.InvalidHandle;
- _FILETIME ft = new _FILETIME();
- string oidValue = null;
- switch(findType) {
- case X509FindType.FindByThumbprint:
- if (findValue.GetType() != typeof(string))
- throw new CryptographicException(SR.GetString(SR.Cryptography_X509_InvalidFindValue));
- byte[] hex = X509Utils.DecodeHexString((string) findValue);
- pb = X509Utils.ByteToPtr(hex);
- HashBlob.pbData = pb.DangerousGetHandle();
- HashBlob.cbData = (uint) hex.Length;
- dwFindType = CAPI.CERT_FIND_HASH;
- pvFindPara = new IntPtr(&HashBlob);
- break;
- case X509FindType.FindBySubjectName:
- if (findValue.GetType() != typeof(string))
- throw new CryptographicException(SR.GetString(SR.Cryptography_X509_InvalidFindValue));
- subject = (string) findValue;
- dwFindType = CAPI.CERT_FIND_SUBJECT_STR;
- pb = X509Utils.StringToUniPtr(subject);
- pvFindPara = pb.DangerousGetHandle();
- break;
- case X509FindType.FindBySubjectDistinguishedName:
- if (findValue.GetType() != typeof(string))
- throw new CryptographicException(SR.GetString(SR.Cryptography_X509_InvalidFindValue));
- subject = (string) findValue;
- pfnCertCallback1 = new FindProcDelegate(FindSubjectDistinguishedNameCallback);
- pvCallbackData1 = subject;
- break;
- case X509FindType.FindByIssuerName:
- if (findValue.GetType() != typeof(string))
- throw new CryptographicException(SR.GetString(SR.Cryptography_X509_InvalidFindValue));
- issuer = (string) findValue;
- dwFindType = CAPI.CERT_FIND_ISSUER_STR;
- pb = X509Utils.StringToUniPtr(issuer);
- pvFindPara = pb.DangerousGetHandle();
- break;
- case X509FindType.FindByIssuerDistinguishedName:
- if (findValue.GetType() != typeof(string))
- throw new CryptographicException(SR.GetString(SR.Cryptography_X509_InvalidFindValue));
- issuer = (string) findValue;
- pfnCertCallback1 = new FindProcDelegate(FindIssuerDistinguishedNameCallback);
- pvCallbackData1 = issuer;
- break;
- case X509FindType.FindBySerialNumber:
- if (findValue.GetType() != typeof(string))
- throw new CryptographicException(SR.GetString(SR.Cryptography_X509_InvalidFindValue));
- pfnCertCallback1 = new FindProcDelegate(FindSerialNumberCallback);
- pfnCertCallback2 = new FindProcDelegate(FindSerialNumberCallback);
- BigInt h = new BigInt();
- h.FromHexadecimal((string) findValue);
- pvCallbackData1 = (byte[]) h.ToByteArray();
- h.FromDecimal((string) findValue);
- pvCallbackData2 = (byte[]) h.ToByteArray();
- break;
- case X509FindType.FindByTimeValid:
- if (findValue.GetType() != typeof(DateTime))
- throw new CryptographicException(SR.GetString(SR.Cryptography_X509_InvalidFindValue));
- *((long*) &ft) = ((DateTime) findValue).ToFileTime();
- pfnCertCallback1 = new FindProcDelegate(FindTimeValidCallback);
- pvCallbackData1 = ft;
- break;
- case X509FindType.FindByTimeNotYetValid:
- if (findValue.GetType() != typeof(DateTime))
- throw new CryptographicException(SR.GetString(SR.Cryptography_X509_InvalidFindValue));
- *((long*) &ft) = ((DateTime) findValue).ToFileTime();
- pfnCertCallback1 = new FindProcDelegate(FindTimeNotBeforeCallback);
- pvCallbackData1 = ft;
- break;
- case X509FindType.FindByTimeExpired:
- if (findValue.GetType() != typeof(DateTime))
- throw new CryptographicException(SR.GetString(SR.Cryptography_X509_InvalidFindValue));
- *((long*) &ft) = ((DateTime) findValue).ToFileTime();
- pfnCertCallback1 = new FindProcDelegate(FindTimeNotAfterCallback);
- pvCallbackData1 = ft;
- break;
- case X509FindType.FindByTemplateName:
- if (findValue.GetType() != typeof(string))
- throw new CryptographicException(SR.GetString(SR.Cryptography_X509_InvalidFindValue));
- pvCallbackData1 = (string) findValue;
- pfnCertCallback1 = new FindProcDelegate(FindTemplateNameCallback);
- break;
- case X509FindType.FindByApplicationPolicy:
- if (findValue.GetType() != typeof(string))
- throw new CryptographicException(SR.GetString(SR.Cryptography_X509_InvalidFindValue));
- // If we were passed the friendly name, retrieve the value string.
- oidValue = X509Utils.FindOidInfoWithFallback(CAPI.CRYPT_OID_INFO_NAME_KEY, (string) findValue, OidGroup.Policy);
- if (oidValue == null) {
- oidValue = (string) findValue;
- X509Utils.ValidateOidValue(oidValue);
- }
- pvCallbackData1 = oidValue;
- pfnCertCallback1 = new FindProcDelegate(FindApplicationPolicyCallback);
- break;
- case X509FindType.FindByCertificatePolicy:
- if (findValue.GetType() != typeof(string))
- throw new CryptographicException(SR.GetString(SR.Cryptography_X509_InvalidFindValue));
- // If we were passed the friendly name, retrieve the value string.
- oidValue = X509Utils.FindOidInfoWithFallback(CAPI.CRYPT_OID_INFO_NAME_KEY, (string)findValue, OidGroup.Policy);
- if (oidValue == null) {
- oidValue = (string) findValue;
- X509Utils.ValidateOidValue(oidValue);
- }
- pvCallbackData1 = oidValue;
- pfnCertCallback1 = new FindProcDelegate(FindCertificatePolicyCallback);
- break;
- case X509FindType.FindByExtension:
- if (findValue.GetType() != typeof(string))
- throw new CryptographicException(SR.GetString(SR.Cryptography_X509_InvalidFindValue));
- // If we were passed the friendly name, retrieve the value string.
- oidValue = X509Utils.FindOidInfoWithFallback(CAPI.CRYPT_OID_INFO_NAME_KEY, (string)findValue, OidGroup.ExtensionOrAttribute);
- if (oidValue == null) {
- oidValue = (string) findValue;
- X509Utils.ValidateOidValue(oidValue);
- }
- pvCallbackData1 = oidValue;
- pfnCertCallback1 = new FindProcDelegate(FindExtensionCallback);
- break;
- case X509FindType.FindByKeyUsage:
- // The findValue object can be either a friendly name, a X509KeyUsageFlags enum or an integer.
- if (findValue.GetType() == typeof(string)) {
- CAPI.KEY_USAGE_STRUCT[] KeyUsages = new CAPI.KEY_USAGE_STRUCT[] {
- new CAPI.KEY_USAGE_STRUCT("DigitalSignature", CAPI.CERT_DIGITAL_SIGNATURE_KEY_USAGE),
- new CAPI.KEY_USAGE_STRUCT("NonRepudiation", CAPI.CERT_NON_REPUDIATION_KEY_USAGE),
- new CAPI.KEY_USAGE_STRUCT("KeyEncipherment", CAPI.CERT_KEY_ENCIPHERMENT_KEY_USAGE),
- new CAPI.KEY_USAGE_STRUCT("DataEncipherment", CAPI.CERT_DATA_ENCIPHERMENT_KEY_USAGE),
- new CAPI.KEY_USAGE_STRUCT("KeyAgreement", CAPI.CERT_KEY_AGREEMENT_KEY_USAGE),
- new CAPI.KEY_USAGE_STRUCT("KeyCertSign", CAPI.CERT_KEY_CERT_SIGN_KEY_USAGE),
- new CAPI.KEY_USAGE_STRUCT("CrlSign", CAPI.CERT_CRL_SIGN_KEY_USAGE),
- new CAPI.KEY_USAGE_STRUCT("EncipherOnly", CAPI.CERT_ENCIPHER_ONLY_KEY_USAGE),
- new CAPI.KEY_USAGE_STRUCT("DecipherOnly", CAPI.CERT_DECIPHER_ONLY_KEY_USAGE)
- };
- for (uint index = 0; index < KeyUsages.Length; index++) {
- if (String.Compare(KeyUsages[index].pwszKeyUsage, (string) findValue, StringComparison.OrdinalIgnoreCase) == 0) {
- pvCallbackData1 = KeyUsages[index].dwKeyUsageBit;
- break;
- }
- }
- if (pvCallbackData1 == null)
- throw new CryptographicException(SR.GetString(SR.Cryptography_X509_InvalidFindType));
- } else if (findValue.GetType() == typeof(X509KeyUsageFlags)) {
- pvCallbackData1 = findValue;
- } else if (findValue.GetType() == typeof(uint) || findValue.GetType() == typeof(int)) {
- // We got the actual DWORD
- pvCallbackData1 = findValue;
- } else
- throw new CryptographicException(SR.GetString(SR.Cryptography_X509_InvalidFindType));
- pfnCertCallback1 = new FindProcDelegate(FindKeyUsageCallback);
- break;
- case X509FindType.FindBySubjectKeyIdentifier:
- if (findValue.GetType() != typeof(string))
- throw new CryptographicException(SR.GetString(SR.Cryptography_X509_InvalidFindValue));
- pvCallbackData1 = (byte[]) X509Utils.DecodeHexString((string) findValue);
- pfnCertCallback1 = new FindProcDelegate(FindSubjectKeyIdentifierCallback);
- break;
- default:
- throw new CryptographicException(SR.GetString(SR.Cryptography_X509_InvalidFindType));
- }
- // First, create a memory store
- SafeCertStoreHandle safeTargetStoreHandle = CAPI.CertOpenStore(new IntPtr(CAPI.CERT_STORE_PROV_MEMORY),
- CAPI.X509_ASN_ENCODING | CAPI.PKCS_7_ASN_ENCODING,
- IntPtr.Zero,
- CAPI.CERT_STORE_ENUM_ARCHIVED_FLAG | CAPI.CERT_STORE_CREATE_NEW_FLAG,
- null);
- if (safeTargetStoreHandle == null || safeTargetStoreHandle.IsInvalid)
- throw new CryptographicException(Marshal.GetLastWin32Error());
- // FindByCert will throw an exception in case of failures.
- FindByCert(safeSourceStoreHandle,
- dwFindType,
- pvFindPara,
- validOnly,
- pfnCertCallback1,
- pfnCertCallback2,
- pvCallbackData1,
- pvCallbackData2,
- safeTargetStoreHandle);
- pb.Dispose();
- return safeTargetStoreHandle;
- }
- #if FEATURE_CORESYSTEM
- [SecuritySafeCritical]
- #endif
- private static void FindByCert(SafeCertStoreHandle safeSourceStoreHandle,
- uint dwFindType,
- IntPtr pvFindPara,
- bool validOnly,
- FindProcDelegate pfnCertCallback1,
- FindProcDelegate pfnCertCallback2,
- object pvCallbackData1,
- object pvCallbackData2,
- SafeCertStoreHandle safeTargetStoreHandle) {
- int hr = CAPI.S_OK;
- SafeCertContextHandle pEnumContext = SafeCertContextHandle.InvalidHandle;
- pEnumContext = CAPI.CertFindCertificateInStore(safeSourceStoreHandle,
- CAPI.X509_ASN_ENCODING | CAPI.PKCS_7_ASN_ENCODING,
- 0,
- dwFindType,
- pvFindPara,
- pEnumContext);
- while (pEnumContext != null && !pEnumContext.IsInvalid) {
- if (pfnCertCallback1 != null) {
- hr = pfnCertCallback1(pEnumContext, pvCallbackData1);
- if (hr == CAPI.S_FALSE) {
- if (pfnCertCallback2 != null)
- hr = pfnCertCallback2(pEnumContext, pvCallbackData2);
- if (hr == CAPI.S_FALSE) // skip this certificate
- goto skip;
- }
- if (hr != CAPI.S_OK)
- break;
- }
- if (validOnly) {
- hr = X509Utils.VerifyCertificate(pEnumContext,
- null,
- null,
- X509RevocationMode.NoCheck,
- X509RevocationFlag.ExcludeRoot,
- DateTime.Now,
- new TimeSpan(0, 0, 0), // default
- null,
- new IntPtr(CAPI.CERT_CHAIN_POLICY_BASE),
- IntPtr.Zero);
- if (hr == CAPI.S_FALSE) // skip this certificate
- goto skip;
- if (hr != CAPI.S_OK)
- break;
- }
- //
- // We use CertAddCertificateLinkToStore to keep a link to the original store, so any property changes get
- // applied to the original store. This has a limit of 99 links per cert context however.
- //
- if (!CAPI.CertAddCertificateLinkToStore(safeTargetStoreHandle,
- pEnumContext,
- CAPI.CERT_STORE_ADD_ALWAYS,
- SafeCertContextHandle.InvalidHandle)) {
- hr = Marshal.GetHRForLastWin32Error();
- break;
- }
- skip:
- // CertFindCertificateInStore always releases the context regardless of success
- // or failure so we don't need to manually release it
- GC.SuppressFinalize(pEnumContext);
- pEnumContext = CAPI.CertFindCertificateInStore(safeSourceStoreHandle,
- CAPI.X509_ASN_ENCODING | CAPI.PKCS_7_ASN_ENCODING,
- 0,
- dwFindType,
- pvFindPara,
- pEnumContext);
- }
- if (pEnumContext != null && !pEnumContext.IsInvalid)
- pEnumContext.Dispose();
- if (hr != CAPI.S_FALSE && hr != CAPI.S_OK)
- throw new CryptographicException(hr);
- }
- //
- // Callback method to find certificates by subject DN.
- //
- #if FEATURE_CORESYSTEM
- [SecurityCritical]
- #endif
- private static unsafe int FindSubjectDistinguishedNameCallback(SafeCertContextHandle safeCertContextHandle, object pvCallbackData) {
- string rdn = CAPI.GetCertNameInfo(safeCertContextHandle, 0, CAPI.CERT_NAME_RDN_TYPE);
- if (String.Compare(rdn, (string) pvCallbackData, StringComparison.OrdinalIgnoreCase) != 0)
- return CAPI.S_FALSE;
- return CAPI.S_OK;
- }
- //
- // Callback method to find certificates by issuer DN.
- //
- #if FEATURE_CORESYSTEM
- [SecurityCritical]
- #endif
- private static unsafe int FindIssuerDistinguishedNameCallback(SafeCertContextHandle safeCertContextHandle, object pvCallbackData) {
- string rdn = CAPI.GetCertNameInfo(safeCertContextHandle, CAPI.CERT_NAME_ISSUER_FLAG, CAPI.CERT_NAME_RDN_TYPE);
- if (String.Compare(rdn, (string) pvCallbackData, StringComparison.OrdinalIgnoreCase) != 0)
- return CAPI.S_FALSE;
- return CAPI.S_OK;
- }
- //
- // Callback method to find certificates by serial number.
- // This can be useful when using XML Digital Signature and X509Data.
- //
- #if FEATURE_CORESYSTEM
- [SecurityCritical]
- #endif
- private static unsafe int FindSerialNumberCallback(SafeCertContextHandle safeCertContextHandle, object pvCallbackData) {
- CAPI.CERT_CONTEXT pCertContext = *((CAPI.CERT_CONTEXT*) safeCertContextHandle.DangerousGetHandle());
- CAPI.CERT_INFO pCertInfo = (CAPI.CERT_INFO) Marshal.PtrToStructure(pCertContext.pCertInfo, typeof(CAPI.CERT_INFO));
- byte[] hex = new byte[pCertInfo.SerialNumber.cbData];
- Marshal.Copy(pCertInfo.SerialNumber.pbData, hex, 0, hex.Length);
- int size = X509Utils.GetHexArraySize(hex);
- byte[] serialNumber = (byte[]) pvCallbackData;
- if (serialNumber.Length != size)
- return CAPI.S_FALSE;
- for (int index = 0; index < serialNumber.Length; index++) {
- if (serialNumber[index] != hex[index])
- return CAPI.S_FALSE;
- }
- return CAPI.S_OK;
- }
- //
- // Callback method to find certificates by validity time.
- // The callback data has to be a UTC FILETEME.
- //
- #if FEATURE_CORESYSTEM
- [SecurityCritical]
- #endif
- private static unsafe int FindTimeValidCallback(SafeCertContextHandle safeCertContextHandle, object pvCallbackData) {
- _FILETIME ft = (_FILETIME) pvCallbackData;
- CAPI.CERT_CONTEXT pCertContext = *((CAPI.CERT_CONTEXT*) safeCertContextHandle.DangerousGetHandle());
- if (CAPI.CertVerifyTimeValidity(ref ft, pCertContext.pCertInfo) == 0)
- return CAPI.S_OK;
- return CAPI.S_FALSE;
- }
- //
- // Callback method to find certificates expired at a certain DateTime.
- // The callback data has to be a UTC FILETEME.
- //
- #if FEATURE_CORESYSTEM
- [SecurityCritical]
- #endif
- private static unsafe int FindTimeNotAfterCallback(SafeCertContextHandle safeCertContextHandle, object pvCallbackData) {
- _FILETIME ft = (_FILETIME) pvCallbackData;
- CAPI.CERT_CONTEXT pCertContext = *((CAPI.CERT_CONTEXT*) safeCertContextHandle.DangerousGetHandle());
- if (CAPI.CertVerifyTimeValidity(ref ft, pCertContext.pCertInfo) == 1)
- return CAPI.S_OK;
- return CAPI.S_FALSE;
- }
- //
- // Callback method to find certificates effective after a certain DateTime.
- // The callback data has to be a UTC FILETEME.
- //
- #if FEATURE_CORESYSTEM
- [SecurityCritical]
- #endif
- private static unsafe int FindTimeNotBeforeCallback(SafeCertContextHandle safeCertContextHandle, object pvCallbackData) {
- _FILETIME ft = (_FILETIME) pvCallbackData;
- CAPI.CERT_CONTEXT pCertContext = *((CAPI.CERT_CONTEXT*) safeCertContextHandle.DangerousGetHandle());
- if (CAPI.CertVerifyTimeValidity(ref ft, pCertContext.pCertInfo) == -1)
- return CAPI.S_OK;
- return CAPI.S_FALSE;
- }
- //
- // Callback method to find certificates by template name.
- // The template name can have 2 different formats: V1 format (<= Win2K) is just a string
- // V2 format (XP only) can be a friendly name or an OID.
- // An example of Template Name can be "ClientAuth".
- //
- #if FEATURE_CORESYSTEM
- [SecurityCritical]
- #endif
- private static unsafe int FindTemplateNameCallback(SafeCertContextHandle safeCertContextHandle, object pvCallbackData) {
- IntPtr pV1Template = IntPtr.Zero;
- IntPtr pV2Template = IntPtr.Zero;
- CAPI.CERT_CONTEXT pCertContext = *((CAPI.CERT_CONTEXT*) safeCertContextHandle.DangerousGetHandle());
- CAPI.CERT_INFO pCertInfo = (CAPI.CERT_INFO) Marshal.PtrToStructure(pCertContext.pCertInfo, typeof(CAPI.CERT_INFO));
- pV1Template = CAPI.CertFindExtension(CAPI.szOID_ENROLL_CERTTYPE_EXTENSION,
- pCertInfo.cExtension,
- pCertInfo.rgExtension);
- pV2Template = CAPI.CertFindExtension(CAPI.szOID_CERTIFICATE_TEMPLATE,
- pCertInfo.cExtension,
- pCertInfo.rgExtension);
- if (pV1Template == IntPtr.Zero && pV2Template == IntPtr.Zero)
- return CAPI.S_FALSE;
- if (pV1Template != IntPtr.Zero) {
- CAPI.CERT_EXTENSION extension = (CAPI.CERT_EXTENSION) Marshal.PtrToStructure(pV1Template, typeof(CAPI.CERT_EXTENSION));
- byte[] rawData = new byte[extension.Value.cbData];
- Marshal.Copy(extension.Value.pbData, rawData, 0, rawData.Length);
- uint cbDecoded = 0;
- SafeLocalAllocHandle decoded = null;
- // Decode the extension.
- bool result = CAPI.DecodeObject(new IntPtr(CAPI.X509_UNICODE_ANY_STRING),
- rawData,
- out decoded,
- out cbDecoded);
- if (result) {
- CAPI.CERT_NAME_VALUE pNameValue = (CAPI.CERT_NAME_VALUE) Marshal.PtrToStructure(decoded.DangerousGetHandle(), typeof(CAPI.CERT_NAME_VALUE));
- string s = Marshal.PtrToStringUni(pNameValue.Value.pbData);
- if (String.Compare(s, (string) pvCallbackData, StringComparison.OrdinalIgnoreCase) == 0)
- return CAPI.S_OK;
- }
- }
- if (pV2Template != IntPtr.Zero) {
- CAPI.CERT_EXTENSION extension = (CAPI.CERT_EXTENSION) Marshal.PtrToStructure(pV2Template, typeof(CAPI.CERT_EXTENSION));
- byte[] rawData = new byte[extension.Value.cbData];
- Marshal.Copy(extension.Value.pbData, rawData, 0, rawData.Length);
- uint cbDecoded = 0;
- SafeLocalAllocHandle decoded = null;
- // Decode the extension.
- bool result = CAPI.DecodeObject(new IntPtr(CAPI.X509_CERTIFICATE_TEMPLATE),
- rawData,
- out decoded,
- out cbDecoded);
- if (result) {
- CAPI.CERT_TEMPLATE_EXT pTemplate = (CAPI.CERT_TEMPLATE_EXT) Marshal.PtrToStructure(decoded.DangerousGetHandle(), typeof(CAPI.CERT_TEMPLATE_EXT));
- // If we were passed the friendly name, retrieve the value string.
- string oidValue = X509Utils.FindOidInfoWithFallback(CAPI.CRYPT_OID_INFO_NAME_KEY, (string)pvCallbackData, OidGroup.Template);
- if (oidValue == null)
- oidValue = (string) pvCallbackData;
- if (String.Compare(pTemplate.pszObjId, oidValue, StringComparison.OrdinalIgnoreCase) == 0)
- return CAPI.S_OK;
- }
- }
- return CAPI.S_FALSE;
- }
- //
- // Callback method to find certificates by application policy (also known as EKU)
- // An example of application policy can be: "Encrypting File System"
- //
- #if FEATURE_CORESYSTEM
- [SecurityCritical]
- #endif
- private static unsafe int FindApplicationPolicyCallback(SafeCertContextHandle safeCertContextHandle, object pvCallbackData) {
- string eku = (string) pvCallbackData;
- if (eku.Length == 0)
- return CAPI.S_FALSE;
- IntPtr pCertContext = safeCertContextHandle.DangerousGetHandle();
- int cNumOIDs = 0;
- uint cbOIDs = 0;
- SafeLocalAllocHandle rghOIDs = SafeLocalAllocHandle.InvalidHandle;
- if (!CAPI.CertGetValidUsages(1, new IntPtr(&pCertContext), new IntPtr(&cNumOIDs), rghOIDs, new IntPtr(&cbOIDs)))
- return CAPI.S_FALSE;
- rghOIDs = CAPI.LocalAlloc(CAPI.LMEM_FIXED, new IntPtr(cbOIDs));
- if (!CAPI.CertGetValidUsages(1, new IntPtr(&pCertContext), new IntPtr(&cNumOIDs), rghOIDs, new IntPtr(&cbOIDs)))
- return CAPI.S_FALSE;
- // -1 means the certificate is good for all usages.
- if (cNumOIDs == -1)
- return CAPI.S_OK;
- for (int index = 0; index < cNumOIDs; index++) {
- IntPtr pszOid = Marshal.ReadIntPtr(new IntPtr((long) rghOIDs.DangerousGetHandle() + index * Marshal.SizeOf(typeof(IntPtr))));
- string oidValue = Marshal.PtrToStringAnsi(pszOid);
- if (String.Compare(eku, oidValue, StringComparison.OrdinalIgnoreCase) == 0)
- return CAPI.S_OK;
- }
- return CAPI.S_FALSE;
- }
- //
- // Callback method to find certificates by certificate policy.
- // This is only recognized in XP platforms. However, passing in an OID value should work on downlevel platforms as well.
- //
- #if FEATURE_CORESYSTEM
- [SecurityCritical]
- #endif
- private static unsafe int FindCertificatePolicyCallback(SafeCertContextHandle safeCertContextHandle, object pvCallbackData) {
- string certPolicy = (string) pvCallbackData;
- if (certPolicy.Length == 0)
- return CAPI.S_FALSE;
- CAPI.CERT_CONTEXT pCertContext = *((CAPI.CERT_CONTEXT*) safeCertContextHandle.DangerousGetHandle());
- CAPI.CERT_INFO pCertInfo = (CAPI.CERT_INFO) Marshal.PtrToStructure(pCertContext.pCertInfo, typeof(CAPI.CERT_INFO));
- IntPtr pExtension = CAPI.CertFindExtension(CAPI.szOID_CERT_POLICIES,
- pCertInfo.cExtension,
- pCertInfo.rgExtension);
- if (pExtension == IntPtr.Zero)
- return CAPI.S_FALSE;
- CAPI.CERT_EXTENSION extension = (CAPI.CERT_EXTENSION) Marshal.PtrToStructure(pExtension, typeof(CAPI.CERT_EXTENSION));
- byte[] rawData = new byte[extension.Value.cbData];
- Marshal.Copy(extension.Value.pbData, rawData, 0, rawData.Length);
- uint cbDecoded = 0;
- SafeLocalAllocHandle decoded = null;
- // Decode the extension.
- bool result = CAPI.DecodeObject(new IntPtr(CAPI.X509_CERT_POLICIES),
- rawData,
- out decoded,
- out cbDecoded);
- if (result) {
- CAPI.CERT_POLICIES_INFO pInfo = (CAPI.CERT_POLICIES_INFO) Marshal.PtrToStructure(decoded.DangerousGetHandle(), typeof(CAPI.CERT_POLICIES_INFO));
- for (int index = 0; index < pInfo.cPolicyInfo; index++) {
- IntPtr pPolicyInfoPtr = new IntPtr((long) pInfo.rgPolicyInfo + index * Marshal.SizeOf(typeof(CAPI.CERT_POLICY_INFO)));
- CAPI.CERT_POLICY_INFO pPolicyInfo = (CAPI.CERT_POLICY_INFO) Marshal.PtrToStructure(pPolicyInfoPtr, typeof(CAPI.CERT_POLICY_INFO));
- if (String.Compare(certPolicy, pPolicyInfo.pszPolicyIdentifier, StringComparison.OrdinalIgnoreCase) == 0)
- return CAPI.S_OK;
- }
- }
- return CAPI.S_FALSE;
- }
- //
- // Callback method to find certificates that have a particular extension.
- // The callback data can be either an OID friendly name or value (all should be ANSI strings).
- //
- #if FEATURE_CORESYSTEM
- [SecurityCritical]
- #endif
- private static unsafe int FindExtensionCallback(SafeCertContextHandle safeCertContextHandle, object pvCallbackData) {
- CAPI.CERT_CONTEXT pCertContext = *((CAPI.CERT_CONTEXT*) safeCertContextHandle.DangerousGetHandle());
- CAPI.CERT_INFO pCertInfo = (CAPI.CERT_INFO) Marshal.PtrToStructure(pCertContext.pCertInfo, typeof(CAPI.CERT_INFO));
- IntPtr pExtension = CAPI.CertFindExtension((string) pvCallbackData,
- pCertInfo.cExtension,
- pCertInfo.rgExtension);
- if (pExtension == IntPtr.Zero)
- return CAPI.S_FALSE;
- return CAPI.S_OK;
- }
- //
- // Callback method to find certificates that have a particular Key Usage.
- // The callback data can be either a string (example: "KeyEncipherment") or a DWORD which can have multiple bits set in it.
- // If the callback data is a string, we can achieve the effect of a bit union by calling it multiple times, each time
- // further restricting the set of selected certificates.
- //
- #if FEATURE_CORESYSTEM
- [SecurityCritical]
- #endif
- private static unsafe int FindKeyUsageCallback(SafeCertContextHandle safeCertContextHandle, object pvCallbackData) {
- CAPI.CERT_CONTEXT pCertContext = *((CAPI.CERT_CONTEXT*) safeCertContextHandle.DangerousGetHandle());
- uint dwUsages = 0;
- if (!CAPI.CertGetIntendedKeyUsage(CAPI.X509_ASN_ENCODING | CAPI.PKCS_7_ASN_ENCODING,
- pCertContext.pCertInfo,
- new IntPtr(&dwUsages),
- 4 /* sizeof(DWORD) */))
- return CAPI.S_OK; // no key usage means it is valid for all key usages.
- uint dwCheckUsage = Convert.ToUInt32(pvCallbackData, null);
- if ((dwUsages & dwCheckUsage) == dwCheckUsage)
- return CAPI.S_OK;
- return CAPI.S_FALSE;
- }
- //
- // Callback method to find certificates by subject key identifier.
- // This can be useful when using XML Digital Signature and X509Data.
- //
- #if FEATURE_CORESYSTEM
- [SecurityCritical]
- #endif
- private static unsafe int FindSubjectKeyIdentifierCallback(SafeCertContextHandle safeCertContextHandle, object pvCallbackData) {
- SafeLocalAllocHandle ptr = SafeLocalAllocHandle.InvalidHandle;
- // We look for the Key Id extended property
- // this will first look if there is a V3 SKI extension
- // and then if that fails, It will return the Key Id extended property.
- uint cbData = 0;
- if (!CAPI.CertGetCertificateContextProperty(safeCertContextHandle,
- CAPI.CERT_KEY_IDENTIFIER_PROP_ID,
- ptr,
- ref cbData))
- return CAPI.S_FALSE;
- ptr = CAPI.LocalAlloc(CAPI.LMEM_FIXED, new IntPtr(cbData));
- if (!CAPI.CertGetCertificateContextProperty(safeCertContextHandle,
- CAPI.CERT_KEY_IDENTIFIER_PROP_ID,
- ptr,
- ref cbData))
- return CAPI.S_FALSE;
- byte[] subjectKeyIdentifier = (byte[]) pvCallbackData;
- if (subjectKeyIdentifier.Length != cbData)
- return CAPI.S_FALSE;
- byte[] hex = new byte[cbData];
- Marshal.Copy(ptr.DangerousGetHandle(), hex, 0, hex.Length);
- ptr.Dispose();
- for (uint index = 0; index < cbData; index++) {
- if (subjectKeyIdentifier[index] != hex[index])
- return CAPI.S_FALSE;
- }
- return CAPI.S_OK;
- }
- private const uint X509_STORE_CONTENT_FLAGS =
- (CAPI.CERT_QUERY_CONTENT_FLAG_CERT |
- CAPI.CERT_QUERY_CONTENT_FLAG_SERIALIZED_CERT |
- CAPI.CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED |
- CAPI.CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED |
- CAPI.CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED |
- CAPI.CERT_QUERY_CONTENT_FLAG_PFX |
- CAPI.CERT_QUERY_CONTENT_FLAG_SERIALIZED_STORE);
- #if FEATURE_CORESYSTEM
- [SecuritySafeCritical]
- #endif
- [ResourceExposure(ResourceScope.None)]
- #if !FEATURE_CORESYSTEM
-