[OpenSSL] STACK_OF Subject Alternate Name and Extended Key Usage Extensions

In A Certificate’s Subject, Issuer and its keyUsage, a certificate was read into memory and its subject and issuer names and its key usage extension contents were outputted. Here, the subject alternate names and extended key usage names are extracted. Both of these extensions are defined in RFC 3280 as a SEQUENCE of something. In the code, this would mean the extension would be parsed into a STACK_OF something.

The ASN.1 description for the extended key usage as defined in RFC 3280:

ExtKeyUsageSyntax ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId

KeyPurposeId ::= OBJECT IDENTIFIER

As mentioned before, the extended key usage is an ASN.1 SEQUENCE, which in our code will be a STACK_OF something. The definition states its a SEQUENCE of KeyPurposeId, which is just an OBJECT IDENTIFIER. In our code, we would extract this as an ASN1_OBJECT. Since KeyPurposeId is an OBJECT IDENTIFIER (aka OID), there will be a unique object for each extended key usage value type. The name of the extend key usage value in the extension can be obtained from OpenSSL.


 1 #include <iostream>
 2 #include <openssl/pem.h>
 3 #include <openssl/x509v3.h>
 4
 5 // Extract the extended key usage values from the
 6 // certificate and output them.
 7 void extractExtendedKeyUsage (X509 *cert)
 8 {
 9   std::cout << std::endl <<
10     "Extended key usages: ";
11   int usageId = 0;
12   const char *kuValue = NULL;
13   STACK_OF(ASN1_OBJECT) *extKu =
14     (STACK_OF(ASN1_OBJECT) *)
15     X509_get_ext_d2i(cert, NID_ext_key_usage,
16      NULL, NULL);
17

As with the stack data structure, a STACK_OF(ASN1_OBJECT) support pop and push operations. With each object in the stack, you can obtain its numeric identifier (NID) or a textual representation of its name by using the OBJ functions. For the code above, it will give back each extend key usage value in the certificate.

18   while (sk_ASN1_OBJECT_num(extKu) > 0)
19   {
20     usageId = OBJ_obj2nid(
21       sk_ASN1_OBJECT_pop(extKu));
22     kuValue = OBJ_nid2sn(usageId);
23     std::cout << " [" << kuValue << "]";
24   }
25   std::cout << std::endl;
26 }
27

The subject alternate name’s ASN.1 definition is:

SubjectAltName ::= GeneralNames

GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName

GeneralName ::= CHOICE {
otherName [0] OtherName,
rfc822Name [1] IA5String,
dNSName [2] IA5String,
x400Address [3] ORAddress,
directoryName [4] Name,
ediPartyName [5] EDIPartyName,
uniformResourceIdentifier [6] IA5String,
iPAddress [7] OCTET STRING,
registeredID [8] OBJECT IDENTIFIER }

OtherName ::= SEQUENCE {
type-id OBJECT IDENTIFIER,
value [0] EXPLICIT ANY DEFINED BY type-id }

EDIPartyName ::= SEQUENCE {
nameAssigner [0] DirectoryString OPTIONAL,
partyName [1] DirectoryString }

Notice that ASN.1 definition states that a subject alternate name is a sequence of GeneralName. It also happens that OpenSSL has define a structure called GENERAL_NAME in x509v3.h.

 1 typedef struct GENERAL_NAME_st {
 2
 3 #define GEN_OTHERNAME 0
 4 #define GEN_EMAIL 1
 5 #define GEN_DNS   2
 6 #define GEN_X400  3
 7 #define GEN_DIRNAME 4
 8 #define GEN_EDIPARTY  5
 9 #define GEN_URI   6
10 #define GEN_IPADD 7
11 #define GEN_RID   8
12
13 int type;
14 union {
15   char *ptr;
16   OTHERNAME *otherName; /* otherName */
17   ASN1_IA5STRING *rfc822Name;
18   ASN1_IA5STRING *dNSName;
19   ASN1_TYPE *x400Address;
20   X509_NAME *directoryName;
21   EDIPARTYNAME *ediPartyName;
22   ASN1_IA5STRING *uniformResourceIdentifier;
23   ASN1_OCTET_STRING *iPAddress;
24   ASN1_OBJECT *registeredID;
25
26   /* Old names */
27   ASN1_OCTET_STRING *ip; /* iPAddress */
28   X509_NAME *dirn;    /* dirn */
29   ASN1_IA5STRING *ia5;/* rfc822Name, dNSName, uniformResourceIdentifier */
30   ASN1_OBJECT *rid; /* registeredID */
31   ASN1_TYPE *other; /* x400Address */
32 } d;
33 } GENERAL_NAME;

Notice that the definition of the GENERAL_NAME structure in the header mirrors that of as defined in the RFC. The member type reveals exactly kind of information is in the structure and, hence, which member of the union, d, to use to access the actual data. In case you are wondering, the definition for the OTHERNAME and EDIPARTYNAME structures are also defined in the same file. Again, their definitions mirrors that as specified by the RFC.

1 typedef struct otherName_st {
2 ASN1_OBJECT *type_id;
3 ASN1_TYPE *value;
4 } OTHERNAME;
5
6 typedef struct EDIPartyName_st {
7   ASN1_STRING *nameAssigner;
8   ASN1_STRING *partyName;
9 } EDIPARTYNAME;

First, to obtain the subject alternate name:

28 // Extract the subject alternate name and output
29 // its contents.
30 void extractSubjectAltName (X509 *cert)
31 {
32   std::cout << std::endl <<
33     "Subject alternate name" << std::endl;
34   GENERAL_NAME *namePart = NULL;
35   STACK_OF(GENERAL_NAME) * san =
36     (STACK_OF(GENERAL_NAME) *)
37     X509_get_ext_d2i(cert,
38       NID_subject_alt_name, NULL, NULL);
39
40   while (sk_GENERAL_NAME_num(san) > 0)
41   {
42     std::cout << "Entry type: ";
43     namePart = sk_GENERAL_NAME_pop(san);
44

Next, we can output the information. The type of information in the GENERAL_NAME is given by the member type, which will also indicate which of the other in the union to use to access the data. Since there are many different types of entry values possible in a GENERAL_NAME, I’ve kept it short here by outputting only URI and email entries. Note that the email entry is stored in the rfc822Name member (yes, RFC 822 is about email, although it has been updated by later RFCs).

45     // Determine what kind of data we have
46     // and handle it appropriately.
47     switch (namePart->type)
48     {
49       case GEN_URI:
50         std::cout << "URI = " <<
51           ASN1_STRING_data(namePart->
52           d.uniformResourceIdentifier);
53         break;
54       case GEN_EMAIL:
55         std::cout << "Email = " <<
56         ASN1_STRING_data(namePart->
57         d.rfc822Name);
58         break;
59       default:
60         // Going to be lazy for this
61         // example.
62         std::cout << "Unrecognisable";
63         break;
64     }
65     std::cout << std::endl;
66   }
67 }

Advertisements

3 Responses to [OpenSSL] STACK_OF Subject Alternate Name and Extended Key Usage Extensions

  1. Branko Majic says:

    Many thanks for this excellent sample of code. I’ve beaten my head around by trying to figure out what the OpenSSL x509 utility does when it prints out the rfc822Name.

    I wish I’ve managed to get a hit on this one earlier – would’ve saved me lots of time 🙂

  2. Jens says:

    Thanks for this great tutorial! But could you provide example code for all the other GENERALNAME-Types such as GEN_OTHERNAME or GEN_X400?

  3. mak says:

    thanks a lot , for the above. I was not able to find the API to get the extended key usage from the certificate, I hope the above code can work from me . thanks again,

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: