Working with Digital Certificates in .NET

Digital certificates are the electronic version of a passport or an ID card, providing means for proving your identity for operations that must be performed securely (such as electronic payments). This article presents the basic .NET API for managing certificates.

Though this article is not a whitepaper on cryptography or certificates or other related concepts, I will start with a short introduction on certificates. If you are not familiar with these concepts I suggest you do additional readings for understanding them.

A short introduction on certificates

A certificate is an electronic document that uses a digital signature to associate a public key with an identity (either of a person or an organization), thus certifying that a public key belongs to an individual. The signing of a certificate can be done either by a certificate authority (CA) or the user, or even other users. Certificates signed by their user are called self-signed certificate, but are also known as root certificates.

A certificate authority is an entity that signs certificates. An individual that wants to prove his identity relies on certificate authority to sign his certificate. The certificate is passed to another individual, which can check it against the issuing certificate authority for validity. Both parties need to trust the certificate authority, which proves its identity with another certificate, signed by a higher ranking certificate authority. Of course, there must be one certificate authority that has no higher authority. This CA signs its own certificate, which is a self-signed certificate, also known as root certificate.

A typical example where root certificates are used is the web. Let's take for instance online banking applications. You connect to a web site, provide a username and password and probably a security number generated by a digital device and you access the application that allows you to manage your account, viewing your balance and transactions, making payments, etc. These kind of applications need to be secure. You don't want to end up on a fake site that steals your credentials and then empties you account. Connections to web servers used for online payments (and others) are made with HTTPS, which is a secure HTTP protocol combined with the SSL protocol for securely identifying the server. The web server has a certificate that proves its identity, signed by a recognized certificate authority, which is trusted by the browsers (or can be verified through its certificate issued by a higher, recognized certificate authority). When your browser connects to the web server, it retrieves the certificate and then checks it with the issuing certificate authority. If the web server is who it claims to be you are allowed to connect to the web site. Otherwise you get a certificate warning.

A digital certificate usually includes the following:

  • Serial number: used to uniquely identify the certificate.
  • Subject: the entity identified (person or organization).
  • Signature algorithm: the algorithm used for creating the signature.
  • Key-usage: purpose of the public key (encryption, signature verification, both).
  • Public key: used to encrypt a message to the subject or to verify the signature from the subject.
  • Issuer: the identify that issued the certificate.
  • Valid from: the date from which the certificate is valid.
  • Valid to: the date when the certificate expires.
  • Thumbprint algorithm: the algorithm used for hashing.
  • Thumbprint: the hash for the certificate used to verify that the certificate was not altered.

.NET support for certificates

Namespace System.Security.Cryptography.X509Certificates contains the implementation of the X.509 v3 certificate. X.509 is the standard for a public key infrastructure (PKI) for single sign-on and Privilege Management Infrastructure. The various classes from this namespace allow operations such as creating stores, importing, exporting, deleting, enumerating and retrieving information on certificates.

The most important classes are:

  • X509Store: represents a X.509 store, which is a physical catalog where certificates are persisted and managed. There are several built in stores grouped in two locations: local machine (contains certificates shared by all the users) and current user (contains certificates specific to the currently logged user).
  • X509Certificate and X509Certificate2: represent a X.509 certificate.
  • X509Certificate2Collection: represents a collection of X509Certificate2 objects.

Enumerating Certificates

To enumerate the certificates of a store one needs to open then store and then iterate over the sequence of certificates, represented by the Certificates property of the X509Store object.

public static void PrintCertificateInfo(X509Certificate2 certificate)
{
   Console.WriteLine("Name: {0}", certificate.FriendlyName);
   Console.WriteLine("Issuer: {0}", certificate.IssuerName.Name);
   Console.WriteLine("Subject: {0}", certificate.SubjectName.Name);
   Console.WriteLine("Version: {0}", certificate.Version);
   Console.WriteLine("Valid from: {0}", certificate.NotBefore);
   Console.WriteLine("Valid until: {0}", certificate.NotAfter);
   Console.WriteLine("Serial number: {0}", certificate.SerialNumber);
   Console.WriteLine("Signature Algorithm: {0}", certificate.SignatureAlgorithm.FriendlyName);
   Console.WriteLine("Thumbprint: {0}", certificate.Thumbprint);
   Console.WriteLine();
}

public static void EnumCertificates(StoreName name, StoreLocation location)
{
   X509Store store = new X509Store(name, location);
   try 
   {
      store.Open(OpenFlags.ReadOnly);
      foreach(X509Certificate2 certificate in store.Certificates)
      {
         PrintCertificateInfo(certificate);
      }
   }
   catch(Exception ex)
   {
      Console.WriteLine(ex.Message);
   }
   finally
   {
      store.Close();
   }
}

public static void EnumCertificates(string name, StoreLocation location)
{
   X509Store store = new X509Store(name, location);
   try
   {
       store.Open(OpenFlags.ReadOnly);
       foreach (X509Certificate2 certificate in store.Certificates)
       {
          PrintCertificateInfo(certificate);
       }
   }
   catch (Exception ex)
   {
      Console.WriteLine(ex.Message);
   }
   finally
   {
      store.Close();
   }
}

The examples above allow opening a named store from a specific location. The location is specified by the StoreLocation enumerator, and can have two values:

  • CurrentUser: the store for the current user
  • LocalMachine: the store assigned to the local machine (whose certificates are available to all the users).

The name of the store can either be a predefined one, indicated with the StoreName enumeration, or one identified by a string. The predefined ones are:

  • AddressBook: store for other users
  • AuthRoot: store for third-party certificate authorities
  • CertificateAuthority: store for intermediate certificate authorities
  • Disallowed: store for revoked certificates
  • My: store for personal certificates
  • Root: store for trusted root certificate authorities
  • TrustedPeople: store for directly trusted people or resources
  • TrustedPublisher: store for directly trusted publishers

Creating a store

You can create your own custome store, either for the local machine or for the current user. To do that you pass the name of a store that doesn't exist to the constructor of X509Store and then open it with any OpenFlags flags, except OpenExistingOnly.

public static bool CreateStore(string name, StoreLocation location)
{
   bool success = false;
   X509Store store = new X509Store(name, location);
   try
   {
      store.Open(OpenFlags.ReadWrite);
      success = true;
      store.Close();
   }
   catch (Exception ex)
   {
       Console.WriteLine(ex.Message);
   }

   return success;
}

Importing Certificates

To import a certificate you have to do the following:

  • Create a X509Certificate2 object, using the path to the certificate file
  • Open the desired store with ReadWrite access rights
  • Add the certificate to the store and close the store

The following code shows how this can be done:

public static bool ImportCertificate(X509Certificate2 certificate, StoreName name, StoreLocation location)
{
   bool success = false;

   X509Store store = new X509Store(name, location);
   try
   {
      store.Open(OpenFlags.ReadWrite);
      store.Add(certificate);
      success = true;
   }
   catch (Exception ex)
   {
      Console.WriteLine(ex.Message);
   }
   finally
   {
      store.Close();
   }

   return success;
}

public static bool ImportCertificate(X509Certificate2 certificate, string name, StoreLocation location)
{
   bool success = false;

   X509Store store = new X509Store(name, location);
   try
   {
      store.Open(OpenFlags.ReadWrite);
      store.Add(certificate);
      success = true;
   }
   catch (Exception ex)
   {
      Console.WriteLine(ex.Message);
   }
   finally
   {
      store.Close();
   }

   return success;
}

public static bool ImportCertificate(string path, StoreName name, StoreLocation location)
{
   bool success = false;

   try 
   {
      X509Certificate2 certificate = new X509Certificate2(path);
      success = ImportCertificate(certificate, name, location);
   }
   catch(Exception ex)
   {
      Console.WriteLine(ex.Message);
   }

   return success;
}

public static bool ImportCertificate(string path, string name, StoreLocation location)
{
   bool success = false;

   try
   {
      X509Certificate2 certificate = new X509Certificate2(path);
      success = ImportCertificate(certificate, name, location);
   }
   catch (Exception ex)
   {
      Console.WriteLine(ex.Message);
   }

   return success;
}

Exporting certificates

The export a certificate you have to do the following:

  • Open the desired store and find the certificate you want to export
  • Export the certificate content to a row stream of bytes
  • Save the row data to a file
public static bool ExportCertificate(
   string certificateName, 
   string path,
   StoreName storeName,
   StoreLocation location)
{
   bool success = false;

   X509Store store = new X509Store(storeName, location);
   store.Open(OpenFlags.ReadOnly);
   try
   {
      X509Certificate2Collection certs
         = store.Certificates.Find(X509FindType.FindBySubjectName, certificateName, true);

      if (certs != null && certs.Count > 0)
      {
         byte[] data = certs[0].Export(X509ContentType.Cert);
         success = WriteFile(data, path);
      }
   }
   catch (Exception ex)
   {
      Console.WriteLine(ex.Message);
   }
   finally
   {
      store.Close();
   }

   return success;
}

public static bool ExportCertificate(
   string certificateName,
   string path,
   string storeName,
   StoreLocation location)
{
   bool success = false;

   X509Store store = new X509Store(storeName, location);
   store.Open(OpenFlags.ReadOnly);
   try
   {
      X509Certificate2Collection certs
         = store.Certificates.Find(X509FindType.FindBySubjectName, certificateName, true);

      if (certs != null && certs.Count > 0)
      {
         byte[] data = certs[0].Export(X509ContentType.Cert);
         success = WriteFile(data, path);
      }
   }
   catch (Exception ex)
   {
      Console.WriteLine(ex.Message);
   }
   finally
   {
      store.Close();
   }

   return success;
}

private static bool WriteFile(byte[] data, string filename)
{
   bool ret = false;
   try
   {
      FileStream f = new FileStream(filename, FileMode.Create, FileAccess.Write);
      f.Write(data, 0, data.Length);
      f.Close();
      ret = true;
   }
   catch (Exception ex)
   {
      Console.WriteLine(ex.Message);
   }

   return ret;
}

When you look up the certificate in the certificates collection you can do it based on several criteria, such as by thumbprint, subject name, issuer name, validity periods, etc. The options for the search are defined by the X509FindType enumerator.

In the above sample the certificates are looked up by name. It is possible though that one store contains several certificates with the same name, but different serial number. In this case this sample locates the first certificate in the collection. You have to handle this appropriately for your application.

Deleting Certificates

To delete a certificate you need to do the following:

  • Open the store with ReadWrite access
  • Locate the certificate(s) you want to delete
  • Remove the certificate(s) from the store
  • Close the store
public static bool DeleteCertificate(string certificateName, string storeName, StoreLocation location)
{
   bool success = false;

   X509Store store = new X509Store(storeName, location);
   try
   {
      store.Open(OpenFlags.ReadWrite);

      X509Certificate2Collection certificates = 
         store.Certificates.Find(X509FindType.FindBySubjectName, certificateName, true);

      if(certificates != null && certificates.Count > 0)
      {
         store.RemoveRange(certificates);
         success = true;
      }
   }
   catch (Exception ex)
   {
      Console.WriteLine(ex.Message);
   }
   finally
   {
      store.Close();
   }

   return success;
}

public static bool DeleteCertificate(
   string certificateName, 
   string thumbprint,
   string storeName, 
   StoreLocation location)
{
   bool success = false;

   X509Store store = new X509Store(storeName, location);
   try
   {
      store.Open(OpenFlags.ReadWrite);

      X509Certificate2Collection certificates =
         store.Certificates.Find(X509FindType.FindBySubjectName, certificateName, true);

      if (certificates != null && certificates.Count > 0)
      {
         foreach(X509Certificate2 certificate in certificates)
         {
            if(certificate.Thumbprint == thumbprint)
            {
               store.Remove(certificate);
               success = true;
               break;
            }
         }
      }
   }
   catch (Exception ex)
   {
      Console.WriteLine(ex.Message);
   }
   finally
   {
      store.Close();
   }

   return success;
}

As you can see in the above samples, class X509Store has two methods for removing a certificate:

  • Remove: deletes a certificate
  • RemoveRange: removes a collection of certificates.

Conclusions

While this article is not a comprehensive tutorial on the support in the .NET framework for handling certificates it shows how one can perform basic operations such as enumerating and finding certificates, importing, exporting or deleting certificates. If you are not very familiar with digital certificates I recommend you to do additional readings for familiarizing with them.



About the Author

Marius Bancila

Marius Bancila is a Microsoft MVP for VC++. He works as a software developer for a Norwegian-based company. He is mainly focused on building desktop applications with MFC and VC#. He keeps a blog at www.mariusbancila.ro/blog, focused on Windows programming. He is the co-founder of codexpert.ro, a community for Romanian C++/VC++ programmers.

Comments

  • Fake Oakley Bottle Rocket free shipping

    Posted by kmpjltsdu on 06/27/2013 03:23pm

    Oakley For Cheap ,Oakley sunglasses, high quality, very stylish, it could be a good option the style fansalso may easily match your cool clothes, sunglasses beautiful feeling. Fashion to mirror the advance in current trends - retro, retro-style framework, chunky tortoiseshell and geometric shapes to attract, as an alternative to to divert attention. Fake Oakleys ,Together with sunscreen and cool concave sense, you will need to utilize explicit style white frame sunglasses. Brings both retro and classy, advocacy and convergence, dignified, and humor. Amazing fan following could possibly be because every one of Oakley is virtually achieved after many years of investigation and progression of excellence and a symbol of excellence. Fake Oakley Flak Jacket ,Good design and output of the framework is additionally good, it doesn't matter under what circumstances, may make people comfortable. As time passes, sunglasses, and gradually become common to daily life necessities, and fashion jewelry. The best set of designer sunglasses over these two distinctive, the thing is, reports of feeling looking within the hot sun day of outdoor great distance. Points too a specific glasses, which will help to make sure that it's in reference to his or her actual eye quality, a range of factors unique importance. If you need to play a greater shade, but protect the eyes, the best option of gray and dark green sunglasses, gray lenses absorb any chromatography balanced and also the scene to observe, without obvious color difference. Natural jewelry along with colored studded stones, attractive design and unique habits, in order that women everywhere, confident and just like the bulk request. Designers and professional sunglasses, for example the employment of a number of sports activities, more than the majority expensive sunglasses. However, you'll discover a number of on-line fashion Oakley sunglasses on the market affordable price. Polarized Oakley sunglasses, discount import high-quality polarized lenses, along with a big impact, reduce glare, eliminate reflected light, scattered light is a bit more gentle, clear. Oakley interchangeable lens technology, created to allow you to keep up with changing light conditions, to increase the performance in different environment. Also, all Oakley lens has excellent impact protection, 100% with the UV filter and incomparable HDO high-definition. Oakley sunglasses sales with many styles so that you can choose. We have Iridium lens coating to balance light transmission to offer you the best visual form of the targeted environment.

    Reply
  • How to read digital certificartes from vb.net

    Posted by Tayron Ovares on 06/21/2013 07:36am

    Dim theForm As Acrobat.CAcroPDDoc Dim jso As Object theForm = CreateObject("AcroExch.PDDoc") theForm.Open("C:\Temp\Maru\DeclaracionJurada.pdf") jso = theForm.GetJSObject 'Verifica que la firma sea valida Dim signatureOne = jso.getField("Signature2") Dim oState = signatureOne.SignatureValidate() Select Case oState Case Is = -1 ListBox1.Items.Add("Estado : Sin Firma ") Case Is = 0 ListBox1.Items.Add("Estado : Firma en blanco ") Case Is = 1 ListBox1.Items.Add("Estado : No conoce el estado de la firma ") Case Is = 2 ListBox1.Items.Add("Estado : Firma invalida ") Case Is = 3 ListBox1.Items.Add("Estado : La firma es valida, pero la identidad del firmante no se pudo verificar ") Case Is = 4 ListBox1.Items.Add("Estado : Firma e identidad son validas ") End Select 'Extrae la info del firmante, nombre y fecha de la firma Dim signatureInformation = signatureOne.signatureInfo ListBox1.Items.Add("Firmante " & signatureInformation.name) ListBox1.Items.Add("Fecha " & signatureInformation.Date) 'Extrae la info del certificado Dim signatureCertificate = signatureInformation.certificates ListBox1.Items.Add("Emitido a : " & signatureCertificate(0).subjectDN.serialNumber) ListBox1.Items.Add("Numero de Serie : " & signatureCertificate(0).serialNumber) ListBox1.Items.Add("Valido desde : " & signatureCertificate(0).validityStart) ListBox1.Items.Add("Valido hasta : " & signatureCertificate(0).validityEnd) ListBox1.Items.Add("Para : " & signatureCertificate(0).subjectDN.o) ListBox1.Items.Add("Tipo : " & signatureCertificate(0).subjectDN.ou) ListBox1.Items.Add("Emitido Por : " & signatureCertificate(0).issuerDN.cn)

    Reply
  • How to read digital certificate from pdf document in vv.net

    Posted by Tayron Ovares on 06/21/2013 07:34am

    Dim theForm As Acrobat.CAcroPDDoc Dim jso As Object theForm = CreateObject("AcroExch.PDDoc") theForm.Open("C:\Temp\Maru\DeclaracionJurada.pdf") jso = theForm.GetJSObject 'Verifica que la firma sea valida Dim signatureOne = jso.getField("Signature2") Dim oState = signatureOne.SignatureValidate() Select Case oState Case Is = -1 ListBox1.Items.Add("Estado : Sin Firma ") Case Is = 0 ListBox1.Items.Add("Estado : Firma en blanco ") Case Is = 1 ListBox1.Items.Add("Estado : No conoce el estado de la firma ") Case Is = 2 ListBox1.Items.Add("Estado : Firma invalida ") Case Is = 3 ListBox1.Items.Add("Estado : La firma es valida, pero la identidad del firmante no se pudo verificar ") Case Is = 4 ListBox1.Items.Add("Estado : Firma e identidad son validas ") End Select 'Extrae la info del firmante, nombre y fecha de la firma Dim signatureInformation = signatureOne.signatureInfo ListBox1.Items.Add("Firmante " & signatureInformation.name) ListBox1.Items.Add("Fecha " & signatureInformation.Date) 'Extrae la info del certificado Dim signatureCertificate = signatureInformation.certificates ListBox1.Items.Add("Emitido a : " & signatureCertificate(0).subjectDN.serialNumber) ListBox1.Items.Add("Numero de Serie : " & signatureCertificate(0).serialNumber) ListBox1.Items.Add("Valido desde : " & signatureCertificate(0).validityStart) ListBox1.Items.Add("Valido hasta : " & signatureCertificate(0).validityEnd) ListBox1.Items.Add("Para : " & signatureCertificate(0).subjectDN.o) ListBox1.Items.Add("Tipo : " & signatureCertificate(0).subjectDN.ou) ListBox1.Items.Add("Emitido Por : " & signatureCertificate(0).issuerDN.cn)

    Reply
  • Problem

    Posted by Meghasyam on 09/14/2012 12:27am

    I have done development for signing pdf documents. In my local host the program has shown the certificates and I uesd to choose then that's it. It's working very fine in my local host. I deployed same code in server. But when we access server to do the same, it is not even showing any certificates. Could you please help regarding this.

    Reply
  • Without .NET in C++!

    Posted by shupantha on 12/14/2009 09:13am

    Hi, Great article, exactly what I was looking for, but with a slight twist! I can't use .NET or C#, is there anyway this can be done without .NET in C++ under Visual Studio 2005/2008? Thanks in advance. Regards, Shup

    • RE: Without .NET in C++!

      Posted by cilu on 12/14/2009 11:57am

      Of course is possible. There is a Windows API for managing certificates, and the .NET classes are only wrappers on that API. But that is a completely different topic, not covered in this article. You can find a reference to all the Windows functions for managing certificates at http://msdn.microsoft.com/en-us/library/aa380252%28VS.85%29.aspx.

      Reply
    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • On-demand Event Event Date: September 10, 2014 Modern mobile applications connect systems-of-engagement (mobile apps) with systems-of-record (traditional IT) to deliver new and innovative business value. But the lifecycle for development of mobile apps is also new and different. Emerging trends in mobile development call for faster delivery of incremental features, coupled with feedback from the users of the app "in the wild." This loop of continuous delivery and continuous feedback is how the best mobile …

  • Packaged application development teams frequently operate with limited testing environments due to time and labor constraints. By virtualizing the entire application stack, packaged application development teams can deliver business results faster, at higher quality, and with lower risk.

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds