public void CopyTo(X509Certificate2Collection collection) { Debug.Assert(collection != null); SafeCertContextHandle?pCertContext = null; while (Interop.crypt32.CertEnumCertificatesInStore(_certStore, ref pCertContext)) { X509Certificate2 cert = new X509Certificate2(pCertContext.DangerousGetHandle()); collection.Add(cert); } }
public SafeCertContextHandle(SafeCertContextHandle parent) { ArgumentNullException.ThrowIfNull(parent); Debug.Assert(!parent.IsInvalid); Debug.Assert(!parent.IsClosed); bool ignored = false; parent.DangerousAddRef(ref ignored); _parent = parent; SetHandle(_parent.handle); }
private static unsafe SafeCertContextHandle GetSignerInPKCS7Store(SafeCertStoreHandle hCertStore, SafeCryptMsgHandle hCryptMsg) { // make sure that there is at least one signer of the certificate store int dwSigners; int cbSigners = sizeof(int); if (!Interop.Crypt32.CryptMsgGetParam(hCryptMsg, Interop.Crypt32.CryptMsgParamType.CMSG_SIGNER_COUNT_PARAM, 0, out dwSigners, ref cbSigners)) { throw Marshal.GetHRForLastWin32Error().ToCryptographicException(); } if (dwSigners == 0) { throw ErrorCode.CRYPT_E_SIGNER_NOT_FOUND.ToCryptographicException(); } // get the first signer from the store, and use that as the loaded certificate int cbData = 0; if (!Interop.Crypt32.CryptMsgGetParam(hCryptMsg, Interop.Crypt32.CryptMsgParamType.CMSG_SIGNER_INFO_PARAM, 0, default(byte *), ref cbData)) { throw Marshal.GetHRForLastWin32Error().ToCryptographicException(); fixed(byte *pCmsgSignerBytes = new byte[cbData]) { if (!Interop.Crypt32.CryptMsgGetParam(hCryptMsg, Interop.Crypt32.CryptMsgParamType.CMSG_SIGNER_INFO_PARAM, 0, pCmsgSignerBytes, ref cbData)) { throw Marshal.GetHRForLastWin32Error().ToCryptographicException(); } CMSG_SIGNER_INFO_Partial *pCmsgSignerInfo = (CMSG_SIGNER_INFO_Partial *)pCmsgSignerBytes; Interop.Crypt32.CERT_INFO certInfo = default(Interop.Crypt32.CERT_INFO); certInfo.Issuer.cbData = pCmsgSignerInfo->Issuer.cbData; certInfo.Issuer.pbData = pCmsgSignerInfo->Issuer.pbData; certInfo.SerialNumber.cbData = pCmsgSignerInfo->SerialNumber.cbData; certInfo.SerialNumber.pbData = pCmsgSignerInfo->SerialNumber.pbData; SafeCertContextHandle?pCertContext = null; if (!Interop.crypt32.CertFindCertificateInStore(hCertStore, Interop.Crypt32.CertFindType.CERT_FIND_SUBJECT_CERT, &certInfo, ref pCertContext)) { Exception e = Marshal.GetHRForLastWin32Error().ToCryptographicException(); pCertContext.Dispose(); throw e; } return(pCertContext); } }
protected override bool ReleaseHandle() { if (_parent != null) { _parent.DangerousRelease(); _parent = null; } else { Interop.Crypt32.CertFreeCertificateContext(handle); } SetHandle(IntPtr.Zero); return(true); }
public SafeCertContextHandle(SafeCertContextHandle parent) { if (parent == null) { throw new ArgumentNullException(nameof(parent)); } Debug.Assert(!parent.IsInvalid); Debug.Assert(!parent.IsClosed); bool ignored = false; parent.DangerousAddRef(ref ignored); _parent = parent; SetHandle(_parent.handle); }
public unsafe void Remove(ICertificatePal certificate) { using (SafeCertContextHandle existingCertContext = ((CertificatePal)certificate).GetCertContext()) { SafeCertContextHandle? enumCertContext = null; Interop.Crypt32.CERT_CONTEXT *pCertContext = existingCertContext.CertContext; if (!Interop.crypt32.CertFindCertificateInStore(_certStore, Interop.Crypt32.CertFindType.CERT_FIND_EXISTING, pCertContext, ref enumCertContext)) { return; // The certificate is not present in the store, simply return. } Interop.Crypt32.CERT_CONTEXT *pCertContextToDelete = enumCertContext.Disconnect(); // CertDeleteCertificateFromContext always frees the context (even on error) enumCertContext.Dispose(); if (!Interop.Crypt32.CertDeleteCertificateFromStore(pCertContextToDelete)) { throw Marshal.GetLastPInvokeError().ToCryptographicException(); } } }
private unsafe void FindCore(CertFindType dwFindType, void *pvFindPara, Func <SafeCertContextHandle, bool>?filter = null) { SafeCertStoreHandle findResults = Interop.crypt32.CertOpenStore( CertStoreProvider.CERT_STORE_PROV_MEMORY, CertEncodingType.All, IntPtr.Zero, CertStoreFlags.CERT_STORE_ENUM_ARCHIVED_FLAG | CertStoreFlags.CERT_STORE_CREATE_NEW_FLAG, null); if (findResults.IsInvalid) { throw Marshal.GetHRForLastWin32Error().ToCryptographicException(); } SafeCertContextHandle?pCertContext = null; while (Interop.crypt32.CertFindCertificateInStore(_storePal.SafeCertStoreHandle, dwFindType, pvFindPara, ref pCertContext)) { if (filter != null && !filter(pCertContext)) { continue; } if (_validOnly) { if (!VerifyCertificateIgnoringErrors(pCertContext)) { continue; } } if (!Interop.crypt32.CertAddCertificateLinkToStore(findResults, pCertContext, CertStoreAddDisposition.CERT_STORE_ADD_ALWAYS, IntPtr.Zero)) { throw Marshal.GetLastWin32Error().ToCryptographicException(); } } using (StorePal resultsStore = new StorePal(findResults)) { resultsStore.CopyTo(_copyTo); } }
private static ICertificatePal FromBlobOrFile(ReadOnlySpan <byte> rawData, string?fileName, SafePasswordHandle password, X509KeyStorageFlags keyStorageFlags) { Debug.Assert(!rawData.IsEmpty || fileName != null); Debug.Assert(password != null); bool loadFromFile = (fileName != null); Interop.Crypt32.PfxCertStoreFlags pfxCertStoreFlags = MapKeyStorageFlags(keyStorageFlags); bool deleteKeyContainer = false; Interop.Crypt32.CertEncodingType msgAndCertEncodingType; Interop.Crypt32.ContentType contentType; Interop.Crypt32.FormatType formatType; SafeCertStoreHandle? hCertStore = null; SafeCryptMsgHandle? hCryptMsg = null; SafeCertContextHandle?pCertContext = null; try { unsafe { fixed(byte *pRawData = rawData) { fixed(char *pFileName = fileName) { Interop.Crypt32.DATA_BLOB certBlob = new Interop.Crypt32.DATA_BLOB(new IntPtr(pRawData), (uint)(loadFromFile ? 0 : rawData.Length)); Interop.Crypt32.CertQueryObjectType objectType = loadFromFile ? Interop.Crypt32.CertQueryObjectType.CERT_QUERY_OBJECT_FILE : Interop.Crypt32.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 == Interop.Crypt32.ContentType.CERT_QUERY_CONTENT_PKCS7_SIGNED || contentType == Interop.Crypt32.ContentType.CERT_QUERY_CONTENT_PKCS7_SIGNED_EMBED) { pCertContext = GetSignerInPKCS7Store(hCertStore, hCryptMsg); } else if (contentType == Interop.Crypt32.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; 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(); } } }
private static SafeCertContextHandle FilterPFXStore( ReadOnlySpan <byte> rawData, SafePasswordHandle password, Interop.Crypt32.PfxCertStoreFlags pfxCertStoreFlags) { SafeCertStoreHandle hStore; unsafe { fixed(byte *pbRawData = rawData) { Interop.Crypt32.DATA_BLOB certBlob = new Interop.Crypt32.DATA_BLOB(new IntPtr(pbRawData), (uint)rawData.Length); 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(); } }
/// <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 end of the store has been reached. /// </summary> public static unsafe bool CertFindCertificateInStore(SafeCertStoreHandle hCertStore, CertFindType dwFindType, void *pvFindPara, [NotNull] ref SafeCertContextHandle?pCertContext) { CERT_CONTEXT *pPrevCertContext = pCertContext == null ? null : pCertContext.Disconnect(); pCertContext = CertFindCertificateInStore(hCertStore, CertEncodingType.All, CertFindFlags.None, dwFindType, pvFindPara, pPrevCertContext); return(!pCertContext.IsInvalid); }
/// <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 end of the store has been reached. /// </summary> public static unsafe bool CertEnumCertificatesInStore(SafeCertStoreHandle hCertStore, [NotNull] ref SafeCertContextHandle?pCertContext) { CERT_CONTEXT *pPrevCertContext; if (pCertContext == null) { pCertContext = new SafeCertContextHandle(); pPrevCertContext = null; } else { pPrevCertContext = pCertContext.Disconnect(); } pCertContext.SetHandle((IntPtr)CertEnumCertificatesInStore(hCertStore, pPrevCertContext)); if (!pCertContext.IsInvalid) { return(true); } pCertContext.Dispose(); return(false); }
/// <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 end of the store has been reached. /// </summary> public static bool CertEnumCertificatesInStore(SafeCertStoreHandle hCertStore, [NotNull] ref SafeCertContextHandle?pCertContext) { unsafe { CERT_CONTEXT *pPrevCertContext = pCertContext == null ? null : pCertContext.Disconnect(); pCertContext = CertEnumCertificatesInStore(hCertStore, pPrevCertContext); return(!pCertContext.IsInvalid); } }
private static StorePal FromBlobOrFile(ReadOnlySpan <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) { Interop.Crypt32.DATA_BLOB blob = new Interop.Crypt32.DATA_BLOB(new IntPtr(pRawData), (uint)(fromFile ? 0 : rawData !.Length)); bool persistKeySet = (0 != (keyStorageFlags & X509KeyStorageFlags.PersistKeySet)); Interop.Crypt32.PfxCertStoreFlags certStoreFlags = MapKeyStorageFlags(keyStorageFlags); void *pvObject = fromFile ? (void *)pFileName : (void *)&blob; Interop.Crypt32.ContentType contentType; SafeCertStoreHandle certStore; if (!Interop.Crypt32.CryptQueryObject( fromFile ? Interop.Crypt32.CertQueryObjectType.CERT_QUERY_OBJECT_FILE : Interop.Crypt32.CertQueryObjectType.CERT_QUERY_OBJECT_BLOB, pvObject, StoreExpectedContentFlags, Interop.Crypt32.ExpectedFormatTypeFlags.CERT_QUERY_FORMAT_FLAG_ALL, 0, IntPtr.Zero, out contentType, IntPtr.Zero, out certStore, IntPtr.Zero, IntPtr.Zero )) { Exception e = Marshal.GetLastPInvokeError().ToCryptographicException(); certStore.Dispose(); throw e; } if (contentType == Interop.Crypt32.ContentType.CERT_QUERY_CONTENT_PFX) { certStore.Dispose(); if (fromFile) { rawData = File.ReadAllBytes(fileName !); } fixed(byte *pRawData2 = rawData) { Interop.Crypt32.DATA_BLOB blob2 = new Interop.Crypt32.DATA_BLOB(new IntPtr(pRawData2), (uint)rawData !.Length); certStore = Interop.Crypt32.PFXImportCertStore(ref blob2, password, certStoreFlags); if (certStore == null || certStore.IsInvalid) { Exception e = Marshal.GetLastPInvokeError().ToCryptographicException(); certStore?.Dispose(); throw e; } } 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)) { Interop.Crypt32.DATA_BLOB nullBlob = new Interop.Crypt32.DATA_BLOB(IntPtr.Zero, 0); if (!Interop.Crypt32.CertSetCertificateContextProperty(pCertContext, Interop.Crypt32.CertContextPropId.CERT_CLR_DELETE_KEY_PROP_ID, Interop.Crypt32.CertSetPropertyFlags.CERT_SET_PROPERTY_INHIBIT_PERSIST_FLAG, &nullBlob)) { Exception e = Marshal.GetLastPInvokeError().ToCryptographicException(); certStore.Dispose(); throw e; } } } } return(new StorePal(certStore)); } } } }
public byte[]? Export(X509ContentType contentType, SafePasswordHandle password) { Debug.Assert(password != null); 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); } }
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 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(); } } }
/// <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 end of the store has been reached. /// </summary> public static unsafe bool CertFindCertificateInStore(SafeCertStoreHandle hCertStore, Interop.Crypt32.CertFindType dwFindType, void *pvFindPara, [NotNull] ref SafeCertContextHandle?pCertContext) { Interop.Crypt32.CERT_CONTEXT *pPrevCertContext = null; if (pCertContext != null) { pPrevCertContext = pCertContext.Disconnect(); pCertContext.Dispose(); } pCertContext = Interop.Crypt32.CertFindCertificateInStore(hCertStore, Interop.Crypt32.CertEncodingType.All, Interop.Crypt32.CertFindFlags.None, dwFindType, pvFindPara, pPrevCertContext); return(!pCertContext.IsInvalid); }