x509Chain.build 失败,certutil -verify 通过

x509Chain.build fails, certutil -verify passes

我有根证书和叶子。叶子有一个指向有效在线位置的 CRL URL OID 扩展。这样做:

certutil -verify .\leaf.cer

失败

ERROR: Verifying leaf certificate revocation status returned The revocation function was unable to check revocation because the revocation server was offline. 0x80092013 (-2146885613 CRYPT_E_REVOCATION_OFFLINE)

如果我这样做:

certutil -verify .\leaf.cer .\root.cer

然后验证通过,我在 Fiddler 中看到 CRL 从网上提取。

在我的 C# 代码中,我这样做:

X509Chain childCertChain = new X509Chain();
childCertChain.ChainPolicy.ExtraStore.Add(rootCert);
childCertChain.ChainPolicy.RevocationMode = X509RevocationMode.Online;
childCertChain.ChainPolicy.UrlRetrievalTimeout = TimeSpan.FromSeconds(10);
if (!childCertChain.Build(childCert))
        {
            // The root cert is not in the windows certificate store, that is fine
            if (childCertChain.ChainStatus.Length != 1 || childCertChain.ChainStatus.First().Status != X509ChainStatusFlags.UntrustedRoot)
            {
                throw new Exception("Certificate validation error.");
            }
        }

这会触发我的异常,即使 chainElements 将正确填充 2 个证书,ChainStatus 也会显示:

OfflineRevocation, RevocationStatusUnknown

我也不会在 Fiddler 中看到任何网络请求。我可以在给定 URL 的情况下以编程方式下载 CRL,因此它不是我的调试环境 AFAIK。有什么想法可以让 x509Chain.Build 成功吗?

我已经从 PC 上阅读了您的代码并了解了问题所在:您的根证书在您的系统上不受信任。 Windows 当根证书不受信任时,CryptoAPI 会抛出 CERT_E_UNTRUSTEDROOT。与此同时,CryptoAPI 终止撤销检查并抛出两个附加错误:CRYPT_E_NO_REVOCATION_CHECKCERT_E_UNTRUSTEDROOT,因为撤销检查被跳过。除了不受信任的根之外,CryptoAPI 还跳过其他检查(例如约束),但不报告它们。一切正确,符合预期。

您试图允许不受信任的 root,但操作不正确,因为这样您会跳过其他检查(如前一段所述)并且您的逻辑容易受到攻击。

您可以在链设置中排除不受信任的根异常并强制 CryptoAPI 继续验证,如果没有发现其他错误则 return 成功,但我强烈建议您不要这样做,因为这样您就可以接受任何类型的MITM

您有两个选择:

  1. 使根证书受机器(本地系统)信任。这可能是不可能的。
  2. 直接调用CertCreateCertificateChainEngine函数,将你的根证书放入CERT_CHAIN_ENGINE_CONFIG结构的hRestrictedTrust成员中。

如果您使用 Windows,第二种方法是最安全可靠的。截至目前,.NET 的 X509Chain 并未实现此功能。它需要额外的编码,但没有太多选择。