[OpenSSL] A Certificate’s Subject, Issuer and its keyUsage

The first code that I ever wrote using OpenSSL was one that read the certificate into memory and examined the values of the keyUsage extension. In fact, OpenSSL provides the functionality to extract all of the information from an X509 certificate that you possibly want. In this tutorial, an X509 certificate is read into memory and the subject and issuer are extracted and the keyUsage extension is examined.

The OpenSSL library provides a few different ways of loading a certificate into memory. For certificates that are in the DER format, the d2i_X509 functions can be used. OpenSSL provides two of these functions – one to read from a file pointer and another to read from a BIO. For anything in the PEM format, openssl provides a set of PEM_read functions. Again, there is a function to read from a BIO and another to read from a file pointer.

  1 #include <iostream>
  2
  3 #include <openssl/pem.h>
  4
  5 // Prototypes
  6 void printSubject (X509 *cert);
  7 void breakdownIssuer (X509 *cert);
  8 void extractNameEntry (X509_NAME *name, int nid);
  9 void checkKeyUsageExtension (X509 *cert);
 10 void testKeyUsage (ASN1_BIT_STRING *keyUsage,
 11   int usageBit, const char *usageName);
 12
 13 int main (int argc, char *argv[])
 14 {
 15   FILE *certFile = fopen("cert.pem", "r");
 16   X509 *cert = NULL;
 17
 18   if (certFile != NULL)
 19   {
 20     cert = PEM_read_X509(certFile, NULL, NULL,
 21       NULL);
 22     printSubject(cert);
 23     breakdownIssuer(cert);
 24     checkKeyUsageExtension(cert);
 25     fclose(certFile);
 26   }
 27   else
 28   {
 29     std::cout << "Could not open file cert.pem";
 30   }
 31
 32   X509_free(cert);
 33 }
 34

Extracting the certificate’s subject name is as simple as a single function call.

 35 // Simple function that prints out the subject name
 36 // using the RFC2253 format.
 37 void printSubject (X509 *cert)
 38 {
 39   std::cout << "— Certificate subject" <<
 40     std::endl;
 41   X509_NAME *subject = X509_get_subject_name(cert);
 42

With the subject name stored in a X509_NAME structure, we can go throught each of the structure’s members and output their values. Alternatively, if we want to obtain a readable format of the entire subject name, we can use OpenSSL’s X509_NAME_print_ex function. However, this function outputs the subject name to a BIO. Fortunately, it is quite easy to extract the string from the BIO and make our own copy.

 43   // Set up a BIO to put the subject line into.
 44   BIO *subjectBio = BIO_new(BIO_s_mem());
 45
 46   // Now, put the subject line into the BIO.
 47   X509_NAME_print_ex(subjectBio, subject, 0,
 48     XN_FLAG_RFC2253);
 49
 50   // Obtain a reference to the data and copy out
 51   // just the length of the data.
 52   char *dataStart = NULL;
 53   char *subjectString = NULL;
 54   long nameLength = BIO_get_mem_data(subjectBio,
 55     &dataStart);
 56   subjectString = new char[nameLength + 1];
 57   memset(subjectString, 0x00, nameLength + 1);
 58   memcpy(subjectString, dataStart, nameLength);
 59
 60   std::cout << "Certificate subject name: " <<
 61     subjectString << std::endl;
 62 }
 63

If you had a look at the documentation for X509_NAME_print_ex, you might have noticed the function X509_NAME_oneline and X509_NAME_print would have done also printed out the subject name in a readable format, with far less code. So then, why have I not used X509_NAME_oneline? It is because the same documentation also states that the two functions are “legacy functions which produce a non standard output form, they don’t handle multi character fields and have various quirks and inconsistencies. Their use is strongly discouraged in new applications.”.

Next, we’ll extract the issuer name and extract the individual parts, such as the common name, country and organisation names. Since the issuer and subjects are stored and retrieved using the X509_NAME structure, this same method can be applied to the subject name (and a readable form of the issuer name can be obtained using the same method as above).

 64 // Simple method that takes the issuer name to
 65 // pieces and prints out a couple of the fields.
 66 void breakdownIssuer (X509 *cert)
 67 {
 68   std::cout << std::endl << "— Issuer breakdown" 
 69     << std::endl;
 70   X509_NAME *issuer = X509_get_issuer_name(cert);
 71
 72   extractNameEntry(issuer, NID_commonName);
 73   extractNameEntry(issuer, NID_countryName);
 74   extractNameEntry(issuer, NID_organizationName);
 75 }
 76

The function extractNameEntry is defined later and is where the individual fields in the issuer name will be extracted. The constants NID_commonName, NID_countryName and NID_organizationName are defined by OpenSSL and references the fields in the issuer name to be extracted. There are defined in objects.h and obj_mac.h.

To extract the actual field from the issuer name, we must determine the location of the field in the name and then extract the entry as a X509_NAME_ENTRY.

 77 // Obtains an entry from a X509 name (i.e. either
 78 // the certificate’s issuer or subject) and
 79 // prints out on standard output.
 80 void extractNameEntry (X509_NAME *name, int nid)
 81 {
 82   // First, let us get the common name from the
 83   // certificate.
 84   int position = X509_NAME_get_index_by_NID(name,
 85     nid, –1);
 86   X509_NAME_ENTRY *entry = X509_NAME_get_entry(
 87     name, position);
 88     

Obtaining a readable string representation of the field requires one more level extraction and conversion.

 89   // This will obtain just the name entry.
 90   ASN1_STRING *asn1Data =
 91     X509_NAME_ENTRY_get_data(entry);
 92
 93   // Next use obtain the actual string data and
 94   // output to standard output.
 95   unsigned char *entryString = ASN1_STRING_data(
 96     asn1Data);
 97
 98   std::cout << OBJ_nid2ln(nid) << ": " <<
 99     entryString << std::endl;
100 }
101

The function OBJ_nid2ln converts the our NID value that we passed in to the name of the field.

Lastly, we’ll extract the keyUsage extension and examine its contents. The method of extracting the extension is same for any extension. RFC 3820 provides a description of the keyUsage extension (actually, it also provides descriptions of other extension as well). Have a look at the RFC if you also want to know what the extension is for. The keyUsage extension is encoded as a bit string, so in OpenSSL, this is extracted as bit string. Furthermore, take note of the meaning of each of the bits in the bit string from RFC.

102 // Extracts the key usage extension from the
103 // certificate.
104 void checkKeyUsageExtension (X509 *cert)
105 {
106   int criticality = –1;
107   int extIndex = –1;
108
109   std::cout << std::endl <<
110     "— Key Usage extension" << std::endl;
111
112   // Obtain the keyUsage extension in the form
113   // of a bit string.
114   ASN1_BIT_STRING *keyUsage = (ASN1_BIT_STRING *)
115     X509_get_ext_d2i(cert, NID_key_usage,
116     &criticality, &extIndex);
117
118   // Output the contents of the keyUsage
119   // extension.
120   const char *usages[] = {"digitalSignature",
121                           "nonRepudiation",
122                           "keyEncipherment",
123                           "dataEncipherment",
124                           "keyAgreement",
125                           "keyCertSign",
126                           "cRLSign",
127                           "encipherOnly",
128                           "decipherOnly"};
129
130   for (int index = 0; index < 8; index++)
131   {
132     testKeyUsage(keyUsage, index, usages[index]);
133   }
134 }
135
136 // Tests the value of the key usage extension to
137 // determine for a given value and outputs the
138 // result to standard output.
139 //
140 // The parameter usageBit is which bit in the
141 // keyUsage to check. RFC 3280 lists the meaning
142 // of each of the bits in the extension.
143 void testKeyUsage (ASN1_BIT_STRING *keyUsage,
144   int usageBit, const char *usageName)
145 {  
146   std::cout << usageName << ": " <<
147     ASN1_BIT_STRING_get_bit(keyUsage, usageBit) <<
148     std::endl;
149 }
150

If you compile and run this program, you should see the output of the contents of cert.pem‘s subject and issuer names and its keyUsage extension (if it can find the certificate). More importantly, note one thing that has been omitted in the sample code above – the lack of checking for successful operations. Throughout the code, I had not checked for things such as whether the subject name was successfully obtained from the certificate, whether we managed to get the individual fields from the issuer name or a keyUsage extension really exists before their contents are used. This was omitted to shorten the amount of code that would have to be displayed in this tutorial. Adding the checks yourself is as simple as checking the return values (usually, a null or -1 is returned on error).

Advertisements

4 Responses to [OpenSSL] A Certificate’s Subject, Issuer and its keyUsage

  1. Pingback: STACK_OF Subject Alternate Name and Extended Key Usage Extensions « Kah - The Developer

  2. Melissa O'Sullivan says:

    Thanks for posting, this is extremely helpful! Could you explain the use of the variables criticality and extIndex in lines 114-116?

  3. Pingback: Fix Openssl Error Code 104 Windows XP, Vista, 7, 8 [Solved]

  4. Pr0ffSa says:

    Всем привет Посоветуйет ,из чего выбрать часы наручыне на кожаном ремешке , обязательно качественные при этом низкая стоимость , да и чо за бренд выбрать. В общем отличное качество и цены.
    Прошу прощения если не туда

    такси новосибирск Купить копию часов Chopard в Новосибирске в на плоские часы наручные

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: