This post contains the bare minimums you need to start working with x509 certificates. After reading the post you should have a better idea about the meaning of the different acronyms related with SSL certificates (ASN1, DER, PEM, etc.). You will also have a better understanding of the format of the certificate.
Tools are provided to create your own certificates and also to use the certificates you have created in SSL communications. The information in this article should be valuable in understanding the certificate format and useful if you need to work with certificate parsing, SSL implementations or fuzzing of the related technologies.
First, ASN1. It is a language to describe the format of a data structure, that is, how many fields, what types, etc. From wikipedia:
Abstract Syntax Notation One (ASN.1) is a standard and flexible notation that describes data structures for representing, encoding, transmitting, and decoding data
ASN1 has allows structures to be of two broad types, complex structures or simple types. Complex structures define objects made of other objects. Simple types are used when fields can be represented by native types: INTEGER, UTCTIME, BIT STRING, etc.
For instance the ASN1 description of a x509 certificate is as follows:-
Certificate ::= SEQUENCE { tbsCertificate TBSCertificate, signatureAlgorithm AlgorithmIdentifier, signature BIT STRING }
Without entering too much into detail, the above structure says that our certificate is a complex object (SEQUENCE) that is made of a three different fields. Two of them are in turn complex structures (TBSCertificate and AlgorithmIdentifier) and one is of an ASN1 native type (signature is of type BIT STRING). Other sections of the x509 ASN1 definition will describe the structure of the TBSCertificate and AlgorithmIdentifier classes. See the References section for full details.
ASN1 is a high-level language and it is also human readable. However, when we want to use the information described in the ASN1 notation, for instance inside a TCP packet, we need to encode our message as a string of bits. This is where BER (Basic Encoding Rules) and DER (Distinguished Encoding Rules) come into play.
The difference between BER and DER is that with BER a single piece of information can be encoded in multiple ways and DER is a restriction of the BER rules to ensure that there is only one possible encoding for a given information.
Each field in the ASN1 description is encoded using the following pattern:
[TAG_TYPE], [TAG_LENGTH], [TAG_CONTENTS]
Each ASN1 type has a corresponding TAG_TYPE value. For instance, the SEQUENCE tag is 0×30, the INTEGER tag is 0×02, etc. Consult the References for a full list.
The tag length can be encoded using the short or the long form. If the length of the contents is under 127 characters, then the sort form is used, otherwise, the long form is used. The sort form has the 8th bit set to 0 and the remaining 7 bits represent the length of the contents. The long form has the 8th bit set to 1 and the remaining 7 representing the number of additional bytes required to represent the length of the contents. Examples:
0x16, // CHAR STRING 0x09, // 0x09 = 9 bytes // 'U', 'S', 'E', 'F', 'U', 'L', 'F', 'O', 'R' 0x55, 0x53, 0x45, 0x46, 0x55, 0x4c, 0x46, 0x4f, 0x52
0x30, // SEQUENCE 0x82, 0x01, 0x13 // 0x113 = 275 // SEQUENCE CONTENTS 0x30, 0x82, 0x01, 0x07, [...] // and 271 additional bytes
In order to create a valid x509 certificate we only need to DER encode the different fields of the ASN1 description using the TAG, LENGTH, CONTENTS format.
Finally PEM is the Base64 encoded version of a DER encoded certificate. Usually PEM certificate files contain a section for the private key and a section for the certificate as shown below:-
-----BEGIN RSA PRIVATE KEY----- MIICXQIBAAKBg [... more base64 encoded data ...] -----END RSA PRIVATE KEY----- -----BEGIN CERTIFICATE----- MIICDTCCAgGgA [... more base64 encoded data ...] -----END CERTIFICATE-----
There are at least three different options to generate a certificate. First is to use the openssl req command (check the certificates HOWTO).
Other option is to use x509.rb, a ruby wrapper around OpenSSL. This would be more useful for instance in a context where you need to create lots of certs (i.e. when fuzzing).
And finally you could always create a certificate by hand, crafting the appropriate DER-encoded ASN1 sequences. This again is something I would like to invest some time into but that unfortunately did not have the time to do this time. If you want to explore this path, the documents in the References section should get you kick started.
To test the new certificate, the easiest way is to use open ssl:
openssl s_server -cert [certificate] -accept [port number] -www
However, if you want to use a broken or malformed certificate openssl would refuse to load it. The are a few options. First, since the server certificate is sent in the second packet of the SSL handshake (server hello) you could always create a small script that listens for the client hello and replies with the malformed package. You could possibly use scapy for that (I hope to look into this in the future).
The other option is to download OpenSSL and patch the function that puts the SSL certificate into the wire. The idea is that you run openssl and point it to a valid certificate in the command line but then hard-code the one you want to use so the command line is ignored.
The function name we are interested in is ssl3_output_cert_chain inside ssl/s3_both.c and the structure you want to modify is buf->data.
Popularity: 11% [?]
Leave a reply