private void AssertCert(X509Certificate2 cert, bool expectValidCert)
        {
            X509Chain       chainBuilder = new X509Chain();
            X509ChainPolicy policy       = new X509ChainPolicy();

            policy.VerificationFlags = X509VerificationFlags.IgnoreWrongUsage;
            chainBuilder.ChainPolicy = policy;


            chainBuilder.Build(cert);
            X509ChainElementCollection chainElements = chainBuilder.ChainElements;

            // If we don't have a trust chain, then we obviously have a problem...
            Assert.False(chainElements.IsNullOrEmpty(), string.Format("Can't find a trust chain: {0} ", cert.Subject));

            // walk the chain starting at the leaf and see if we hit any issues
            foreach (X509ChainElement chainElement in chainElements)
            {
                if (expectValidCert)
                {
                    AssertChainHasNoProblems(chainElement);
                }
                else
                {
                    AssertChainHasProblems(chainElement);
                }
            }
        }
Exemple #2
0
        public static X509Certificate2Collection FilterValidCerts(
            X509Certificate2Collection certs,
            X509ChainPolicy policy,
            X509ChainStatusFlags problemFlags,
            Action <Exception> notification)
        {
            var validCerts = new X509Certificate2Collection();

            if (certs == null)
            {
                return(null);
            }
            foreach (var cert in certs)
            {
                X509Chain chainBuilder = new X509Chain();
                chainBuilder.ChainPolicy = policy.Clone();

                try
                {
                    // We're using the system class as a helper to merely build the chain
                    // However, we will review each item in the chain ourselves, because we have our own rules...
                    chainBuilder.Build(cert);
                    X509ChainElementCollection chainElements = chainBuilder.ChainElements;

                    // If we don't have a trust chain, then we obviously have a problem...
                    if (chainElements.IsNullOrEmpty())
                    {
                        notification(new Exception(string.Format("Can't find a trust chain: {0} ", cert.Subject)));
                        return(null);
                    }


                    // walk the chain starting at the leaf and see if we hit any issues before the anchor
                    foreach (X509ChainElement chainElement in chainElements)
                    {
                        if (ChainElementHasProblems(chainElement, problemFlags))
                        {
                            //this.NotifyProblem(chainElement);

                            notification(new Exception(string.Format("Chain Element has problem {0}", Summarize(chainElement, problemFlags))));
                            // Whoops... problem with at least one cert in the chain. Stop immediately
                            return(null);
                        }
                    }
                }
                catch (Exception ex)
                {
                    //this.NotifyError(certificate, ex);
                    // just eat it and drop out to return null
                    notification(ex);
                    return(null);
                }
                validCerts.Add(cert);
            }
            return(validCerts);
        }
        /// <summary>
        /// Validates a certificate by walking the certificate chain for all trust anchor chain, validating the leaf certificate against the chain.
        /// </summary>
        /// <remarks>
        /// Chain buiding is implemented with P/Invoke to create a custom chain engine allowing CRL checking without installing the anchor was in a trusted location in the Windows certificate store.
        /// </remarks>
        /// <param name="certificate">The leaf <see cref="X509Certificate2"/> to validate</param>
        /// <param name="trustedRoots">The collection of certificates representing anchors or roots of trust.</param>
        /// <returns><c>true</c> if at least one anchor has a valid chain of certs that verify trust in the leaf certificate,
        /// <c>false</c> if no anchors validate trust in the leaf cert.</returns>
        public bool IsTrustedCertificate(X509Certificate2 certificate, X509Certificate2Collection trustedRoots)
        {
            if (certificate == null)
            {
                throw new ArgumentNullException("certificate");
            }

            // if there are no anchors we should always fail
            if (CollectionExtensions.IsNullOrEmpty(trustedRoots))
            {
                this.NotifyUntrusted(certificate);
                return(false);
            }

            try
            {
                var chainPolicy = ValidationPolicy.Clone();

                chainPolicy.ExtraStore.Add(trustedRoots);
                if (this.HasCertificateResolver)
                {
                    this.ResolveIntermediateIssuers(certificate, chainPolicy.ExtraStore);
                }

                X509Chain chainBuilder;

                if (IsNewerThanWin2008R2())
                {
                    using (X509ChainEngine secureChainEngine = new X509ChainEngine(trustedRoots.Enumerate()))
                    {
                        secureChainEngine.BuildChain(certificate, chainPolicy, out chainBuilder);
                    }
                }
                else
                {
                    chainBuilder             = new X509Chain();
                    chainBuilder.ChainPolicy = chainPolicy;
                    chainBuilder.Build(certificate);
                }

                // We're using the system class as a helper to build the chain
                // However, we will review each item in the chain ourselves, because we have our own rules...
                X509ChainElementCollection chainElements = chainBuilder.ChainElements;

                // If we don't have a trust chain, then we obviously have a problem...
                if (chainElements.IsNullOrEmpty())
                {
                    this.NotifyUntrusted(certificate);
                    return(false);
                }

                bool foundAnchor = false;

                // walk the chain starting at the leaf and see if we hit any issues before the anchor
                foreach (X509ChainElement chainElement in chainElements)
                {
                    bool isAnchor = trustedRoots.FindByThumbprint(chainElement.Certificate.Thumbprint) != null;
                    if (isAnchor)
                    {
                        // Found a valid anchor!
                        // Because we found an anchor we trust, we can skip trust
                        foundAnchor = true;
                        continue;
                    }

                    if (this.ChainElementHasProblems(chainElement))
                    {
                        this.NotifyProblem(chainElement);

                        // Whoops... problem with at least one cert in the chain. Stop immediately
                        return(false);
                    }
                }

                return(foundAnchor);
            }
            catch (Exception ex)
            {
                this.NotifyError(certificate, ex);
                // just eat it and drop out to return false
            }

            this.NotifyUntrusted(certificate);
            return(false);
        }