Friday 15 February 2019

Linux SSL Certificate verification in .NET Core

This is some analysis into the verification of SSL in .NET Core.
There is a behavioural difference: it you add a self-signed certificate into "Trusted Publishers" on a Windows machine then self-signed certificates are accepted, but on Linux machines they still error.

System.Net.Security.SecureChannel:VerifyRemoteCertificate

If CompleteHandshake fails then the error is thrown:
SR.net_ssl_io_cert_validation  "The remote certificate is invalid according to the validation procedure."

CompleteHandshake calls VerifyRemoteCertificate

SecureChannel.VerifyRemoteCertificate returns false if the certificate cannot be validated.

It calls CertificateValidationPal.GetRemoteCertificate and then CertificateValidationPal....

At this point the logic forks depending upon the OS.
CertificateValidationPal.VerifyCertificateProperties is in CertificateValidationPal.Unix.cs.

For Unix, this calls the CertificateValidation.BuildChainAndVerifyProperties.
This is in CertificateValidation.Unix.cs.

The X509Chain is built. It returns a ChainPal and runs BuildChain on it.
A linux ChainPal is returned.
It then runs the OpenSslX509ChainProcessor and runs BuildChain.
This has recursion as it enumerates the chain. It has a timeout to ensure the loading of certificates does not take too long.

The OpenSslX509ChainProcessor is run, and it runs the Pal.Unix/ChainVerifier.cs.
This runs HasUnsuppressedError which checks for errors that have not been surpressed. This includes checking for self-signed certificates.

The  Interop.Crypto.X509VerifyCert is called which calls calls native C code which calls the openSSL library function X509_verify_cert. This calls verify_chain.
OpenSSL build_chain will check for self signed certificates which has a return value of 18.

In OpenSSL, a self-signed certificate has a chain of 1.
Running 
openssl s_client -showcerts -verify 5 -connect cosmosdb.test:8081 
against a server will retun 

Debian ca-certificates notes.

Verify return code: 18 (self signed certificate)

In the dotnet core implhementation for Unix, Self-signed is when the subject name is the same as the issuer name (see code). Errors can occur because the peer trust is only supported for Windows certificate stores. Some of this is discussed here.

Having a self-signed certificate raises the X509VerificationFlags.IgnoreRootRevocationUnknown flag which needs to be surpressed, otherwise an error is returned.


This is a subtle difference from the standard Linux implementation of dotnet core; in dotnet core Self-signed is when the subject name is the same as the issuer name (see code).

If you have running Windows and a self-signed certificate in the Trusted Publishers store, then dotnet core will respect it and not throw an error. If you are running the same code on Linux and have installed the self-signed certificate into the ca-certificates store, it will throw an error.

The X509 Store differs by platform
The LocalMachine\Root store on Linux is an interpretation of the CA bundle in the default path for OpenSSL. The LocalMachine\Intermediate store on Linux is an interpretation of the CA bundle in the default path for OpenSSL. The CurrentUser\Intermediate store on Linux is used as a cache when downloading intermediate CAs by their Authority Information Access records on successful X509Chain builds.





No comments:

Post a Comment