Пример #1
0
 internal static partial int CryptoNative_BioTell(SafeBioHandle bio);
Пример #2
0
 private static partial int BioWrite(SafeBioHandle b, ref byte data, int len);
Пример #3
0
 internal static partial int BioCtrlPending(SafeBioHandle bio);
Пример #4
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 (PkcsFormatReader.IsPkcs7Der(fileBio))
                    {
                        return(X509ContentType.Pkcs7);
                    }

                    OpenSslX509CertificateReader.RewindBio(fileBio, bioPosition);

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

                    OpenSslX509CertificateReader.RewindBio(fileBio, bioPosition);
                }

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

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

                        return(X509ContentType.Pkcs12);
                    }

                    OpenSslX509CertificateReader.RewindBio(fileBio, bioPosition);
                }
            }

            // Unsupported format.
            // Windows throws new CryptographicException(CRYPT_E_NO_MATCH)
            throw new CryptographicException();
        }
Пример #5
0
 internal static partial int BioWrite(SafeBioHandle b, byte[] data, int len);
Пример #6
0
 internal static extern SafePkcs12Handle d2i_PKCS12_bio(SafeBioHandle bio, IntPtr zero);
Пример #7
0
 internal static partial SafePkcs7Handle PemReadBioPkcs7(SafeBioHandle bp);
Пример #8
0
        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>();

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

            if (rootStorePath != null && rootStorePath.Exists)
            {
                newDirTime = rootStorePath.LastWriteTimeUtc;
                foreach (FileInfo file in rootStorePath.EnumerateFiles())
                {
                    ProcessFile(file);
                }
            }

            void ProcessFile(FileInfo file)
            {
                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;
                    }

                    // 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 corefx doesn'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))
                    {
                        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();
                    }
                }
            }

            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);
        }
Пример #9
0
 internal static extern SafePkcs7Handle PemReadBioPkcs7(SafeBioHandle bp);
Пример #10
0
 internal static extern SafeX509CrlHandle PemReadBioX509Crl(SafeBioHandle bio);
Пример #11
0
 internal static extern SafeX509Handle PemReadX509FromBio(SafeBioHandle bio);
Пример #12
0
 internal static extern int PemWriteBioX509Crl(SafeBioHandle bio, SafeX509CrlHandle crl);
Пример #13
0
 internal static partial SafeX509Handle ReadX509AsDerFromBio(SafeBioHandle bio);
Пример #14
0
 internal static partial int BioSeek(SafeBioHandle bio, int pos);
Пример #15
0
 internal static extern int BioCtrlPending(SafeBioHandle bio);
Пример #16
0
 internal static extern SafePkcs7Handle D2IPkcs7Bio(SafeBioHandle bp);
Пример #17
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);
                                continue;
                            }
                        }
                        else
                        {
                            if (uniqueIntermediateCerts.Add(cert))
                            {
                                s_machineIntermediateStore.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();
                    }
                }
            }

            s_machineRootStore = rootStore;
        }
Пример #18
0
        private static bool AddCachedCrl(string crlFileName, SafeX509StoreHandle store, DateTime verificationTime)
        {
            string crlFile = GetCachedCrlPath(crlFileName);

            using (SafeBioHandle bio = Interop.Crypto.BioNewFile(crlFile, "rb"))
            {
                if (bio.IsInvalid)
                {
                    Interop.Crypto.ErrClearError();
                    return(false);
                }

                // X509_STORE_add_crl will increase the refcount on the CRL object, so we should still
                // dispose our copy.
                using (SafeX509CrlHandle crl = Interop.Crypto.PemReadBioX509Crl(bio))
                {
                    if (crl.IsInvalid)
                    {
                        Interop.Crypto.ErrClearError();
                        return(false);
                    }

                    // If crl.LastUpdate is in the past, downloading a new version isn't really going
                    // to help, since we can't rewind the Internet. So this is just going to fail, but
                    // at least it can fail without using the network.
                    //
                    // If crl.NextUpdate is in the past, try downloading a newer version.
                    IntPtr   nextUpdatePtr = Interop.Crypto.GetX509CrlNextUpdate(crl);
                    DateTime nextUpdate;

                    // If there is no crl.NextUpdate, this indicates that the CA is not providing
                    // any more updates to the CRL, or they made a mistake not providing a NextUpdate.
                    // We'll cache it for a few days to cover the case it was a mistake.
                    if (nextUpdatePtr == IntPtr.Zero)
                    {
                        try
                        {
                            nextUpdate = File.GetLastWriteTime(crlFile).AddDays(3);
                        }
                        catch
                        {
                            // We couldn't determine when the CRL was last written to,
                            // so consider it expired.
                            Debug.Fail("Failed to get the last write time of the CRL file");
                            return(false);
                        }
                    }
                    else
                    {
                        nextUpdate = OpenSslX509CertificateReader.ExtractValidityDateTime(nextUpdatePtr);
                    }

                    // OpenSSL is going to convert our input time to universal, so we should be in Local or
                    // Unspecified (local-assumed).
                    Debug.Assert(
                        verificationTime.Kind != DateTimeKind.Utc,
                        "UTC verificationTime should have been normalized to Local");

                    // In the event that we're to-the-second accurate on the match, OpenSSL will consider this
                    // to be already expired.
                    if (nextUpdate <= verificationTime)
                    {
                        return(false);
                    }

                    if (!Interop.Crypto.X509StoreAddCrl(store, crl))
                    {
                        // Ignore error "cert already in store", throw on anything else. In any case the error queue will be cleared.
                        if (X509_R_CERT_ALREADY_IN_HASH_TABLE == Interop.Crypto.ErrPeekLastError())
                        {
                            Interop.Crypto.ErrClearError();
                        }
                        else
                        {
                            throw Interop.Crypto.CreateOpenSslCryptographicException();
                        }
                    }

                    return(true);
                }
            }
        }
Пример #19
0
        public static unsafe ICertificatePal FromBlob(byte[] rawData, string password, X509KeyStorageFlags keyStorageFlags)
        {
            // If we can see a hyphen, assume it's PEM.  Otherwise try DER-X509, then fall back to DER-PKCS12.
            SafeX509Handle cert;

            // PEM
            if (rawData[0] == '-')
            {
                using (SafeBioHandle bio = Interop.libcrypto.BIO_new(Interop.libcrypto.BIO_s_mem()))
                {
                    Interop.libcrypto.CheckValidOpenSslHandle(bio);

                    Interop.libcrypto.BIO_write(bio, rawData, rawData.Length);
                    cert = Interop.libcrypto.PEM_read_bio_X509_AUX(bio, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
                }

                Interop.libcrypto.CheckValidOpenSslHandle(cert);

                return(new OpenSslX509CertificateReader(cert));
            }

            // DER-X509
            cert = Interop.libcrypto.OpenSslD2I((ptr, b, i) => Interop.libcrypto.d2i_X509(ptr, b, i), rawData, checkHandle: false);

            if (!cert.IsInvalid)
            {
                return(new OpenSslX509CertificateReader(cert));
            }

            // DER-PKCS12
            OpenSslPkcs12Reader pfx;

            if (OpenSslPkcs12Reader.TryRead(rawData, out pfx))
            {
                using (pfx)
                {
                    pfx.Decrypt(password);

                    ICertificatePal first = null;

                    foreach (OpenSslX509CertificateReader certPal in pfx.ReadCertificates())
                    {
                        // When requesting an X509Certificate2 from a PFX only the first entry is
                        // returned.  Other entries should be disposed.
                        if (first == null)
                        {
                            first = certPal;
                        }
                        else
                        {
                            certPal.Dispose();
                        }
                    }

                    if (first == null)
                    {
                        throw new CryptographicException();
                    }

                    return(first);
                }
            }

            // Unsupported
            throw Interop.libcrypto.CreateOpenSslCryptographicException();
        }
Пример #20
0
 internal static extern void SslSetBio(SafeSslHandle ssl, SafeBioHandle rbio, SafeBioHandle wbio);
Пример #21
0
 internal static partial SafePkcs7Handle D2IPkcs7Bio(SafeBioHandle bp);
Пример #22
0
 internal static extern int BioGets(SafeBioHandle b, byte[] buf, int size);
Пример #23
0
 internal static partial int BioGets(SafeBioHandle b, byte[] buf, int size);
Пример #24
0
 internal static extern int BioWrite(SafeBioHandle b, byte[] data, int len);
Пример #25
0
 internal static int BioWrite(SafeBioHandle b, ReadOnlySpan <byte> data) =>
 BioWrite(b, ref MemoryMarshal.GetReference(data), data.Length);
Пример #26
0
 private static extern int BioWrite(SafeBioHandle b, ref byte data, int len);
Пример #27
0
 internal static partial int GetMemoryBioSize(SafeBioHandle bio);
Пример #28
0
 internal static extern int GetMemoryBioSize(SafeBioHandle bio);
Пример #29
0
 internal static extern unsafe int BioWrite(SafeBioHandle b, byte *data, int len);
Пример #30
0
 private static extern int Asn1StringPrintEx(SafeBioHandle bio, SafeSharedAsn1StringHandle str, Asn1StringPrintFlags flags);