예제 #1
0
        internal static bool TryReadX509Der(SafeBioHandle bio, out ICertificatePal fromBio)
        {
            SafeX509Handle cert = Interop.Crypto.ReadX509AsDerFromBio(bio);

            if (cert.IsInvalid)
            {
                cert.Dispose();
                fromBio = null;
                return(false);
            }

            fromBio = new OpenSslX509CertificateReader(cert);
            return(true);
        }
예제 #2
0
        internal static bool TryReadX509Pem(SafeBioHandle bio, out ICertificatePal certPal)
        {
            SafeX509Handle cert = Interop.Crypto.PemReadX509FromBio(bio);

            if (cert.IsInvalid)
            {
                cert.Dispose();
                certPal = null;
                return(false);
            }

            certPal = new OpenSslX509CertificateReader(cert);
            return(true);
        }
예제 #3
0
        internal static bool TryReadX509Der(byte[] rawData, out ICertificatePal certPal)
        {
            SafeX509Handle certHandle = Interop.Crypto.DecodeX509(rawData, rawData.Length);

            if (certHandle.IsInvalid)
            {
                certHandle.Dispose();
                certPal = null;
                return(false);
            }

            certPal = new OpenSslX509CertificateReader(certHandle);
            return(true);
        }
예제 #4
0
파일: CrlCache.cs 프로젝트: talha020/corefx
        private static bool AddCachedCrl(X509Certificate2 cert, SafeX509StoreHandle store, DateTime verificationTime)
        {
            string crlFile = GetCachedCrlPath(cert);

            using (SafeBioHandle bio = Interop.libcrypto.BIO_new_file(crlFile, "rb"))
            {
                if (bio.IsInvalid)
                {
                    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.libcrypto.PEM_read_bio_X509_CRL(bio))
                {
                    if (crl.IsInvalid)
                    {
                        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.
                    DateTime nextUpdate = OpenSslX509CertificateReader.ExtractValidityDateTime(
                        Interop.Crypto.GetX509CrlNextUpdate(crl));

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

                    // TODO (#3063): Check the return value of X509_STORE_add_crl, and throw on any error other
                    // than X509_R_CERT_ALREADY_IN_HASH_TABLE
                    Interop.libcrypto.X509_STORE_add_crl(store, crl);

                    return(true);
                }
            }
        }
예제 #5
0
        private static string GetCdpUrl(SafeX509Handle cert)
        {
            ArraySegment <byte> crlDistributionPoints =
                OpenSslX509CertificateReader.FindFirstExtension(cert, Oids.CrlDistributionPoints);

            if (crlDistributionPoints.Array == null)
            {
                return(null);
            }

            try
            {
                AsnValueReader reader         = new AsnValueReader(crlDistributionPoints, AsnEncodingRules.DER);
                AsnValueReader sequenceReader = reader.ReadSequence();
                reader.ThrowIfNotEmpty();

                while (sequenceReader.HasData)
                {
                    DistributionPointAsn.Decode(ref sequenceReader, crlDistributionPoints, out DistributionPointAsn distributionPoint);

                    // Only distributionPoint is supported
                    // Only fullName is supported, nameRelativeToCRLIssuer is for LDAP-based lookup.
                    if (distributionPoint.DistributionPoint.HasValue &&
                        distributionPoint.DistributionPoint.Value.FullName != null)
                    {
                        foreach (GeneralNameAsn name in distributionPoint.DistributionPoint.Value.FullName)
                        {
                            if (name.Uri != null &&
                                Uri.TryCreate(name.Uri, UriKind.Absolute, out Uri uri) &&
                                uri.Scheme == "http")
                            {
                                return(name.Uri);
                            }
                        }
                    }
                }
            }
            catch (CryptographicException)
            {
                // Treat any ASN errors as if the extension was missing.
            }
            finally
            {
                // The data came from a certificate, so it's public.
                CryptoPool.Return(crlDistributionPoints.Array, clearSize: 0);
            }

            return(null);
        }
        internal static bool TryReadX509PemNoAux(SafeBioHandle bio, [NotNullWhen(true)] out ICertificatePal?certPal)
        {
            SafeX509Handle cert = Interop.Crypto.PemReadX509FromBio(bio);

            if (cert.IsInvalid)
            {
                cert.Dispose();
                certPal = null;
                Interop.Crypto.ErrClearError();
                return(false);
            }

            certPal = new OpenSslX509CertificateReader(cert);
            return(true);
        }
예제 #7
0
        internal static unsafe bool TryReadX509Der(byte[] rawData, out ICertificatePal certPal)
        {
            SafeX509Handle certHandle = Interop.libcrypto.OpenSslD2I(
                (ptr, b, i) => Interop.libcrypto.d2i_X509(ptr, b, i),
                rawData,
                checkHandle: false);

            if (certHandle.IsInvalid)
            {
                certPal = null;
                return(false);
            }

            certPal = new OpenSslX509CertificateReader(certHandle);
            return(true);
        }
예제 #8
0
        // Handles both DER and PEM
        internal static bool TryReadX509(ReadOnlySpan <byte> rawData, [NotNullWhen(true)] out ICertificatePal?handle)
        {
            handle = null;
            SafeX509Handle certHandle = Interop.AndroidCrypto.DecodeX509(
                ref MemoryMarshal.GetReference(rawData),
                rawData.Length);

            if (certHandle.IsInvalid)
            {
                certHandle.Dispose();
                return(false);
            }

            handle = new OpenSslX509CertificateReader(certHandle);
            return(true);
        }
        internal static bool TryReadX509Der(ReadOnlySpan <byte> rawData, out ICertificatePal certPal)
        {
            SafeX509Handle certHandle = Interop.Crypto.DecodeX509(
                ref MemoryMarshal.GetReference(rawData),
                rawData.Length);

            if (certHandle.IsInvalid)
            {
                certHandle.Dispose();
                certPal = null;
                Interop.Crypto.ErrClearError();
                return(false);
            }

            certPal = new OpenSslX509CertificateReader(certHandle);
            return(true);
        }
예제 #10
0
파일: CrlCache.cs 프로젝트: zsd4yr/corefx
        private static string GetCdpUrl(SafeX509Handle cert)
        {
            ArraySegment <byte> crlDistributionPoints =
                OpenSslX509CertificateReader.FindFirstExtension(cert, Oids.CrlDistributionPoints);

            if (crlDistributionPoints.Array == null)
            {
                return(null);
            }

            try
            {
                AsnReader reader         = new AsnReader(crlDistributionPoints, AsnEncodingRules.DER);
                AsnReader sequenceReader = reader.ReadSequence();
                reader.ThrowIfNotEmpty();

                while (sequenceReader.HasData)
                {
                    DistributionPointAsn.Decode(sequenceReader, out DistributionPointAsn distributionPoint);

                    // Only distributionPoint is supported
                    // Only fullName is supported, nameRelativeToCRLIssuer is for LDAP-based lookup.
                    if (distributionPoint.DistributionPoint.HasValue &&
                        distributionPoint.DistributionPoint.Value.FullName != null)
                    {
                        foreach (GeneralNameAsn name in distributionPoint.DistributionPoint.Value.FullName)
                        {
                            if (name.Uri != null &&
                                Uri.TryCreate(name.Uri, UriKind.Absolute, out Uri uri) &&
                                uri.Scheme == "http")
                            {
                                return(name.Uri);
                            }
                        }
                    }
                }

                return(null);
            }
            finally
            {
                ArrayPool <byte> .Shared.Return(crlDistributionPoints.Array);
            }
        }
예제 #11
0
        private static bool TryReadPkcs12(
            OpenSslPkcs12Reader pfx,
            SafePasswordHandle password,
            bool single,
            bool ephemeralSpecified,
            out ICertificatePal?readPal,
            out List <ICertificatePal>?readCerts)
        {
            pfx.Decrypt(password, ephemeralSpecified);

            if (single)
            {
                UnixPkcs12Reader.CertAndKey  certAndKey = pfx.GetSingleCert();
                OpenSslX509CertificateReader pal        = (OpenSslX509CertificateReader)certAndKey.Cert !;

                if (certAndKey.Key != null)
                {
                    pal.SetPrivateKey(OpenSslPkcs12Reader.GetPrivateKey(certAndKey.Key));
                }

                readPal   = pal;
                readCerts = null;
                return(true);
            }

            readPal = null;
            List <ICertificatePal> certs = new List <ICertificatePal>(pfx.GetCertCount());

            foreach (UnixPkcs12Reader.CertAndKey certAndKey in pfx.EnumerateAll())
            {
                OpenSslX509CertificateReader pal = (OpenSslX509CertificateReader)certAndKey.Cert !;

                if (certAndKey.Key != null)
                {
                    pal.SetPrivateKey(OpenSslPkcs12Reader.GetPrivateKey(certAndKey.Key));
                }

                certs.Add(pal);
            }

            readCerts = certs;
            return(true);
        }
예제 #12
0
        internal static bool TryReadX509Pem(byte[] rawData, out ICertificatePal certPal)
        {
            SafeX509Handle certHandle;

            using (SafeBioHandle bio = Interop.libcrypto.BIO_new(Interop.libcrypto.BIO_s_mem()))
            {
                Interop.Crypto.CheckValidOpenSslHandle(bio);

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

            if (certHandle.IsInvalid)
            {
                certPal = null;
                return(false);
            }

            certPal = new OpenSslX509CertificateReader(certHandle);
            return(true);
        }
        public void Remove(ICertificatePal certPal)
        {
            OpenSslX509CertificateReader cert = (OpenSslX509CertificateReader)certPal;

            using (X509Certificate2 copy = new X509Certificate2(cert.DuplicateHandles()))
            {
                bool   hadCandidates;
                string currentFilename = FindExistingFilename(copy, _storePath, out hadCandidates);

                if (currentFilename != null)
                {
                    if (_readOnly)
                    {
                        // Windows compatibility, the readonly check isn't done until after a match is found.
                        throw new CryptographicException(SR.Cryptography_X509_StoreReadOnly);
                    }

                    File.Delete(currentFilename);
                }
            }
        }
예제 #14
0
        public void FindBySubjectKeyIdentifier(byte[] keyIdentifier)
        {
            FindCore(
                cert =>
            {
                X509Extension ext = FindExtension(cert, Oids.SubjectKeyIdentifier);
                byte[] certKeyId;

                if (ext != null)
                {
                    // The extension exposes the value as a hexadecimal string, or we can decode here.
                    // Enough parsing has gone on, let's decode.
                    certKeyId = OpenSslX509Encoder.DecodeX509SubjectKeyIdentifierExtension(ext.RawData);
                }
                else
                {
                    // The Desktop/Windows version of this method use CertGetCertificateContextProperty
                    // with a property ID of CERT_KEY_IDENTIFIER_PROP_ID.
                    //
                    // MSDN says that when there's no extension, this method takes the SHA-1 of the
                    // SubjectPublicKeyInfo block, and returns that.
                    //
                    // https://msdn.microsoft.com/en-us/library/windows/desktop/aa376079%28v=vs.85%29.aspx

                    OpenSslX509CertificateReader certPal = (OpenSslX509CertificateReader)cert.Pal;

                    using (HashAlgorithm hash = SHA1.Create())
                    {
                        byte[] publicKeyInfoBytes = Interop.Crypto.OpenSslEncode(
                            Interop.Crypto.GetX509SubjectPublicKeyInfoDerSize,
                            Interop.Crypto.EncodeX509SubjectPublicKeyInfo,
                            certPal.SafeHandle);

                        certKeyId = hash.ComputeHash(publicKeyInfoBytes);
                    }
                }

                return(keyIdentifier.ContentsEqual(certKeyId));
            });
        }
예제 #15
0
        public List <OpenSslX509CertificateReader> ReadCertificates()
        {
            var certs = new List <OpenSslX509CertificateReader>();

            if (_caStackHandle != null && !_caStackHandle.IsInvalid)
            {
                int caCertCount = Interop.Crypto.GetX509StackFieldCount(_caStackHandle);

                for (int i = 0; i < caCertCount; i++)
                {
                    IntPtr certPtr = Interop.Crypto.GetX509StackField(_caStackHandle, i);

                    if (certPtr != IntPtr.Zero)
                    {
                        // The STACK_OF(X509) still needs to be cleaned up, so upref the handle out of it.
                        certs.Add(new OpenSslX509CertificateReader(Interop.Crypto.X509UpRef(certPtr)));
                    }
                }
            }

            if (_x509Handle != null && !_x509Handle.IsInvalid)
            {
                // The certificate and (if applicable) private key handles will be given over
                // to the OpenSslX509CertificateReader, and the fields here are thus nulled out to
                // prevent double-Dispose.
                OpenSslX509CertificateReader reader = new OpenSslX509CertificateReader(_x509Handle);
                _x509Handle = null;

                if (_evpPkeyHandle != null && !_evpPkeyHandle.IsInvalid)
                {
                    reader.SetPrivateKey(_evpPkeyHandle);
                    _evpPkeyHandle = null;
                }

                certs.Add(reader);
            }

            return(certs);
        }
예제 #16
0
파일: CrlCache.cs 프로젝트: talha020/corefx
        private static string GetCachedCrlPath(X509Certificate2 cert, bool mkDir = false)
        {
            OpenSslX509CertificateReader pal = (OpenSslX509CertificateReader)cert.Pal;

            string crlDir = PersistedFiles.GetUserFeatureDirectory(
                X509Persistence.CryptographyFeatureName,
                X509Persistence.CrlsSubFeatureName);

            // X509_issuer_name_hash returns "unsigned long", which is marshalled as UIntPtr.
            // But it only sets 32 bits worth of data, so force it down to uint just... in case.
            ulong persistentHashLong = Interop.libcrypto.X509_issuer_name_hash(pal.SafeHandle).ToUInt64();
            uint  persistentHash     = unchecked ((uint)persistentHashLong);

            // OpenSSL's hashed filename algorithm is the 8-character hex version of the 32-bit value
            // of X509_issuer_name_hash (or X509_subject_name_hash, depending on the context).
            string localFileName = persistentHash.ToString("x8") + ".crl";

            if (mkDir)
            {
                Directory.CreateDirectory(crlDir);
            }

            return(Path.Combine(crlDir, localFileName));
        }
예제 #17
0
        internal static bool TryReadX509Der(SafeBioHandle bio, out ICertificatePal fromBio)
        {
            SafeX509Handle cert = Interop.Crypto.ReadX509AsDerFromBio(bio);

            if (cert.IsInvalid)
            {
                cert.Dispose();
                fromBio = null;
                return false;
            }

            fromBio = new OpenSslX509CertificateReader(cert);
            return true;
        }
예제 #18
0
        internal static bool TryReadX509Pem(SafeBioHandle bio, out ICertificatePal certPal)
        {
            SafeX509Handle cert = Interop.Crypto.PemReadX509FromBio(bio);

            if (cert.IsInvalid)
            {
                cert.Dispose();
                certPal = null;
                return false;
            }

            certPal = new OpenSslX509CertificateReader(cert);
            return true;
        }
예제 #19
0
        internal static bool TryReadX509Der(byte[] rawData, out ICertificatePal certPal)
        {
            SafeX509Handle certHandle = Interop.Crypto.DecodeX509(rawData, rawData.Length);

            if (certHandle.IsInvalid)
            {
                certHandle.Dispose();
                certPal = null;
                return false;
            }

            certPal = new OpenSslX509CertificateReader(certHandle);
            return true;
        }
예제 #20
0
        public static IChainPal BuildChain(
            X509Certificate2 leaf,
            HashSet <X509Certificate2> candidates,
            HashSet <X509Certificate2> downloaded,
            HashSet <X509Certificate2> systemTrusted,
            OidCollection applicationPolicy,
            OidCollection certificatePolicy,
            X509RevocationMode revocationMode,
            X509RevocationFlag revocationFlag,
            DateTime verificationTime,
            ref TimeSpan remainingDownloadTime)
        {
            X509ChainElement[]     elements;
            List <X509ChainStatus> overallStatus = new List <X509ChainStatus>();
            WorkingChain           workingChain  = new WorkingChain();

            Interop.Crypto.X509StoreVerifyCallback workingCallback = workingChain.VerifyCallback;

            // An X509_STORE is more comparable to Cryptography.X509Certificate2Collection than to
            // Cryptography.X509Store. So read this with OpenSSL eyes, not CAPI/CNG eyes.
            //
            // (If you need to think of it as an X509Store, it's a volatile memory store)
            using (SafeX509StoreHandle store = Interop.Crypto.X509StoreCreate())
                using (SafeX509StoreCtxHandle storeCtx = Interop.Crypto.X509StoreCtxCreate())
                {
                    Interop.Crypto.CheckValidOpenSslHandle(store);
                    Interop.Crypto.CheckValidOpenSslHandle(storeCtx);

                    bool lookupCrl = revocationMode != X509RevocationMode.NoCheck;

                    foreach (X509Certificate2 cert in candidates)
                    {
                        OpenSslX509CertificateReader pal = (OpenSslX509CertificateReader)cert.Pal;

                        if (!Interop.Crypto.X509StoreAddCert(store, pal.SafeHandle))
                        {
                            throw Interop.Crypto.CreateOpenSslCryptographicException();
                        }

                        if (lookupCrl)
                        {
                            CrlCache.AddCrlForCertificate(
                                cert,
                                store,
                                revocationMode,
                                verificationTime,
                                ref remainingDownloadTime);

                            // If we only wanted the end-entity certificate CRL then don't look up
                            // any more of them.
                            lookupCrl = revocationFlag != X509RevocationFlag.EndCertificateOnly;
                        }
                    }

                    if (revocationMode != X509RevocationMode.NoCheck)
                    {
                        if (!Interop.Crypto.X509StoreSetRevocationFlag(store, revocationFlag))
                        {
                            throw Interop.Crypto.CreateOpenSslCryptographicException();
                        }
                    }

                    SafeX509Handle leafHandle = ((OpenSslX509CertificateReader)leaf.Pal).SafeHandle;

                    if (!Interop.Crypto.X509StoreCtxInit(storeCtx, store, leafHandle))
                    {
                        throw Interop.Crypto.CreateOpenSslCryptographicException();
                    }

                    Interop.Crypto.X509StoreCtxSetVerifyCallback(storeCtx, workingCallback);
                    Interop.Crypto.SetX509ChainVerifyTime(storeCtx, verificationTime);

                    int verify = Interop.Crypto.X509VerifyCert(storeCtx);

                    if (verify < 0)
                    {
                        throw Interop.Crypto.CreateOpenSslCryptographicException();
                    }

                    // Because our callback tells OpenSSL that every problem is ignorable, it should tell us that the
                    // chain is just fine (unless it returned a negative code for an exception)
                    Debug.Assert(verify == 1, "verify == 1");

                    using (SafeX509StackHandle chainStack = Interop.Crypto.X509StoreCtxGetChain(storeCtx))
                    {
                        int chainSize = Interop.Crypto.GetX509StackFieldCount(chainStack);
                        elements = new X509ChainElement[chainSize];
                        int maybeRootDepth = chainSize - 1;

                        // The leaf cert is 0, up to (maybe) the root at chainSize - 1
                        for (int i = 0; i < chainSize; i++)
                        {
                            List <X509ChainStatus> status = new List <X509ChainStatus>();

                            List <Interop.Crypto.X509VerifyStatusCode> elementErrors =
                                i < workingChain.Errors.Count ? workingChain.Errors[i] : null;

                            if (elementErrors != null)
                            {
                                AddElementStatus(elementErrors, status, overallStatus);
                            }

                            IntPtr elementCertPtr = Interop.Crypto.GetX509StackField(chainStack, i);

                            if (elementCertPtr == IntPtr.Zero)
                            {
                                throw Interop.Crypto.CreateOpenSslCryptographicException();
                            }

                            // Duplicate the certificate handle
                            X509Certificate2 elementCert = new X509Certificate2(elementCertPtr);

                            // If the last cert is self signed then it's the root cert, do any extra checks.
                            if (i == maybeRootDepth && IsSelfSigned(elementCert))
                            {
                                // If the root certificate was downloaded or the system
                                // doesn't trust it, it's untrusted.
                                if (downloaded.Contains(elementCert) ||
                                    !systemTrusted.Contains(elementCert))
                                {
                                    AddElementStatus(
                                        Interop.Crypto.X509VerifyStatusCode.X509_V_ERR_CERT_UNTRUSTED,
                                        status,
                                        overallStatus);
                                }
                            }

                            elements[i] = new X509ChainElement(elementCert, status.ToArray(), "");
                        }
                    }
                }

            GC.KeepAlive(workingCallback);

            if ((certificatePolicy != null && certificatePolicy.Count > 0) ||
                (applicationPolicy != null && applicationPolicy.Count > 0))
            {
                List <X509Certificate2> certsToRead = new List <X509Certificate2>();

                foreach (X509ChainElement element in elements)
                {
                    certsToRead.Add(element.Certificate);
                }

                CertificatePolicyChain policyChain = new CertificatePolicyChain(certsToRead);

                bool failsPolicyChecks = false;

                if (certificatePolicy != null)
                {
                    if (!policyChain.MatchesCertificatePolicies(certificatePolicy))
                    {
                        failsPolicyChecks = true;
                    }
                }

                if (applicationPolicy != null)
                {
                    if (!policyChain.MatchesApplicationPolicies(applicationPolicy))
                    {
                        failsPolicyChecks = true;
                    }
                }

                if (failsPolicyChecks)
                {
                    X509ChainElement leafElement = elements[0];

                    X509ChainStatus chainStatus = new X509ChainStatus
                    {
                        Status            = X509ChainStatusFlags.InvalidPolicyConstraints,
                        StatusInformation = SR.Chain_NoPolicyMatch,
                    };

                    var elementStatus = new List <X509ChainStatus>(leafElement.ChainElementStatus.Length + 1);
                    elementStatus.AddRange(leafElement.ChainElementStatus);

                    AddUniqueStatus(elementStatus, ref chainStatus);
                    AddUniqueStatus(overallStatus, ref chainStatus);

                    elements[0] = new X509ChainElement(
                        leafElement.Certificate,
                        elementStatus.ToArray(),
                        leafElement.Information);
                }
            }

            return(new OpenSslX509ChainProcessor
            {
                ChainStatus = overallStatus.ToArray(),
                ChainElements = elements,
            });
        }
예제 #21
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 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))
                    {
                        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);
        }
예제 #22
0
 public static ICertificatePal FromBlob(ReadOnlySpan <byte> rawData, SafePasswordHandle password, X509KeyStorageFlags keyStorageFlags)
 {
     return(OpenSslX509CertificateReader.FromBlob(rawData, password, keyStorageFlags));
 }
예제 #23
0
 public static ICertificatePal FromHandle(IntPtr handle)
 {
     return(OpenSslX509CertificateReader.FromHandle(handle));
 }
        public void Add(ICertificatePal certPal)
        {
            if (_readOnly)
            {
                // Windows compatibility: Remove only throws when it needs to do work, add throws always.
                throw new CryptographicException(SR.Cryptography_X509_StoreReadOnly);
            }

            // This may well be the first time that we've added something to this store.
            Directory.CreateDirectory(_storePath);

            uint userId = Interop.Sys.GetEUid();

            EnsureDirectoryPermissions(_storePath, userId);

            OpenSslX509CertificateReader cert = (OpenSslX509CertificateReader)certPal;

            using (X509Certificate2 copy = new X509Certificate2(cert.DuplicateHandles()))
            {
                string thumbprint = copy.Thumbprint;
                bool   findOpenSlot;

                // The odds are low that we'd have a thumbprint collision, but check anyways.
                string existingFilename = FindExistingFilename(copy, _storePath, out findOpenSlot);

                if (existingFilename != null)
                {
                    if (!copy.HasPrivateKey)
                    {
                        return;
                    }

                    try
                    {
                        using (X509Certificate2 fromFile = new X509Certificate2(existingFilename))
                        {
                            if (fromFile.HasPrivateKey)
                            {
                                // We have a private key, the file has a private key, we're done here.
                                return;
                            }
                        }
                    }
                    catch (CryptographicException)
                    {
                        // We can't read this file anymore, but a moment ago it was this certificate,
                        // so go ahead and overwrite it.
                    }
                }

                string   destinationFilename;
                FileMode mode = FileMode.CreateNew;

                if (existingFilename != null)
                {
                    destinationFilename = existingFilename;
                    mode = FileMode.Create;
                }
                else if (findOpenSlot)
                {
                    destinationFilename = FindOpenSlot(thumbprint);
                }
                else
                {
                    destinationFilename = Path.Combine(_storePath, thumbprint + PfxExtension);
                }

                using (FileStream stream = new FileStream(destinationFilename, mode))
                {
                    EnsureFilePermissions(stream, userId);
                    byte[] pkcs12 = copy.Export(X509ContentType.Pkcs12);
                    stream.Write(pkcs12, 0, pkcs12.Length);
                }
            }
        }
예제 #25
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();
        }
예제 #26
0
        public List<OpenSslX509CertificateReader> ReadCertificates()
        {
            var certs = new List<OpenSslX509CertificateReader>();

            if (_caStackHandle != null && !_caStackHandle.IsInvalid)
            {
                int caCertCount = Interop.Crypto.GetX509StackFieldCount(_caStackHandle);

                for (int i = 0; i < caCertCount; i++)
                {
                    IntPtr certPtr = Interop.Crypto.GetX509StackField(_caStackHandle, i);

                    if (certPtr != IntPtr.Zero)
                    {
                        // The STACK_OF(X509) still needs to be cleaned up, so upref the handle out of it.
                        certs.Add(new OpenSslX509CertificateReader(Interop.Crypto.X509UpRef(certPtr)));
                    }
                }
            }

            if (_x509Handle != null && !_x509Handle.IsInvalid)
            {
                // The certificate and (if applicable) private key handles will be given over
                // to the OpenSslX509CertificateReader, and the fields here are thus nulled out to
                // prevent double-Dispose.
                OpenSslX509CertificateReader reader = new OpenSslX509CertificateReader(_x509Handle);
                _x509Handle = null;

                if (_evpPkeyHandle != null && !_evpPkeyHandle.IsInvalid)
                {
                    reader.SetPrivateKey(_evpPkeyHandle);
                    _evpPkeyHandle = null;
                }

                certs.Add(reader);
            }

            return certs;
        }
예제 #27
0
        internal Interop.Crypto.X509VerifyStatusCode FindChainViaAia(
            ref List <X509Certificate2> downloadedCerts)
        {
            IntPtr lastCert = IntPtr.Zero;
            SafeX509StoreCtxHandle storeCtx = _storeCtx;

            Interop.Crypto.X509VerifyStatusCode statusCode =
                Interop.Crypto.X509VerifyStatusCode.X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT;

            while (!IsCompleteChain(statusCode))
            {
                using (SafeX509Handle currentCert = Interop.Crypto.X509StoreCtxGetCurrentCert(storeCtx))
                {
                    IntPtr currentHandle = currentCert.DangerousGetHandle();

                    // No progress was made, give up.
                    if (currentHandle == lastCert)
                    {
                        break;
                    }

                    lastCert = currentHandle;

                    ArraySegment <byte> authorityInformationAccess =
                        OpenSslX509CertificateReader.FindFirstExtension(
                            currentCert,
                            Oids.AuthorityInformationAccess);

                    if (authorityInformationAccess.Count == 0)
                    {
                        break;
                    }

                    X509Certificate2 downloaded = DownloadCertificate(
                        authorityInformationAccess,
                        ref _remainingDownloadTime);

                    // The AIA record is contained in a public structure, so no need to clear it.
                    CryptoPool.Return(authorityInformationAccess.Array, clearSize: 0);

                    if (downloaded == null)
                    {
                        break;
                    }

                    if (downloadedCerts == null)
                    {
                        downloadedCerts = new List <X509Certificate2>();
                    }

                    AddToStackAndUpRef(downloaded.Handle, _untrustedLookup);
                    downloadedCerts.Add(downloaded);

                    Interop.Crypto.X509StoreCtxRebuildChain(storeCtx);
                    statusCode = Interop.Crypto.X509StoreCtxGetError(storeCtx);
                }
            }

            if (statusCode == Interop.Crypto.X509VerifyStatusCode.X509_V_OK && downloadedCerts != null)
            {
                using (SafeX509StackHandle chainStack = Interop.Crypto.X509StoreCtxGetChain(_storeCtx))
                {
                    int           chainSize     = Interop.Crypto.GetX509StackFieldCount(chainStack);
                    Span <IntPtr> tempChain     = stackalloc IntPtr[DefaultChainCapacity];
                    byte[]        tempChainRent = null;

                    if (chainSize <= tempChain.Length)
                    {
                        tempChain = tempChain.Slice(0, chainSize);
                    }
                    else
                    {
                        int targetSize = checked (chainSize * IntPtr.Size);
                        tempChainRent = CryptoPool.Rent(targetSize);
                        tempChain     = MemoryMarshal.Cast <byte, IntPtr>(tempChainRent.AsSpan(0, targetSize));
                    }

                    for (int i = 0; i < chainSize; i++)
                    {
                        tempChain[i] = Interop.Crypto.GetX509StackField(chainStack, i);
                    }

                    // In the average case we never made it here.
                    //
                    // Given that we made it here, in the average remaining case
                    // we are doing a one item for which will match in the second position
                    // of an (on-average) 3 item collection.
                    //
                    // The only case where this loop really matters is if downloading the
                    // certificate made an alternate chain better, which may have resulted in
                    // an extra download and made the first one not be involved any longer. In
                    // that case, it's a 2 item for loop matching against a three item set.
                    //
                    // So N*M is well contained.
                    for (int i = downloadedCerts.Count - 1; i >= 0; i--)
                    {
                        X509Certificate2 downloadedCert = downloadedCerts[i];

                        if (!tempChain.Contains(downloadedCert.Handle))
                        {
                            downloadedCert.Dispose();
                            downloadedCerts.RemoveAt(i);
                        }
                    }

                    if (downloadedCerts.Count == 0)
                    {
                        downloadedCerts = null;
                    }

                    if (tempChainRent != null)
                    {
                        CryptoPool.Return(tempChainRent);
                    }
                }
            }

            return(statusCode);
        }
예제 #28
0
        protected override X509Certificate2 CloneCertificate(X509Certificate2 cert)
        {
            OpenSslX509CertificateReader certPal = (OpenSslX509CertificateReader)cert.Pal;

            return(new X509Certificate2(certPal.DuplicateHandles()));
        }
        public void Add(ICertificatePal certPal)
        {
            if (_readOnly)
            {
                // Windows compatibility: Remove only throws when it needs to do work, add throws always.
                throw new CryptographicException(SR.Cryptography_X509_StoreReadOnly);
            }

            // Save the collection to a local so it's consistent for the whole method
            List <X509Certificate2>      certificates = _certificates;
            OpenSslX509CertificateReader cert         = (OpenSslX509CertificateReader)certPal;

            using (X509Certificate2 copy = new X509Certificate2(cert.DuplicateHandles()))
            {
                // certificates will be null if anything has changed since the last call to
                // get_Certificates; including Add being called without get_Certificates being
                // called at all.
                if (certificates != null)
                {
                    foreach (X509Certificate2 inCollection in certificates)
                    {
                        if (inCollection.Equals(copy))
                        {
                            if (!copy.HasPrivateKey || inCollection.HasPrivateKey)
                            {
                                // If the existing store only knows about a public key, but we're
                                // adding a public+private pair, continue with the add.
                                //
                                // So, therefore, if we aren't adding a private key, or already have one,
                                // we don't need to do anything.
                                return;
                            }
                        }
                    }
                }

                // This may well be the first time that we've added something to this store.
                Directory.CreateDirectory(_storePath);

                uint userId = Interop.Sys.GetEUid();
                EnsureDirectoryPermissions(_storePath, userId);

                string thumbprint = copy.Thumbprint;
                bool   findOpenSlot;

                // The odds are low that we'd have a thumbprint collision, but check anyways.
                string existingFilename = FindExistingFilename(copy, _storePath, out findOpenSlot);

                if (existingFilename != null)
                {
                    bool dataExistsAlready = false;

                    // If the file on disk is just a public key, but we're trying to add a private key,
                    // we'll want to overwrite it.
                    if (copy.HasPrivateKey)
                    {
                        try
                        {
                            using (X509Certificate2 fromFile = new X509Certificate2(existingFilename))
                            {
                                if (fromFile.HasPrivateKey)
                                {
                                    // We have a private key, the file has a private key, we're done here.
                                    dataExistsAlready = true;
                                }
                            }
                        }
                        catch (CryptographicException)
                        {
                            // We can't read this file anymore, but a moment ago it was this certificate,
                            // so go ahead and overwrite it.
                        }
                    }
                    else
                    {
                        // If we're just a public key then the file has at least as much data as we do.
                        dataExistsAlready = true;
                    }

                    if (dataExistsAlready)
                    {
                        // The file was added but our collection hasn't resynced yet.
                        // Set _certificates to null to force a resync.
                        _certificates = null;
                        return;
                    }
                }

                string   destinationFilename;
                FileMode mode = FileMode.CreateNew;

                if (existingFilename != null)
                {
                    destinationFilename = existingFilename;
                    mode = FileMode.Create;
                }
                else if (findOpenSlot)
                {
                    destinationFilename = FindOpenSlot(thumbprint);
                }
                else
                {
                    destinationFilename = Path.Combine(_storePath, thumbprint + PfxExtension);
                }

                using (FileStream stream = new FileStream(destinationFilename, mode))
                {
                    EnsureFilePermissions(stream, userId);
                    byte[] pkcs12 = copy.Export(X509ContentType.Pkcs12);
                    stream.Write(pkcs12, 0, pkcs12.Length);
                }
            }

            // Null out _certificates so the next call to get_Certificates causes a re-scan.
            _certificates = null;
        }
예제 #30
0
        internal static unsafe bool TryReadX509Der(byte[] rawData, out ICertificatePal certPal)
        {
            SafeX509Handle certHandle = Interop.libcrypto.OpenSslD2I(
                (ptr, b, i) => Interop.libcrypto.d2i_X509(ptr, b, i),
                rawData,
                checkHandle: false);

            if (certHandle.IsInvalid)
            {
                certPal = null;
                return false;
            }

            certPal = new OpenSslX509CertificateReader(certHandle);
            return true;
        }
예제 #31
0
        internal OpenSslX509CertificateReader DuplicateHandles()
        {
            SafeX509Handle certHandle = Interop.Crypto.X509Duplicate(_cert);
            OpenSslX509CertificateReader duplicate = new OpenSslX509CertificateReader(certHandle);

            if (_privateKey != null)
            {
                SafeEvpPKeyHandle keyHandle = _privateKey.DuplicateHandle();
                duplicate.SetPrivateKey(keyHandle);
            }

            return duplicate;
        }
예제 #32
0
        internal static bool TryReadX509Pem(byte[] rawData, out ICertificatePal certPal)
        {
            SafeX509Handle certHandle;
            using (SafeBioHandle bio = Interop.libcrypto.BIO_new(Interop.libcrypto.BIO_s_mem()))
            {
                Interop.libcrypto.CheckValidOpenSslHandle(bio);

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

            if (certHandle.IsInvalid)
            {
                certPal = null;
                return false;
            }

            certPal = new OpenSslX509CertificateReader(certHandle);
            return true;
        }
예제 #33
0
 public static ICertificatePal FromOtherCert(X509Certificate cert)
 {
     return(OpenSslX509CertificateReader.FromOtherCert(cert));
 }
예제 #34
0
        internal static bool TryReadX509Pem(SafeBioHandle bio, out ICertificatePal certPal)
        {
            SafeX509Handle cert = Interop.libcrypto.PEM_read_bio_X509_AUX(bio, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);

            if (cert.IsInvalid)
            {
                certPal = null;
                return false;
            }

            certPal = new OpenSslX509CertificateReader(cert);
            return true;
        }
예제 #35
0
 public static ICertificatePal FromFile(string fileName, SafePasswordHandle password, X509KeyStorageFlags keyStorageFlags)
 {
     return(OpenSslX509CertificateReader.FromFile(fileName, password, keyStorageFlags));
 }
예제 #36
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 = trustedCertFiles.Prepend(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"))
                {
                    // The handle may be invalid, for example when we don't have read permission for the file.
                    if (fileBio.IsInvalid)
                    {
                        Interop.Crypto.ErrClearError();
                        continue;
                    }

                    ICertificatePal pal;

                    // 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.
                    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))
                            {
                                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);
        }
        private byte[] ExportPfx(string password)
        {
            using (SafeX509StackHandle publicCerts = Interop.Crypto.NewX509Stack())
            {
                X509Certificate2 privateCert = null;

                // Walk the collection backwards, because we're pushing onto a stack.
                // This will cause the read order later to be the same as it was now.
                for (int i = _certs.Length - 1; i >= 0; --i)
                {
                    X509Certificate2 cert = _certs[i];

                    if (cert.HasPrivateKey)
                    {
                        if (privateCert != null)
                        {
                            // OpenSSL's PKCS12 accelerator (PKCS12_create) only supports one
                            // private key.  The data structure supports more than one, but
                            // being able to use that functionality requires a lot more code for
                            // a low-usage scenario.
                            throw new PlatformNotSupportedException(SR.NotSupported_Export_MultiplePrivateCerts);
                        }

                        privateCert = cert;
                    }
                    else
                    {
                        using (SafeX509Handle certHandle = Interop.libcrypto.X509_dup(cert.Handle))
                        {
                            if (!Interop.Crypto.PushX509StackField(publicCerts, certHandle))
                            {
                                throw Interop.libcrypto.CreateOpenSslCryptographicException();
                            }

                            // The handle ownership has been transferred into the STACK_OF(X509).
                            certHandle.SetHandleAsInvalid();
                        }
                    }
                }

                SafeX509Handle    privateCertHandle;
                SafeEvpPKeyHandle privateCertKeyHandle;

                if (privateCert != null)
                {
                    OpenSslX509CertificateReader pal = (OpenSslX509CertificateReader)privateCert.Pal;
                    privateCertHandle    = pal.SafeHandle;
                    privateCertKeyHandle = pal.PrivateKeyHandle ?? InvalidPKeyHandle;
                }
                else
                {
                    privateCertHandle    = SafeX509Handle.InvalidHandle;
                    privateCertKeyHandle = InvalidPKeyHandle;
                }

                using (SafePkcs12Handle pkcs12 = Interop.libcrypto.PKCS12_create(
                           password,
                           null,
                           privateCertKeyHandle,
                           privateCertHandle,
                           publicCerts,
                           Interop.libcrypto.NID_undef,
                           Interop.libcrypto.NID_undef,
                           Interop.libcrypto.PKCS12_DEFAULT_ITER,
                           Interop.libcrypto.PKCS12_DEFAULT_ITER,
                           0))
                {
                    if (pkcs12.IsInvalid)
                    {
                        throw Interop.libcrypto.CreateOpenSslCryptographicException();
                    }

                    unsafe
                    {
                        return(Interop.libcrypto.OpenSslI2D(
                                   (handle, b) => Interop.libcrypto.i2d_PKCS12(handle, b),
                                   pkcs12));
                    }
                }
            }
        }
예제 #38
0
        private static ILoaderPal FromBio(SafeBioHandle bio, SafePasswordHandle password)
        {
            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 (PkcsFormatReader.TryReadPkcs7Pem(bio, out certPals))
            {
                return(ListToLoaderPal(certPals));
            }

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

            if (PkcsFormatReader.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;

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