我有一堆以字节数组形式提供的根证书和中间证书,我也有最终用户证书。我想为给定的最终用户证书构建证书链。在.NET框架中,我可以这样做:
using System.Security.Cryptography.X509Certificates;
static IEnumerable<X509ChainElement>
BuildCertificateChain(byte[] primaryCertificate, IEnumerable<byte[]> 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<X509ChainElement>();
}
如何在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<X509Certificate> BuildCertificateChainBC(byte[] primary, IEnumerable<byte[]> additional)
{
X509CertificateParser parser = new X509CertificateParser();
PkixCertPathBuilder builder = new PkixCertPathBuilder();
// Separate root from itermediate
List<X509Certificate> intermediateCerts = new List<X509Certificate>();
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<X509Certificate>();
}
修改:我添加了修复问题的行。它评论了全部大写。案件结案。
答案 0 :(得分:8)
我已经在Java中做了很多次。鉴于API似乎是Java的直接端口,我将采取刺激。
这是我使用PkixCertPathBuilder时遇到的两个最常见的问题。
答案 1 :(得分:6)
下面的代码没有回答您的问题(这是一个纯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());
}
并验证():
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;
}
}