15

私はバイト配列として与えられたたくさんのルート証明書と中間証明書を持っています、そして私はエンドユーザー証明書も持っています。特定のエンドユーザー証明書の証明書チェーンを構築したいと思います。.NET Frameworkでは、次のように実行できます。

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

編集:問題を修正した行を追加しました。すべて大文字でコメントされています。名探偵コナン

4

2 に答える 2

9

私はこれをJavaで何度も行ってきました。APIがJavaのストレートポートのように見えることを考えると、私は突き刺します。

  1. ストアをビルダーに追加すると、そのコレクションには、中間のものだけでなく、構築されるチェーン内のすべての証明書が含まれることが期待されます。したがって、rootCertsとprimaryを追加する必要があります。
  2. それでも問題が解決しない場合は、目的の証明書を別の方法で指定してみます。次の2つのいずれかを実行できます。
    • 常に目的の証明書(例ではプライマリ)にのみ一致する独自のセレクターを実装します。
    • holder.Certificateを設定する代わりに、holder.Certificateに1つ以上の基準を設定します。たとえば、setSubject、setSubjectPublicKey、setIssuerです。

これらは、PkixCertPathBuilderで発生した最も一般的な2つの問題です。

于 2012-05-28T17:28:08.520 に答える
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;
}

次の2つの追加メソッドが必要です。

isSelfSigned():

public static boolean isSelfSigned(X509Certificate cert)
    throws CertificateException, InvalidKeyException,
    NoSuchAlgorithmException, NoSuchProviderException {

    return verify(cert, cert.getPublicKey());
}

そしてverify():

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;
    }
}
于 2012-05-30T18:33:23.670 に答える