OpenSSL is able to use a specific directory structure for CA certificates and CRLs. If you pass a directory name as the third argument to SSL_CTX_load_verify_locations
(as described in this question), it will look for CA certificates in this directory in order to verify client certificates. It finds the correct CA certificate by taking the hash of the issuer of the client certificate and appending an integer, e.g. 34bb8598.0
. Usually, those names are symlinks pointing to the real files, and the symlinks are created using the c_rehash
tool.
Likewise, OpenSSL can store certificate revocation lists in such directories, as described in this question, and look up the correct revocation list by the hash of the certificate issuer.
Now, I need to make a program reuse such a CRL directory. The program doesn't use OpenSSL, so I need to generate those hashes in some other way. What is the algorithm for generating those hashed filenames?
The hash format is not documented, so this is likely to change — in fact, it has changed once already. The x509
command supports the options -subject_hash
and -issuer_hash
along with -subject_hash_old
and -issuer_hash_old
. This description is for the "new" hash format as of OpenSSL 1.0.1f.
The X509_subject_name_hash
and X509_issuer_name_hash
functions just call X509_NAME_hash
on the corresponding certificate attribute. That function takes the SHA-1 hash of the "canonical encoding" of the name, treats its first four bytes as a little-endian 32-bit integer, and returns it (effectively reversing the first four bytes of the hash).
So what is the "canonical encoding"? It is a mutation of the DER representation of the issuer name, generated by the function x509_name_canon
. DER is a tag-length-value encoding. The object tree we're representing looks like this:
rdnSequence
, with tag 0x31
(decimal 49)
0x30
(decimal 48)
0x06
The string values, as given in the certificate, can be represented with a number of different types, e.g. a "printable string" with tag 0x13
, an "IA5 string" with tag 0x16
, or a UTF-8 string with tag 0x0c
.
When generating the "canonical encoding", the value for each item in the RDNSequence gets converted to UTF-8, and reencoded as a UTF-8 string with the tag 0x0c
. This happens in the asn1_string_canon
function. Furthermore, the following transformations are applied:
0x20
).And that's all you need to do.
Note that the ASN.1 definitions of some of the fields in question do not permit UTF-8 strings (for example, country codes are restricted to "printable strings"), so you may not be able to use your ASN.1 encoding library directly.