在 C# 中的 BouncyCastle 中构建证书链
本文关键字:构建 证书链 BouncyCastle 中的 | 更新日期: 2023-09-27 18:35:18
我有一堆以字节数组形式给出的根证书和中间证书,我也有最终用户证书。我想为给定的最终用户证书构建证书链。在.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>();
}
如何在充气城堡中做到这一点?我尝试使用下面的代码,但得到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>();
}
编辑:我添加了解决我问题的行。它以所有大写字母进行注释。 案件已结案。
我在 Java 中做过很多次。鉴于 API 似乎是 Java 的直接端口,我会试一试。
- 我很确定当您将商店添加到构建器时,该集合应包含要构建的链中的所有证书,而不仅仅是中间证书。所以应该添加rootCerts和prime。
- 如果这本身不能解决问题,我会尝试以不同的方式指定所需的证书。您可以执行以下两项操作之一:
- 实现您自己的选择器,该选择器始终仅与所需的证书(示例中的主要证书)匹配。
- 而不是设置支架。证书,对持有人设置一个或多个标准。例如,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());
}
并验证():
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;
}
}