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_CHECK
和 CERT_E_UNTRUSTEDROOT
,因为撤销检查被跳过。除了不受信任的根之外,CryptoAPI 还跳过其他检查(例如约束),但不报告它们。一切正确,符合预期。
您试图允许不受信任的 root,但操作不正确,因为这样您会跳过其他检查(如前一段所述)并且您的逻辑容易受到攻击。
您可以在链设置中排除不受信任的根异常并强制 CryptoAPI 继续验证,如果没有发现其他错误则 return 成功,但我强烈建议您不要这样做,因为这样您就可以接受任何类型的MITM
您有两个选择:
- 使根证书受机器(本地系统)信任。这可能是不可能的。
- 直接调用
CertCreateCertificateChainEngine
函数,将你的根证书放入CERT_CHAIN_ENGINE_CONFIG
结构的hRestrictedTrust
成员中。
如果您使用 Windows,第二种方法是最安全可靠的。截至目前,.NET 的 X509Chain
并未实现此功能。它需要额外的编码,但没有太多选择。
我有根证书和叶子。叶子有一个指向有效在线位置的 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_CHECK
和 CERT_E_UNTRUSTEDROOT
,因为撤销检查被跳过。除了不受信任的根之外,CryptoAPI 还跳过其他检查(例如约束),但不报告它们。一切正确,符合预期。
您试图允许不受信任的 root,但操作不正确,因为这样您会跳过其他检查(如前一段所述)并且您的逻辑容易受到攻击。
您可以在链设置中排除不受信任的根异常并强制 CryptoAPI 继续验证,如果没有发现其他错误则 return 成功,但我强烈建议您不要这样做,因为这样您就可以接受任何类型的MITM
您有两个选择:
- 使根证书受机器(本地系统)信任。这可能是不可能的。
- 直接调用
CertCreateCertificateChainEngine
函数,将你的根证书放入CERT_CHAIN_ENGINE_CONFIG
结构的hRestrictedTrust
成员中。
如果您使用 Windows,第二种方法是最安全可靠的。截至目前,.NET 的 X509Chain
并未实现此功能。它需要额外的编码,但没有太多选择。