Skip to content

RemoteCertificateValidationCallback can not detect some incomplete certificate chains #59944

Closed
@stephenweaver

Description

@stephenweaver

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
---

Metadata

Metadata

Assignees

No one assigned

    Labels

    area-System.Net.SecurityenhancementProduct code improvement that does NOT require public API changes/additions

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions