как определить сертификаты с неполными цепочками сертификатов с помощью C#? Ядро dotnet C # говорит, что они действительны, а не недействительны

Я пытаюсь написать код для проверки действительности сертификата веб-сайта (например, incomplete-chain.badssl.com). Эта проблема, с которой я сталкиваюсь, заключается в том, что, похоже, окна (или инфраструктура 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

      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
    return result;
}

Вот два старых вопроса, которые, кажется, имеют похожую проблему, но не имеют решения.

  1. SSL-сертификат с неполной цепочкой, проходит проверку в .NET Core 2.2

  2. Метод X509Chain.Build() возвращает истину для недействительного сертификата

1 ответ

Если вы используете .NET 5+, вы можете установить chain.ChainPolicy.DisableCertificateDownloads = trueчтобы предотвратить использование записей AIA для восстановления цепочки. Обратите внимание, что это не обойдет решение проблем из локальных кешей, поэтому, если промежуточное звено уже кэшировано, вы все равно получите полностью построенную цепочку.

Невозможно получить этот набор в цепочках, созданных SslStream для проверки удаленных сертификатов, и SslStream, строящий цепочку, может привести к тому, что базовая система кэширует промежуточное звено (поскольку она должна была загрузить его, и она была привязана к доверенному корню, поэтому она достойный кеширования).

Другие вопросы по тегам