Download, parse, and store SSL certificates in C#

As part of elmah.io Uptime Monitoring, we offer SSL expiration warnings. We recently both simplified the code and had to do some additional parsing of the common names in the certificates. This post is a summary of how we did that.

Download, parse, and store SSL certificates in C#

When dealing with SSL certificates in C#, that part is typically handled by the HTTP client used. In some cases, you may need to download and store the certificate. You may even need to parse the content of the various fields within the certificate. Well, this is the post for you.

I have seen a range of different tips (hacks basically) to use HttpClient for fetching an SSL certificate. I even used some of them myself until seeing this post from Gérald Barré. To sum up, the easiest way to fetch a certificate from a URL can be done like this:
RemoteCertificateValidationCallback certCallback = (_, _, _, _) => true;
using var client = new TcpClient("blog.elmah.io", 443);
using var sslStream = new SslStream(client.GetStream(), true, certCallback);
await sslStream.AuthenticateAsClientAsync(domain);
var serverCertificate = sslStream.RemoteCertificate;
var certificate = new X509Certificate2(serverCertificate);

The code uses the TcpClient and SslStream classes to fetch the certificate without a single HttpClient. Then create a new X509Certificate2 instance which we will work with in the following sections. If you are running on a previous version of C#, make sure to add the following property to your csproj file:

<LangVersion>9.0</LangVersion>

Once loaded into memory, a certificate can be easily saved by using the Export method to generate a byte array representation and save it:

var content = certificate.Export(X509ContentType.Cert);
await File.WriteAllBytesAsync("certificate.cer", content);

So, how about displaying the fields from the SSL certificate. You've probably seen the Windows dialog to display an SSL certificate:

Certificate information

Let's build something similar, but for the command line. To illustrate how to parse the various fields within the certificate, I'll go through how we can display the Issued to field.

Would your users appreciate fewer errors?

➡️ Reduce errors by 90% with elmah.io error logging and uptime monitoring ⬅️

The X509Certificate2 class has a range of properties to fetch the different information about the certificate. The Issued to information is located in a property named Subject. In security, the subject means the thing being secured. In this case the domain. Let's write that to the screen:

Console.WriteLine(certificate.Subject);

You might expect this to write out sni.cloudflaressl.com. Sorry to disappoint you:

CN=sni.cloudflaressl.com, O="Cloudflare, Inc.", L=San Francisco, S=California, C=US

That's the "distinguished name" (DName) of the subject. To get the common name (CN) you could start parsing and splitting the text. Or you can install the Rfc2253 NuGet package by Eric Li:

dotnet add package Rfc2253

The package is great at parsing DNames like the one we already have in the subject:

var subject = DistinguishedName.Create(certificate.Subject);
var commonName = subject.Rdns.FirstOrDefault(x => x.Type.Value == "CN");
if (commonName != null)
{
    Console.WriteLine(commonName.Value);
}

Rfc2253 parses the subject into an array of keys and values. All we have to do then is to find the common name by looking for the CN type.

As expected, we now see the common name in the console:

sni.cloudflaressl.com

elmah.io: Error logging and Uptime Monitoring for your web apps

This blog post is brought to you by elmah.io. elmah.io is error logging, uptime monitoring, deployment tracking, and service heartbeats for your .NET and JavaScript applications. Stop relying on your users to notify you when something is wrong or dig through hundreds of megabytes of log files spread across servers. With elmah.io, we store all of your log messages, notify you through popular channels like email, Slack, and Microsoft Teams, and help you fix errors fast.

See how we can help you monitor your website for crashes Monitor your website