X509Certificate2.Verify()总是返回false

24

遇到一个奇怪的问题,X509Certificate2.Verify()对于有效的证书返回false。也许有人之前已经遇到过这种奇怪的情况并且可以为此提供一些帮助。

我正在使用openssl生成用于测试目的的客户端证书。 我创建了一个根CA,基于该根CA生成客户端证书,并将根CA添加到其链中。

我将根CA和客户端证书加载到本地证书存储中,看起来没问题,但当我从我的NUnit代码加载它来测试X509Certificate2.Verify()时,它总是返回false。

enter image description here

下面是从存储中加载证书的代码:

        X509Store store = new X509Store(StoreName.My);
        string thumbprint = "60 d1 38 95 ee 3a 73 1e 7e 0d 70 68 0f 2d d0 69 1e 9a eb 72";
        store.Open(OpenFlags.ReadOnly);
        var mCert = store.Certificates.Find(
                                X509FindType.FindByThumbprint,
                                thumbprint,
                                true
                              ).OfType<System.Security.Cryptography.X509Certificates.X509Certificate>().FirstOrDefault();
        if(mCert != null)
        {
            var testClientCert = new X509Certificate2(mCert);
        }

这是我刚刚生成的客户端证书: (CRL网址可以从我的本地计算机正确访问)

-----BEGIN CERTIFICATE-----
MIIC7jCCAlegAwIBAgIBATANBgkqhkiG9w0BAQUFADBtMR0wGwYDVQQKExRWaXRh
bEhlYWx0aCBTb2Z0d2FyZTElMCMGA1UECxMcVml0YWxIZWFsdGggU29mdHdhcmUg
Um9vdCBDQTElMCMGA1UEAxMcVml0YWxIZWFsdGggU29mdHdhcmUgUm9vdCBDQTAe
Fw0xNTAyMjcwODQ2MzNaFw0xNjAyMjcwODQ2MzNaMEUxHTAbBgNVBAoTFFZpdGFs
SGVhbHRoIFNvZnR3YXJlMREwDwYDVQQLEwhQbGF0Zm9ybTERMA8GA1UEAxMIVGVz
dFVzZXIwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAOkfyjX0PSnRYrBbCC8u
rw7IiFdAUj6frPKEmt0TLAR/4g+NazKdGjRRqxE9mNwX/2zGhIcucfGDVwPtOtiV
opicQEzGiSQkvAc+473MN5D6j3XtBYblALMeMyEYoh3LnHO4K+6kV6XE4BXV/2lV
mAVgXGkZzaayd40DLvg48vPlAgMBAAGjgcUwgcIwCQYDVR0TBAIwADARBglghkgB
hvhCAQEEBAMCB4AwCwYDVR0PBAQDAgWgMBMGA1UdJQQMMAoGCCsGAQUFBwMCMDEG
CWCGSAGG+EIBDQQkFiJPcGVuU1NMIENlcnRpZmljYXRlIGZvciBTU0wgQ2xpZW50
ME0GA1UdHwRGMEQwQqBAoD6GPGh0dHA6Ly9wbGF0Zm9ybWRhc2hib2FyZC5ubC52
aXRhbGhlYWx0aC5sb2NhbC9wb3J0YWwvY3JsLmNybDANBgkqhkiG9w0BAQUFAAOB
gQBXYSmZaVu6vnyl94SO4qpNOutsUm4p7fQHehljhZ+aRrXE10rivWCt4g0k961E
PDsp4J0DR6uth6et42pBp8v2gFIGSQY/F7NhmOAsOJvM7z0oIBxMLcclIDTygbRp
KjZZpNjvf+YJasbidosiL4VSeRiCZ+HPzvKDb3wNeafoZA==
-----END CERTIFICATE-----

这里是当我从浏览器访问时下载的CRL文件:

-----BEGIN X509 CRL-----
MIIBMjCBnDANBgkqhkiG9w0BAQUFADBtMR0wGwYDVQQKExRWaXRhbEhlYWx0aCBT
b2Z0d2FyZTElMCMGA1UECxMcVml0YWxIZWFsdGggU29mdHdhcmUgUm9vdCBDQTEl
MCMGA1UEAxMcVml0YWxIZWFsdGggU29mdHdhcmUgUm9vdCBDQRcNMTQwODA3MTQz
OTIyWhcNMTQwOTA2MTQzOTIyWjANBgkqhkiG9w0BAQUFAAOBgQA8MSxAorbxpdDm
1IA2Aqjb/OkZydua1Tm5k5KtHknI4zyYPZb3GzO0eRygpKBSAqtYkxDI6eCv6xgf
+anXT56md+cPGZ+2YvSicxqwP2GL2kymc9mVMTiQieioS1/7apjCIjZEgWxqf3Up
zvy/kNQRg3lII8hYu0idGs9byKZJFQ==
-----END X509 CRL-----

有几个与此相关的问题,比如这个:http://stackoverflow.com/questions/1277791/x509certificate2-validation-on-web-service 你试过其中任何一个吗? - weston
@weston 是的,确实如此。 我查看了以下链接,它似乎与我的问题相似,https://dev59.com/UGLVa4cB1Zd3GeqPyaYi?rq=1 但是我可以从浏览器中轻松访问客户端证书中的CRL url,并且我正在使用Nunits测试,该测试在本地Windows用户帐户下运行,我用它来安装Cert及其RootCA到当前Cert存储区域以供此Windows用户使用。 - Deb
请将此证书导出到文件并向我们显示certutil命令输出:certutil -verify -urlfetch <path>\file.cer - Crypt32
@CryptoGuy非常感谢您的回答 - 非常有帮助。我按照您的要求做了,这是输出结果:certutil命令输出的截图链接 - Deb
谢谢,这很有帮助,但还不够。请更新您的帖子并包括颁发者证书。 - Crypt32
1个回答

40
根据 X509Certificate2.Verify 文件的文档,该方法为证书构建了一个简单的链并对该链应用基本策略。如果需要更多有关失败的信息,请使用 X509Chain 对象直接验证证书。因此,我将尝试使用以下代码构建链(请将 Log 方法替换为您自己的实现,我正在使用 Console.Writeline)。
X509Chain chain = new X509Chain();

try
{
    var chainBuilt = chain.Build(testClientCert );
    Log(string.Format("Chain building status: {0}", chainBuilt));

    if (chainBuilt == false)
        foreach (X509ChainStatus chainStatus in chain.ChainStatus)
            Log(string.Format("Chain error: {0} {1}", chainStatus.Status, chainStatus.StatusInformation));
}
catch (Exception ex)
{
    Log(ex.ToString());
}

这段代码将告诉您证书无法验证的原因。如果需要调整证书链策略,则设置chain.ChainPolicy属性,即:

chain.ChainPolicy = new X509ChainPolicy()
{
    RevocationMode = X509RevocationMode.NoCheck,
    VerificationFlags = X509VerificationFlags.IgnoreNotTimeValid,
    UrlRetrievalTimeout = new TimeSpan(0, 1, 0)
};

是的,没错。但我首先想要进行基本检查,以确定证书是否有效,然后再继续检查整个链。在基本验证通过证书之前,我不想浪费时间检查整个链(顺便说一句,在我的情况下可能非常大),我认为这是一个相当简单和有效的用例。 - Deb
1
这段代码帮助我找出了为什么Verify()返回false的原因。chainStatus.StatusInformation返回了以下信息:“撤销功能无法检查证书的撤销状态。”在你的情况下,状态可能不同,但我相信上述代码对于故障排除是有用的。 - user3308241
4
@Deb Verify会构建完整的链式结构,但会将其丢弃。你可以考虑自己构建它(前提是在完成后使用Dispose(4.6)或在其他情况下调用Reset来清除它)。 - bartonjs
但是在Mono中,chain.Build总是返回true。 - sakiM

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接