如果您知道哪些证书可以是要检查的证书的根证书和中间证书,则可以在对象ChainPolicy.ExtraStore
集合中加载根证书和中间证书的公钥。X509Chain
我的任务也是编写一个 Windows 窗体应用程序来安装证书,前提是它是根据我国政府已知的“国家根证书”颁发的。还有数量有限的 CA 被允许颁发证书以验证与国家 Web 服务的连接,所以我有一组有限的证书,它们可以在链中并且可能在目标机器上丢失。我在应用程序的子目录“cert”中收集了 CA 的所有公钥和政府根证书:
在 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 更新中,但理论上也可能丢失),我将友好名称和指纹与发布的值进行比较:
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 服务客户端是正确的)。