Exemplo n.º 1
0
        internal static partial ILoaderPal FromBlob(ReadOnlySpan <byte> rawData, SafePasswordHandle password, X509KeyStorageFlags keyStorageFlags)
        {
            Debug.Assert(password != null);

            ICertificatePal?singleCert;
            bool            ephemeralSpecified = keyStorageFlags.HasFlag(X509KeyStorageFlags.EphemeralKeySet);

            if (OpenSslX509CertificateReader.TryReadX509Der(rawData, out singleCert) ||
                OpenSslX509CertificateReader.TryReadX509Pem(rawData, out singleCert))
            {
                // The single X509 structure methods shouldn't return true and out null, only empty
                // collections have that behavior.
                Debug.Assert(singleCert != null);

                return(SingleCertToLoaderPal(singleCert));
            }

            List <ICertificatePal>?certPals;
            Exception?openSslException;

            if (OpenSslPkcsFormatReader.TryReadPkcs7Der(rawData, out certPals) ||
                OpenSslPkcsFormatReader.TryReadPkcs7Pem(rawData, out certPals) ||
                OpenSslPkcsFormatReader.TryReadPkcs12(rawData, password, ephemeralSpecified, out certPals, out openSslException))
            {
                Debug.Assert(certPals != null);

                return(ListToLoaderPal(certPals));
            }

            Debug.Assert(openSslException != null);
            throw openSslException;
        }
Exemplo n.º 2
0
        public X509ContentType GetCertContentType(ReadOnlySpan <byte> rawData)
        {
            {
                ICertificatePal?certPal;

                if (OpenSslX509CertificateReader.TryReadX509Der(rawData, out certPal) ||
                    OpenSslX509CertificateReader.TryReadX509Pem(rawData, out certPal))
                {
                    certPal.Dispose();

                    return(X509ContentType.Cert);
                }
            }

            if (OpenSslPkcsFormatReader.IsPkcs7(rawData))
            {
                return(X509ContentType.Pkcs7);
            }

            {
                OpenSslPkcs12Reader?pfx;

                if (OpenSslPkcs12Reader.TryRead(rawData, out pfx))
                {
                    pfx.Dispose();
                    return(X509ContentType.Pkcs12);
                }
            }

            // Unsupported format.
            // Windows throws new CryptographicException(CRYPT_E_NO_MATCH)
            throw new CryptographicException();
        }
Exemplo n.º 3
0
        protected override ICertificatePalCore ReadX509Der(ReadOnlyMemory <byte> data)
        {
            if (OpenSslX509CertificateReader.TryReadX509Der(data.Span, out ICertificatePal? ret))
            {
                return(ret);
            }

            throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
        }
        private static Tuple <SafeX509StackHandle, SafeX509StackHandle> LoadMachineStores(
            DirectoryInfo?rootStorePath,
            FileInfo?rootStoreFile)
        {
            Debug.Assert(
                Monitor.IsEntered(s_recheckStopwatch),
                "LoadMachineStores assumes a lock(s_recheckStopwatch)");

            SafeX509StackHandle rootStore = Interop.Crypto.NewX509Stack();

            Interop.Crypto.CheckValidOpenSslHandle(rootStore);
            SafeX509StackHandle intermedStore = Interop.Crypto.NewX509Stack();

            Interop.Crypto.CheckValidOpenSslHandle(intermedStore);

            DateTime newFileTime = default;
            DateTime newDirTime  = default;

            var  uniqueRootCerts         = new HashSet <X509Certificate2>();
            var  uniqueIntermediateCerts = new HashSet <X509Certificate2>();
            bool firstLoad = (s_nativeCollections == null);

            if (rootStoreFile != null && rootStoreFile.Exists)
            {
                newFileTime = ContentWriteTime(rootStoreFile);
                ProcessFile(rootStoreFile);
            }

            bool hasStoreData = false;

            if (rootStorePath != null && rootStorePath.Exists)
            {
                newDirTime   = ContentWriteTime(rootStorePath);
                hasStoreData = ProcessDir(rootStorePath);
            }

            if (firstLoad && !hasStoreData && s_defaultRootDir)
            {
                DirectoryInfo etcSslCerts = new DirectoryInfo("/etc/ssl/certs");

                if (etcSslCerts.Exists)
                {
                    DateTime tmpTime = ContentWriteTime(etcSslCerts);
                    hasStoreData = ProcessDir(etcSslCerts);

                    if (hasStoreData)
                    {
                        newDirTime = tmpTime;
                        s_rootStoreDirectoryInfo = etcSslCerts;
                    }
                }
            }

            bool ProcessDir(DirectoryInfo dir)
            {
                bool hasStoreData = false;

                foreach (FileInfo file in dir.EnumerateFiles())
                {
                    hasStoreData |= ProcessFile(file);
                }

                return(hasStoreData);
            }

            bool ProcessFile(FileInfo file)
            {
                bool readData = false;

                using (SafeBioHandle fileBio = Interop.Crypto.BioNewFile(file.FullName, "rb"))
                {
                    // The handle may be invalid, for example when we don't have read permission for the file.
                    if (fileBio.IsInvalid)
                    {
                        Interop.Crypto.ErrClearError();
                        return(false);
                    }

                    // Some distros ship with two variants of the same certificate.
                    // One is the regular format ('BEGIN CERTIFICATE') and the other
                    // contains additional AUX-data ('BEGIN TRUSTED CERTIFICATE').
                    // The additional data contains the appropriate usage (e.g. emailProtection, serverAuth, ...).
                    // Because we don't validate for a specific usage, derived certificates are rejected.
                    // For now, we skip the certificates with AUX data and use the regular certificates.
                    ICertificatePal?pal;
                    while (OpenSslX509CertificateReader.TryReadX509PemNoAux(fileBio, out pal) ||
                           OpenSslX509CertificateReader.TryReadX509Der(fileBio, out pal))
                    {
                        readData = true;
                        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))
                            {
                                using (SafeX509Handle tmp = Interop.Crypto.X509UpRef(pal.Handle))
                                {
                                    if (!Interop.Crypto.PushX509StackField(rootStore, tmp))
                                    {
                                        throw Interop.Crypto.CreateOpenSslCryptographicException();
                                    }

                                    // The ownership has been transferred to the stack
                                    tmp.SetHandleAsInvalid();
                                }

                                continue;
                            }
                        }
                        else
                        {
                            if (uniqueIntermediateCerts.Add(cert))
                            {
                                using (SafeX509Handle tmp = Interop.Crypto.X509UpRef(pal.Handle))
                                {
                                    if (!Interop.Crypto.PushX509StackField(intermedStore, tmp))
                                    {
                                        throw Interop.Crypto.CreateOpenSslCryptographicException();
                                    }

                                    // The ownership has been transferred to the stack
                                    tmp.SetHandleAsInvalid();
                                }

                                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();
                    }
                }

                return(readData);
            }

            foreach (X509Certificate2 cert in uniqueRootCerts)
            {
                cert.Dispose();
            }

            foreach (X509Certificate2 cert in uniqueIntermediateCerts)
            {
                cert.Dispose();
            }

            Tuple <SafeX509StackHandle, SafeX509StackHandle> newCollections =
                Tuple.Create(rootStore, intermedStore);

            Debug.Assert(
                Monitor.IsEntered(s_recheckStopwatch),
                "LoadMachineStores assumes a lock(s_recheckStopwatch)");

            // The existing collections are not Disposed here, intentionally.
            // They could be in the gap between when they are returned from this method and not yet used
            // in a P/Invoke, which would result in exceptions being thrown.
            // In order to maintain "finalization-free" the GetNativeCollections method would need to
            // DangerousAddRef, and the callers would need to DangerousRelease, adding more interlocked operations
            // on every call.

            Volatile.Write(ref s_nativeCollections, newCollections);
            s_directoryCertsLastWrite = newDirTime;
            s_fileCertsLastWrite      = newFileTime;
            s_recheckStopwatch.Restart();
            return(newCollections);
        }
Exemplo n.º 5
0
        private static ILoaderPal FromBio(
            string fileName,
            SafeBioHandle bio,
            SafePasswordHandle password,
            bool ephemeralSpecified)
        {
            int bioPosition = Interop.Crypto.BioTell(bio);

            Debug.Assert(bioPosition >= 0);

            ICertificatePal?singleCert;

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

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

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

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

            List <ICertificatePal>?certPals;

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

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

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

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

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

            byte[] data = File.ReadAllBytes(fileName);
            if (OpenSslPkcsFormatReader.TryReadPkcs12(data, password, ephemeralSpecified, 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;
        }
Exemplo n.º 6
0
        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 (OpenSslX509CertificateReader.TryReadX509Der(fileBio, out certPal))
                    {
                        certPal.Dispose();

                        return(X509ContentType.Cert);
                    }

                    OpenSslX509CertificateReader.RewindBio(fileBio, bioPosition);

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

                        return(X509ContentType.Cert);
                    }

                    OpenSslX509CertificateReader.RewindBio(fileBio, bioPosition);
                }

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

                    OpenSslX509CertificateReader.RewindBio(fileBio, bioPosition);

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

                    OpenSslX509CertificateReader.RewindBio(fileBio, bioPosition);
                }
            }

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

                if (OpenSslPkcs12Reader.TryRead(File.ReadAllBytes(fileName), out pkcs12Reader))
                {
                    pkcs12Reader.Dispose();

                    return(X509ContentType.Pkcs12);
                }
            }

            // Unsupported format.
            // Windows throws new CryptographicException(CRYPT_E_NO_MATCH)
            throw new CryptographicException();
        }