2

我正在尝试编写一些代码来验证网站的证书是否有效(例如,不完整的链.badssl.com)。我遇到的这个问题是,在证书验证期间,windows(或 dotnet 框架)似乎过于有用,甚至可以修复链。当链到达我的验证证书回调函数时,链与主机服务器不同并且是有效的。有谁知道绕过似乎是cryptoapi的链修复功能并仅使用“原样”证书来验证链的方法?

我已经尝试过使用 httpclient 和 sslstream 的验证证书回调。两者都说链是有效的而不是无效的。

例如,curl 请求失败,如果证书链无效,我希望我的请求失败。

 curl get https://incomplete-chain.badssl.com
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:--  0:00:02 --:--:--     0
curl: (6) Could not resolve host: get
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
curl: (60) SSL certificate problem: unable to get local issuer certificate
More details here: https://curl.se/docs/sslcerts.html

curl failed to verify the legitimacy of the server and therefore could not
establish a secure connection to it. To learn more about this situation and
how to fix it, please visit the web page mentioned above.

openssl 也正确地将这些不完整链显示为无效

$ openssl s_client -showcerts -connect incomplete-chain.badssl.com:443
CONNECTED(00000188)
---
Certificate chain
 0 s:C = US, ST = California, L = Walnut Creek, O = Lucas Garron Torres, CN = *.badssl.com
   i:C = US, O = DigiCert Inc, CN = DigiCert SHA2 Secure Server CA
-----BEGIN CERTIFICATE-----
the certificate 
-----END CERTIFICATE-----
---
Server certificate
subject=C = US, ST = California, L = Walnut Creek, O = Lucas Garron Torres, CN = *.badssl.com

issuer=C = US, O = DigiCert Inc, CN = DigiCert SHA2 Secure Server CA

---
No client certificate CA names sent
Peer signing digest: SHA512
Peer signature type: RSA
Server Temp Key: ECDH, P-256, 256 bits
---
SSL handshake has read 2414 bytes and written 455 bytes
Verification error: unable to verify the first certificate
---

编辑:这是使用 WebRequest 的尝试(https://dotnetfiddle.net/2aybuI

using System;
using System.Net;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;

public class Program
{
    public static void Main(string[] args)
    {
        var request = (HttpWebRequest)WebRequest.Create("https://incomplete-chain.badssl.com");
        request.AllowAutoRedirect = false;
        request.ServerCertificateValidationCallback = ServerCertificateValidationCallback;
        var response = (HttpWebResponse)request.GetResponse();
        response.Close();
    }

    private static bool ServerCertificateValidationCallback(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
    {
        if (sslPolicyErrors != SslPolicyErrors.None)
        {
            return false;
        }

        var newChain = new X509Chain();
        newChain.ChainPolicy.DisableCertificateDownloads = true;

        // Skip the leaf cert and stop short of the root cert.      
        X509ChainElementCollection chainElements = chain.ChainElements;
        for (int i = 1; i < chainElements.Count - 1; i++)
        {
            newChain.ChainPolicy.ExtraStore.Add(chainElements[i].Certificate);
        }

        var result = newChain.Build(chainElements[0].Certificate);

        // This is True and I want it to be False
        Console.WriteLine($"This is {result} and I want it to be False");
        return result;
    }
}

这是两个似乎有类似问题但没有解决方案的老问题。

  1. 具有不完整链的 SSL 证书,在 .NET Core 2.2 中通过验证

  2. X509Chain.Build() 方法为无效证书返回 true

4

1 回答 1

1

如果您使用的是 .NET 5+,您可以设置chain.ChainPolicy.DisableCertificateDownloads = true以防止它使用 AIA 记录来重建链。请注意,这不会绕过从本地缓存中解析内容,因此如果中间已经缓存,您仍然会得到一个完全构建的链。

没有办法在 SslStream 构建的链上获取该设置来验证远程证书,并且构建链的 SslStream 可能会导致底层系统缓存中间体(因为它必须下载它,并且它链接到受信任的根,所以它是值得缓存)。

于 2021-09-28T19:28:41.883 回答