Validating Remote Server Certificates
19 October 2017
Recently, we ran into a problem at work that required us to validate remote server X.509 certificates. Fortunately, this is quite easy to do with .NET.
It starts with creating a new HttpWebRequest
. The request
instance has a multicast delegate for validating certificates.
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(@"https://www.google.com");
request.ServerCertificateValidationCallback += OnCertificateValidation;
try
{
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
Console.WriteLine("Response status: {0} ({1})", response.StatusCode, response.StatusDescription);
}
catch (WebException e)
{
Console.WriteLine("Exception: {0}", e.Message);
}
Here is our validation callback. If this returns true
, then the certificate is valid. If this return false
, then the certificate is invalid.
public static bool OnCertificateValidation(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors)
{
Console.WriteLine("Subject: {0}", certificate.Subject);
Console.WriteLine("Effective date: {0}", certificate.GetEffectiveDateString());
Console.WriteLine("Expiration date: {0}", certificate.GetExpirationDateString());
Console.WriteLine("Issuer: {0}", certificate.Issuer);
Console.WriteLine("Key algorithm: {0}", certificate.GetKeyAlgorithm());
Console.WriteLine("Certificate hash: {0}", certificate.GetCertHashString());
Console.WriteLine("Public key: {0}", certificate.GetPublicKeyString());
Console.WriteLine("Serial number: {0}", certificate.GetSerialNumberString());
Console.WriteLine("SSL policy errors: {0}", errors);
return (errors == SslPolicyErrors.None);
}
Here is the completed code.
This is the output when run against https://www.google.com.
Subject: CN=www.google.com, O=Google Inc, L=Mountain View, S=California, C=US
Effective date: 10/10/2017 10:37:01 AM
Expiration date: 12/28/2017 7:00:00 PM
Issuer: CN=Google Internet Authority G2, O=Google Inc, C=US
Key algorithm: 1.2.840.10045.2.1
Certificate hash: 891903894CFF80CBDF78D476967E332CD7A47AD4
Public key: 046BF4DBB3878545941DAE561637B5F7DAC9B305530F1E56332014308D699480D4662E19A004DB434EFEAFD79028F925A4C1E229877E9202353F4EB76E75702F67
Serial number: 5686E45C3812155C
SSL policy errors: None
Response status: OK (OK)
And this is the output when run against https://self-signed.badssl.com.
Subject: CN=*.badssl.com, O=BadSSL, L=San Francisco, S=California, C=US
Effective date: 8/8/2016 5:17:05 PM
Expiration date: 8/8/2018 5:17:05 PM
Issuer: CN=*.badssl.com, O=BadSSL, L=San Francisco, S=California, C=US
Key algorithm: 1.2.840.113549.1.1.1
Certificate hash: 641450D94A65FAEB3B631028D8E86C95431DB811
Public key: 3082010A0282010100C204ECF88CEE04C2B3D850D57058CC9318EB5CA86849B022B5F9959EB12B2C763E6CC04B604C4CEAB2B4C00F80B6B0F972C98602F95C415D132B7F71C44BBCE9942E5037A6671C618CF64142C546D31687279F74EB0A9D11522621736C844C7955E4D16BE8063D481552ADB328DBAAFF6EFF60954A776B39F124D131B6DD4DC0C4FC53B96D42ADB57CFEAEF515D23348E72271C7C2147A6C28EA374ADFEA6CB572B47E5AA216DC69B15744DB0A12ABDEC30F47745C4122E19AF91B93E6AD2206292EB1BA491C0C279EA3FB8BF7407200AC9208D98C5784538105CBE6FE6B5498402785C710BB7370EF6918410745557CF9643F3D2CC3A97CEB931A4C86D1CA850203010001
Serial number: 0086FB4DC8E5DD0F18
SSL policy errors: RemoteCertificateChainErrors
Exception: The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel.
Happy coding!