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); }
public static void VerifyCloneBehavior() { using (X509Certificate2 cert = new X509Certificate2(TestData.SelfSigned1PemBytes)) using (X509Certificate2 cert2 = new X509Certificate2(TestData.SelfSigned1PemBytes)) { X509ChainPolicy source = new X509ChainPolicy(); source.CertificatePolicy.Add(s_timestampEku); source.ApplicationPolicy.Add(s_emailProtectionEku); source.ExtraStore.Add(cert); source.CustomTrustStore.Add(cert2); source.DisableCertificateDownloads = true; source.VerificationTime = DateTime.MinValue; source.VerificationTimeIgnored = false; source.UrlRetrievalTimeout = TimeSpan.MaxValue; source.VerificationFlags = X509VerificationFlags.IgnoreCtlNotTimeValid; source.RevocationMode = X509RevocationMode.Offline; source.RevocationFlag = X509RevocationFlag.EntireChain; X509ChainPolicy clone = source.Clone(); Assert.Equal(source.VerificationTime, clone.VerificationTime); Assert.Equal(source.VerificationTimeIgnored, clone.VerificationTimeIgnored); Assert.Equal(source.VerificationFlags, clone.VerificationFlags); Assert.Equal(source.RevocationFlag, clone.RevocationFlag); Assert.Equal(source.RevocationMode, clone.RevocationMode); Assert.Equal(source.UrlRetrievalTimeout, clone.UrlRetrievalTimeout); Assert.Equal(source.DisableCertificateDownloads, clone.DisableCertificateDownloads); Assert.NotSame(source.CertificatePolicy, clone.CertificatePolicy); Assert.Equal(source.CertificatePolicy, clone.CertificatePolicy); Assert.Same(source.CertificatePolicy[0], clone.CertificatePolicy[0]); Assert.NotSame(source.ApplicationPolicy, clone.ApplicationPolicy); Assert.Equal(source.ApplicationPolicy, clone.ApplicationPolicy); Assert.Same(source.ApplicationPolicy[0], clone.ApplicationPolicy[0]); Assert.NotSame(source.ExtraStore, clone.ExtraStore); Assert.Equal(source.ExtraStore, clone.ExtraStore); Assert.Same(source.ExtraStore[0], clone.ExtraStore[0]); Assert.NotSame(source.CustomTrustStore, clone.CustomTrustStore); Assert.Equal(source.CustomTrustStore, clone.CustomTrustStore); Assert.Same(source.CustomTrustStore[0], clone.CustomTrustStore[0]); Assert.NotSame(source.ExtraStore[0], clone.CustomTrustStore[0]); } }
/// <summary> /// Validates a certificate by walking the certificate chain for all trust anchor chain, validating the leaf certificate against the chain. /// </summary> /// <remarks>Currently, all intermediate certificates must be stored in the system.</remarks> /// <param name="certificate">The leaf <see cref="X509Certificate2"/> to validate</param> /// <param name="anchors">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 anchors) { if (certificate == null) { throw new ArgumentNullException("certificate"); } // if there are no anchors we should always fail if (CollectionExtensions.IsNullOrEmpty(anchors)) { this.NotifyUntrusted(certificate); return(false); } X509Chain chainBuilder = new X509Chain(); chainBuilder.ChainPolicy = m_policy.Clone(); chainBuilder.ChainPolicy.ExtraStore.Add(anchors); if (this.HasCertificateResolver) { this.ResolveIntermediateIssuers(certificate, chainBuilder.ChainPolicy.ExtraStore); } 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(certificate); 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 = (anchors.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); } } if (foundAnchor) { return(true); } return(false); } catch (Exception ex) { this.NotifyError(certificate, ex); // just eat it and drop out to return false } this.NotifyUntrusted(certificate); return(false); }