2012-05-23 32 views
7

私は、バイト配列として与えられたルートと中間証明書の束を持っており、私はエンドユーザ証明書も持っています。特定のエンドユーザー証明書の証明書チェーンを構築したい.NETフレームワークでは、次のようにできます:C#の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とプライマリを追加する必要があります。
  2. これで問題が解決しない場合は、別の方法で希望の証明書を指定してみます。
    • 目的の証明書(この例ではプライマリ)と常に一致する独自のセレクタを実装します。
    • holder.Certificateを設定する代わりに、ホルダーに1つ以上の基準を設定します。たとえば、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メソッドは私の方法(issuer == subject)よりも優れています。 – Dialecticus

+0

私はそれが両方を持っているほうがいいと思うので、例外を少なくします –

関連する問題