示例#1
0
        public void Dispose()
        {
            SafeCertContextHandle certContext = _certContext;

            _certContext = null !;
            if (certContext != null && !certContext.IsInvalid)
            {
                certContext.Dispose();
            }
        }
示例#2
0
        internal static partial ICertificatePal FromHandle(IntPtr handle)
        {
            if (handle == IntPtr.Zero)
            {
                throw new ArgumentException(SR.Arg_InvalidHandle, nameof(handle));
            }

            SafeCertContextHandle safeCertContextHandle = Interop.Crypt32.CertDuplicateCertificateContext(handle);

            if (safeCertContextHandle.IsInvalid)
            {
                Exception e = ErrorCode.HRESULT_INVALID_HANDLE.ToCryptographicException();
                safeCertContextHandle.Dispose();
                throw e;
            }

            int  cbData             = 0;
            bool deleteKeyContainer = Interop.Crypt32.CertGetCertificateContextProperty(safeCertContextHandle, Interop.Crypt32.CertContextPropId.CERT_CLR_DELETE_KEY_PROP_ID, out Interop.Crypt32.DATA_BLOB _, ref cbData);

            return(new CertificatePal(safeCertContextHandle, deleteKeyContainer));
        }
示例#3
0
#pragma warning restore 618
        public virtual void Reset()
        {
            m_subjectName         = null;
            m_issuerName          = null;
            m_serialNumber        = null;
            m_publicKeyParameters = null;
            m_publicKeyValue      = null;
            m_publicKeyOid        = null;
            m_rawData             = null;
            m_thumbprint          = null;
            m_notBefore           = DateTime.MinValue;
            m_notAfter            = DateTime.MinValue;
            if (!m_safeCertContext.IsInvalid)
            {
                // Free the current certificate handle
                if (!m_certContextCloned)
                {
                    m_safeCertContext.Dispose();
                }
                m_safeCertContext = SafeCertContextHandle.InvalidHandle;
            }
            m_certContextCloned = false;
        }
        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();
            }
        }
        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?.Dispose();
                        pCertContext = GetSignerInPKCS7Store(hCertStore, hCryptMsg);
                    }
                    else if (contentType == Interop.Crypt32.ContentType.CERT_QUERY_CONTENT_PFX)
                    {
                        if (loadFromFile)
                        {
                            rawData = File.ReadAllBytes(fileName !);
                        }

                        pCertContext?.Dispose();
                        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
            {
                hCertStore?.Dispose();
                hCryptMsg?.Dispose();
                pCertContext?.Dispose();
            }
        }
示例#6
0
        private static unsafe SafeCertStoreHandle SelectFromStore(SafeCertStoreHandle safeSourceStoreHandle, string?title, string?message, X509SelectionFlag selectionFlags, IntPtr hwndParent)
        {
            int dwErrorCode = ERROR_SUCCESS;

            SafeCertStoreHandle safeCertStoreHandle = Interop.Crypt32.CertOpenStore(
                (IntPtr)Interop.Crypt32.CERT_STORE_PROV_MEMORY,
                Interop.Crypt32.X509_ASN_ENCODING | Interop.Crypt32.PKCS_7_ASN_ENCODING,
                IntPtr.Zero,
                0,
                IntPtr.Zero);

            if (safeCertStoreHandle == null || safeCertStoreHandle.IsInvalid)
            {
                Exception e = new CryptographicException(Marshal.GetLastWin32Error());
                safeCertStoreHandle?.Dispose();
                throw e;
            }

            Interop.CryptUI.CRYPTUI_SELECTCERTIFICATE_STRUCTW csc = default;
            // Older versions of CRYPTUI do not check the size correctly,
            // so always force it to the oldest version of the structure.
#if NET7_0_OR_GREATER
            // Declare a local for Native to enable us to get the managed byte offset
            // without having a null check cause a failure.
            Interop.CryptUI.CRYPTUI_SELECTCERTIFICATE_STRUCTW.Marshaller.Native native;
            Unsafe.SkipInit(out native);
            csc.dwSize = (uint)Unsafe.ByteOffset(ref Unsafe.As <Interop.CryptUI.CRYPTUI_SELECTCERTIFICATE_STRUCTW.Marshaller.Native, byte>(ref native), ref Unsafe.As <IntPtr, byte>(ref native.hSelectedCertStore));
#else
            csc.dwSize = (uint)Marshal.OffsetOf(typeof(Interop.CryptUI.CRYPTUI_SELECTCERTIFICATE_STRUCTW), "hSelectedCertStore");
#endif
            csc.hwndParent       = hwndParent;
            csc.dwFlags          = (uint)selectionFlags;
            csc.szTitle          = title;
            csc.dwDontUseColumn  = 0;
            csc.szDisplayString  = message;
            csc.pFilterCallback  = IntPtr.Zero;
            csc.pDisplayCallback = IntPtr.Zero;
            csc.pvCallbackData   = IntPtr.Zero;
            csc.cDisplayStores   = 1;
            IntPtr hSourceCertStore = safeSourceStoreHandle.DangerousGetHandle();
            csc.rghDisplayStores   = new IntPtr(&hSourceCertStore);
            csc.cStores            = 0;
            csc.rghStores          = IntPtr.Zero;
            csc.cPropSheetPages    = 0;
            csc.rgPropSheetPages   = IntPtr.Zero;
            csc.hSelectedCertStore = safeCertStoreHandle.DangerousGetHandle();

            SafeCertContextHandle safeCertContextHandle = Interop.CryptUI.CryptUIDlgSelectCertificateW(ref csc);

            if (safeCertContextHandle != null && !safeCertContextHandle.IsInvalid)
            {
                // Single select, so add it to our hCertStore
                SafeCertContextHandle ppStoreContext = SafeCertContextHandle.InvalidHandle;
                if (!Interop.Crypt32.CertAddCertificateLinkToStore(safeCertStoreHandle,
                                                                   safeCertContextHandle,
                                                                   Interop.Crypt32.CERT_STORE_ADD_ALWAYS,
                                                                   ppStoreContext))
                {
                    dwErrorCode = Marshal.GetLastWin32Error();
                }
            }

            if (dwErrorCode != ERROR_SUCCESS)
            {
                safeCertContextHandle?.Dispose();
                throw new CryptographicException(dwErrorCode);
            }

            return(safeCertStoreHandle);
        }