private static SafeBCryptKeyHandle ImportPublicKeyInfo(SafeCertContextHandle certContext) { #if NETNATIVE // CryptImportPublicKeyInfoEx2() not in the UWP api list. throw new PlatformNotSupportedException(); #else unsafe { SafeBCryptKeyHandle bCryptKeyHandle; bool mustRelease = false; certContext.DangerousAddRef(ref mustRelease); try { unsafe { bool success = Interop.crypt32.CryptImportPublicKeyInfoEx2(CertEncodingType.X509_ASN_ENCODING, &(certContext.CertContext->pCertInfo->SubjectPublicKeyInfo), 0, null, out bCryptKeyHandle); if (!success) throw Marshal.GetHRForLastWin32Error().ToCryptographicException(); return bCryptKeyHandle; } } finally { if (mustRelease) certContext.DangerousRelease(); } } #endif //NETNATIVE }
public static unsafe extern bool CryptQueryObject( CertQueryObjectType dwObjectType, void* pvObject, ExpectedContentTypeFlags dwExpectedContentTypeFlags, ExpectedFormatTypeFlags dwExpectedFormatTypeFlags, int dwFlags, // reserved - always pass 0 out CertEncodingType pdwMsgAndCertEncodingType, out ContentType pdwContentType, out FormatType pdwFormatType, out SafeCertStoreHandle phCertStore, out SafeCryptMsgHandle phMsg, out SafeCertContextHandle ppvContext );
private static void DisplayX509Certificate (SafeCertContextHandle safeCertContext, IntPtr hwndParent) { if (safeCertContext.IsInvalid) throw new CryptographicException(SecurityResources.GetResourceString("Cryptography_InvalidHandle"), "safeCertContext"); int dwErrorCode = CAPI.ERROR_SUCCESS; // Initialize view structure. CAPI.CRYPTUI_VIEWCERTIFICATE_STRUCTW ViewInfo = new CAPI.CRYPTUI_VIEWCERTIFICATE_STRUCTW(); ViewInfo.dwSize = (uint) Marshal.SizeOf(ViewInfo); ViewInfo.hwndParent = hwndParent; ViewInfo.dwFlags = 0; ViewInfo.szTitle = null; ViewInfo.pCertContext = safeCertContext.DangerousGetHandle(); ViewInfo.rgszPurposes = IntPtr.Zero; ViewInfo.cPurposes = 0; ViewInfo.pCryptProviderData = IntPtr.Zero; ViewInfo.fpCryptProviderDataTrustedUsage = false; ViewInfo.idxSigner = 0; ViewInfo.idxCert = 0; ViewInfo.fCounterSigner = false; ViewInfo.idxCounterSigner = 0; ViewInfo.cStores = 0; ViewInfo.rghStores = IntPtr.Zero; ViewInfo.cPropSheetPages = 0; ViewInfo.rgPropSheetPages = IntPtr.Zero; ViewInfo.nStartPage = 0; // View the certificate if (!CAPI.CryptUIDlgViewCertificateW(ViewInfo, IntPtr.Zero)) dwErrorCode = Marshal.GetLastWin32Error(); // CryptUIDlgViewCertificateW returns ERROR_CANCELLED if the user closes // the window through the x button or by pressing CANCEL, so ignore this error code if (dwErrorCode != CAPI.ERROR_SUCCESS && dwErrorCode != CAPI.ERROR_CANCELLED) throw new CryptographicException(Marshal.GetLastWin32Error()); }
// // 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). // 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 effective after a certain DateTime. // The callback data has to be a UTC FILETEME. // 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 application policy (also known as EKU) // An example of application policy can be: "Encrypting File System" // 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; }
public static extern bool CertAddCertificateContextToStore(SafeCertStoreHandle hCertStore, SafeCertContextHandle pCertContext, CertStoreAddDisposition dwAddDisposition, IntPtr ppStoreContext);
internal static unsafe int VerifyCertificate (SafeCertContextHandle pCertContext, OidCollection applicationPolicy, OidCollection certificatePolicy, X509RevocationMode revocationMode, X509RevocationFlag revocationFlag, DateTime verificationTime, TimeSpan timeout, X509Certificate2Collection extraStore, IntPtr pszPolicy, IntPtr pdwErrorStatus) { if (pCertContext == null || pCertContext.IsInvalid) throw new ArgumentException("pCertContext"); CAPI.CERT_CHAIN_POLICY_PARA PolicyPara = new CAPI.CERT_CHAIN_POLICY_PARA(Marshal.SizeOf(typeof(CAPI.CERT_CHAIN_POLICY_PARA))); CAPI.CERT_CHAIN_POLICY_STATUS PolicyStatus = new CAPI.CERT_CHAIN_POLICY_STATUS(Marshal.SizeOf(typeof(CAPI.CERT_CHAIN_POLICY_STATUS))); // Build the chain. SafeCertChainHandle pChainContext = SafeCertChainHandle.InvalidHandle; int hr = X509Utils.BuildChain(new IntPtr(CAPI.HCCE_CURRENT_USER), pCertContext, extraStore, applicationPolicy, certificatePolicy, revocationMode, revocationFlag, verificationTime, timeout, ref pChainContext); if (hr != CAPI.S_OK) return hr; // Verify the chain using the specified policy. if (CAPI.CAPISafe.CertVerifyCertificateChainPolicy(pszPolicy, pChainContext, ref PolicyPara, ref PolicyStatus)) { if (pdwErrorStatus != IntPtr.Zero) *(uint*) pdwErrorStatus = PolicyStatus.dwError; if (PolicyStatus.dwError != 0) return CAPI.S_FALSE; } else { // The API failed. return Marshal.GetHRForLastWin32Error(); } return CAPI.S_OK; }
public static unsafe bool CertGetCertificateChain(ChainEngine hChainEngine, SafeCertContextHandle pCertContext, FILETIME* pTime, SafeCertStoreHandle hStore, [In] ref CERT_CHAIN_PARA pChainPara, CertChainFlags dwFlags, IntPtr pvReserved, out SafeX509ChainHandle ppChainContext) { return CertGetCertificateChain((IntPtr)hChainEngine, pCertContext, pTime, hStore, ref pChainPara, dwFlags, pvReserved, out ppChainContext); }
public static extern bool CertGetCertificateContextProperty(SafeCertContextHandle pCertContext, CertContextPropId dwPropId, [Out] out CRYPTOAPI_BLOB pvData, [In, Out] ref int pcbData);
private CertificatePal(CertificatePal copyFrom) { // Use _certContext (instead of CertContext) to keep the original context handle from being // finalized until all cert copies are no longer referenced. _certContext = new SafeCertContextHandle(copyFrom._certContext); }
public static extern bool CertAddCertificateContextToStore(SafeCertStoreHandle hCertStore, SafeCertContextHandle pCertContext, CertStoreAddDisposition dwAddDisposition, IntPtr ppStoreContext);
internal static unsafe partial bool CertSetCertificateContextProperty(SafeCertContextHandle pCertContext, CertContextPropId dwPropId, CertSetPropertyFlags dwFlags, SafeNCryptKeyHandle keyHandle);
private static SafeNCryptKeyHandle TryAcquireCngPrivateKey( SafeCertContextHandle certificateContext, out CngKeyHandleOpenOptions handleOptions) { Debug.Assert(certificateContext != null, "certificateContext != null"); Debug.Assert(!certificateContext.IsClosed && !certificateContext.IsInvalid, "!certificateContext.IsClosed && !certificateContext.IsInvalid"); IntPtr privateKeyPtr; // If the certificate has a key handle instead of a key prov info, return the // ephemeral key { int cbData = IntPtr.Size; if (Interop.crypt32.CertGetCertificateContextProperty( certificateContext, CertContextPropId.CERT_NCRYPT_KEY_HANDLE_PROP_ID, out privateKeyPtr, ref cbData)) { handleOptions = CngKeyHandleOpenOptions.EphemeralKey; return(new SafeNCryptKeyHandle(privateKeyPtr, certificateContext)); } } bool freeKey = true; SafeNCryptKeyHandle privateKey = null; handleOptions = CngKeyHandleOpenOptions.None; try { int keySpec = 0; if (!Interop.crypt32.CryptAcquireCertificatePrivateKey( certificateContext, CryptAcquireFlags.CRYPT_ACQUIRE_ONLY_NCRYPT_KEY_FLAG, IntPtr.Zero, out privateKey, out keySpec, out freeKey)) { int dwErrorCode = Marshal.GetLastWin32Error(); // The documentation for CryptAcquireCertificatePrivateKey says that freeKey // should already be false if "key acquisition fails", and it can be presumed // that privateKey was set to 0. But, just in case: freeKey = false; privateKey?.SetHandleAsInvalid(); return(null); } // It is very unlikely that Windows will tell us !freeKey other than when reporting failure, // because we set neither CRYPT_ACQUIRE_CACHE_FLAG nor CRYPT_ACQUIRE_USE_PROV_INFO_FLAG, which are // currently the only two success situations documented. However, any !freeKey response means the // key's lifetime is tied to that of the certificate, so re-register the handle as a child handle // of the certificate. if (!freeKey && privateKey != null && !privateKey.IsInvalid) { var newKeyHandle = new SafeNCryptKeyHandle(privateKey.DangerousGetHandle(), certificateContext); privateKey.SetHandleAsInvalid(); privateKey = newKeyHandle; freeKey = true; } return(privateKey); } catch { // If we aren't supposed to free the key, and we're not returning it, // just tell the SafeHandle to not free itself. if (privateKey != null && !freeKey) { privateKey.SetHandleAsInvalid(); } throw; } }
internal static SafeProvOrNCryptKeyHandle GetCertificatePrivateKey( X509Certificate2 cert, bool silent, bool preferNCrypt, out CryptKeySpec keySpec, out Exception exception) { CryptAcquireCertificatePrivateKeyFlags flags = CryptAcquireCertificatePrivateKeyFlags.CRYPT_ACQUIRE_USE_PROV_INFO_FLAG | CryptAcquireCertificatePrivateKeyFlags.CRYPT_ACQUIRE_COMPARE_KEY_FLAG; if (preferNCrypt) { flags |= CryptAcquireCertificatePrivateKeyFlags.CRYPT_ACQUIRE_PREFER_NCRYPT_KEY_FLAG; } else { flags |= CryptAcquireCertificatePrivateKeyFlags.CRYPT_ACQUIRE_ALLOW_NCRYPT_KEY_FLAG; } if (silent) { flags |= CryptAcquireCertificatePrivateKeyFlags.CRYPT_ACQUIRE_SILENT_FLAG; } bool isNCrypt; bool mustFree; using (SafeCertContextHandle hCertContext = cert.CreateCertContextHandle()) { IntPtr hKey; int cbSize = IntPtr.Size; if (Interop.Crypt32.CertGetCertificateContextProperty( hCertContext, CertContextPropId.CERT_NCRYPT_KEY_HANDLE_PROP_ID, out hKey, ref cbSize)) { exception = null; keySpec = CryptKeySpec.CERT_NCRYPT_KEY_SPEC; return(new SafeProvOrNCryptKeyHandleUwp(hKey, hCertContext)); } if (!Interop.Crypt32.CryptAcquireCertificatePrivateKey( hCertContext, flags, IntPtr.Zero, out hKey, out keySpec, out mustFree)) { exception = Marshal.GetHRForLastWin32Error().ToCryptographicException(); return(null); } // We need to know whether we got back a CRYPTPROV or NCrypt handle. // Unfortunately, NCryptIsKeyHandle() is a prohibited api on UWP. // Fortunately, CryptAcquireCertificatePrivateKey() is documented to tell us which // one we got through the keySpec value. switch (keySpec) { case CryptKeySpec.AT_KEYEXCHANGE: case CryptKeySpec.AT_SIGNATURE: isNCrypt = false; break; case CryptKeySpec.CERT_NCRYPT_KEY_SPEC: isNCrypt = true; break; default: // As of this writing, we've exhausted all the known values of keySpec. // We have no idea what kind of key handle we got so play it safe and fail fast. throw new NotSupportedException(SR.Format(SR.Cryptography_Cms_UnknownKeySpec, keySpec)); } SafeProvOrNCryptKeyHandleUwp hProvOrNCryptKey = new SafeProvOrNCryptKeyHandleUwp( hKey, ownsHandle: mustFree, isNcrypt: isNCrypt); exception = null; return(hProvOrNCryptKey); } }
static bool IsSelfSigned(SafeCertContextHandle certificate) { var certificateInfo = (CERT_INFO)Marshal.PtrToStructure(certificate.CertificateContext.pCertInfo, typeof(CERT_INFO)); return(CertCompareCertificateName(CertificateEncodingType.Pkcs7OrX509AsnEncoding, ref certificateInfo.Subject, ref certificateInfo.Issuer)); }
static void AddPrivateKeyAccessRules(ICollection <PrivateKeyAccessRule> accessRules, SafeCertContextHandle certificate) { try { var keyProvInfo = certificate.GetCertificateProperty <KeyProviderInfo>( CertificateProperty.KeyProviderInfo); // If it is a CNG key if (keyProvInfo.dwProvType == 0) { SetCngPrivateKeySecurity(certificate, accessRules); } else { SetCspPrivateKeySecurity(certificate, accessRules); } } catch (Exception ex) { throw new Exception("Could not set security on private-key", ex); } }
// // Callback method to find certificates by subject key identifier. // This can be useful when using XML Digital Signature and X509Data. // 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; }
/// <summary> /// A less error-prone wrapper for CertEnumCertificatesInStore(). /// /// To begin the enumeration, set pCertContext to null. Each iteration replaces pCertContext with /// the next certificate in the iteration. The final call sets pCertContext to an invalid SafeCertStoreHandle /// and returns "false" to indicate the the end of the store has been reached. /// </summary> public static bool CertEnumCertificatesInStore(SafeCertStoreHandle hCertStore, ref SafeCertContextHandle pCertContext) { unsafe { CERT_CONTEXT *pPrevCertContext = pCertContext == null ? null : pCertContext.Disconnect(); pCertContext = CertEnumCertificatesInStore(hCertStore, pPrevCertContext); return(!pCertContext.IsInvalid); } }
public static extern bool CertSerializeCertificateStoreElement(SafeCertContextHandle pCertContext, int dwFlags, [Out] byte[] pbElement, [In, Out] ref int pcbElement);
public static extern bool CertSerializeCertificateStoreElement(SafeCertContextHandle pCertContext, int dwFlags, [Out] byte[] pbElement, [In, Out] ref int pcbElement);
/// <summary> /// A less error-prone wrapper for CertEnumCertificatesInStore(). /// /// To begin the enumeration, set pCertContext to null. Each iteration replaces pCertContext with /// the next certificate in the iteration. The final call sets pCertContext to an invalid SafeCertStoreHandle /// and returns "false" to indicate the the end of the store has been reached. /// </summary> public static unsafe bool CertFindCertificateInStore(SafeCertStoreHandle hCertStore, CertFindType dwFindType, void* pvFindPara, ref SafeCertContextHandle pCertContext) { CERT_CONTEXT* pPrevCertContext = pCertContext == null ? null : pCertContext.Disconnect(); pCertContext = CertFindCertificateInStore(hCertStore, CertEncodingType.All, CertFindFlags.None, dwFindType, pvFindPara, pPrevCertContext); return !pCertContext.IsInvalid; }
public static unsafe bool CertGetCertificateChain(ChainEngine hChainEngine, SafeCertContextHandle pCertContext, FILETIME *pTime, SafeCertStoreHandle hStore, [In] ref CERT_CHAIN_PARA pChainPara, CertChainFlags dwFlags, IntPtr pvReserved, out SafeX509ChainHandle ppChainContext) { return(CertGetCertificateChain((IntPtr)hChainEngine, pCertContext, pTime, hStore, ref pChainPara, dwFlags, pvReserved, out ppChainContext)); }
public static extern unsafe bool CertSetCertificateContextProperty(SafeCertContextHandle pCertContext, CertContextPropId dwPropId, CertSetPropertyFlags dwFlags, [In] CRYPT_KEY_PROV_INFO* pvData);
private static extern unsafe bool CertGetCertificateChain(IntPtr hChainEngine, SafeCertContextHandle pCertContext, FILETIME *pTime, SafeCertStoreHandle hStore, [In] ref CERT_CHAIN_PARA pChainPara, CertChainFlags dwFlags, IntPtr pvReserved, out SafeX509ChainHandle ppChainContext);
internal static bool GetPrivateKeyInfo (SafeCertContextHandle safeCertContext, ref CspParameters parameters) { SafeLocalAllocHandle ptr = SafeLocalAllocHandle.InvalidHandle; uint cbData = 0; if (!CAPI.CAPISafe.CertGetCertificateContextProperty(safeCertContext, CAPI.CERT_KEY_PROV_INFO_PROP_ID, ptr, ref cbData)) { int dwErrorCode = Marshal.GetLastWin32Error(); if (dwErrorCode == CAPI.CRYPT_E_NOT_FOUND) return false; else throw new CryptographicException(Marshal.GetLastWin32Error()); } ptr = CAPI.LocalAlloc(CAPI.LMEM_FIXED, new IntPtr(cbData)); if (!CAPI.CAPISafe.CertGetCertificateContextProperty(safeCertContext, CAPI.CERT_KEY_PROV_INFO_PROP_ID, ptr, ref cbData)) { int dwErrorCode = Marshal.GetLastWin32Error(); if (dwErrorCode == CAPI.CRYPT_E_NOT_FOUND) return false; else throw new CryptographicException(Marshal.GetLastWin32Error()); } CAPI.CRYPT_KEY_PROV_INFO pKeyProvInfo = (CAPI.CRYPT_KEY_PROV_INFO) Marshal.PtrToStructure(ptr.DangerousGetHandle(), typeof(CAPI.CRYPT_KEY_PROV_INFO)); parameters.ProviderName = pKeyProvInfo.pwszProvName; parameters.KeyContainerName = pKeyProvInfo.pwszContainerName; parameters.ProviderType = (int) pKeyProvInfo.dwProvType; parameters.KeyNumber = (int) pKeyProvInfo.dwKeySpec; parameters.Flags = (CspProviderFlags) ((pKeyProvInfo.dwFlags & CAPI.CRYPT_MACHINE_KEYSET) == CAPI.CRYPT_MACHINE_KEYSET ? CspProviderFlags.UseMachineKeyStore : 0); ptr.Dispose(); return true; }
/// <summary> /// A less error-prone wrapper for CertEnumCertificatesInStore(). /// /// To begin the enumeration, set pCertContext to null. Each iteration replaces pCertContext with /// the next certificate in the iteration. The final call sets pCertContext to an invalid SafeCertStoreHandle /// and returns "false" to indicate the the end of the store has been reached. /// </summary> public static unsafe bool CertFindCertificateInStore(SafeCertStoreHandle hCertStore, CertFindType dwFindType, void *pvFindPara, ref SafeCertContextHandle pCertContext) { CERT_CONTEXT *pPrevCertContext = pCertContext == null ? null : pCertContext.Disconnect(); pCertContext = CertFindCertificateInStore(hCertStore, CertEncodingType.All, CertFindFlags.None, dwFindType, pvFindPara, pPrevCertContext); return(!pCertContext.IsInvalid); }
static void AddCertificateToStore(CertificateSystemStoreLocation storeLocation, string storeName, SafeCertContextHandle certificate) { try { using (var store = CertOpenStore(CertStoreProviders.CERT_STORE_PROV_SYSTEM, IntPtr.Zero, IntPtr.Zero, storeLocation, storeName)) { var subjectName = CertificatePal.GetSubjectName(certificate); var storeContext = IntPtr.Zero; if (!CertAddCertificateContextToStore(store, certificate, AddCertificateDisposition.CERT_STORE_ADD_NEW, ref storeContext)) { var error = Marshal.GetLastWin32Error(); if (error == (int)CapiErrorCode.CRYPT_E_EXISTS) { Log.Info($"Certificate '{subjectName}' already exists in store '{storeName}'."); return; } throw new CryptographicException(error); } Log.Info($"Imported certificate '{subjectName}' into store '{storeName}'"); } } catch (Exception ex) { throw new Exception("Could not add certificate to store", ex); } }
public static unsafe extern bool CertGetValidUsages(int cCerts, [In] ref SafeCertContextHandle rghCerts, out int cNumOIDs, [Out] void *rghOIDs, [In, Out] ref int pcbOIDs);
// // 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". // 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; }
public static extern bool CryptAcquireCertificatePrivateKey(SafeCertContextHandle pCert, CryptAcquireFlags dwFlags, IntPtr pvParameters, out SafeNCryptKeyHandle phCryptProvOrNCryptKey, out int pdwKeySpec, out bool pfCallerFreeProvOrNCryptKey);
// // 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. // 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; }
public static extern bool CertGetCertificateContextProperty(SafeCertContextHandle pCertContext, CertContextPropId dwPropId, [Out] byte[] pvData, [In, Out] ref int pcbData);
// // 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. // 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; }
public static extern bool CertGetCertificateContextProperty(SafeCertContextHandle pCertContext, CertContextPropId dwPropId, [Out] out CRYPTOAPI_BLOB pvData, [In, Out] ref int pcbData);
/// <summary> /// A less error-prone wrapper for CertEnumCertificatesInStore(). /// /// To begin the enumeration, set pCertContext to null. Each iteration replaces pCertContext with /// the next certificate in the iteration. The final call sets pCertContext to an invalid SafeCertStoreHandle /// and returns "false" to indicate the the end of the store has been reached. /// </summary> public static bool CertEnumCertificatesInStore(SafeCertStoreHandle hCertStore, ref SafeCertContextHandle pCertContext) { unsafe { CERT_CONTEXT* pPrevCertContext = pCertContext == null ? null : pCertContext.Disconnect(); pCertContext = CertEnumCertificatesInStore(hCertStore, pPrevCertContext); return !pCertContext.IsInvalid; } }
public static extern bool CertGetCertificateContextPropertyString(SafeCertContextHandle pCertContext, CertContextPropId dwPropId, [Out] StringBuilder pvData, [In, Out] ref int pcbData);
public static extern unsafe bool CertSetCertificateContextProperty(SafeCertContextHandle pCertContext, CertContextPropId dwPropId, CertSetPropertyFlags dwFlags, [In] SafeNCryptKeyHandle keyHandle);
public static extern unsafe bool CertSetCertificateContextProperty(SafeCertContextHandle pCertContext, CertContextPropId dwPropId, CertSetPropertyFlags dwFlags, [In] CRYPT_KEY_PROV_INFO *pvData);
private static extern unsafe bool CertGetCertificateChain(IntPtr hChainEngine, SafeCertContextHandle pCertContext, FILETIME* pTime, SafeCertStoreHandle hStore, [In] ref CERT_CHAIN_PARA pChainPara, CertChainFlags dwFlags, IntPtr pvReserved, out SafeX509ChainHandle ppChainContext);
public static extern int CertGetNameString(SafeCertContextHandle pCertContext, CertNameType dwType, CertNameFlags dwFlags, [In] ref CertNameStringType pvTypePara, [Out] StringBuilder pszNameString, int cchNameString);
public static extern bool CertGetCertificateContextProperty(SafeCertContextHandle pCertContext, CertContextPropId dwPropId, [Out] byte[] pvData, [In, Out] ref int pcbData);
public byte[] Export(X509ContentType contentType, string password) { switch (contentType) { case X509ContentType.Cert: { SafeCertContextHandle pCertContext = null; if (!Interop.crypt32.CertEnumCertificatesInStore(_certStore, ref pCertContext)) { return(null); } try { unsafe { byte[] rawData = new byte[pCertContext.CertContext->cbCertEncoded]; Marshal.Copy((IntPtr)(pCertContext.CertContext->pbCertEncoded), rawData, 0, rawData.Length); GC.KeepAlive(pCertContext); return(rawData); } } finally { pCertContext.Dispose(); } } case X509ContentType.SerializedCert: { SafeCertContextHandle pCertContext = null; if (!Interop.crypt32.CertEnumCertificatesInStore(_certStore, ref pCertContext)) { return(null); } try { int cbEncoded = 0; if (!Interop.crypt32.CertSerializeCertificateStoreElement(pCertContext, 0, null, ref cbEncoded)) { throw Marshal.GetHRForLastWin32Error().ToCryptographicException(); } ; byte[] pbEncoded = new byte[cbEncoded]; if (!Interop.crypt32.CertSerializeCertificateStoreElement(pCertContext, 0, pbEncoded, ref cbEncoded)) { throw Marshal.GetHRForLastWin32Error().ToCryptographicException(); } ; return(pbEncoded); } finally { pCertContext.Dispose(); } } case X509ContentType.Pkcs12: { unsafe { CRYPTOAPI_BLOB dataBlob = new CRYPTOAPI_BLOB(0, (byte *)null); if (!Interop.crypt32.PFXExportCertStore(_certStore, ref dataBlob, password, PFXExportFlags.EXPORT_PRIVATE_KEYS | PFXExportFlags.REPORT_NOT_ABLE_TO_EXPORT_PRIVATE_KEY)) { throw Marshal.GetHRForLastWin32Error().ToCryptographicException(); } ; byte[] pbEncoded = new byte[dataBlob.cbData]; fixed(byte *ppbEncoded = pbEncoded) { dataBlob.pbData = ppbEncoded; if (!Interop.crypt32.PFXExportCertStore(_certStore, ref dataBlob, password, PFXExportFlags.EXPORT_PRIVATE_KEYS | PFXExportFlags.REPORT_NOT_ABLE_TO_EXPORT_PRIVATE_KEY)) { throw Marshal.GetHRForLastWin32Error().ToCryptographicException(); } ; } return(pbEncoded); } } case X509ContentType.SerializedStore: return(SaveToMemoryStore(CertStoreSaveAs.CERT_STORE_SAVE_AS_STORE)); case X509ContentType.Pkcs7: return(SaveToMemoryStore(CertStoreSaveAs.CERT_STORE_SAVE_AS_PKCS7)); default: throw new CryptographicException(SR.Cryptography_X509_InvalidContentType); } }
public static extern bool CertGetCertificateContextPropertyString(SafeCertContextHandle pCertContext, CertContextPropId dwPropId, [Out] StringBuilder pvData, [In, Out] ref int pcbData);
internal static unsafe partial bool CertGetValidUsages(int cCerts, ref SafeCertContextHandle rghCerts, out int cNumOIDs, void *rghOIDs, ref int pcbOIDs);
public static extern int CertGetNameString(SafeCertContextHandle pCertContext, CertNameType dwType, CertNameFlags dwFlags, [In] ref CertNameStringType pvTypePara, [Out] StringBuilder pszNameString, int cchNameString);
public void Dispose() { SafeCertContextHandle certContext = _certContext; _certContext = null; if (certContext != null && !certContext.IsInvalid) { certContext.Dispose(); } }
internal unsafe X509ExtensionCollection(SafeCertContextHandle safeCertContextHandle) { using (SafeCertContextHandle certContext = CAPI.CertDuplicateCertificateContext(safeCertContextHandle)) { CAPI.CERT_CONTEXT pCertContext = *((CAPI.CERT_CONTEXT*) certContext.DangerousGetHandle()); CAPI.CERT_INFO pCertInfo = (CAPI.CERT_INFO) Marshal.PtrToStructure(pCertContext.pCertInfo, typeof(CAPI.CERT_INFO)); uint cExtensions = pCertInfo.cExtension; IntPtr rgExtensions = pCertInfo.rgExtension; for (uint index = 0; index < cExtensions; index++) { X509Extension extension = new X509Extension(new IntPtr((long)rgExtensions + (index * Marshal.SizeOf(typeof(CAPI.CERT_EXTENSION))))); X509Extension customExtension = CryptoConfig.CreateFromName(extension.Oid.Value) as X509Extension; if (customExtension != null) { customExtension.CopyFrom(extension); extension = customExtension; } Add(extension); } } }
private CertificatePal(SafeCertContextHandle certContext, bool deleteKeyContainer) { if (deleteKeyContainer) { // We need to delete any associated key container upon disposition. Thus, replace the safehandle we got with a safehandle whose // Release() method performs the key container deletion. SafeCertContextHandle oldCertContext = certContext; certContext = Interop.crypt32.CertDuplicateCertificateContextWithKeyContainerDeletion(oldCertContext.DangerousGetHandle()); GC.KeepAlive(oldCertContext); } _certContext = certContext; }
internal static unsafe int BuildChain (IntPtr hChainEngine, SafeCertContextHandle pCertContext, X509Certificate2Collection extraStore, OidCollection applicationPolicy, OidCollection certificatePolicy, X509RevocationMode revocationMode, X509RevocationFlag revocationFlag, DateTime verificationTime, TimeSpan timeout, ref SafeCertChainHandle ppChainContext) { if (pCertContext == null || pCertContext.IsInvalid) throw new ArgumentException(SecurityResources.GetResourceString("Cryptography_InvalidContextHandle"), "pCertContext"); SafeCertStoreHandle hCertStore = SafeCertStoreHandle.InvalidHandle; if (extraStore != null && extraStore.Count > 0) hCertStore = X509Utils.ExportToMemoryStore(extraStore); CAPI.CERT_CHAIN_PARA ChainPara = new CAPI.CERT_CHAIN_PARA(); // Initialize the structure size. ChainPara.cbSize = (uint) Marshal.SizeOf(ChainPara); // Application policy SafeLocalAllocHandle applicationPolicyHandle = SafeLocalAllocHandle.InvalidHandle; if (applicationPolicy != null && applicationPolicy.Count > 0) { ChainPara.RequestedUsage.dwType = CAPI.USAGE_MATCH_TYPE_AND; ChainPara.RequestedUsage.Usage.cUsageIdentifier = (uint) applicationPolicy.Count; applicationPolicyHandle = X509Utils.CopyOidsToUnmanagedMemory(applicationPolicy); ChainPara.RequestedUsage.Usage.rgpszUsageIdentifier = applicationPolicyHandle.DangerousGetHandle(); } // Certificate policy SafeLocalAllocHandle certificatePolicyHandle = SafeLocalAllocHandle.InvalidHandle; if (certificatePolicy != null && certificatePolicy.Count > 0) { ChainPara.RequestedIssuancePolicy.dwType = CAPI.USAGE_MATCH_TYPE_AND; ChainPara.RequestedIssuancePolicy.Usage.cUsageIdentifier = (uint) certificatePolicy.Count; certificatePolicyHandle = X509Utils.CopyOidsToUnmanagedMemory(certificatePolicy); ChainPara.RequestedIssuancePolicy.Usage.rgpszUsageIdentifier = certificatePolicyHandle.DangerousGetHandle(); } ChainPara.dwUrlRetrievalTimeout = (uint) timeout.Milliseconds; _FILETIME ft = new _FILETIME(); *((long*) &ft) = verificationTime.ToFileTime(); uint flags = X509Utils.MapRevocationFlags(revocationMode, revocationFlag); // Build the chain. if (!CAPI.CAPISafe.CertGetCertificateChain(hChainEngine, pCertContext, ref ft, hCertStore, ref ChainPara, flags, IntPtr.Zero, ref ppChainContext)) return Marshal.GetHRForLastWin32Error(); applicationPolicyHandle.Dispose(); certificatePolicyHandle.Dispose(); return CAPI.S_OK; }
public static extern unsafe bool CertGetCertificateContextPropertyString(SafeCertContextHandle pCertContext, CertContextPropId dwPropId, byte *pvData, ref int pcbData);
internal static partial bool CertAddCertificateLinkToStore(SafeCertStoreHandle hCertStore, SafeCertContextHandle pCertContext, CertStoreAddDisposition dwAddDisposition, IntPtr ppStoreContext);
/// <summary> /// Unlike X509Store.Remove() this function also cleans up private-keys /// </summary> public static void RemoveCertificateFromStore(string thumbprint, StoreLocation storeLocation, string storeName) { using (AcquireSemaphore()) { var store = new X509Store(storeName, storeLocation); store.Open(OpenFlags.ReadWrite); var found = store.Certificates.Find(X509FindType.FindByThumbprint, thumbprint, false); if (found.Count == 0) { return; } var certificate = found[0]; var certificateHandle = new SafeCertContextHandle(found[0].Handle, false); // If the certificate has a private-key, remove it if (certificateHandle.HasPrivateKey()) { var keyProvInfo = certificateHandle.GetCertificateProperty <KeyProviderInfo>(CertificateProperty.KeyProviderInfo); // If it is a CNG key if (keyProvInfo.dwProvType == 0) { try { var key = CertificatePal.GetCngPrivateKey(certificateHandle); CertificatePal.DeleteCngKey(key); } catch (Exception ex) { throw new Exception("Exception while deleting CNG private key", ex); } } else // CAPI key { try { IntPtr providerHandle; var acquireContextFlags = CryptAcquireContextFlags.Delete | CryptAcquireContextFlags.Silent; if (storeLocation == StoreLocation.LocalMachine) { acquireContextFlags = acquireContextFlags | CryptAcquireContextFlags.MachineKeySet; } var success = Native.CryptAcquireContext(out providerHandle, keyProvInfo.pwszContainerName, keyProvInfo.pwszProvName, keyProvInfo.dwProvType, acquireContextFlags); if (!success) { throw new CryptographicException(Marshal.GetLastWin32Error()); } } catch (Exception ex) { // Swallow keyset does not exist if (!(ex is CryptographicException && ex.Message.Contains("Keyset does not exist"))) { throw new Exception("Exception while deleting CAPI private key", ex); } } } } store.Remove(certificate); store.Close(); } }
private CertificatePal(CertificatePal copyFrom) { // Use _certContext (instead of CertContext) to keep the original context handle from being // finalized until all cert copies are no longer referenced. _certContext = new SafeCertContextHandle(copyFrom._certContext); }
// // Callback method to find certificates by serial number. // This can be useful when using XML Digital Signature and X509Data. // 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; }
public static SafeCertContextHandle CreateCertContextHandle(this X509Certificate2 cert) { IntPtr pCertContext = cert.Handle; pCertContext = Interop.Crypt32.CertDuplicateCertificateContext(pCertContext); SafeCertContextHandle hCertContext = new SafeCertContextHandle(pCertContext); GC.KeepAlive(cert); return hCertContext; }
private static extern unsafe int CertGetNameString(SafeCertContextHandle pCertContext, CertNameType dwType, CertNameFlags dwFlags, in CertNameStringType pvTypePara, char *pszNameString, int cchNameString);