public static void DeleteKeyContainer(SafeCertContextHandle pCertContext) { if (pCertContext.IsInvalid) { return; } int cb = 0; bool containsPrivateKey = Interop.crypt32.CertGetCertificateContextProperty(pCertContext, CertContextPropId.CERT_KEY_PROV_INFO_PROP_ID, null, ref cb); if (!containsPrivateKey) { return; } byte[] provInfoAsBytes = new byte[cb]; if (!Interop.crypt32.CertGetCertificateContextProperty(pCertContext, CertContextPropId.CERT_KEY_PROV_INFO_PROP_ID, provInfoAsBytes, ref cb)) { return; } unsafe { fixed(byte *pProvInfoAsBytes = provInfoAsBytes) { CRYPT_KEY_PROV_INFO *pProvInfo = (CRYPT_KEY_PROV_INFO *)pProvInfoAsBytes; if (pProvInfo->dwProvType == 0) { // dwProvType being 0 indicates that the key is stored in CNG. // dwProvType being non-zero indicates that the key is stored in CAPI. string providerName = Marshal.PtrToStringUni((IntPtr)(pProvInfo->pwszProvName)) !; string keyContainerName = Marshal.PtrToStringUni((IntPtr)(pProvInfo->pwszContainerName)) !; try { using (CngKey cngKey = CngKey.Open(keyContainerName, new CngProvider(providerName))) { cngKey.Delete(); } } catch (CryptographicException) { // While leaving the file on disk is undesirable, an inability to perform this cleanup // should not manifest itself to a user. } } else { CryptAcquireContextFlags flags = (pProvInfo->dwFlags & CryptAcquireContextFlags.CRYPT_MACHINE_KEYSET) | CryptAcquireContextFlags.CRYPT_DELETEKEYSET; IntPtr hProv; _ = Interop.cryptoapi.CryptAcquireContext(out hProv, pProvInfo->pwszContainerName, pProvInfo->pwszProvName, pProvInfo->dwProvType, flags); // Called CryptAcquireContext solely for the side effect of deleting the key containers. When called with these flags, no actual // hProv is returned (so there's nothing to clean up.) Debug.Assert(hProv == IntPtr.Zero); } } } }