static SafeCertStoreHandle ExportToMemoryStore(X509Certificate2Collection collection, IntPtr pCertContext) { CAPI.CERT_CONTEXT certContext = (CAPI.CERT_CONTEXT)Marshal.PtrToStructure(pCertContext, typeof(CAPI.CERT_CONTEXT)); // No extra store nor intermediate certificates if ((collection == null || collection.Count <= 0) && certContext.hCertStore == IntPtr.Zero) { return(SafeCertStoreHandle.InvalidHandle); } // we always want to use CERT_STORE_ENUM_ARCHIVED_FLAG since we want to preserve the collection in this operation. // By default, Archived certificates will not be included. SafeCertStoreHandle certStoreHandle = CAPI.CertOpenStore( new IntPtr(CAPI.CERT_STORE_PROV_MEMORY), CAPI.X509_ASN_ENCODING | CAPI.PKCS_7_ASN_ENCODING, IntPtr.Zero, CAPI.CERT_STORE_ENUM_ARCHIVED_FLAG | CAPI.CERT_STORE_CREATE_NEW_FLAG, null); if (certStoreHandle == null || certStoreHandle.IsInvalid) { int error = Marshal.GetLastWin32Error(); throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CryptographicException(error)); } // // We use CertAddCertificateLinkToStore to keep a link to the original store, so any property changes get // applied to the original store. This has a limit of 99 links per cert context however. // // Add extra store if (collection != null && collection.Count > 0) { foreach (X509Certificate2 x509 in collection) { if (!CAPI.CertAddCertificateLinkToStore(certStoreHandle, x509.Handle, CAPI.CERT_STORE_ADD_ALWAYS, SafeCertContextHandle.InvalidHandle)) { int error = Marshal.GetLastWin32Error(); throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CryptographicException(error)); } } } // Add intermediates // The hCertStore needs to be acquired from an X509Certificate2 object // constructed using a fresh cert context handle. If we simply refer to the hCertStore // property of the certContext local variable directly, there is a risk that we are accessing // a closed store. This is because if the X509Certificate2(rawdata) constructor closes the store handle (hCertStore). // There is no way to know which constructor was used at this point. // using (SafeCertContextHandle safeCertContext = CAPI.CertCreateCertificateContext(certContext.dwCertEncodingType, certContext.pbCertEncoded, certContext.cbCertEncoded)) { // // Create an X509Certificate2 using the new cert context that dup's the provided certificate. // X509Certificate2 intermediatesCert = new X509Certificate2(safeCertContext.DangerousGetHandle()); // // Dereference the handle to this intermediate cert and use it to access the handle // of this certificate's cert store. Then, call CAPI.CertAddCertificateLinkToStore // on each cert in this store by wrapping this cert store handle with an X509Store // object. // CAPI.CERT_CONTEXT intermediatesCertContext = (CAPI.CERT_CONTEXT)Marshal.PtrToStructure(intermediatesCert.Handle, typeof(CAPI.CERT_CONTEXT)); if (intermediatesCertContext.hCertStore != IntPtr.Zero) { X509Certificate2Collection intermediates = null; X509Store store = new X509Store(intermediatesCertContext.hCertStore); try { intermediates = store.Certificates; foreach (X509Certificate2 x509 in intermediates) { if (!CAPI.CertAddCertificateLinkToStore(certStoreHandle, x509.Handle, CAPI.CERT_STORE_ADD_ALWAYS, SafeCertContextHandle.InvalidHandle)) { int error = Marshal.GetLastWin32Error(); throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CryptographicException(error)); } } } finally { SecurityUtils.ResetAllCertificates(intermediates); store.Close(); } } } return(certStoreHandle); }