Certificates in PHP, or what ASN.1 asks of you

Most applications treat a certificate as an opaque file to hand to OpenSSL. Sooner or later one asks a question the extension does not answer, and you find yourself inside ASN.1.

Three layers, often confused

  • ASN.1 describes the structure: this is a sequence, containing an integer, then a set of names.
  • DER is one way of writing that structure as bytes, and it is distinguished: exactly one valid encoding per value. That uniqueness is what makes a signature over it meaningful.
  • PEM is DER in base64 between two banner lines, so it survives a copy and paste.

When somebody says a certificate is « in PEM », they are describing the envelope, not the content.

Why the distinguished part matters

A certificate is signed over its DER bytes. Two encodings of the same logical value would produce two different signatures, so DER forbids the choice: lengths in their shortest form, set members in a defined order, no leading zeros.

The consequence for anyone parsing: keep the original bytes. Decode to read, verify against what you received. Re-encoding a structure and verifying against the result is a bug that only appears with certain inputs, which is the worst kind. The same trap exists in CBOR, for the same reason.

What you actually need this for

  • Reading a Subject Alternative Name properly, including its several forms.
  • Walking a chain and checking basic constraints rather than trusting the order you were given.
  • Verifying a Webauthn attestation, where the certificate carries extensions specific to the authenticator.
  • Producing a certificate signing request without shelling out to a binary.

pki-framework handles ASN.1, X.509, PKCS#10 and the surrounding structures in PHP, without the OpenSSL extension standing between you and the bytes. It is the most recently updated of the small libraries here.