runtime: RemoteCertificateValidationCallback can not detect some incomplete certificate chains
Description
It appears that RemoteCertificateValidationCallback
(tested with SslStream
and HttpWebRequest
) incorrectly validates some certificates with chain issues (ex. https://incomplete-chain.badssl.com). The code I’m attempting to write validates certificates, similar to what this tool is doing https://www.sslshopper.com/ssl-checker.html.
There does not appear to be a way to detect these issues, which is why this feels like a bug to me.
Here is my attempt at overriding the default behavior, but by the time my code it hit, all 3 certificates look like they exist. (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;
}
}
Configuration
Here is a sample app using .NET 5 (my code base is .NET core 3.1 with the same issue)
Here’s a .NET Fiddle demonstrating the code above. https://dotnetfiddle.net/2aybuI
Regression?
Tested on several versions of .NET and this bug has been around for a long time.
Other information
curl requests, for example, fail how I want my requests to fail if the cert chain is not valid.
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 also correctly shows these incomplete-chains as invalid
$ 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
---
About this issue
- Original URL
- State: closed
- Created 3 years ago
- Reactions: 1
- Comments: 22 (13 by maintainers)
The trusted root should not be sent. You either have root in your trust or you won’t be able to validate anyway. Sending root CA does not really help and it is only waste. It should be valid to send it but the sample code I posted simply ignores root.
For TLS 1.2
TLS 1.3 only adds note that order should not mater.
As far as the link: It clearly states
The certificate chain sent by this site is missing an intermediate certificate. This will cause a certificate error unless the browser already has the intermediate certificate in a cache or implements [AIA fetching](https://tools.ietf.org/html/rfc3280#section-4.2.2.1).
I agree that adding control for AIA would be useful. That is already tracked by #59979.
There was never attempt to order the certificates anyhow. There were some platform differences (like extra leaf cert) I tried to fix in 7.0. Tls 1.3 explicitly states that receiver should make no assumption about the order
the third work around, which is proved works fine: use
js
running inNodeJs
to detect the incomplete-chain.badssl.com useJering.Javascript.NodeJS
to interop withNodeJs
donehttps://github.com/shamork/detect-incomplete-chain