Lion Cipher Lab
Parse an X.509 certificate byte by byte, with a DER decoder you write from scratch
- Foundations
- Advanced
- ~2 hours
- Free · no account required
Why it matters
Every TLS connection, signed update and passkey registration starts with a program reading an X.509 certificate out of raw bytes. That reading step is a security boundary. If two programs read the same bytes differently, an attacker can show each one a different certificate. That is not a theory: it is how the 2009 NUL-in-the-name certificates fooled browsers, and how a 2014 bug let forged RSA signatures past Firefox and Chrome. This lab takes the mystery out of the format. You write a decoder for DER, the strict binary encoding certificates use, from nothing but the specification. You prove…
What you'll learn
- reading a DER tag-length-value header by hand: class bits, the constructed bit, the high-tag-number form, and short, long and indefinite lengths (your lab certificate starts 30 82 01 df: a SEQUENCE of 479 bytes)
- decoding the value types a certificate uses: two's-complement INTEGER (02 01 80 is -128, not 128), OBJECT IDENTIFIER with the 40*X+Y first byte and base-128 arcs, BIT STRING with its unused-bits byte, and UTCTime vs GeneralizedTime with the RFC 5280 2050 rule
- walking tbsCertificate into its fields, including the [0] version that stores 2 to mean v3 and the [3] extensions whose values are DER inside an OCTET STRING
- proving a parser correct against an independent one: 60 of 60 TLVs and 12 of 12 fields identical to openssl asn1parse and openssl x509
- running your parser over the real roots your OS trusts (90 on the test machine, 0 strict rejections) and finding a real RFC 5280 profile deviation in one of them
- measuring strictness as a security property: of 8 non-DER mutants of your own certificate, a lax parser accepted 8, the strict parser 0, and OpenSSL 5
- explaining parser differentials with two verified historical cases (the 2009 NUL-in-CN certificates, CVE-2009-2408, and the 2014 NSS signature-parsing flaw, CVE-2014-1568) without building an exploit
- knowing the limits: a strict parser accepted both valid-DER traps (a NUL inside the CN and a corrupted signature), so parsing is never validation
Steps in this lab
- What you are building: a decoder for the bytes under every certificate
- Set up: a terminal, Python and OpenSSL
- Make two certificates of your own with openssl req -x509
- Read the first sixteen bytes by hand: tags and lengths
- Write the decoder: der.py, with a strict mode and a lax mode
- Value types, proven on hand-made bytes: INTEGER, OID, tags, lengths, times, BIT STRING
- Walk your certificate: the tree, then tbsCertificate field by field
- Prove it against OpenSSL: every TLV and every field, then the 2050 rule
- Run it over the real roots your computer trusts
- Strictness as a security property: mutate your own certificate and measure who accepts it
- Why parser differentials mattered: two real cases, explained
- Honest negatives: what strict parsing does not do, measured
- Do it better: never ship this parser, and what a pro does instead