web-dev-qa-db-ja.com

C#どうすればルートCA証明書(x509)チェーンを検証できますか?

3つの証明書(Base64形式)があるとしましょう

Root
 |
 --- CA
     |
     --- Cert (client/signing/whatever)

C#で証明書と証明書パス/チェーンを検証するにはどうすればよいですか? (これらの3つの証明書はすべて私のコンピューターの証明書ストアにない場合があります)

編集:BouncyCastleには検証機能があります。しかし、私はサードパーティのライブラリを使用しないようにしています。

    byte[] b1 = Convert.FromBase64String(x509Str1);
    byte[] b2 = Convert.FromBase64String(x509Str2);
    X509Certificate cer1 = 
        new X509CertificateParser().ReadCertificate(b1);
    X509Certificate cer2 =
        new X509CertificateParser().ReadCertificate(b2);
    cer1.Verify(cer2.GetPublicKey());

Cer1がcert2(CAまたはルート)によって署名されていない場合、例外が発生します。これがまさに私が欲しいものです。

20
Jacob

_X509Chain_ クラスはこれを行うように設計されており、チェーン構築プロセスの実行方法をカスタマイズすることもできます。

_static bool VerifyCertificate(byte[] primaryCertificate, IEnumerable<byte[]> additionalCertificates)
{
    var 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 validation.
    var primaryCert = new X509Certificate2(primaryCertificate);
    return chain.Build(primaryCert);
}
_

_X509Chain_には、必要に応じて、Build() == falseの後に検証エラーに関する追加情報が含まれます。

Edit:これは、CAが有効であることを確認するだけです。チェーンが同一であることを確認したい場合は、サムプリントを手動で確認できます。次のメソッドを使用して、認証チェーンが正しいことを確認できます。これは、チェーンが次の順序であると想定しています:..., INTERMEDIATE2, INTERMEDIATE1 (Signer of INTERMEDIATE2), CA (Signer of INTERMEDIATE1)

_static bool VerifyCertificate(byte[] primaryCertificate, IEnumerable<byte[]> additionalCertificates)
{
    var 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))
        return false;

    // Make sure we have the same number of elements.
    if (chain.ChainElements.Count != chain.ChainPolicy.ExtraStore.Count + 1)
        return false;

    // Make sure all the thumbprints of the CAs match up.
    // The first one should be 'primaryCert', leading up to the root CA.
    for (var i = 1; i < chain.ChainElements.Count; i++)
    {
        if (chain.ChainElements[i].Certificate.Thumbprint != chain.ChainPolicy.ExtraStore[i - 1].Thumbprint)
            return false;
    }

    return true;
}
_

完全なCAチェーンを持っていないため、これをテストすることはできません。コードをデバッグしてステップ実行するのが最善です。

28