PKI and code signing for C#


This post is to document my understanding of the terms used in and standards used to implement Public Key Infrastructure (PKI) components. We use PKI components all the time when visiting an HTTPS site, signing an email or checking an executable is from who its supposed to be. I’ve a short term interest in code signing and to break out of the tyranny (in my view) of central certificate authorities like VeriSign, Thawte, GlobalSign which are given the right to create some of the most expensive bits on the planet (certificates) without any real responsibility (see this post from Andrews and Arnold).

This interest led me on a chase through a maze of standards like X.509, ASN.1, PKCS, SHA1 hashing, RSA key pairs, certificate generation, revocation lists and so on. So much so I know without documenting it I’ll forget what I’ve learned. I know I could use the certificate authority which comes with Windows 2003/2008 or I could use OpenSSL or Peter Gutmann’s Cryptlib but wanted to learn about what’s going on under the surface and, as importantly, to be able to generate signed certificates in code myself. By the way the option to use the MS CA is out because unless you’re using an Enterprise edition of 2003/2008 you don’t have the option to control the private keys of certificates you generate!

There’s C# source code to accompany this article which shows how to create a root, intermediate along with code and mail signing certificates, link them into certificate hierarchy and store the certificates and applicable key in a PKCS 12 key store or save the certificate in a .cer file. There’s a small charge of $5 for the source code if you want it. Of course you may not want to pay and instead work it out for yourself. If so, I respect your decision. If you want the examples source code, you can find out more this this post.

My language preference is C# but this post isn’t really about code its about all the bits that make up a code signing certificate and all is language agnostic. If you want a library which implements the PKI features you’ve plenty to choose from including the open source Peter Gutmann’s Cryptlib (http://www.cryptlib.com/) and many commercial implementations. I’m going to be using BouncyCastle (www.bouncycastle.org).

There’s precious little documentation provided with or of BouncyCastle. We’re all guilty of failing to realize how much we’ve learned once we’ve become expert and so often fail to appreciate what non-experts need to have explained slowly. It’s inevitable because its too hard to communicate efficiently if you’ve to do back to basics all the time. This is definitely true in the world of PKI (and BouncyCastle specifically) so this post is something of a boot camp and for these reasons I thought this post might also be a useful starter for others wanting to find out more about PKI related standards and technologies. The material is too extensive to go into any one topic in any detail so there are links to resources you can use to fill out your understanding of specific areas.

What is a certificate?
A certificate is part of the public key infrastructure (PKI) and aims to provide the recipient of some information assurances about the integrity of that information. A certificate is a byte array, which may be contained in a file, representing a document identifying the person or organization which owns the certificate, known as the ‘subject’ and the person or organization which created the certificate for the subject known as the ‘issuer’. Certificates bear a ‘not before’ date and an not after date. Based on this and other information contained in the certificate you can decide if you can trust the information to which the certificate is attached whether that’s a web site, an email, some software or a document. There’s a review of some the certificate detail below.

Public Key Infrastructure
Importantly, embedded within the certificate is a public key which is one half of the core of the public key infrastructure. The other half is the private key. As the name suggests this key is private. That is, it is for the use of the certificate issuer only and is not included in the the certificate. The public and private keys are asymmetric not the same. They use mathematical tricks applied to prime numbers so ensure that information encrypted by the private can be decoded by the public key, even though they are different, so the private key never needs to be disclosed.

The public key may be necessary for the recipient of some information to decode its content if it has been encrypted using the subject’s private key though it’s by no means a requirement that a certificate is used to decrypt encrypted content. However, the public key is unable to generate the same value as the private key even when hashing identical information so there’s no risk releasing the public key.

So how are the public and private keys used?
There are standard processes for using the keys to sign an email, to produce and consume a certificate along with its public key, and for checking the signature attached to an email or software. That is, the ability to sign a document relies on several standards. Collectively the standards define what is known as the Public Key Infrastructure. In my view the standards which most embody this definition are the Public Key Cryptography Standards (PKCS) which have, in part, been subsumed into X.509 – the standard for certificate generation. While there are others, X.509 and the PKCS are the ones used for the ‘normal’ PKI implementations of the web such as that used in web trust, email signatures and code signing.

For example, in the case of a signed email, the certificate’s owner will have generated a hash of the email’s content (text and any attachments) using a standard algorithm such as MD5 or SHA1. The hash generated by the certificate’s owner will be encrypted using the owner’s private key and added to the email, along with the certificate, as a ‘signature’. Any email recipient is able to verify the contents are from the sender by: also hashing the email body and attachments (except the signature), extracting the certificate from the signature and using it’s public key to decrypt the hash computed by the sender using the sender’s private key and comparing your hash with the sender’s hash. If the two are the same, you know you have what was sent (because only the sender’s private key could encrypt the hash in a way that could be decrypted by the certificate’s public key). There’s a page about this process on Wikipedia.

X.509
Currently on version 3 (X.509 v3) it is the standard which describes the structure and use of a certificate. Developed from X.500 defined many years ago in Britain, at a time when paper was still the thing, the objective for X.500 was to create a syntax for a master, inherently hierarchical, directory in which everything could be labeled. The idea is that everything has a ‘distinguished name’ (DN) which, as the name suggests, would distinguish everything uniquely. Peter Gutmann’s great PKI tutorial describes some of the history of X.509. Despite its flaws, X.500 is still alive and kicking today not only because it’s used in X.509 certificate definitions but because it is used as an essential definition in the Lightweight Directory Application Protocol (LDAP) or, as users of Windows will know it, Active Directory.

A Distinguished Name (DN) is supposed to comprise several ‘names’ including (but not limited to):

Organisation (O) My Company Inc
Organisational Unit (OU) Sales
Country (C) GB
Location (L) London
Common Name (CN) Bill Seddon
Email Address (E) bms@lyquidity.com

A DN is used to identify both the issuer and the subject of a certificate. However X.509 standard goes further than just using distinguished names, it defines and describes all the components of a certificate. An example is shown in appendix II and there’s more about the components of a certificate further down.

Certificate Authority (CA)
X.509 introduces the concept of a ‘certificate authority’ or CA. This is an entity which is responsible for issuing certificates to other entities. CAs are important features within the PKI as they are places which allow a certificate consumer to confirm the identity of the certificate owner (subject) and to find out if the certificate is still valid.

Certificate Trust
Any issuer can be an certificate authority. However some certificates are self-signed in which case they are ‘root’ authorities. If you trust a certificate you can include the certificate’s issuer as a trusted CA and if that CA is a root CA you can trust it as ‘Trusted Root Certification Authority’ (at least that’s what Microsoft calls them). In FireFox they are just called ‘Authorities’. You trust a certificate issuer by adding their certificate to your Trusted Root Certification Authority store. In Windows the store accessible from the Internet Options control panel applet or via Internet Explorer options. In FireFox its available from the View Certificates button of the options pop-up window.

Certificate Revocation lists CRLs
As mentioned above, a certificate has a ‘not before date’ and a ‘not after date’. These are useful. But what happens if you need to make a certificate expire earlier than originally planned? The date can’t be change because that in the already distributed certificate. Instead an essential, if clumsy, means to expire a certificate early is through the creation and use of revocation list. Certificates, identified by their attributes, especially a serial number can be revoked by adding them to a revocation list.

It’s clumsy because it requires that an application reach out the certificate issuer’s revocation list location (often a web site) each time it validates a certificate just so see if the certificate has been revoked. What happens if the application cannot access the internet at that time? When that’s up to the application checking the signature. However, there’s nothing better yet so its necessary to live with it.

Object Identifiers
Parallel to X.500 names are ‘object identifiers’ OIDs. Each element in a certificate, including each part of a DN is described by an OID. An OID is a member of strictly hierarchical definition of entities. A repository of all OIDs is here. For example 2.5.29.29 is the OID for the element in a certificate which identifies the issuer. As described above, in the certificate will be an Issuer DN. From the repository you will see that 2.5 is for directory services (X.500 is a directory service definition) 2.5.29 is ‘certificate attributes’ and 2.5.29.29 is ‘certificateIssuer’.

You will see from Appendix I and II that OIDs are used to describe most if not all things in an certificate. For example OID 1.2.840.113549.1.1.5 shown in the appendix I listing indicates that the certificate hash has been generated using ‘sha1WithRSAEncryption’.

X.509 v3 uses OIDs to unambiguously identify each attribute in a certificate. X.509 v3 provides a mechanism to be able to add ‘extensions’ to the standard set of certificate attributes and it defines a number of standard extensions. More will be included about extensions later. Extentions are an ASN.1 sequence of an OID (which denote the purpose of the exention) and a the related content. The extension defines the shape of the content which may be just a number or a complex hierachy of OIDs and content. You can create your own extensions either by using an existing OID which is not already defined for using in a cerficate or by requesting and using your own OID. The International Standards Organsation (ISO) is responsible for the high levels of the OID hierarchy and you can apply to them for an OID of your own. Or you can apply to the owner of an OID node and ask them for an OID within their scope. We applied to Microsoft (1.2.840.113556.1.8000) for our OID (1.2.840.113556.1.8000.2596). Microsoft uses OIDs extensively in Active Directory to identify AD objects.

In practice, when using modern libraries which provide PKI functionality, programmers do not use the OID values directly because they are presented as named properties of some class which renders the correct byte sequence for the OID with a particular property. Certainly that’s how it works in BouncyCastle. However there may be times when you want or need to create your own certificate extensions, for example if you want or need to embed custom information in a certificate and there are no existing extensions which work for you.

PKCS
The Public Key Cryptography Standards (PKCS) are property of RSA Laboratories (owned by EMC at the time of writing) founded by Rivest, Shamir and Adleman who created the widely used RSA public key scheme which was awarded a patent in the US in 1983. The PKCS are a family of 15 standards. But if you take out the two which are not yet published (for the use of advanced cryptography), ones that are now obsolete usually because they were absorbed into later revisions of earlier members of the family or revisions of the X.509 standard there are just 5 of the PKCSs to learn something about: PKCS 1, PKCS 7, PKCS 8, PKCS 9 and PKCS12. However this is just background reading. An overview of the standards can be found on the Wikipedia PKCS page.

The PKCS 1 defines the mathematical properties and format of RSA public and private keys and the basic algorithms and encoding/padding schemes for performing RSA encryption, decryption, and producing and verifying signatures. That is, the PKCS describe the processes for encoding and decoding and transmitting information between two parties – for example the email signing scheme described above. An important focus of the PKCS is to define the structure of the byte array that is, for example, the email signature. The byte array has a definite structure which is an encoding of what I think of as a nested set of envelopes, their content and, usually, stamps. The number and placement of the envelopes, of their content and their stamps is defined by the PKCSs. Appendix 1 shows the structure of PKCS encoded certificate.

ASN.1
RSA chose to use a standard and flexible notation called the Abstract Syntax Notation One or ASN.1 to describe the structures defined by the PKCS, presumably because it was an ISO standard at the time the first PKCS was being defined. Here’s an example definition in ASN.1 – a bit like a schema definition of Xml:
<br />
FooProtocol DEFINITIONS ::= BEGIN</p>
<p>    FooQuestion ::= SEQUENCE {<br />
        trackingNumber INTEGER,<br />
        question       IA5String<br />
    }</p>
<p>    FooAnswer ::= SEQUENCE {<br />
        questionNumber INTEGER,<br />
        answer         BOOLEAN<br />
    }</p>
<p>END<br />

And it might be used like:
<br />
myQuestion FooQuestion ::= {<br />
    trackingNumber     5,<br />
    question           "Anybody there?"<br />
}<br />

So you end up with an ASN.1 encoded entity like this:
<br />
SEQUENCE {<br />
        INTEGER 5,<br />
        IA5String "Anybody there?"<br />
}<br />

Sequences, which form the envelopes of PKI message, can be nested inside sequences as you see in appendix I. One element of a sequence will be the envelope content. Another might the associated stamp. In turn both may be sequences of yet more atomic items.

PKCS 1 is now managed by the Internet Engineering Task Force (IETF) as RFC3281. You will see the PKCS standard is defined in terms of verbose ASN.1 rules.

ASN.1 encoding rules
If you open a certificate file using Notepad you don’t see anything like this verbose notation. That’s because the high level notation is encoded using one of 6 encoding rules. The two used to encode certificate files are: Basic Encoding Rules (BER) and Distinguished Encoding Rules (DER). Another ASN.1 encoding rule is Xml which defines how the ASN.1 structure should be converted to Xml and back again but Xml is not used by PKI.

You can see from the dump of the certificate in appendix I that certificates are encoded using DER. Encoding really means that a label like ‘SEQUENCE’ is converted to a number. In this case 0x30 or the character ‘0’ (zero). That is, if you look inside a certificate file the first character will be the character zero because the whole certificate is held in an outer sequence or envelope.

So one of the challenges of any software wanting to create certificate and other PKCS files is to be able to encode to and decode from ASN.1 DER. Fortunately, all libraries providing PKI functionality do. For example, the listing in Appendix I was created by using the Asn1.Utilities.Asn1Print method from the C# port of BouncyCastle.

Key Stores
A .cer (or .crt) is just a DER encoded certificate (with a hash signature) saved to a file. Some times more is needed. For example, when an issuer provides your expensive certificate to sign code or an email or to authenticate computer access its not just a certificate that’s provided. To be able to sign code you need a private key and, ideally, the issuers certificate and public key. PKCS12 provides a file format able to store these and other components protected with a password. The structure of a key store is defined in PKCS 12. Accordingly, such files often have a filename extension of .p12 and sometimes .pkf. Again software supporting PKI includes the ability to read and generate key stores. For example, the code associated with this post shows how to generate master (root), code signing and email signing certificates and how they can be saved in a keystore.

The Microsoft key stores
Microsoft Windows includes a respository of key stores and certificated. These are accessed through the Internet Explorer tools. Select Internet Options from the IE tools menu or from the Control Panel, select the “Content” page and finally press the ‘Certificates’ button. There are different stores available from ‘Personal’ to ‘Trusted Root Certificate Authorities’ Very often a Windows product will require that key stores you buy or generate (for example using the idea presented here) are installed into Windows certificate stores. In a similar way, FireFox has its own stores.

So what’s in a certificate?
At this point the relevant standards have been identified. That’s not to say all standards for all PKI applications have been introduced but for code signing and many applications such as digital signatures they have.

The final piece is to understand the component of a certificate and how certificates are linked together in a hierarchy. This provides you the option of creating your own root certificate and any number of subordinate certificates you need.

An example structure of a certificate (the CACert root CA) is show in Appendix I below. This shows some of the information a certificate can contain. Here is a list of likely features. Although shown as single items each one is likely to be a nested set of sequences. For example the Authority Key Id is a hash. For you to be able verify the hash you need to know the hashing algorithm employed and any related parameters.

  • Public Key – Used to verify signatures generated using the corresponding private key
  • Issuer Distinguished Name (DN) – The name of the issuing authority
  • Subject Distinguished Name (DN) – The name of the subject of subject of the certificate
  • Serial number – An assigned number that should be unique in a collection of cerficates
  • AuthorityKeyId – A hash generated from the public key of the certificate’s issuer
  • Not before date
  • Not after date
  • Basic constaints – Whether or not the certificate is a CA
  • Key use – Such as signing, encryption, non-repuditation
  • Extended key use – Such as code signing, digital signature
  • SubjectKeyId – A hash generated from the public key associated with the certificate
  • Authority Information – The location of the issuer’s certificate and any revocation list
  • Certificate policies – Any set of information relevant to the

A certificate is ‘self-signed’ if the AuthorityKeyId and SubjectKeyId are the same. When these are the same the certficate may be a root CA. You can check this by seeing if the Basic constraint value confirms that it is.

An application is able to check the certificate chain by following the AuthorityKeyId and SubjectKeyId. The AuthorityKeyId will be the SubjectKeyId of the next link in the certificate chain.

Appendix 1 Structure of certificate (DER)
<br />
DER Sequence<br />
    DER Sequence<br />
        Tagged [0]<br />
            Integer(2)<br />
        Integer(566581) (Serial number)<br />
        DER Sequence<br />
            ObjectIdentifier(1.2.840.113549.1.1.5)<br />
            NULL<br />
        DER Sequence<br />
            DER Set<br />
                DER Sequence<br />
                    ObjectIdentifier(2.5.4.10)<br />
                    PrintableString(Root CA)<br />
            DER Set<br />
                DER Sequence<br />
                    ObjectIdentifier(2.5.4.11)<br />
                    PrintableString(http://www.cacert.org)<br />
            DER Set<br />
                DER Sequence<br />
                    ObjectIdentifier(2.5.4.3)<br />
                    PrintableString(CA Cert Signing Authority)<br />
            DER Set<br />
                DER Sequence<br />
                    ObjectIdentifier(1.2.840.113549.1.9.1)<br />
                    IA5String(support@cacert.org)<br />
        DER Sequence    (Not before/not after dates)<br />
            UTCTime(100514145948GMT+00:00)<br />
            UTCTime(120513145948GMT+00:00)<br />
        DER Sequence    (Distinguished name)<br />
            DER Set<br />
                DER Sequence<br />
                    ObjectIdentifier(2.5.4.6)<br />
                    PrintableString(AU)<br />
            DER Set<br />
                DER Sequence<br />
                    ObjectIdentifier(2.5.4.8)<br />
                    PrintableString(NSW)<br />
            DER Set<br />
                DER Sequence<br />
                    ObjectIdentifier(2.5.4.7)<br />
                    PrintableString(Sydney)<br />
            DER Set<br />
                DER Sequence<br />
                    ObjectIdentifier(2.5.4.10)<br />
                    PrintableString(CAcert Inc.)<br />
            DER Set<br />
                DER Sequence<br />
                    ObjectIdentifier(2.5.4.3)<br />
                    PrintableString(www.cacert.org)<br />
            DER Set<br />
                DER Sequence<br />
                    ObjectIdentifier(1.2.840.113549.1.9.1)<br />
                    IA5String(support@cacert.org)<br />
        DER Sequence<br />
            DER Sequence (Subject identifier)<br />
                ObjectIdentifier(1.2.840.113549.1.1.1)<br />
                NULL<br />
            DER Bit String[270, 0]<br />
        Tagged<br />

Appendix II Example certificate showing issuer and subjecct distinguished names
<br />
Certificate:<br />
   Data:<br />
       Version: 1 (0x0)<br />
       Serial Number: 7829 (0x1e95)<br />
       Signature Algorithm: md5WithRSAEncryption<br />
       Issuer: C=ZA, ST=Western Cape, L=Cape Town, O=Thawte Consulting cc,<br />
               OU=Certification Services Division,<br />
               CN=Thawte Server CA/emailAddress=server-certs@thawte.com<br />
       Validity<br />
           Not Before: Jul  9 16:04:02 1998 GMT<br />
           Not After : Jul  9 16:04:02 1999 GMT<br />
       Subject: C=US, ST=Maryland, L=Pasadena, O=Brent Baccala,<br />
                OU=FreeSoft, CN=www.freesoft.org/emailAddress=baccala@freesoft.org<br />
       Subject Public Key Info:<br />
           Public Key Algorithm: rsaEncryption<br />
           RSA Public Key: (1024 bit)<br />
               Modulus (1024 bit):<br />
                   00:b4:31:98:0a:c4:bc:62:c1:88:aa:dc:b0:c8:bb:<br />
                   33:35:19:d5:0c:64:b9:3d:41:b2:96:fc:f3:31:e1:<br />
                   66:36:d0:8e:56:12:44:ba:75:eb:e8:1c:9c:5b:66:<br />
                   70:33:52:14:c9:ec:4f:91:51:70:39:de:53:85:17:<br />
                   16:94:6e:ee:f4:d5:6f:d5:ca:b3:47:5e:1b:0c:7b:<br />
                   c5:cc:2b:6b:c1:90:c3:16:31:0d:bf:7a:c7:47:77:<br />
                   8f:a0:21:c7:4c:d0:16:65:00:c1:0f:d7:b8:80:e3:<br />
                   d2:75:6b:c1:ea:9e:5c:5c:ea:7d:c1:a1:10:bc:b8:<br />
                   e8:35:1c:9e:27:52:7e:41:8f<br />
               Exponent: 65537 (0x10001)<br />
   Signature Algorithm: md5WithRSAEncryption<br />
       93:5f:8f:5f:c5:af:bf:0a:ab:a5:6d:fb:24:5f:b6:59:5d:9d:<br />
       92:2e:4a:1b:8b:ac:7d:99:17:5d:cd:19:f6:ad:ef:63:2f:92:<br />
       ab:2f:4b:cf:0a:13:90:ee:2c:0e:43:03:be:f6:ea:8e:9c:67:<br />
       d0:a2:40:03:f7:ef:6a:15:09:79:a9:46:ed:b7:16:1b:41:72:<br />
       0d:19:aa:ad:dd:9a:df:ab:97:50:65:f5:5e:85:a6:ef:19:d1:<br />
       5a:de:9d:ea:63:cd:cb:cc:6d:5d:01:85:b5:6d:c8:f3:d9:f7:<br />
       8f:0e:fc:ba:1f:34:e9:96:6e:6c:cf:f2:ef:9b:bf:de:b5:22:<br />
       68:9f<br />

Information and Links

Join the fray by commenting, tracking what others have to say, or linking to it from your blog.


Other Posts

Reader Comments

Sorry, comments are closed.