Search code examples
c#.netsslcertificatex509certificate

How to fully validate a X509 certificate?


I need to validate a certificate(X509Certificate2) the same way it´s validated before it is used for communication.

The X509Certificate2.Verify() will in this case return true while the certificate is not issued to the server it is installed on.

Is there any finished code block to do a full validation of the X509 certificate?

Regards

Edit : This is the code I have tried with :

var certificate = GetServerCertificate(CertificateStore,CertificateLocation,Thumbprint);

            if(certificate != null)
            {
                if(certificate.Verify())
                    _logger.Log(NLog.LogLevel.Info, $"Yes");
                else
                    _logger.Log(NLog.LogLevel.Info, $"No");
            }

Solution

  • The X509Certificate2.Verify() will in this case return true while the certificate is not issued to the server it is installed on.

    The Verify method doesn't check anything about hostnames. It verifies that

    • The certificate is not expired.
    • The certificate eventually chains to a trusted root authority.
    • All certificates in the chain have appropriately nested expiration.
    • The target certificate, unless it's self-issued, has a revocation endpoint, and is not revoked.
    • Any intermediate certificates have revocation endpoints and are not revoked.

    It's exactly equal to

    using (X509Chain chain = new X509Chain())
    {
        // Use the default vales of chain.ChainPolicy including:
        //  RevocationMode = X509RevocationMode.Online
        //  RevocationFlag = X509RevocationFlag.ExcludeRoot
        //  VerificationFlags = X509VerificationFlags.NoFlag
        //  VerificationTime = DateTime.Now
        //  UrlRetrievalTimeout = new TimeSpan(0, 0, 0)
    
        bool verified = chain.Build(cert);
    
        for (int i = 0; i < chain.ChainElements.Count; i++)
        {
            chain.ChainElements[i].Certificate.Dispose();
        }
    
        return verified;
    }
    

    Is there any finished code block to do a full validation of the X509 certificate?

    If "full validation" just means all the things Verify does, then yes. If you also care that it's valid for use as a TLS client certificate (or TLS server certificate) then you would use the longer form (using X509Chain directly) and add an application policy requirement before calling chain.Build:

    // See if it's valid as a TLS server
    chain.ChainPolicy.ApplicationPolicy.Add(new Oid("1.3.6.1.5.5.7.3.1"));
    // Alternatively, if it's valid as a TLS client
    chain.ChainPolicy.ApplicationPolicy.Add(new Oid("1.3.6.1.5.5.7.3.2"));
    

    The hostname is much harder. Client certificates don't have validatable names, it's just up to what the server does with it. Server certificates have hostname matching against SAN/Subject-CN, but there's nothing built-in that does that check other than just connecting with TLS (SslStream).

    Update (2023-09-08): Hostnames can be verified on X509Certificate2 instances starting in .NET 7, via the MatchesHostname method.