在C#中使用BouncyCastle构建证书链

我有一堆作为字节数组给出的根证书和中间证书,我也有最终用户证书。 我想为给定的最终用户证书构建证书链。 在.NET框架中,我可以这样做:

using System.Security.Cryptography.X509Certificates; static IEnumerable BuildCertificateChain(byte[] primaryCertificate, IEnumerable additionalCertificates) { X509Chain chain = new X509Chain(); foreach (var cert in additionalCertificates.Select(x => new X509Certificate2(x))) { chain.ChainPolicy.ExtraStore.Add(cert); } // You can alter how the chain is built/validated. chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck; chain.ChainPolicy.VerificationFlags = X509VerificationFlags.IgnoreWrongUsage; // Do the preliminary validation. var primaryCert = new X509Certificate2(primaryCertificate); if (!chain.Build(primaryCert)) throw new Exception("Unable to build certificate chain"); return chain.ChainElements.Cast(); } 

如何在BouncyCastle中做到这一点? 我尝试使用下面的代码,但我得到PkixCertPathBuilderException: No certificate found matching targetContraints

 using Org.BouncyCastle; using Org.BouncyCastle.Pkix; using Org.BouncyCastle.Utilities.Collections; using Org.BouncyCastle.X509; using Org.BouncyCastle.X509.Store; static IEnumerable BuildCertificateChainBC(byte[] primary, IEnumerable additional) { X509CertificateParser parser = new X509CertificateParser(); PkixCertPathBuilder builder = new PkixCertPathBuilder(); // Separate root from itermediate List intermediateCerts = new List(); HashSet rootCerts = new HashSet(); foreach (byte[] cert in additional) { X509Certificate x509Cert = parser.ReadCertificate(cert); // Separate root and subordinate certificates if (x509Cert.IssuerDN.Equivalent(x509Cert.SubjectDN)) rootCerts.Add(new TrustAnchor(x509Cert, null)); else intermediateCerts.Add(x509Cert); } // Create chain for this certificate X509CertStoreSelector holder = new X509CertStoreSelector(); holder.Certificate = parser.ReadCertificate(primary); // WITHOUT THIS LINE BUILDER CANNOT BEGIN BUILDING THE CHAIN intermediateCerts.Add(holder.Certificate); PkixBuilderParameters builderParams = new PkixBuilderParameters(rootCerts, holder); builderParams.IsRevocationEnabled = false; X509CollectionStoreParameters intermediateStoreParameters = new X509CollectionStoreParameters(intermediateCerts); builderParams.AddStore(X509StoreFactory.Create( "Certificate/Collection", intermediateStoreParameters)); PkixCertPathBuilderResult result = builder.Build(builderParams); return result.CertPath.Certificates.Cast(); } 

编辑 :我添加了修复我的问题的行。 它评论了全部大写。 案件结案。

我已经在Java中做了很多次。 鉴于API似乎是Java的直接端口,我将采取措施。

  1. 我很确定当你将商店添加到构建器时,该集合应该包含要构建的链中的所有证书,而不仅仅是中间证书。 所以应该添加rootCerts和primary。
  2. 如果这不能解决问题,我会尝试以不同的方式指定所需的证书。 你可以做以下两件事之一:
    • 实现您自己的Selector,它始终只匹配您想要的证书(示例中为primary)。
    • 而不是设置holder.Certificate,在holder上设置一个或多个条件。 例如,setSubject,setSubjectPublicKey,setIssuer。

这是我使用PkixCertPathBuilder时遇到的两个最常见的问题。

下面的代码没有回答你的问题(这是一个纯Java解决方案)。 我只是在输入了它没有回答你问题的一切之后才意识到! 我忘了BouncyCastle有一个C#版本! 哎呀。

它仍然可以帮助您推动自己的链构建器。 您可能不需要任何库或框架。

祝好运!

http://juliusdavies.ca/commons-ssl/src/java/org/apache/commons/ssl/X509CertificateChainBuilder.java

 /** * @param startingPoint the X509Certificate for which we want to find * ancestors * * @param certificates A pool of certificates in which we expect to find * the startingPoint's ancestors. * * @return Array of X509Certificates, starting with the "startingPoint" and * ending with highest level ancestor we could find in the supplied * collection. */ public static X509Certificate[] buildPath( X509Certificate startingPoint, Collection certificates ) throws NoSuchAlgorithmException, InvalidKeyException, NoSuchProviderException, CertificateException { LinkedList path = new LinkedList(); path.add(startingPoint); boolean nodeAdded = true; // Keep looping until an iteration happens where we don't add any nodes // to our path. while (nodeAdded) { // We'll start out by assuming nothing gets added. If something // gets added, then nodeAdded will be changed to "true". nodeAdded = false; X509Certificate top = (X509Certificate) path.getLast(); if (isSelfSigned(top)) { // We're self-signed, so we're done! break; } // Not self-signed. Let's see if we're signed by anyone in the // collection. Iterator it = certificates.iterator(); while (it.hasNext()) { X509Certificate x509 = (X509Certificate) it.next(); if (verify(top, x509.getPublicKey())) { // We're signed by this guy! Add him to the chain we're // building up. path.add(x509); nodeAdded = true; it.remove(); // Not interested in this guy anymore! break; } // Not signed by this guy, let's try the next guy. } } X509Certificate[] results = new X509Certificate[path.size()]; path.toArray(results); return results; } 

需要以下两种方法:

isSelfSigned():

 public static boolean isSelfSigned(X509Certificate cert) throws CertificateException, InvalidKeyException, NoSuchAlgorithmException, NoSuchProviderException { return verify(cert, cert.getPublicKey()); } 

并validation():

 public static boolean verify(X509Certificate cert, PublicKey key) throws CertificateException, InvalidKeyException, NoSuchAlgorithmException, NoSuchProviderException { String sigAlg = cert.getSigAlgName(); String keyAlg = key.getAlgorithm(); sigAlg = sigAlg != null ? sigAlg.trim().toUpperCase() : ""; keyAlg = keyAlg != null ? keyAlg.trim().toUpperCase() : ""; if (keyAlg.length() >= 2 && sigAlg.endsWith(keyAlg)) { try { cert.verify(key); return true; } catch (SignatureException se) { return false; } } else { return false; } }