private StorePal CreatedLinkedStoreWithFindResults(X509FindType findType, Object findValue, bool validOnly) { unsafe { switch (findType) { case X509FindType.FindByThumbprint: { byte[] thumbPrint = ConfirmedCast <String>(findValue).DecodeHexString(); fixed(byte *pThumbPrint = thumbPrint) { CRYPTOAPI_BLOB blob = new CRYPTOAPI_BLOB(thumbPrint.Length, pThumbPrint); return(FindCore(CertFindType.CERT_FIND_HASH, &blob, validOnly)); } } case X509FindType.FindBySubjectName: { String subjectName = ConfirmedCast <String>(findValue); fixed(char *pSubjectName = subjectName) { return(FindCore(CertFindType.CERT_FIND_SUBJECT_STR, pSubjectName, validOnly)); } } case X509FindType.FindBySubjectDistinguishedName: { String subjectDistinguishedName = ConfirmedCast <String>(findValue); return(FindCore(validOnly, delegate(SafeCertContextHandle pCertContext) { String actual = GetCertNameInfo(pCertContext, CertNameType.CERT_NAME_RDN_TYPE, CertNameFlags.None); return subjectDistinguishedName.Equals(actual, StringComparison.OrdinalIgnoreCase); } )); } case X509FindType.FindByIssuerName: { String issuerName = ConfirmedCast <String>(findValue); fixed(char *pIssuerName = issuerName) { return(FindCore(CertFindType.CERT_FIND_ISSUER_STR, pIssuerName, validOnly)); } } case X509FindType.FindByIssuerDistinguishedName: { String issuerDistinguishedName = ConfirmedCast <String>(findValue); return(FindCore(validOnly, delegate(SafeCertContextHandle pCertContext) { String actual = GetCertNameInfo(pCertContext, CertNameType.CERT_NAME_RDN_TYPE, CertNameFlags.CERT_NAME_ISSUER_FLAG); return issuerDistinguishedName.Equals(actual, StringComparison.OrdinalIgnoreCase); } )); } case X509FindType.FindBySerialNumber: { String decimalOrHexString = ConfirmedCast <String>(findValue); // FindBySerialNumber allows the input format to be either in hex or decimal. Since we can't know which one was intended, // it compares against both interpretations and treats a match of either as a successful find. byte[] hexBytes = decimalOrHexString.DecodeHexString(); Array.Reverse(hexBytes); // String is big-endian, BigInteger constructor requires little-endian. BigInteger expected1 = PositiveBigIntegerFromByteArray(hexBytes); BigInteger ten = new BigInteger(10); BigInteger expected2 = BigInteger.Zero; foreach (char c in decimalOrHexString) { if (c >= '0' && c <= '9') { expected2 = BigInteger.Multiply(expected2, ten); expected2 = BigInteger.Add(expected2, c - '0'); } } return(FindCore(validOnly, delegate(SafeCertContextHandle pCertContext) { byte[] actual = pCertContext.CertContext->pCertInfo->SerialNumber.ToByteArray(); BigInteger actualAsBigInteger = PositiveBigIntegerFromByteArray(actual); // Convert to BigInteger as the comparison must not fail due to spurious leading zeros GC.KeepAlive(pCertContext); return expected1.Equals(actualAsBigInteger) || expected2.Equals(actualAsBigInteger); } )); } case X509FindType.FindByTimeValid: { DateTime dateTime = ConfirmedCast <DateTime>(findValue); FILETIME fileTime = FILETIME.FromDateTime(dateTime); return(FindCore(validOnly, delegate(SafeCertContextHandle pCertContext) { int comparison = Interop.crypt32.CertVerifyTimeValidity(ref fileTime, pCertContext.CertContext->pCertInfo); GC.KeepAlive(pCertContext); return comparison == 0; } )); } case X509FindType.FindByTimeNotYetValid: { DateTime dateTime = ConfirmedCast <DateTime>(findValue); FILETIME fileTime = FILETIME.FromDateTime(dateTime); return(FindCore(validOnly, delegate(SafeCertContextHandle pCertContext) { int comparison = Interop.crypt32.CertVerifyTimeValidity(ref fileTime, pCertContext.CertContext->pCertInfo); GC.KeepAlive(pCertContext); return comparison == -1; } )); } case X509FindType.FindByTimeExpired: { DateTime dateTime = ConfirmedCast <DateTime>(findValue); FILETIME fileTime = FILETIME.FromDateTime(dateTime); return(FindCore(validOnly, delegate(SafeCertContextHandle pCertContext) { int comparison = Interop.crypt32.CertVerifyTimeValidity(ref fileTime, pCertContext.CertContext->pCertInfo); GC.KeepAlive(pCertContext); return comparison == 1; } )); } case X509FindType.FindByTemplateName: { String expected = ConfirmedCast <String>(findValue); return(FindCore(validOnly, delegate(SafeCertContextHandle pCertContext) { // 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". bool foundMatch = false; CERT_INFO *pCertInfo = pCertContext.CertContext->pCertInfo; { CERT_EXTENSION *pV1Template = Interop.crypt32.CertFindExtension(Oids.EnrollCertTypeExtension, pCertInfo->cExtension, pCertInfo->rgExtension); if (pV1Template != null) { byte[] extensionRawData = pV1Template->Value.ToByteArray(); if (!extensionRawData.DecodeObjectNoThrow( CryptDecodeObjectStructType.X509_UNICODE_ANY_STRING, delegate(void *pvDecoded) { CERT_NAME_VALUE *pNameValue = (CERT_NAME_VALUE *)pvDecoded; String actual = Marshal.PtrToStringUni(new IntPtr(pNameValue->Value.pbData)); if (expected.Equals(actual, StringComparison.OrdinalIgnoreCase)) { foundMatch = true; } })) { return false; } } } if (!foundMatch) { CERT_EXTENSION *pV2Template = Interop.crypt32.CertFindExtension(Oids.CertificateTemplate, pCertInfo->cExtension, pCertInfo->rgExtension); if (pV2Template != null) { byte[] extensionRawData = pV2Template->Value.ToByteArray(); if (!extensionRawData.DecodeObjectNoThrow( CryptDecodeObjectStructType.X509_CERTIFICATE_TEMPLATE, delegate(void *pvDecoded) { CERT_TEMPLATE_EXT *pTemplateExt = (CERT_TEMPLATE_EXT *)pvDecoded; String actual = Marshal.PtrToStringAnsi(pTemplateExt->pszObjId); String expectedOidValue = OidInfo.FindOidInfo(CryptOidInfoKeyType.CRYPT_OID_INFO_NAME_KEY, expected, OidGroup.Template, fallBackToAllGroups: true).OID; if (expectedOidValue == null) { expectedOidValue = expected; } if (expected.Equals(actual, StringComparison.OrdinalIgnoreCase)) { foundMatch = true; } })) { return false; } } } GC.KeepAlive(pCertContext); return foundMatch; })); } case X509FindType.FindByApplicationPolicy: { String expected = ConfirmedOidValue(findValue, OidGroup.Policy); return(FindCore(validOnly, delegate(SafeCertContextHandle pCertContext) { int numOids; int cbData = 0; if (!Interop.crypt32.CertGetValidUsages(1, ref pCertContext, out numOids, null, ref cbData)) { return false; } // -1 means the certificate is good for all usages. if (numOids == -1) { return true; } fixed(byte *pOidsPointer = new byte[cbData]) { if (!Interop.crypt32.CertGetValidUsages(1, ref pCertContext, out numOids, pOidsPointer, ref cbData)) { return false; } IntPtr *pOids = (IntPtr *)pOidsPointer; for (int i = 0; i < numOids; i++) { String actual = Marshal.PtrToStringAnsi(pOids[i]); if (expected.Equals(actual, StringComparison.OrdinalIgnoreCase)) { return true; } } return false; } } )); } case X509FindType.FindByCertificatePolicy: { String expected = ConfirmedOidValue(findValue, OidGroup.Policy); return(FindCore(validOnly, delegate(SafeCertContextHandle pCertContext) { CERT_INFO *pCertInfo = pCertContext.CertContext->pCertInfo; CERT_EXTENSION *pCertExtension = Interop.crypt32.CertFindExtension(Oids.CertPolicies, pCertInfo->cExtension, pCertInfo->rgExtension); if (pCertExtension == null) { return false; } bool foundMatch = false; byte[] extensionRawData = pCertExtension->Value.ToByteArray(); if (!extensionRawData.DecodeObjectNoThrow( CryptDecodeObjectStructType.X509_CERT_POLICIES, delegate(void *pvDecoded) { CERT_POLICIES_INFO *pCertPoliciesInfo = (CERT_POLICIES_INFO *)pvDecoded; for (int i = 0; i < pCertPoliciesInfo->cPolicyInfo; i++) { CERT_POLICY_INFO *pCertPolicyInfo = &(pCertPoliciesInfo->rgPolicyInfo[i]); String actual = Marshal.PtrToStringAnsi(pCertPolicyInfo->pszPolicyIdentifier); if (expected.Equals(actual, StringComparison.OrdinalIgnoreCase)) { foundMatch = true; break; } } } )) { return false; } GC.KeepAlive(pCertContext); return foundMatch; } )); } case X509FindType.FindByExtension: { String oidValue = ConfirmedOidValue(findValue, OidGroup.ExtensionOrAttribute); return(FindCore(validOnly, delegate(SafeCertContextHandle pCertContext) { CERT_INFO *pCertInfo = pCertContext.CertContext->pCertInfo; CERT_EXTENSION *pCertExtension = Interop.crypt32.CertFindExtension(oidValue, pCertInfo->cExtension, pCertInfo->rgExtension); GC.KeepAlive(pCertContext); return pCertExtension != null; } )); } case X509FindType.FindByKeyUsage: { X509KeyUsageFlags expected = ConfirmedX509KeyUsage(findValue); return(FindCore(validOnly, delegate(SafeCertContextHandle pCertContext) { CERT_INFO *pCertInfo = pCertContext.CertContext->pCertInfo; X509KeyUsageFlags actual; if (!Interop.crypt32.CertGetIntendedKeyUsage(CertEncodingType.All, pCertInfo, out actual, sizeof(X509KeyUsageFlags))) { return true; // no key usage means it is valid for all key usages. } GC.KeepAlive(pCertContext); return (actual & expected) == expected; } )); } case X509FindType.FindBySubjectKeyIdentifier: { byte[] expected = ConfirmedCast <String>(findValue).DecodeHexString(); return(FindCore(validOnly, delegate(SafeCertContextHandle pCertContext) { int cbData = 0; if (!Interop.crypt32.CertGetCertificateContextProperty(pCertContext, CertContextPropId.CERT_KEY_IDENTIFIER_PROP_ID, null, ref cbData)) { return false; } byte[] actual = new byte[cbData]; if (!Interop.crypt32.CertGetCertificateContextProperty(pCertContext, CertContextPropId.CERT_KEY_IDENTIFIER_PROP_ID, actual, ref cbData)) { return false; } return expected.ContentsEqual(actual); } )); } default: throw new CryptographicException(SR.Cryptography_X509_InvalidFindType); } } }