Inheritance: IDisposable, ICertificatePal
示例#1
0
 private static ECDsa DecodeECDsaPublicKey(CertificatePal certificatePal)
 {
     using (SafeBCryptKeyHandle bCryptKeyHandle = ImportPublicKeyInfo(certificatePal.CertContext))
     {
         CngKeyBlobFormat blobFormat = CngKeyBlobFormat.EccPublicBlob;
         byte[] keyBlob = ExportKeyBlob(bCryptKeyHandle, blobFormat);
         using (CngKey cngKey = CngKey.Import(keyBlob, blobFormat))
         {
             return new ECDsaCng(cngKey);
         }
     }
 }
        private static ECDsa DecodeECDsaPublicKey(CertificatePal certificatePal)
        {
            ECDsa ecdsa;
            using (SafeBCryptKeyHandle bCryptKeyHandle = ImportPublicKeyInfo(certificatePal.CertContext))
            {
                CngKeyBlobFormat blobFormat;
                byte[] keyBlob;
#if NETNATIVE
                blobFormat = CngKeyBlobFormat.EccPublicBlob;
                keyBlob = ExportKeyBlob(bCryptKeyHandle, blobFormat);
                using (CngKey cngKey = CngKey.Import(keyBlob, blobFormat))
                {
                    ecdsa = new ECDsaCng(cngKey);
                }
#else
                string curveName = GetCurveName(bCryptKeyHandle);

                if (curveName == null)
                {
                    if (HasExplicitParameters(bCryptKeyHandle))
                    {
                        blobFormat = CngKeyBlobFormat.EccFullPublicBlob;
                    }
                    else
                    {
                        blobFormat = CngKeyBlobFormat.EccPublicBlob;
                    }

                    keyBlob = ExportKeyBlob(bCryptKeyHandle, blobFormat);
                    using (CngKey cngKey = CngKey.Import(keyBlob, blobFormat))
                    {
                        ecdsa = new ECDsaCng(cngKey);
                    }
                }
                else
                {
                    blobFormat = CngKeyBlobFormat.EccPublicBlob;
                    keyBlob = ExportKeyBlob(bCryptKeyHandle, blobFormat);
                    ECParameters ecparams = new ECParameters();
                    ExportNamedCurveParameters(ref ecparams, keyBlob, false);
                    ecparams.Curve = ECCurve.CreateFromFriendlyName(curveName);
                    ecdsa = new ECDsaCng();
                    ecdsa.ImportParameters(ecparams);
                }
#endif
            }

            return ecdsa;
        }
示例#3
0
 private CertificatePal(CertificatePal copyFrom)
 {
     // Use _certContext (instead of CertContext) to keep the original context handle from being
     // finalized until all cert copies are no longer referenced.
     _certContext = new SafeCertContextHandle(copyFrom._certContext);
 }
示例#4
0
 /// <summary>
 /// Returns the SafeCertContextHandle. Use this instead of FromHandle() when
 /// creating another X509Certificate object based on this one to ensure the underlying
 /// cert context is not released at the wrong time.
 /// </summary>
 public static ICertificatePal FromOtherCert(X509Certificate copyFrom)
 {
     CertificatePal pal = new CertificatePal((CertificatePal)copyFrom.Pal);
     return pal;
 }
示例#5
0
        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();
            }
        }
        public X509ContentType GetCertContentType(string fileName)
        {
            // If we can't open the file, fail right away.
            using (SafeBioHandle fileBio = Interop.Crypto.BioNewFile(fileName, "rb"))
            {
                Interop.Crypto.CheckValidOpenSslHandle(fileBio);

                int bioPosition = Interop.Crypto.BioTell(fileBio);
                Debug.Assert(bioPosition >= 0);

                // X509ContentType.Cert
                {
                    ICertificatePal certPal;

                    if (CertificatePal.TryReadX509Der(fileBio, out certPal))
                    {
                        certPal.Dispose();

                        return(X509ContentType.Cert);
                    }

                    CertificatePal.RewindBio(fileBio, bioPosition);

                    if (CertificatePal.TryReadX509Pem(fileBio, out certPal))
                    {
                        certPal.Dispose();

                        return(X509ContentType.Cert);
                    }

                    CertificatePal.RewindBio(fileBio, bioPosition);
                }

                // X509ContentType.Pkcs7
                {
                    if (PkcsFormatReader.IsPkcs7Der(fileBio))
                    {
                        return(X509ContentType.Pkcs7);
                    }

                    CertificatePal.RewindBio(fileBio, bioPosition);

                    if (PkcsFormatReader.IsPkcs7Pem(fileBio))
                    {
                        return(X509ContentType.Pkcs7);
                    }

                    CertificatePal.RewindBio(fileBio, bioPosition);
                }

                // X509ContentType.Pkcs12 (aka PFX)
                {
                    OpenSslPkcs12Reader pkcs12Reader;

                    if (OpenSslPkcs12Reader.TryRead(fileBio, out pkcs12Reader))
                    {
                        pkcs12Reader.Dispose();

                        return(X509ContentType.Pkcs12);
                    }

                    CertificatePal.RewindBio(fileBio, bioPosition);
                }
            }

            // Unsupported format.
            // Windows throws new CryptographicException(CRYPT_E_NO_MATCH)
            throw new CryptographicException();
        }
        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();
                }
            }
        }
示例#8
0
        private static void LoadMachineStores()
        {
            Debug.Assert(
                Monitor.IsEntered(s_machineLoadLock),
                "LoadMachineStores assumes a lock(s_machineLoadLock)");

            var rootStore     = new List <X509Certificate2>();
            var intermedStore = new List <X509Certificate2>();

            DirectoryInfo          rootStorePath = null;
            IEnumerable <FileInfo> trustedCertFiles;

            try
            {
                rootStorePath = new DirectoryInfo(Interop.Crypto.GetX509RootStorePath());
            }
            catch (ArgumentException)
            {
                // If SSL_CERT_DIR is set to the empty string, or anything else which gives
                // "The path is not of a legal form", then the GetX509RootStorePath value is ignored.
            }

            if (rootStorePath != null && rootStorePath.Exists)
            {
                trustedCertFiles = rootStorePath.EnumerateFiles();
            }
            else
            {
                trustedCertFiles = Array.Empty <FileInfo>();
            }

            FileInfo rootStoreFile = null;

            try
            {
                rootStoreFile = new FileInfo(Interop.Crypto.GetX509RootStoreFile());
            }
            catch (ArgumentException)
            {
                // If SSL_CERT_FILE is set to the empty string, or anything else which gives
                // "The path is not of a legal form", then the GetX509RootStoreFile value is ignored.
            }

            if (rootStoreFile != null && rootStoreFile.Exists)
            {
                trustedCertFiles = Append(trustedCertFiles, rootStoreFile);
            }

            HashSet <X509Certificate2> uniqueRootCerts         = new HashSet <X509Certificate2>();
            HashSet <X509Certificate2> uniqueIntermediateCerts = new HashSet <X509Certificate2>();

            foreach (FileInfo file in trustedCertFiles)
            {
                using (SafeBioHandle fileBio = Interop.Crypto.BioNewFile(file.FullName, "rb"))
                {
                    ICertificatePal pal;

                    while (CertificatePal.TryReadX509Pem(fileBio, out pal) ||
                           CertificatePal.TryReadX509Der(fileBio, out pal))
                    {
                        X509Certificate2 cert = new X509Certificate2(pal);

                        // The HashSets are just used for uniqueness filters, they do not survive this method.
                        if (StringComparer.Ordinal.Equals(cert.Subject, cert.Issuer))
                        {
                            if (uniqueRootCerts.Add(cert))
                            {
                                rootStore.Add(cert);
                                continue;
                            }
                        }
                        else
                        {
                            if (uniqueIntermediateCerts.Add(cert))
                            {
                                intermedStore.Add(cert);
                                continue;
                            }
                        }

                        // There's a good chance we'll encounter duplicates on systems that have both one-cert-per-file
                        // and one-big-file trusted certificate stores. Anything that wasn't unique will end up here.
                        cert.Dispose();
                    }
                }
            }

            var rootStorePal = new CollectionBackedStoreProvider(rootStore);

            s_machineIntermediateStore = new CollectionBackedStoreProvider(intermedStore);

            // s_machineRootStore's nullarity is the loaded-state sentinel, so write it with Volatile.
            Debug.Assert(Monitor.IsEntered(s_machineLoadLock), "LoadMachineStores assumes a lock(s_machineLoadLock)");
            Volatile.Write(ref s_machineRootStore, rootStorePal);
        }
示例#9
0
        public static ILoaderPal FromBlob(ReadOnlySpan <byte> rawData, SafePasswordHandle password, X509KeyStorageFlags keyStorageFlags)
        {
            List <ICertificatePal>?certificateList = null;

            AppleCertificatePal.TryDecodePem(
                rawData,
                (derData, contentType) =>
            {
                certificateList = certificateList ?? new List <ICertificatePal>();
                certificateList.Add(AppleCertificatePal.FromDerBlob(derData, contentType, password, keyStorageFlags));
                return(true);
            });

            if (certificateList != null)
            {
                return(new CertCollectionLoader(certificateList));
            }

            X509ContentType contentType = AppleCertificatePal.GetDerCertContentType(rawData);

            if (contentType == X509ContentType.Pkcs7)
            {
                throw new CryptographicException(
                          SR.Cryptography_X509_PKCS7_Unsupported,
                          new PlatformNotSupportedException(SR.Cryptography_X509_PKCS7_Unsupported));
            }

            if (contentType == X509ContentType.Pkcs12)
            {
                ApplePkcs12Reader reader = new ApplePkcs12Reader(rawData);

                try
                {
                    reader.Decrypt(password);
                    return(new ApplePkcs12CertLoader(reader, password));
                }
                catch
                {
                    reader.Dispose();
                    throw;
                }
            }

            SafeCFArrayHandle certs = Interop.AppleCrypto.X509ImportCollection(
                rawData,
                contentType,
                password);

            using (certs)
            {
                long longCount = Interop.CoreFoundation.CFArrayGetCount(certs);

                if (longCount > int.MaxValue)
                {
                    throw new CryptographicException();
                }

                int count = (int)longCount;

                // Apple returns things in the opposite order from Windows, so read backwards.
                certificateList = new List <ICertificatePal>(count);
                for (int i = count - 1; i >= 0; i--)
                {
                    IntPtr handle = Interop.CoreFoundation.CFArrayGetValueAtIndex(certs, i);

                    if (handle != IntPtr.Zero)
                    {
                        ICertificatePal?certPal = CertificatePal.FromHandle(handle, throwOnFail: false);

                        if (certPal != null)
                        {
                            certificateList.Add(certPal);
                        }
                    }
                }
            }

            return(new CertCollectionLoader(certificateList));
        }
示例#10
0
 private CertificatePal(CertificatePal copyFrom)
 {
     // Use _certContext (instead of CertContext) to keep the original context handle from being
     // finalized until all cert copies are no longer referenced.
     _certContext = new SafeCertContextHandle(copyFrom._certContext);
 }
示例#11
0
        /// <summary>
        /// Returns the SafeCertContextHandle. Use this instead of FromHandle() when
        /// creating another X509Certificate object based on this one to ensure the underlying
        /// cert context is not released at the wrong time.
        /// </summary>
        public static ICertificatePal FromOtherCert(X509Certificate copyFrom)
        {
            CertificatePal pal = new CertificatePal((CertificatePal)copyFrom.Pal);

            return(pal);
        }
示例#12
0
        private static void LoadMachineStores()
        {
            Debug.Assert(
                Monitor.IsEntered(s_machineIntermediateStore),
                "LoadMachineStores assumes a lock(s_machineIntermediateStore)");

            X509Certificate2Collection rootStore = new X509Certificate2Collection();

            DirectoryInfo          rootStorePath = null;
            IEnumerable <FileInfo> trustedCertFiles;

            try
            {
                rootStorePath = new DirectoryInfo(Interop.Crypto.GetX509RootStorePath());
            }
            catch (ArgumentException)
            {
                // If SSL_CERT_DIR is set to the empty string, or anything else which gives
                // "The path is not of a legal form", then the GetX509RootStorePath value is ignored.
            }

            if (rootStorePath != null && rootStorePath.Exists)
            {
                trustedCertFiles = rootStorePath.EnumerateFiles();
            }
            else
            {
                trustedCertFiles = Array.Empty <FileInfo>();
            }

            FileInfo rootStoreFile = null;

            try
            {
                rootStoreFile = new FileInfo(Interop.Crypto.GetX509RootStoreFile());
            }
            catch (ArgumentException)
            {
                // If SSL_CERT_FILE is set to the empty string, or anything else which gives
                // "The path is not of a legal form", then the GetX509RootStoreFile value is ignored.
            }

            if (rootStoreFile != null && rootStoreFile.Exists)
            {
                trustedCertFiles = Append(trustedCertFiles, rootStoreFile);
            }

            HashSet <X509Certificate2> uniqueRootCerts         = new HashSet <X509Certificate2>();
            HashSet <X509Certificate2> uniqueIntermediateCerts = new HashSet <X509Certificate2>();

            foreach (FileInfo file in trustedCertFiles)
            {
                using (SafeBioHandle fileBio = Interop.Crypto.BioNewFile(file.FullName, "rb"))
                {
                    ICertificatePal pal;

                    while (CertificatePal.TryReadX509Pem(fileBio, out pal) ||
                           CertificatePal.TryReadX509Der(fileBio, out pal))
                    {
                        X509Certificate2 cert = new X509Certificate2(pal);

                        // The HashSets are just used for uniqueness filters, they do not survive this method.
                        if (StringComparer.Ordinal.Equals(cert.Subject, cert.Issuer))
                        {
                            if (uniqueRootCerts.Add(cert))
                            {
                                rootStore.Add(cert);
                            }
                        }
                        else
                        {
                            if (uniqueIntermediateCerts.Add(cert))
                            {
                                s_machineIntermediateStore.Add(cert);
                            }
                        }
                    }
                }
            }

            s_machineRootStore = rootStore;
        }
示例#13
0
        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();
                }
            }
        }
示例#14
0
        private static ILoaderPal FromBio(SafeBioHandle bio, SafePasswordHandle password)
        {
            int bioPosition = Interop.Crypto.BioTell(bio);

            Debug.Assert(bioPosition >= 0);

            ICertificatePal singleCert;

            if (CertificatePal.TryReadX509Pem(bio, out singleCert))
            {
                return(SingleCertToLoaderPal(singleCert));
            }

            // Rewind, try again.
            CertificatePal.RewindBio(bio, bioPosition);

            if (CertificatePal.TryReadX509Der(bio, out singleCert))
            {
                return(SingleCertToLoaderPal(singleCert));
            }

            // Rewind, try again.
            CertificatePal.RewindBio(bio, bioPosition);

            List <ICertificatePal> certPals;

            if (PkcsFormatReader.TryReadPkcs7Pem(bio, out certPals))
            {
                return(ListToLoaderPal(certPals));
            }

            // Rewind, try again.
            CertificatePal.RewindBio(bio, bioPosition);

            if (PkcsFormatReader.TryReadPkcs7Der(bio, out certPals))
            {
                return(ListToLoaderPal(certPals));
            }

            // Rewind, try again.
            CertificatePal.RewindBio(bio, bioPosition);

            // Capture the exception so in case of failure, the call to BioSeek does not override it.
            Exception openSslException;

            if (PkcsFormatReader.TryReadPkcs12(bio, password, out certPals, out openSslException))
            {
                return(ListToLoaderPal(certPals));
            }

            // Since we aren't going to finish reading, leaving the buffer where it was when we got
            // it seems better than leaving it in some arbitrary other position.
            //
            // Use BioSeek directly for the last seek attempt, because any failure here should instead
            // report the already created (but not yet thrown) exception.
            if (Interop.Crypto.BioSeek(bio, bioPosition) < 0)
            {
                Interop.Crypto.ErrClearError();
            }

            Debug.Assert(openSslException != null);
            throw openSslException;
        }