2012-05-23 37 views
7

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

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>(); 
} 

编辑:我补充说,固定我的问题就行了。它评论全部大写。案件结案。

回答

7

我已经在Java中做了很多次。鉴于该API似乎是Java的直通端口,我会采取刺。

  1. 我非常确定,当您将商店添加到生成器时,该集合预计将包含要构建的链中的所有证书,而不仅仅是中间商。所以应该添加rootCerts和primary。
  2. 如果这并不能解决问题,我会尝试以不同的方式指定所需的证书。您可以执行以下两项操作之一:
    • 实现您自己的选择器,该选择器始终只与您所需的证书相匹配(示例中的主要部分)。
    • 而不是设置holder.Certificate,设置一个或多个持有人的标准。例如,setSubject,setSubjectPublicKey,setIssuer。

这些是两种最常见的问题,我曾与PkixCertPathBuilder。

+1

第一个回答的一半人它对我来说。将我的最终用户证书添加到我称为中间商店的解决方案中。 – Dialecticus

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; 
    } 
} 
+0

有一件事是肯定的,你的isSelfSigned方法比我的更好(发行者==主题)。 – Dialecticus

+0

我认为两者都会更好,所以你会抛出更少的例外 –

相关问题