private static Exception TryGetKeySpecForCertificate(X509Certificate2 cert, out CryptKeySpec keySpec) { using (SafeCertContextHandle hCertContext = cert.CreateCertContextHandle()) { int cbSize = 0; if (!Interop.Crypt32.CertGetCertificateContextProperty(hCertContext, CertContextPropId.CERT_KEY_PROV_INFO_PROP_ID, null, ref cbSize)) { ErrorCode errorCode = (ErrorCode)(Marshal.GetLastWin32Error()); keySpec = default(CryptKeySpec); return(errorCode.ToCryptographicException()); } byte[] pData = new byte[cbSize]; unsafe { fixed(byte *pvData = pData) { if (!Interop.Crypt32.CertGetCertificateContextProperty(hCertContext, CertContextPropId.CERT_KEY_PROV_INFO_PROP_ID, pData, ref cbSize)) { ErrorCode errorCode = (ErrorCode)(Marshal.GetLastWin32Error()); keySpec = default(CryptKeySpec); return(errorCode.ToCryptographicException()); } CRYPT_KEY_PROV_INFO *pCryptKeyProvInfo = (CRYPT_KEY_PROV_INFO *)pvData; keySpec = pCryptKeyProvInfo->dwKeySpec; return(null); } } } }
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; string providerName = pwszToString((IntPtr)(pProvInfo->pwszProvName)); string keyContainerName = pwszToString((IntPtr)(pProvInfo->pwszContainerName)); 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. 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; bool success = Interop.cryptoapi.CryptAcquireContext(out hProv, keyContainerName, providerName, 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); } } } }
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; // For UWP the key was opened in a CNG-only context, so it can/should be deleted via CngKey.Delete. // In all other contexts, the key was loaded into CAPI, so deleting it via CryptAcquireContext is // the correct action. #if NETNATIVE 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; bool success = Interop.advapi32.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); #endif } } }
// // Returns the private key referenced by a store certificate. Note that despite the return type being declared "CspParameters", // the key can actually be a CNG key. To distinguish, examine the ProviderType property. If it is 0, this key is a CNG key with // the various properties of CspParameters being "repurposed" into storing CNG info. // // This is a behavior this method inherits directly from the Crypt32 CRYPT_KEY_PROV_INFO semantics. // // It would have been nice not to let this ugliness escape out of this helper method. But X509Certificate2.ToString() calls this // method too so we cannot just change it without breaking its output. // private CspParameters GetPrivateKeyCsp() { int cbData = 0; if (!Interop.crypt32.CertGetCertificateContextProperty(_certContext, CertContextPropId.CERT_KEY_PROV_INFO_PROP_ID, null, ref cbData)) { int dwErrorCode = Marshal.GetLastWin32Error(); if (dwErrorCode == ErrorCode.CRYPT_E_NOT_FOUND) { return(null); } throw dwErrorCode.ToCryptographicException(); } unsafe { byte[] privateKey = new byte[cbData]; fixed(byte *pPrivateKey = privateKey) { if (!Interop.crypt32.CertGetCertificateContextProperty(_certContext, CertContextPropId.CERT_KEY_PROV_INFO_PROP_ID, privateKey, ref cbData)) { throw Marshal.GetLastWin32Error().ToCryptographicException(); } CRYPT_KEY_PROV_INFO *pKeyProvInfo = (CRYPT_KEY_PROV_INFO *)pPrivateKey; CspParameters cspParameters = new CspParameters(); cspParameters.ProviderName = Marshal.PtrToStringUni((IntPtr)(pKeyProvInfo->pwszProvName)); cspParameters.KeyContainerName = Marshal.PtrToStringUni((IntPtr)(pKeyProvInfo->pwszContainerName)); cspParameters.ProviderType = pKeyProvInfo->dwProvType; cspParameters.KeyNumber = pKeyProvInfo->dwKeySpec; cspParameters.Flags = (CspProviderFlags)((pKeyProvInfo->dwFlags & CryptAcquireContextFlags.CRYPT_MACHINE_KEYSET) == CryptAcquireContextFlags.CRYPT_MACHINE_KEYSET ? CspProviderFlags.UseMachineKeyStore : 0); return(cspParameters); } } }
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; CryptAcquireContextFlags flags = (pProvInfo->dwFlags & CryptAcquireContextFlags.CRYPT_MACHINE_KEYSET) | CryptAcquireContextFlags.CRYPT_DELETEKEYSET; IntPtr hProv; bool success = Interop.advapi32.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); } } }
internal static unsafe partial bool CertSetCertificateContextProperty(SafeCertContextHandle pCertContext, CertContextPropId dwPropId, CertSetPropertyFlags dwFlags, CRYPT_KEY_PROV_INFO *pvData);
public static extern unsafe bool CertSetCertificateContextProperty(SafeCertContextHandle pCertContext, CertContextPropId dwPropId, CertSetPropertyFlags dwFlags, [In] CRYPT_KEY_PROV_INFO *pvData);