HTTPS and X509 certificates in .NET Part 4: working with certificates in code

Introduction

In the previous post we successfully installed our self-signed CA certificate in the Trusted Root CA folder. We also installed a derived certificate in the Personal certificates folder. We then saw how to make IIS use our certificate for a secured web site.

In this post we’ll start looking into the certificate-related classes in .NET.

Loading a certificate from a file

Digital certificates are represented by the X509Certificate2 class in .NET located in the System.Security.Cryptography.X509Certificates namespace. The class has numerous overloaded constructors. You can pass in the file path to the certificate, a byte array content, a password etc. Let’s see whether we can load the CA certificate we created before in this series:

X509Certificate2 certificate = new X509Certificate2(@"C:\TestProjects\Certificates\Certificates\RootCert.cer");
					
string expirationDate = certificate.GetExpirationDateString();
string issuer = certificate.Issuer;			
string effectiveDateString = certificate.GetEffectiveDateString();
string nameInfo = certificate.GetNameInfo(X509NameType.SimpleName, true);
bool hasPrivateKey = certificate.HasPrivateKey;
			
Debug.WriteLine(expirationDate);
Debug.WriteLine(issuer);
Debug.WriteLine(effectiveDateString);
Debug.WriteLine(nameInfo);
Debug.WriteLine(hasPrivateKey);

The code prints the following values:

2029-12-31 23:00:00
CN=RootCert
2014-12-31 23:00:00
RootCert
False

We can also load pfx files:

X509Certificate2 certificate = new X509Certificate2(@"C:\TestProjects\Certificates\Certificates\mylocalsite.local.pfx");

The HasPrivateKey property will be True now as the pfx file includes the private key as well. The X509Certificate2 class also has an Export method with various overloads to transform it into a byte array.

Loading a certificate from the store

If you want to inspect a certificate that’s already installed in the Windows certificate store then it’s easier to use the X509Store class. The X509Store class has an overload where you can specify the store location and the store name. Store location will be either User Store or Computer Store. The store names map to the folder names in the certificates snap-in GUI:

Store names as folders in MMC certificates snap-in

You can provide the store name either as a string or as an enumeration. The enumeration includes the built-in store locations such as Personal and Trusted Root CA. You’ll see some non-standard store locations in the printscreen above, like “testCertStore”. Obviously there won’t be any entry for custom locations in the StoreName enumeration.

It’s not always straightforward to find the exact mapping between the folder names in the GUI and the StoreName enumeration values. E.g. StoreName.CertificateAuthority maps to “Intermediate Certification Authorities” in the GUI and not the “Trusted Root Certification Authorities”. Trusted CAs are represented by StoreName.Root. Also, the “Personal” folder is represented by StoreName.My.

The following code will open the trusted CA store on the local machine and enumerate through the available certificates. The store must be closed as well at the end:

X509Store computerCaStore = new X509Store(StoreName.Root, StoreLocation.LocalMachine);
			
try
{
	computerCaStore.Open(OpenFlags.ReadOnly);
	X509Certificate2Collection certificatesInStore = computerCaStore.Certificates;
	foreach (X509Certificate2 cert in certificatesInStore)
	{
		Debug.WriteLine(cert.GetExpirationDateString());
		Debug.WriteLine(cert.Issuer);
		Debug.WriteLine(cert.GetEffectiveDateString());
		Debug.WriteLine(cert.GetNameInfo(X509NameType.SimpleName, true));
		Debug.WriteLine(cert.HasPrivateKey);
                Debug.WriteLine(cert.SubjectName.Name);
		Debug.WriteLine("-----------------------------------");
	}
}
finally
{
	computerCaStore.Close();
}

Our self-signed CA will also be listed:

2029-12-31 23:00:00
CN=RootCert
2014-12-31 23:00:00
RootCert
False
CN=RootCert

Let’s do the same for the Personal store name:

X509Store computerCaStore = new X509Store(StoreName.My, StoreLocation.LocalMachine);

The derived certificate is also found:

2029-12-31 23:00:00
CN=RootCert
2014-12-31 23:00:00
RootCert
True
CN=mylocalsite.local

Searching for certificates

The X509Certificate2Collection object has a Find method where you can search for specific certificates by a number of criteria. The exact search type is defined by the X509FindType enumeration. The following example will locate all certificates whose issuer name is equal to “RootCert”:

X509Certificate2Collection findResult = certificatesInStore.Find(X509FindType.FindByIssuerName, "RootCert", false);

…and this is how you can find a certificate by its subject name:

X509Certificate2Collection findResult = certificatesInStore.Find(X509FindType.FindBySubjectName, "mylocalsite.local", false);

The boolean parameter indicates that we want to look at all certificates and not only the valid ones.

Installing and deleting certificates

The X509Store class provides methods to install and delete certificates as well. I’ll quickly create a new CA root and a derived certificate to test the Add and Remove methods of X509Store using the makecert tool like we did before:

makecert.exe -r -n “CN=RootCertReloaded” -pe -sv RootCertReloaded.pvk -a sha1 -len 2048 -b 01/01/2015 -e 01/01/2030 -cy authority RootCertReloaded.cer
pvk2pfx.exe -pvk RootCertReloaded.pvk -spc RootCertReloaded.cer -pfx RootCertReloaded.pfx
makecert.exe -ic RootCertReloaded.cer -iv RootCertReloaded.pvk -pe -sv greatsite.com.pvk -a sha1 -n “CN=greatsite.com” -len 2048 -b 01/01/2015 -e 01/01/2030 -sky exchange greatsite.com.cer -eku 1.3.6.1.5.5.7.3.1
pvk2pfx.exe -pvk greatsite.com.pvk -spc greatsite.com.cer -pfx greatsite.com.pfx

I ignored the password fields and clicked “None” to simplify the process.

Note that you’ll need to run Visual Studio with administrator rights otherwise the code will fail.

This is how the CA certificate can be installed:

X509Store computerCaStore = new X509Store(StoreName.Root, StoreLocation.LocalMachine);
X509Certificate2 rootCert = new X509Certificate2(@"C:\TestProjects\Certificates\DummyCerts\RootCertReloaded.cer");
try
{
	computerCaStore.Open(OpenFlags.ReadWrite);
	computerCaStore.Add(rootCert);
}
catch (Exception ex)
{
	Debug.WriteLine("Root certificate import failed: " + ex.Message);
}
finally
{
	computerCaStore.Close();
}

Refresh the certificates snap-in in the MMC GUI and the RootCertReloaded certificate should be visible:

CA certificate installed in code

The code to install the derived certificate pfx file is almost identical:

X509Store personalStore = new X509Store(StoreName.My, StoreLocation.LocalMachine);
X509Certificate2 sslCert = new X509Certificate2(@"C:\TestProjects\Certificates\DummyCerts\greatsite.com.pfx");
try
{
	personalStore.Open(OpenFlags.ReadWrite);
	personalStore.Add(sslCert);
}
catch (Exception ex)
{
	Debug.WriteLine("SSL certificate import failed: " + ex.Message);
}
finally
{
	personalStore.Close();
}

The derived certificate is visible in the Personal store after a refresh:

Derived certificate installed in code

The uninstallation process is very similar. We’ll need to locate the certificate in the appropriate store and call the Remove method of X509Store:

X509Store personalStore = new X509Store(StoreName.My, StoreLocation.LocalMachine);
try
{
	personalStore.Open(OpenFlags.ReadWrite);
	X509Certificate2Collection findResult = personalStore.Certificates.Find(X509FindType.FindBySubjectName, "greatsite.com", false);
	if (findResult.Count > 0)
	{
		foreach (X509Certificate2 item in findResult)
		{
			personalStore.Remove(item);
		}
	}
}
catch (Exception ex)
{
	Debug.WriteLine("SSL certificate import failed: " + ex.Message);
}
finally
{
	personalStore.Close();
}

X509Store computerCaStore = new X509Store(StoreName.Root, StoreLocation.LocalMachine);
try
{
	computerCaStore.Open(OpenFlags.ReadWrite);
	X509Certificate2Collection findResult = computerCaStore.Certificates.Find(X509FindType.FindBySubjectName, "RootCertReloaded", false);
	if (findResult.Count > 0)
	{
		foreach (X509Certificate2 item in findResult)
		{
			computerCaStore.Remove(item);
		}
	}
}
catch (Exception ex)
{
	Debug.WriteLine("Root certificate uninstall failed: " + ex.Message);
}
finally
{
	computerCaStore.Close();
}

Refresh the GUI and the CA and derived certificates should be gone from the list.

In the next post we’ll see how to validate certificates in code.

You can view the list of posts on Security and Cryptography here.

About Andras Nemes
I'm a .NET/Java developer living and working in Stockholm, Sweden.

11 Responses to HTTPS and X509 certificates in .NET Part 4: working with certificates in code

  1. Steve Bower says:

    This is very helpful, neat intro into HTTPS and certificates. Do you happen to have any links to getting certificates from the personal store using Python?

  2. Kornel says:

    Useful post thanks mate! Let me ask that would be possible to force popping up the certificate selection window from the server (asp.net mvc) for example when a user pushes a button? I’d like to get 2nd factor (smart card) auth, even after login at a certain point of the use case. I just want to avoid burdening users on login since the 2nd factor need rarely.

  3. Dorothy says:

    Nicely written post! I tried your code and it returned 52 out of my 53 certs? And of course, the one I need is missing. I am new to working with certificates. Do you know why that one doesn’t return?

    X509Store computerCaStore = new X509Store(StoreName.Root, StoreLocation.LocalMachine);
    computerCaStore.Open(OpenFlags.ReadOnly);
    X509Certificate2Collection certificatesInStore = computerCaStore.Certificates;

  4. Pingback: X.509 certificates in .NET | Around computing

  5. Dennis says:

    Thanks for nice post. Do you have ideas on how to write certificate to USB token

  6. Marvin says:

    I, thank you for this post. It really helps a lot. But I have some problem, how can I install the certificate in a specific physical store, like in root under the “Registry” folder.

  7. Raguram Mohandas says:

    Andras Nemes ,
    Really a nice post that I have ever seen. good explanation of the concepts of certificate.
    Do you have any info of how to access the certificates of any HTTPS URL and it to the certificate store ?

    You have discussed only importing the certificates from local, Could you please describe also the ways in which we can import ( or obtain ) the server certificates and add it to our local certificate store.

    Thanks in advance !!

    Thanks
    Raguram

  8. Howdy from Greece Andras,
    thank you for the rather thorough presentation, on the subject. I actually have a specific question :
    is there a way (some property of the X509Certificate2 class I probably haven’t discovered, i guess) for someone to distinguish in code that their users are working with smart cards (for example : eToken Java Applet 1.1.25) when digitally signing their docs ?

    Kind Regards,

    Panos

  9. Dr. Amresh Nikam says:

    Nice article. Can you please explain how read the certificate from USB token,

Leave a comment

Elliot Balynn's Blog

A directory of wonderful thoughts

Software Engineering

Web development

Disparate Opinions

Various tidbits

chsakell's Blog

WEB APPLICATION DEVELOPMENT TUTORIALS WITH OPEN-SOURCE PROJECTS

Once Upon a Camayoc

Bite-size insight on Cyber Security for the not too technical.