確認する証明書のルート証明書および中間証明書になり得る証明書がわかっている場合は、ルート証明書および中間証明書の公開鍵をオブジェクトのChainPolicy.ExtraStore
コレクションにロードできX509Chain
ます。
私の仕事は、私の国の政府の既知の "National Root certificate" に依存して発行された場合にのみ、証明書をインストールするための Windows Forms アプリケーションを作成することでもありました。国内の Web サービスへの接続を認証するための証明書を発行できる CA の数も限られているため、チェーンに含めることができ、ターゲット マシンで欠落している可能性がある証明書のセットは限られていました。CA のすべての公開鍵と政府のルート証明書を、アプリケーションのサブディレクトリ「cert」に集めました。

Visual Studio で、ディレクトリ cert をソリューションに追加し、このディレクトリ内のすべてのファイルを埋め込みリソースとしてマークしました。これにより、C# ライブラリ コードで「信頼できる」証明書のコレクションを列挙し、発行者証明書がインストールされていない場合でも証明書をチェックするためのチェーンを構築することができました。この目的のために、X509Chain のラッパー クラスを作成しました。
private class X509TestChain : X509Chain, IDisposable
{
public X509TestChain(X509Certificate2 oCert)
: base(false)
{
try
{
ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;
ChainPolicy.VerificationFlags = X509VerificationFlags.AllowUnknownCertificateAuthority;
if (!Build(oCert) || (ChainElements.Count <= 1))
{
Trace.WriteLine("X509Chain.Build failed with installed certificates.");
Assembly asmExe = System.Reflection.Assembly.GetEntryAssembly();
if (asmExe != null)
{
string[] asResources = asmExe.GetManifestResourceNames();
foreach (string sResource in asResources)
{
if (sResource.IndexOf(".cert.") >= 0)
{
try
{
using (Stream str = asmExe.GetManifestResourceStream(sResource))
using (BinaryReader br = new BinaryReader(str))
{
byte[] abResCert = new byte[str.Length];
br.Read(abResCert, 0, abResCert.Length);
X509Certificate2 oResCert = new X509Certificate2(abResCert);
Trace.WriteLine("Adding extra certificate: " + oResCert.Subject);
ChainPolicy.ExtraStore.Add(oResCert);
}
}
catch (Exception ex)
{
Trace.Write(ex);
}
}
}
}
if (Build(oCert) && (ChainElements.Count > 1))
Trace.WriteLine("X509Chain.Build succeeded with extra certificates.");
else
Trace.WriteLine("X509Chain.Build still fails with extra certificates.");
}
}
catch (Exception ex)
{
Trace.Write(ex);
}
}
public void Dispose()
{
try
{
Trace.WriteLine(string.Format("Dispose: remove {0} extra certificates.", ChainPolicy.ExtraStore.Count));
ChainPolicy.ExtraStore.Clear();
}
catch (Exception ex)
{
Trace.Write(ex);
}
}
}
呼び出し関数で、不明な証明書が国のルート証明書から派生しているかどうかを正常に確認できるようになりました。
bool bChainOK = false;
using (X509TestChain oChain = new X509TestChain(oCert))
{
if ((oChain.ChainElements.Count > 0)
&& IsPKIOverheidRootCert(oChain.ChainElements[oChain.ChainElements.Count - 1].Certificate))
bChainOK = true;
if (!bChainOK)
{
TraceChain(oChain);
sMessage = "Root certificate not present or not PKI Overheid (Staat der Nederlanden)";
return false;
}
}
return true;
全体像を完成させるために、ルート証明書 (通常は Windows Update に含まれているためインストールされますが、理論的には不足している可能性もあります) を確認するために、フレンドリ名と拇印を公開された値と比較します。
private static bool IsPKIOverheidRootCert(X509Certificate2 oCert)
{
if (oCert != null)
{
string sFriendlyName = oCert.FriendlyName;
if ((sFriendlyName.IndexOf("Staat der Nederlanden") >= 0)
&& (sFriendlyName.IndexOf(" Root CA") >= 0))
{
switch (oCert.Thumbprint)
{
case "101DFA3FD50BCBBB9BB5600C1955A41AF4733A04": // Staat der Nederlanden Root CA - G1
case "59AF82799186C7B47507CBCF035746EB04DDB716": // Staat der Nederlanden Root CA - G2
case "76E27EC14FDB82C1C0A675B505BE3D29B4EDDBBB": // Staat der Nederlanden EV Root CA
return true;
}
}
}
return false;
}
このチェックが安全かどうかはまったくわかりませんが、私の場合、Windows フォーム アプリケーションのオペレーターは、インストールされる有効な証明書にアクセスできることを確信しています。ソフトウェアの目的は、証明書リストをフィルタリングして、コンピュータのマシン ストアに正しい証明書のみをインストールできるようにすることです (ソフトウェアは、中間証明書とルート証明書の公開鍵もインストールして、 Web サービス クライアントが正しい)。