Parsing X.509 certificates

Long, long time ago, someone implemented a very simple batch request/response processing with signature verification, using openssl_verify[1]. Yes, PHP.
Now we are re-implementing the receiver part in Racket.

Trouble is the information stored in database is in the form X.509 certificates and not just DER-encoded public info which can be loaded directly by datum->pk-key[2].

Using asn1[3] I was able to parse the source certificate from PEM form (stripping delimiters, base64-decode, then bytes->asn1/DER with (SEQUENCE-OF ANY*) type). Yet when I traverse down the certificate structure tree to find the 270 bytes in bit-string which represent 2048-bit RSA key (including modulus), I failed to load it into the pk-key as supported by the crypto module.

Is it really that hard as there are still some missing bits and pieces or am I missing something? As a workaround, we can extract SubkectPublicKeyInfo using openssl binary into DER format and use datum->pk-key, but that solution is far from optimal given the fact that the certificates are stored in a database we need to query...

[1] https://www.php.net/manual/en/function.openssl-verify.php
[2] https://docs.racket-lang.org/crypto/pk.html#(def._((lib._crypto%2Fmain..rkt)._datum-~3epk-key))
[3] ASN.1
[4] Crypto: Cryptographic Operations

Does read-pem from crypto/pem help? It mentions X.509 specifically.

If you hit a bit string, you've gone too far: the bit string contains the encoded public key, but the SubjectPublicKeyInfo contains that and also an AlgorithmIdentifier that determines what pk algorithm the key belongs to (and how the key is encoded).

You might be able to "repack" the SubjectPublicKeyInfo by extracting the sequence that contains the bit string (and the partly-decoded AlgorithmIdentifier) and then re-encoding it as a (SEQUENCE-OF ANY*).

If you can wait a week or so, I have a ~95% complete branch for dealing with certificates that I just haven't gotten back to finishing. The repo is GitHub - rmculpepper/crypto, and the branch is b-x509. Note that the branch has a separate crypto-x509-lib package. With that installed, you can do the following:

> (require crypto/x509)
> (define c (car (pem-file->certificates "path/to/cert.pem")))
> (send c get-spki)
;; returns the SubjectPublicKeyInfo as a byte string
3 Likes

Thanks Ryan! Repacking the whole sequence - of course - works. My problem was I was trying to do it as (SEQUENCE-OF ANY) and not (SEQUENCE-OF ANY*) and tried to handle the frame structs myself.

I've created a small module that does exactly this and we will use it for development. Looking at your b-x509 branch makes me appreciate why you were dealing with ASN.1 notation DSL - that could simplify things like private/asn1.rkt... Of course we'll switch to pem-file->certificates once it is possible. Also no rush - we can discuss the current state on Saturday, I assume you'll show up at the meetup. And presumably, I might be able to help - 23 years of X.509 and related stuff lurk in my head...

2 Likes

Oh, that would've saved me the manual decode at least :wink: Next time I'll sift through the docs more vigilantly. Thanks!