/// <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; } // walk the chain starting at the leaf and see if we hit any issues before the anchor foreach (X509ChainElement chainElement in chainElements) { if (this.ChainElementHasProblems(chainElement)) { this.NotifyProblem(chainElement); // Whoops... problem with at least one cert in the chain. Stop immediately return false; } bool isAnchor = (anchors.FindByThumbprint(chainElement.Certificate.Thumbprint) != null); if (isAnchor) { // Found a valid anchor! // Because we found an anchor we trust, we can now trust the entire trust chain return true; } } } catch(Exception ex) { this.NotifyError(certificate, ex); // just eat it and drop out to return false } this.NotifyUntrusted(certificate); return (false); }
private void VerifyValidCert(X509Certificate2Collection source, X509Certificate2Collection cached) { Assert.NotNull(source); Assert.NotNull(cached); Assert.True(cached.Count > 0); Assert.Equal(source.Count, cached.Count); source.Enumerate().All((x) => cached.FindByThumbprint(x.Thumbprint) != null); cached.Enumerate().All((x) => source.FindByThumbprint(x.Thumbprint) != null); }