// this method maps a X509KeyStorageFlags enum to a combination of crypto API flags private static PfxCertStoreFlags MapKeyStorageFlags(X509KeyStorageFlags keyStorageFlags) { PfxCertStoreFlags dwFlags = 0; if ((keyStorageFlags & X509KeyStorageFlags.UserKeySet) == X509KeyStorageFlags.UserKeySet) { dwFlags |= PfxCertStoreFlags.CRYPT_USER_KEYSET; } else if ((keyStorageFlags & X509KeyStorageFlags.MachineKeySet) == X509KeyStorageFlags.MachineKeySet) { dwFlags |= PfxCertStoreFlags.CRYPT_MACHINE_KEYSET; } if ((keyStorageFlags & X509KeyStorageFlags.Exportable) == X509KeyStorageFlags.Exportable) { dwFlags |= PfxCertStoreFlags.CRYPT_EXPORTABLE; } if ((keyStorageFlags & X509KeyStorageFlags.UserProtected) == X509KeyStorageFlags.UserProtected) { dwFlags |= PfxCertStoreFlags.CRYPT_USER_PROTECTED; } if ((keyStorageFlags & X509KeyStorageFlags.EphemeralKeySet) == X509KeyStorageFlags.EphemeralKeySet) { dwFlags |= PfxCertStoreFlags.PKCS12_NO_PERSIST_KEY | PfxCertStoreFlags.PKCS12_ALWAYS_CNG_KSP; } return(dwFlags); }
private static PfxCertStoreFlags MapKeyStorageFlags(X509KeyStorageFlags keyStorageFlags) { if ((keyStorageFlags & X509Certificate.KeyStorageFlagsAll) != keyStorageFlags) { throw new ArgumentException(SR.Argument_InvalidFlag, nameof(keyStorageFlags)); } PfxCertStoreFlags pfxCertStoreFlags = 0; if ((keyStorageFlags & X509KeyStorageFlags.UserKeySet) == X509KeyStorageFlags.UserKeySet) { pfxCertStoreFlags |= PfxCertStoreFlags.CRYPT_USER_KEYSET; } else if ((keyStorageFlags & X509KeyStorageFlags.MachineKeySet) == X509KeyStorageFlags.MachineKeySet) { pfxCertStoreFlags |= PfxCertStoreFlags.CRYPT_MACHINE_KEYSET; } if ((keyStorageFlags & X509KeyStorageFlags.Exportable) == X509KeyStorageFlags.Exportable) { pfxCertStoreFlags |= PfxCertStoreFlags.CRYPT_EXPORTABLE; } if ((keyStorageFlags & X509KeyStorageFlags.UserProtected) == X509KeyStorageFlags.UserProtected) { pfxCertStoreFlags |= PfxCertStoreFlags.CRYPT_USER_PROTECTED; } // If a user is asking for an Ephemeral key they should be willing to test their code to find out // that it will no longer import into CAPI. This solves problems of legacy CSPs being // difficult to do SHA-2 RSA signatures with, simplifies the story for UWP, and reduces the // complexity of pointer interpretation. if ((keyStorageFlags & X509KeyStorageFlags.EphemeralKeySet) == X509KeyStorageFlags.EphemeralKeySet) pfxCertStoreFlags |= PfxCertStoreFlags.PKCS12_NO_PERSIST_KEY | PfxCertStoreFlags.PKCS12_ALWAYS_CNG_KSP; }
private static PfxCertStoreFlags MapKeyStorageFlags(X509KeyStorageFlags keyStorageFlags) { if ((keyStorageFlags & (X509KeyStorageFlags) ~0x1F) != 0) { throw new ArgumentException(SR.Argument_InvalidFlag, "keyStorageFlags"); } PfxCertStoreFlags pfxCertStoreFlags = 0; if ((keyStorageFlags & X509KeyStorageFlags.UserKeySet) == X509KeyStorageFlags.UserKeySet) { pfxCertStoreFlags |= PfxCertStoreFlags.CRYPT_USER_KEYSET; } else if ((keyStorageFlags & X509KeyStorageFlags.MachineKeySet) == X509KeyStorageFlags.MachineKeySet) { pfxCertStoreFlags |= PfxCertStoreFlags.CRYPT_MACHINE_KEYSET; } if ((keyStorageFlags & X509KeyStorageFlags.Exportable) == X509KeyStorageFlags.Exportable) { pfxCertStoreFlags |= PfxCertStoreFlags.CRYPT_EXPORTABLE; } if ((keyStorageFlags & X509KeyStorageFlags.UserProtected) == X509KeyStorageFlags.UserProtected) { pfxCertStoreFlags |= PfxCertStoreFlags.CRYPT_USER_PROTECTED; } return(pfxCertStoreFlags); }
private static PfxCertStoreFlags MapKeyStorageFlags(X509KeyStorageFlags keyStorageFlags) { if ((keyStorageFlags & X509Certificate.KeyStorageFlagsAll) != keyStorageFlags) { throw new ArgumentException(SR.Argument_InvalidFlag, nameof(keyStorageFlags)); } PfxCertStoreFlags pfxCertStoreFlags = 0; if ((keyStorageFlags & X509KeyStorageFlags.UserKeySet) == X509KeyStorageFlags.UserKeySet) { pfxCertStoreFlags |= PfxCertStoreFlags.CRYPT_USER_KEYSET; } else if ((keyStorageFlags & X509KeyStorageFlags.MachineKeySet) == X509KeyStorageFlags.MachineKeySet) { pfxCertStoreFlags |= PfxCertStoreFlags.CRYPT_MACHINE_KEYSET; } if ((keyStorageFlags & X509KeyStorageFlags.Exportable) == X509KeyStorageFlags.Exportable) { pfxCertStoreFlags |= PfxCertStoreFlags.CRYPT_EXPORTABLE; } if ((keyStorageFlags & X509KeyStorageFlags.UserProtected) == X509KeyStorageFlags.UserProtected) { pfxCertStoreFlags |= PfxCertStoreFlags.CRYPT_USER_PROTECTED; } // If a user is asking for an Ephemeral key they should be willing to test their code to find out // that it will no longer import into CAPI. This solves problems of legacy CSPs being // difficult to do SHA-2 RSA signatures with, simplifies the story for UWP, and reduces the // complexity of pointer interpretation. if ((keyStorageFlags & X509KeyStorageFlags.EphemeralKeySet) == X509KeyStorageFlags.EphemeralKeySet) { pfxCertStoreFlags |= PfxCertStoreFlags.PKCS12_NO_PERSIST_KEY | PfxCertStoreFlags.PKCS12_ALWAYS_CNG_KSP; } // In the full .NET Framework loading a PFX then adding the key to the Windows Certificate Store would // enable a native application compiled against CAPI to find that private key and interoperate with it. // // For CoreFX this behavior is being retained. // // For .NET Native (UWP) the API used to delete the private key (if it wasn't added to a store) is not // allowed to be called if the key is stored in CAPI. So for UWP force the key to be stored in the // CNG Key Storage Provider, then deleting the key with CngKey.Delete will clean up the file on disk, too. #if NETNATIVE pfxCertStoreFlags |= PfxCertStoreFlags.PKCS12_ALWAYS_CNG_KSP; #endif return(pfxCertStoreFlags); }
private static PfxCertStoreFlags MapKeyStorageFlags(X509KeyStorageFlags keyStorageFlags) { if ((keyStorageFlags & (X509KeyStorageFlags) ~0x1F) != 0) { throw new ArgumentException(SR.Argument_InvalidFlag, "keyStorageFlags"); } PfxCertStoreFlags pfxCertStoreFlags = 0; if ((keyStorageFlags & X509KeyStorageFlags.UserKeySet) == X509KeyStorageFlags.UserKeySet) { pfxCertStoreFlags |= PfxCertStoreFlags.CRYPT_USER_KEYSET; } else if ((keyStorageFlags & X509KeyStorageFlags.MachineKeySet) == X509KeyStorageFlags.MachineKeySet) { pfxCertStoreFlags |= PfxCertStoreFlags.CRYPT_MACHINE_KEYSET; } if ((keyStorageFlags & X509KeyStorageFlags.Exportable) == X509KeyStorageFlags.Exportable) { pfxCertStoreFlags |= PfxCertStoreFlags.CRYPT_EXPORTABLE; } if ((keyStorageFlags & X509KeyStorageFlags.UserProtected) == X509KeyStorageFlags.UserProtected) { pfxCertStoreFlags |= PfxCertStoreFlags.CRYPT_USER_PROTECTED; } // In the full .NET Framework loading a PFX then adding the key to the Windows Certificate Store would // enable a native application compiled against CAPI to find that private key and interoperate with it. // // For CoreFX this behavior is being retained. // // For .NET Native (UWP) the API used to delete the private key (if it wasn't added to a store) is not // allowed to be called if the key is stored in CAPI. So for UWP force the key to be stored in the // CNG Key Storage Provider, then deleting the key with CngKey.Delete will clean up the file on disk, too. #if NETNATIVE pfxCertStoreFlags |= PfxCertStoreFlags.PKCS12_ALWAYS_CNG_KSP; #endif return(pfxCertStoreFlags); }
// this method maps a X509KeyStorageFlags enum to a combination of crypto API flags private static PfxCertStoreFlags MapKeyStorageFlags(X509KeyStorageFlags keyStorageFlags) { PfxCertStoreFlags dwFlags = 0; if ((keyStorageFlags & X509KeyStorageFlags.UserKeySet) == X509KeyStorageFlags.UserKeySet) { dwFlags |= PfxCertStoreFlags.CRYPT_USER_KEYSET; } else if ((keyStorageFlags & X509KeyStorageFlags.MachineKeySet) == X509KeyStorageFlags.MachineKeySet) { dwFlags |= PfxCertStoreFlags.CRYPT_MACHINE_KEYSET; } if ((keyStorageFlags & X509KeyStorageFlags.Exportable) == X509KeyStorageFlags.Exportable) { dwFlags |= PfxCertStoreFlags.CRYPT_EXPORTABLE; } if ((keyStorageFlags & X509KeyStorageFlags.UserProtected) == X509KeyStorageFlags.UserProtected) { dwFlags |= PfxCertStoreFlags.CRYPT_USER_PROTECTED; } if ((keyStorageFlags & X509KeyStorageFlags.EphemeralKeySet) == X509KeyStorageFlags.EphemeralKeySet) { dwFlags |= PfxCertStoreFlags.PKCS12_NO_PERSIST_KEY | PfxCertStoreFlags.PKCS12_ALWAYS_CNG_KSP; } // begin: gost // Allows to import pfx without csp windows if ((keyStorageFlags & X509KeyStorageFlags.CspNoPersistKeySet) == X509KeyStorageFlags.CspNoPersistKeySet) { dwFlags |= PfxCertStoreFlags.PKCS12_NO_PERSIST_KEY | PfxCertStoreFlags.CRYPT_EXPORTABLE; } // end: gost return(dwFlags); }
private static StorePal FromBlobOrFile(byte[] rawData, string fileName, SafePasswordHandle password, X509KeyStorageFlags keyStorageFlags) { Debug.Assert(password != null); bool fromFile = fileName != null; unsafe { fixed(byte *pRawData = rawData) { fixed(char *pFileName = fileName) { CRYPTOAPI_BLOB blob = new CRYPTOAPI_BLOB(fromFile ? 0 : rawData.Length, pRawData); bool persistKeySet = (0 != (keyStorageFlags & X509KeyStorageFlags.PersistKeySet)); PfxCertStoreFlags certStoreFlags = MapKeyStorageFlags(keyStorageFlags); void *pvObject = fromFile ? (void *)pFileName : (void *)&blob; ContentType contentType; SafeCertStoreHandle certStore; if (!Interop.crypt32.CryptQueryObject( fromFile ? CertQueryObjectType.CERT_QUERY_OBJECT_FILE : CertQueryObjectType.CERT_QUERY_OBJECT_BLOB, pvObject, StoreExpectedContentFlags, ExpectedFormatTypeFlags.CERT_QUERY_FORMAT_FLAG_ALL, 0, IntPtr.Zero, out contentType, IntPtr.Zero, out certStore, IntPtr.Zero, IntPtr.Zero )) { throw Marshal.GetLastWin32Error().ToCryptographicException(); } if (contentType == ContentType.CERT_QUERY_CONTENT_PFX) { certStore.Dispose(); if (fromFile) { rawData = File.ReadAllBytes(fileName); } fixed(byte *pRawData2 = rawData) { CRYPTOAPI_BLOB blob2 = new CRYPTOAPI_BLOB(rawData.Length, pRawData2); certStore = Interop.crypt32.PFXImportCertStore(ref blob2, password, certStoreFlags); if (certStore == null || certStore.IsInvalid) { throw Marshal.GetLastWin32Error().ToCryptographicException(); } } if (!persistKeySet) { // // If the user did not want us to persist private keys, then we should loop through all // the certificates in the collection and set our custom CERT_CLR_DELETE_KEY_PROP_ID property // so the key container will be deleted when the cert contexts will go away. // SafeCertContextHandle pCertContext = null; while (Interop.crypt32.CertEnumCertificatesInStore(certStore, ref pCertContext)) { CRYPTOAPI_BLOB nullBlob = new CRYPTOAPI_BLOB(0, null); if (!Interop.crypt32.CertSetCertificateContextProperty(pCertContext, CertContextPropId.CERT_CLR_DELETE_KEY_PROP_ID, CertSetPropertyFlags.CERT_SET_PROPERTY_INHIBIT_PERSIST_FLAG, &nullBlob)) { throw Marshal.GetLastWin32Error().ToCryptographicException(); } } } } return(new StorePal(certStore)); } } } }
public static extern SafeCertStoreHandle PFXImportCertStore([In] ref CRYPTOAPI_BLOB pPFX, SafePasswordHandle password, PfxCertStoreFlags dwFlags);
private static ICertificatePal FromBlobOrFile(byte[] rawData, String fileName, String password, X509KeyStorageFlags keyStorageFlags) { Debug.Assert(rawData != null || fileName != null); bool loadFromFile = (fileName != null); PfxCertStoreFlags pfxCertStoreFlags = MapKeyStorageFlags(keyStorageFlags); bool persistKeySet = (0 != (keyStorageFlags & X509KeyStorageFlags.PersistKeySet)); CertEncodingType msgAndCertEncodingType; ContentType contentType; FormatType formatType; SafeCertStoreHandle hCertStore = null; SafeCryptMsgHandle hCryptMsg = null; SafeCertContextHandle pCertContext = null; try { unsafe { fixed(byte *pRawData = rawData) { fixed(char *pFileName = fileName) { CRYPTOAPI_BLOB certBlob = new CRYPTOAPI_BLOB(loadFromFile ? 0 : rawData.Length, pRawData); CertQueryObjectType objectType = loadFromFile ? CertQueryObjectType.CERT_QUERY_OBJECT_FILE : CertQueryObjectType.CERT_QUERY_OBJECT_BLOB; void *pvObject = loadFromFile ? (void *)pFileName : (void *)&certBlob; bool success = Interop.crypt32.CryptQueryObject( objectType, pvObject, X509ExpectedContentTypeFlags, X509ExpectedFormatTypeFlags, 0, out msgAndCertEncodingType, out contentType, out formatType, out hCertStore, out hCryptMsg, out pCertContext ); if (!success) { int hr = Marshal.GetHRForLastWin32Error(); throw hr.ToCryptographicException(); } } } if (contentType == ContentType.CERT_QUERY_CONTENT_PKCS7_SIGNED || contentType == ContentType.CERT_QUERY_CONTENT_PKCS7_SIGNED_EMBED) { pCertContext = GetSignerInPKCS7Store(hCertStore, hCryptMsg); } else if (contentType == ContentType.CERT_QUERY_CONTENT_PFX) { if (loadFromFile) { rawData = File.ReadAllBytes(fileName); } pCertContext = FilterPFXStore(rawData, password, pfxCertStoreFlags); } CertificatePal pal = new CertificatePal(pCertContext, deleteKeyContainer: !persistKeySet); pCertContext = null; return(pal); } } finally { if (hCertStore != null) { hCertStore.Dispose(); } if (hCryptMsg != null) { hCryptMsg.Dispose(); } if (pCertContext != null) { pCertContext.Dispose(); } } }
private static SafeCertContextHandle FilterPFXStore(byte[] rawData, String password, PfxCertStoreFlags pfxCertStoreFlags) { SafeCertStoreHandle hStore; unsafe { fixed(byte *pbRawData = rawData) { CRYPTOAPI_BLOB certBlob = new CRYPTOAPI_BLOB(rawData.Length, pbRawData); hStore = Interop.crypt32.PFXImportCertStore(ref certBlob, password, pfxCertStoreFlags); if (hStore.IsInvalid) { throw Marshal.GetHRForLastWin32Error().ToCryptographicException(); } ; } } try { // Find the first cert with private key. If none, then simply take the very first cert. Along the way, delete the keycontainers // of any cert we don't accept. SafeCertContextHandle pCertContext = SafeCertContextHandle.InvalidHandle; SafeCertContextHandle pEnumContext = null; while (Interop.crypt32.CertEnumCertificatesInStore(hStore, ref pEnumContext)) { if (pEnumContext.ContainsPrivateKey) { if ((!pCertContext.IsInvalid) && pCertContext.ContainsPrivateKey) { // We already found our chosen one. Free up this one's key and move on. SafeCertContextHandleWithKeyContainerDeletion.DeleteKeyContainer(pEnumContext); } else { // Found our first cert that has a private key. Set him up as our chosen one but keep iterating // as we need to free up the keys of any remaining certs. pCertContext.Dispose(); pCertContext = pEnumContext.Duplicate(); } } else { if (pCertContext.IsInvalid) { pCertContext = pEnumContext.Duplicate(); // Doesn't have a private key but hang on to it anyway in case we don't find any certs with a private key. } } } if (pCertContext.IsInvalid) { // For compat, setting "hr" to ERROR_INVALID_PARAMETER even though ERROR_INVALID_PARAMETER is not actually an HRESULT. throw ErrorCode.ERROR_INVALID_PARAMETER.ToCryptographicException(); } return(pCertContext); } finally { hStore.Dispose(); } }
private static ICertificatePal FromBlobOrFile(byte[] rawData, string fileName, SafePasswordHandle password, X509KeyStorageFlags keyStorageFlags) { Debug.Assert(rawData != null || fileName != null); Debug.Assert(password != null); bool loadFromFile = (fileName != null); PfxCertStoreFlags pfxCertStoreFlags = MapKeyStorageFlags(keyStorageFlags); bool deleteKeyContainer = false; CertEncodingType msgAndCertEncodingType; ContentType contentType; FormatType formatType; SafeCertStoreHandle hCertStore = null; SafeCryptMsgHandle hCryptMsg = null; SafeCertContextHandle pCertContext = null; try { unsafe { fixed(byte *pRawData = rawData) { fixed(char *pFileName = fileName) { CRYPTOAPI_BLOB certBlob = new CRYPTOAPI_BLOB(loadFromFile ? 0 : rawData.Length, pRawData); CertQueryObjectType objectType = loadFromFile ? CertQueryObjectType.CERT_QUERY_OBJECT_FILE : CertQueryObjectType.CERT_QUERY_OBJECT_BLOB; void *pvObject = loadFromFile ? (void *)pFileName : (void *)&certBlob; bool success = Interop.crypt32.CryptQueryObject( objectType, pvObject, X509ExpectedContentTypeFlags, X509ExpectedFormatTypeFlags, 0, out msgAndCertEncodingType, out contentType, out formatType, out hCertStore, out hCryptMsg, out pCertContext ); if (!success) { int hr = Interop.CPError.GetHRForLastWin32Error(); throw hr.ToCryptographicException(); } } } if (contentType == ContentType.CERT_QUERY_CONTENT_PKCS7_SIGNED || contentType == ContentType.CERT_QUERY_CONTENT_PKCS7_SIGNED_EMBED) { pCertContext = GetSignerInPKCS7Store(hCertStore, hCryptMsg); } else if (contentType == ContentType.CERT_QUERY_CONTENT_PFX) { if (loadFromFile) { rawData = File.ReadAllBytes(fileName); } pCertContext = FilterPFXStore(rawData, password, pfxCertStoreFlags); // If PersistKeySet is set we don't delete the key, so that it persists. // If EphemeralKeySet is set we don't delete the key, because there's no file, so it's a wasteful call. const X509KeyStorageFlags DeleteUnless = X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.EphemeralKeySet | // begin: gost X509KeyStorageFlags.CspNoPersistKeySet; // end gost deleteKeyContainer = ((keyStorageFlags & DeleteUnless) == 0); } CertificatePal pal = new CertificatePal(pCertContext, deleteKeyContainer); pCertContext = null; return(pal); } } finally { if (hCertStore != null) { hCertStore.Dispose(); } if (hCryptMsg != null) { hCryptMsg.Dispose(); } if (pCertContext != null) { pCertContext.Dispose(); } } }
public static extern SafeCertStoreHandle PFXImportCertStore([In] ref CRYPTOAPI_BLOB pPFX, String szPassword, PfxCertStoreFlags dwFlags);
private static SafeCertContextHandle FilterPFXStore( ReadOnlySpan <byte> rawData, SafePasswordHandle password, PfxCertStoreFlags pfxCertStoreFlags) { SafeCertStoreHandle hStore; unsafe { fixed(byte *pbRawData = rawData) { CRYPTOAPI_BLOB certBlob = new CRYPTOAPI_BLOB(rawData.Length, pbRawData); hStore = Interop.crypt32.PFXImportCertStore(ref certBlob, password, pfxCertStoreFlags); if (hStore.IsInvalid) { throw Marshal.GetHRForLastWin32Error().ToCryptographicException(); } } } try { // Find the first cert with private key. If none, then simply take the very first cert. Along the way, delete the keycontainers // of any cert we don't accept. SafeCertContextHandle pCertContext = SafeCertContextHandle.InvalidHandle; SafeCertContextHandle?pEnumContext = null; while (Interop.crypt32.CertEnumCertificatesInStore(hStore, ref pEnumContext)) { if (pEnumContext.ContainsPrivateKey) { if ((!pCertContext.IsInvalid) && pCertContext.ContainsPrivateKey) { // We already found our chosen one. Free up this one's key and move on. // If this one has a persisted private key, clean up the key file. // If it was an ephemeral private key no action is required. if (pEnumContext.HasPersistedPrivateKey) { SafeCertContextHandleWithKeyContainerDeletion.DeleteKeyContainer(pEnumContext); } } else { // Found our first cert that has a private key. Set it up as our chosen one but keep iterating // as we need to free up the keys of any remaining certs. pCertContext.Dispose(); pCertContext = pEnumContext.Duplicate(); } } else { if (pCertContext.IsInvalid) { // Doesn't have a private key but hang on to it anyway in case we don't find any certs with a private key. pCertContext = pEnumContext.Duplicate(); } } } if (pCertContext.IsInvalid) { throw new CryptographicException(SR.Cryptography_Pfx_NoCertificates); } return(pCertContext); } finally { hStore.Dispose(); } }
private static StorePal FromBlobOrFile(byte[] rawData, String fileName, String password, X509KeyStorageFlags keyStorageFlags) { bool fromFile = fileName != null; unsafe { fixed(byte *pRawData = rawData) { fixed(char *pFileName = fileName) { CRYPTOAPI_BLOB blob = new CRYPTOAPI_BLOB(fromFile ? 0 : rawData.Length, pRawData); bool persistKeySet = (0 != (keyStorageFlags & X509KeyStorageFlags.PersistKeySet)); PfxCertStoreFlags certStoreFlags = MapKeyStorageFlags(keyStorageFlags); void *pvObject = fromFile ? (void *)pFileName : (void *)&blob; ContentType contentType; SafeCertStoreHandle certStore; if (!Interop.crypt32.CryptQueryObject( fromFile ? CertQueryObjectType.CERT_QUERY_OBJECT_FILE : CertQueryObjectType.CERT_QUERY_OBJECT_BLOB, pvObject, StoreExpectedContentFlags, ExpectedFormatTypeFlags.CERT_QUERY_FORMAT_FLAG_ALL, 0, IntPtr.Zero, out contentType, IntPtr.Zero, out certStore, IntPtr.Zero, IntPtr.Zero )) { throw new CryptographicException(Marshal.GetLastWin32Error()); } if (contentType == ContentType.CERT_QUERY_CONTENT_PFX) { certStore.Dispose(); if (fromFile) { rawData = File.ReadAllBytes(fileName); } fixed(byte *pRawData2 = rawData) { CRYPTOAPI_BLOB blob2 = new CRYPTOAPI_BLOB(rawData.Length, pRawData2); certStore = Interop.crypt32.PFXImportCertStore(ref blob2, password, certStoreFlags); if (certStore == null || certStore.IsInvalid) { throw new CryptographicException(Marshal.GetLastWin32Error()); } } } if (!persistKeySet) { SafeCertContextHandle pCertContext = null; while (Interop.crypt32.CertEnumCertificatesInStore(certStore, ref pCertContext)) { CRYPTOAPI_BLOB nullBlob = new CRYPTOAPI_BLOB(0, null); if (!Interop.crypt32.CertSetCertificateContextProperty(pCertContext, CertContextPropId.CERT_DELETE_KEYSET_PROP_ID, CertSetPropertyFlags.CERT_SET_PROPERTY_INHIBIT_PERSIST_FLAG, &nullBlob)) { throw new CryptographicException(Marshal.GetLastWin32Error()); } } } return(new StorePal(certStore)); } } } }
public static partial SafeCertStoreHandle PFXImportCertStore(ref CRYPTOAPI_BLOB pPFX, SafePasswordHandle password, PfxCertStoreFlags dwFlags);
private static SafeCertContextHandle FilterPFXStore(byte[] rawData, string password, PfxCertStoreFlags pfxCertStoreFlags) { SafeCertStoreHandle hStore; unsafe { fixed (byte* pbRawData = rawData) { CRYPTOAPI_BLOB certBlob = new CRYPTOAPI_BLOB(rawData.Length, pbRawData); hStore = Interop.crypt32.PFXImportCertStore(ref certBlob, password, pfxCertStoreFlags); if (hStore.IsInvalid) throw Marshal.GetHRForLastWin32Error().ToCryptographicException();; } } try { // Find the first cert with private key. If none, then simply take the very first cert. Along the way, delete the keycontainers // of any cert we don't accept. SafeCertContextHandle pCertContext = SafeCertContextHandle.InvalidHandle; SafeCertContextHandle pEnumContext = null; while (Interop.crypt32.CertEnumCertificatesInStore(hStore, ref pEnumContext)) { if (pEnumContext.ContainsPrivateKey) { if ((!pCertContext.IsInvalid) && pCertContext.ContainsPrivateKey) { // We already found our chosen one. Free up this one's key and move on. SafeCertContextHandleWithKeyContainerDeletion.DeleteKeyContainer(pEnumContext); } else { // Found our first cert that has a private key. Set him up as our chosen one but keep iterating // as we need to free up the keys of any remaining certs. pCertContext.Dispose(); pCertContext = pEnumContext.Duplicate(); } } else { if (pCertContext.IsInvalid) pCertContext = pEnumContext.Duplicate(); // Doesn't have a private key but hang on to it anyway in case we don't find any certs with a private key. } } if (pCertContext.IsInvalid) { // For compat, setting "hr" to ERROR_INVALID_PARAMETER even though ERROR_INVALID_PARAMETER is not actually an HRESULT. throw ErrorCode.ERROR_INVALID_PARAMETER.ToCryptographicException(); } return pCertContext; } finally { hStore.Dispose(); } }
internal static partial SafeCertStoreHandle PFXImportCertStore(ref DATA_BLOB pPFX, SafePasswordHandle password, PfxCertStoreFlags dwFlags);