2016-02-24 17 views
16

私のC#コードでは、SSL証明書を表すX509Certificate2オブジェクトがあります(ローカルストアまたはSSL経由の正常なHTTP要求から)。証明書にはローカルストアに存在する可能性のある中間証明書で署名されている可能性がありますので、X509Chain.Build()を使用するとおそらく動作しません。どの証明書が特定の証明書に署名するために使用されたかをプログラムでどのように見つけるか?

Firefoxの証明書ビューア(私はまだ使用可能なコードを持っていないので)の絵:詳細の下

enter image description here

、 "証明書階層" で、私はこれを参照してください。

  • DigiCertをハイアシュアランスEVルートCA
    • DigiCert SHA2拡張バリデーションサーバーCA
      • github.com

私のオブジェクトは、チェーン内の最低ラインを "github.com" を表します。真ん中の行(「DigiCert SHA2 Extended Validation Server CA」)をプログラムで特定する必要があります。

私の証明書に署名するために使用された証明書を特定するための拇印などを知るにはどうすればよいですか?

+4

[閉鎖についてのメタ質問](http://meta.stackoverflow.com/q/317570/1364007)のとおり、私はそこで詳細に答えます。返信するのに数分かかります。 –

+0

私は[回答済み](http://meta.stackoverflow.com/a/317581/1364007)です。遅延のお詫び –

+0

IssuerName'プロパティの何が問題なのですか? – erickson

答えて

10

この特定の場合(github.com)、X509Chain.Buildは、エンド証明書に(発行者情報アクセス拡張内の)発行者証明書の場所に関する情報が含まれているため動作します。

ただし、Thawteが発行者の証明書の所在地に関する明示的な情報を提供しないため、Thawte証明書などでこの機能が動作しないことがあります。また、証明書がローカル証明書ストアにインストールされている場合は、自動的に発行者を見つける方法はありません。 https://msdn.microsoft.com/en-us/library/system.net.servicepointmanager.servercertificatevalidationcallback.aspx

: -

オプション1 SSL証明書と連携して、SSLセッションを確立することができれば、SSL接続

しかし、あなたはServicePointManager.ServerCertificateValidationCallbackプロパティにリスナーを追加することにより、証明書を取得することができますRemoteCertificateValidationCallbackデリゲートにはいくつかのパラメータがあり、そのうちの1つはchainです。このパラメータには、サーバによって返されたSSL証明書チェーンが含まれています。リモートサーバーに発行者証明書が含まれている場合は、ChainElementsコレクションにその証明書が表示されます。このオブジェクトは、通常、いくつかの要素が含まれています:ChainElementsは、少なくとも二つの要素(例えば、リーフ証明書と提案発行者)が含まれている場合

  1. -Leaf Certificate 
        -Issuer Certificate 
         -(Optional Issuer certs when available) 
    

    だから、あなたは二つのことをチェックする必要があります。

  2. ChainElementsコレクションの最初の要素がコレクションにNotSignatureValidステータスを持たない場合。

    X509Certificate2 issuer = null; 
    if (
        chain.ChainElements.Count > 1 && 
        !chain.ChainElements[0].ChainElementStatus.Any(x => x.Status == X509ChainStatusFlags.NotSignatureValid)) { 
        issuer = chain.ChainElements[1].Certificate; 
    } 
    

    コードのこの部分を実行した後issuer変数がnullであれば、あなたは自動的に誰であるかを判断することはできません:あなたはこれらのチェックを実行するためにRemoteCertificateValidationCallbackデリゲートに次のコードを追加することができ

あなたの証明書の発行人。このプロセスにはさらにいくつかの研究が必要です。また、nullではない場合は、issuer変数に実際の発行者証明書が保持されます。

オプション2 - 検索

は、[OK]を、あなたのコメントによると、あなたは発行者証明書は、ローカル証明書ストアにインストールされているかどうかを判断するローカル証明書ストア。あなたの質問を読んで、私はそれを得ていませんでした。なぜあなたは実際にあなたが探しているものを推測する必要がありますか?最終的には、あなたが達成したいことを知っているか理解しているかどうかはまだ分かりません。見つける)

1)X509Certificate2Collection.Findメソッドを使用し、そのサブジェクト名

2で候補証明書を見つける:あなたは、発行者がローカルストアにインストールされているかどうかを検索したい場合は

は、次のアルゴリズムを使用することができます(ステップ1で検索された)候補リストにおいて、サブジェクト内の証明書のオーソリティ・キー識別子値と同じサブジェクト・キー識別子値を有するもの。対象におけるcert変数を格納する証明書(そのために発行者を検索する)と仮定

X509Certificate2Collection certs = new X509Certificate2Collection(); 
// grab candidates from CA and Root stores 
foreach (var storeName in new[] { StoreName.CertificateAuthority, StoreName.Root }) { 
    X509Store store = new X509Store(storeName, StoreLocation.CurrentUser); 
    store.Open(OpenFlags.ReadOnly); 
    certs.AddRange(store.Certificates); 
    store.Close(); 
} 
certs = certs.Find(X509FindType.FindBySubjectDistinguishedName, cert.Issuer, false); 
if (certs.Count == 0) { 
    Console.WriteLine("Issuer is not installed in the local certificate store."); 
    return; 
} 
var aki = cert.Extensions["2.5.29.35"]; 
if (aki == null) { 
    Console.WriteLine("Issuer candidates: "); 
    foreach (var candidate in certs) { 
     Console.WriteLine(candidate.Thumbprint); 
    } 
    return; 
} 
var match = Regex.Match(aki.Format(false), "KeyID=(.+)", RegexOptions.IgnoreCase); 
if (match.Success) { 
    var keyid = match.Groups[1].Value.Replace(" ", null).ToUpper(); 
    Console.WriteLine("Issuer candidates: "); 
    foreach (var candidate in certs.Find(X509FindType.FindBySubjectKeyIdentifier, keyid, false)) { 
     Console.WriteLine(candidate.Thumbprint); 
    } 
} else { 
    // if KeyID is not presented in the AKI extension, attempt to get serial number from AKI: 
    match = Regex.Match(aki.Format(false), "Certificate SerialNumber=(.+)", RegexOptions.IgnoreCase); 
    var serial = match.Groups[1].Value.Replace(" ", null); 
    Console.WriteLine("Issuer candidates: "); 
    foreach (var candidate in certs.Find(X509FindType.FindBySerialNumber, serial, false)) { 
     Console.WriteLine(candidate.Thumbprint); 
    } 
} 

。このアプローチには、シグネチャを検証しないために偽陽性を返す可能性があるため、問題があります。

2

私は「IssuerNameプロパティに何が問題なのですか?」と尋ねました。

返信は「署名者証明書の件名と一致する必要はなく、正確に正しい証明書であるか同じ主題である証明書であるかを知る方法はありません。

これは間違っています。

PKIX § 6.1は、「{1、...、n-1}のすべてのxについて、証明書xの主体は証明書x + 1の発行者です」と述べています。

サブセクションでは、「証明書のサブジェクト名をworking_issuer_nameに割り当てて」チェーンの次の証明書に対して、「…証明書の発行者名がworking_issuer_name」であることを確認することでこれを明確にしています。

同じ名前で異なるキーを持つ発行者証明書が多数ある可能性があるので、混乱するかもしれません。その場合、正しい署名鍵は、発行者のsubject key identifierを被験者の権限鍵識別子に一致させることによって識別することができる。一致するキー識別子では不十分ですが、の名前が最初に一致する必要があります。

これを手動で行う理由は不明です。あなたはpath-building library,provide all available intermediatesを渡すことができ、存在する場合は有効なチェーンを見つけることができます。

+0

'ExtraStore'プロパティは、必ずしもそうでない正しい証明書がある場合に役立ちます。 Thawteに言及したように、クライアントはWebブラウザで正常に動作するためにThawte CAの中間証明書を持つ必要はありません。なぜなら、この証明書はWebサーバーによって配信され、証明書の検証後に破棄されるからです。 – Crypt32

+0

@CryptoGuyあなたのコメントには関連性がありません。サーバーがあなたに中間体を送るなら、それを持って、それを 'ExtraStore'に入れることができます。それが "正しい"証明書であるかどうかは、検証によってテストするものです。あなたのポイントをより明確にすることはできますか? – erickson

+0

私はいくつかのコードを追加して私の反応を編集し、私のポイントを明確にしました。これが明らかになることを願っています。 – Crypt32

関連する問題