X.509 Certificates

X.509 Certificates are a combination of public key, key owner properties and a signature over them. The key owner is called certificate Subject.

The other party which made the signature (using their private key) is called certificate Issuer.

Table of contents

Certificate Properties

Before we begin with the base methods for operating with X.509 Certificates, we have to introduce the owner details structure contained in the certificate, the so called Distinguished Name. This structure gives information for the certificate owner (subject) so everyone who uses the certificate can read it. In DidiSoft OpenSSL Library for .NET this structure is represented by the class DidiSoft.OpenSsl.X509.X509Name:

C#

1
2
3
4
5
6
7
8
9
X509Name certificateProperties = new DidiSoft.OpenSsl.X509.X509Name()
                                   {
                                    CommonName = "My CA",
                                    CountryCode = "US",
                                    Organization = "My CA company",
                                    OrganizationUnit = "Certificate Authority",
                                    Locality = "My towm",
                                    EmailAddress = "office@myca.com"
                                   };

VB.NET

1
2
3
4
5
6
7
Dim certificateProperties As New DidiSoft.OpenSsl.X509.X509Name()
certificateProperties.CommonName = "My CA"
certificateProperties.CountryCode = "US"
certificateProperties.Organization = "My CA company"
certificateProperties.OrganizationUnit = "Certificate Authority"
certificateProperties.Locality = "My towm"
certificateProperties.EmailAddress = "office@myca.com"

There are some cryptic members like CN, C, O, etc. all of them evolved from LDAP (Light Weight Directory) protocol internal database. The most commonly used fields are:

CountryCode – two letter country of the certificate owner, like US, UK, DE, FR, etc.
CommonName – common name, this is the name of the certificate owner (subject)
Organization – organization of the certificate owner (for companies this can be the same as CN)
OrganizationUnit – organization unit (for example Sales, IT, etc.)
Street – street address
Locality – location (city/town/village)
State – state
PostalCode – post code
EmailAddress – email address

Each certificate contains such structure for the certificate owner (subject) and another for the certificate issuer. A minimalistic X509Name instance can be one where only the CommonName field is initialized.

Load Certificate

A certificate can be loaded from file, Stream or byte array. Here is how to load an existing certificate, so we can use it or inspect its properties:

using DidiSoft.OpenSsl.X509;
...
Certificate cert = Certificate.Load(@"c:\certs\john_doe.cert");

Save Certificate

Certificates can be stored in files, Streams or byte arrays in PEM or DER format. The format is specified with the second parameter of the Certificate.Save method:

C# sample

1
2
3
Certificate cert = Certificate.Load("mycert.crt");
bool pemFormat = true;
cert.Save("mycert.crt", pemFormat);

VB.NET sample

1
2
3
Dim cert As Certificate = Certificate.Load("mycert.crt")
Dim pemFormat As Boolean = True
cert.Save("mycert.cert", pemFormat)

Create Self Signed Certificate

A self-signed certificate is a certificate, signed with the private key corresponding to the certificate public key and usually the subject and owner details are the same. All root Certificate Authorities certificates are self-signed.

In order to create a self-signed certificate we need a public and its corresponding private key and of course a Properties instance:

C# example

1
2
3
4
5
6
7
8
9
10
11
using DidiSoft.OpenSsl;
using DidiSoft.OpenSsl.Rsa;
using DidiSoft.OpenSsl.X509;
...
OpenSslRsa rsa = new OpenSslRsa();
KeyPair keypair = rsa.GenerateRsaKeyPair(KeyLength.Length2048);
 
// certificate owner details 
X509Name certificateProperties = new X509Name() { CN = "My Test Name" };
 
Certificate cert = Certificate.CreateSelfSignedCertificate(keypair.Public, keypair.Private, certificateProperties);

VB.NET example

1
2
3
4
5
6
7
8
9
10
11
using DidiSoft.OpenSsl;
using DidiSoft.OpenSsl.Rsa;
using DidiSoft.OpenSsl.X509;
...
OpenSslRsa rsa = new OpenSslRsa();
KeyPair keypair = rsa.GenerateRsaKeyPair(KeyLength.Length2048);
 
// certificate owner details 
X509Name certificateProperties = new X509Name() { CommonName = "My Test Name" };
 
Certificate cert = Certificate.CreateSelfSignedCertificate(keypair.Public, keypair.Private, certificateProperties);

This is just a basic example for a quick creation of a self-signed X.509 certificate. You can check the more extended examples in order to find out how to customize the additional details that can be stored inside a certificate.

Verifying a certificate

A certificate verification consists of checking the digital signature inside it with a public key, usually embedded inside the issuer Certificate.

Check the dedicated chapter for examples on Certificate Verification.

Certificate details

In addition to the certificate owner (Subject) properties, other details can be found as well inside a certificate. In short there are four groups of information details:

Certificate cert = Certificate.Load("my.cert");

Information for the certificate

(subject properties, serial number, validity period, version, etc.)

string serialNumber = cert.SerialNumber;
string thumbprint = cert.GetThumbprint();
string keyId = cert.GetSubjectKeyIdentifier();
Properties subject = cert.Subject;

Information for the issuer

(issuer properties, issuer key identifier)

string issuerKeyId = cert.GetAuthorityKeyIdentifier();
string issuedTo = cert.Subject.CommonName;
string issuedFrom = cert.Issuer.CommonName;
X509Name issuer = cert.Issuer;

Allowed usages of the certificate

A certificate’s public key and corresponding private key uses may be limited, with special settings called Key Usages stored inside the certificate. For example in order to limit the certificate to only be used for data signing, only the KeyUsages.DigitalSignature will be present.

Here is how to list the allowed key usages for a certificate:

C# example:

1
2
3
4
5
6
7
8
9
KeyUsages[] usages = cert.GetKeyUsages();
// if nothing is specify all key usages are allowed
bool allUsagesAllowed = (usages.Length == 0);
 
// Print allowed key usages
foreach (KeyUsages usage in usages)
{
    Console.WriteLine(usage);
}

VB.NET example

1
2
3
4
5
6
7
Dim usages As KeyUsages() = cert.GetKeyUsages()
Dim allUsagesAllowed As Boolean = (usages.Length = 0)
 
' Print allowed key usages
For Each usage As KeyUsages In usages
    Console.WriteLine(usage)
Next

Information for the Certificate Authority

A certificate authority usually stores inside a certificate additional information for itself. This information is useful for the people to whom the certificate will be distributed in order to know how to contact the issuing Certificate Authority for additional information. Of course, all of these methods may return null, if there is no such information.

Especially valuable information is the location of the CRL (certificate revocation) list and the OCSP (On-line certificate status) protocol endpoint:

string urlOfCACertificate = cert.GetUrlOfCACertificate();
string urlOfCAPoliciesDocument = cert.GetUrlOfCertificatePolicies();
string urlOfCRL = cert.GetUrlOfCrlList();
string urlOfOCSP = cert.GetUrlOfOcsp();

Public key

The public key stored inside a X.509 certificate can be obtained with:

DidiSoft.OpenSsl.PublicKey pubKey = cert.SubjectPublicKey;

Afterward the key can be stored or used for other purposes.

Interoperability with X509Certificate2

In places where the library must be put in place with the default .NET cryptography code we can create certificates to and from the System.Security.Cryptography.X509Certificate and System.Security.Cryptography.X509Certificate2 class instances like:

1
2
3
4
5
6
7
8
System.Security.Cryptography.X509Certificate cert1 = ...
System.Security.Cryptography.X509Certificate2 cert2 = ...
 
DidiSoft.OpenSsl.X509.Certificate mycert1 = new DidiSoft.OpenSsl.X509.Certificate(cert1);
DidiSoft.OpenSsl.X509.Certificate mycert2 = new DidiSoft.OpenSsl.X509.Certificate(cert2);
 
cert1 = mycert1.ToX509Certificate();
cert2 = mycert2.ToX509Certificate2();

Of course the value of the X509Certificate2 class is in its capability to hold also the corresponding private key. In that case, we can also create such an instance with ToX509Certificate2:

1
2
3
4
5
6
7
8
DidiSoft.OpenSsl.KeyPair key = DidiSoft.OpenSsl.KeyPair.GenerateKeyPair(KeyAlgorithm.Rsa, KeyLength.Length1024);
var properties = new DidiSoft.OpenSsl.X509.X509Name()
{
  CN = "MyCN"
};
var newCert = DidiSoft.OpenSsl.X509.Certificate.CreateSelfSignedCertificate(key.Public, key.Private, properties);
 
System.Security.Cryptography.X509Certificate2 cert2 = newCert.ToX509Certificate2(key.Private, "SomeSecureString");

Summary

This chapter introduced DidiSoft.OpenSs.X509.Certificate class and illustrated basic usage scenarios with it.

From here you may check the other chapters dedicated to X.509 certificate creation and verification, CSR, and Certificate Authority.