I have a root certificate and a leaf. The leaf has a CRL URL OID extension which points to a valid online location. Doing this:
certutil -verify .\leaf.cer
fails with
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)
If I do this:
certutil -verify .\leaf.cer .\root.cer
Then verification passes, and I see the CRL getting pulled from online in Fiddler.
In my C# code, I do this:
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.");
}
}
This will hit my exception, and even though chainElements will be correctly filled with the 2 certs, ChainStatus will show:
OfflineRevocation, RevocationStatusUnknown
I also will not see any web requests in Fiddler. I can programmatically download the CRL given the URL so it's not my debug environment AFAIK. Any ideas how to get x509Chain.Build to succeed?
I've read your code from PC and figured what's up: your root certificate is not trusted on your system. Windows CryptoAPI throws CERT_E_UNTRUSTEDROOT
when root certificate is not trusted. Along with this, CryptoAPI terminates revocation checking and throw two addition errors: CRYPT_E_NO_REVOCATION_CHECK
and CERT_E_UNTRUSTEDROOT
, because revocation checking was skipped. In addition with untrusted root, CryptoAPI skips other checks (such as constraints, for example), but do not report them. Everything is correct and as expected.
You are trying to allow untrusted root, but do it incorrectly, because this way you skip other checks (as mentioned in previous paragraph) and your logic is vulnerable.
You can exclude untrusted root exception in chain settings and force CryptoAPI to continue validation and return success if no other errors found, but I strongly recommend to not do that, because then you are open to any kind of MITM.
You have two options:
CertCreateCertificateChainEngine
function directly and put your root certificate in hRestrictedTrust
member of CERT_CHAIN_ENGINE_CONFIG
structure.If you are on Windows, 2nd approach is the most secure and reliable. As of now, .NET's X509Chain
doesn't implement this functionality. It requires extra coding, but there are no much alternatives.
User contributions licensed under CC BY-SA 3.0