Skip to content
KEDBYTE
How Identity Works
Chapter
26

The Certificate

Part III · The Certificate and the Signature|11,536 words|about 50 min read|Volume 3

26.0 What this chapter gives you#

  1. You will be able to say, in one sentence, what a certificate is and what it is not, without using the word “trust” as a hiding place.
  2. You will be able to name the three top-level parts of an X.509 certificate and say which of them the signature covers.
  3. You will be able to read the output of the command openssl x509 -text line by line and say what every field is for.
  4. You will be able to explain why the name a browser checks lives in the Subject Alternative Name extension and not in the Common Name.
  5. You will be able to state the wildcard matching rules exactly, and decide correctly whether a given certificate covers a given hostname.
  6. You will be able to tell the difference between key usage and extended key usage, and predict what breaks when either one is wrong.
  7. You will be able to explain the basic constraints extension, the CA bit, and why one missing check in 2002 made every browser on Windows forgeable.
  8. You will be able to convert a certificate between its binary form and its text form, and say how many bytes and lines each takes.
  9. You will be able to build a certificate yourself and watch a real verifier refuse it, for the exact reason you planted.

A certificate is the most misunderstood object in computing. People call it a “security certificate”, which suggests it makes something secure. People say a site “has a certificate”, as though the certificate were a badge of good character. Neither is right. A certificate is a piece of paperwork. It is a short, rigidly structured statement, written by one party about another, and signed so that the statement cannot be edited afterwards. The statement is almost always the same dull sentence: this name goes with this key.

That sentence is dull, and it is also the whole problem of public key cryptography. Anyone can make a key pair. A key pair is just two large numbers with a mathematical relationship, and generating one costs a fraction of a second on a phone. What nobody can do, by mathematics alone, is prove which person or which machine a given key belongs to. Chapter 25 set out that problem in full: the maths gives you secrecy and it gives you signatures, but it cannot tell you whose key you are holding. A certificate is the paperwork that answers the question, and like all paperwork it answers it only as well as the clerk who filled it in.

What makes the certificate worth a chapter of its own is the shape of it. X.509, the format in question, has about a dozen fields in its body and about fifteen standard extensions, and almost none of them were in the original 1988 design. They were added one at a time, over thirty-odd years, and each one was added because something broke. A field that stops a certificate being used for the wrong purpose exists because certificates were once used for the wrong purpose. A field that stops an ordinary web server certificate being used to issue other certificates exists because, for years, on the most popular browser in the world, it could be. Read the certificate as a list of fields and it is tedious. Read it as a list of scars and it is a history of the internet’s security failures, written in a form you can print out.

This chapter reads real certificates. Not diagrams of certificates, not made-up examples: two certificates that are, as of August 2026, in live use holding up a large fraction of the web, plus one that we will build ourselves so that we can break it on purpose and watch a verifier catch us. Everything printed here was produced by running the commands shown, on the machine this chapter was written on, against files you can obtain yourself. Where a line has been shortened to fit the page, the text says so.

One boundary, stated once. This chapter is about a single certificate: what is inside it and why. It is not about how a verifier finds the parent of a certificate, orders a set of them into a chain and validates that chain; that is genuinely a different algorithm, implementations genuinely disagree about it, and chapter 27, “The Chain”, handles it properly. Nor is this chapter about who is allowed to sign certificates and what they must check first; chapter 28, “The Certificate Authority”, covers that. We stay inside the four corners of one document.

The plain version#

A shop, a lock, and a stranger#

Ravi runs an electrical shop. He wants customers to be able to send him orders that nobody else can read. So he does something clever with locks.

He buys a special kind of padlock. It has one key, which he keeps, and the padlock itself he gives away freely: he leaves a basket of open padlocks on his counter, and anyone may take one. If you want to send Ravi a private order, you put your order in a box, snap one of his padlocks shut on it, and send the box. Once the padlock is shut, only Ravi’s key opens it. Not even you can reopen it. You never had to share a secret with Ravi in advance. This is the whole trick of public key cryptography in one object: the padlock is public, the key is private, and giving out padlocks costs Ravi nothing.

Now the problem. You are not in Ravi’s shop. You are three hundred kilometres away, and a padlock arrives in the post with a note saying “this is Ravi’s padlock, from Ravi’s Electricals”. How do you know it is? Anybody can buy a padlock. Anybody can write a note. If Priya intercepts your letters, she can send you her own padlock with Ravi’s name on the note, read everything you send, and pass it on to Ravi in one of his real padlocks. You would never notice. The padlock cannot vouch for itself. A padlock has no name written into it that means anything; it is a lump of metal with a shape.

So the town does something ordinary and old. The Chamber of Commerce keeps an office on the main road. Every shopkeeper who wants one goes there in person, brings the shop’s lease, and shows the office a padlock. The office writes a card:

The padlock whose shape is 7F 3A 91 ... belongs to
Ravi's Electricals, 14 Market Road. Written by the
Kochi Chamber of Commerce, good from 1 March 2026
until 1 June 2026, card number 4471.

Then the office presses its seal into the card. The seal is the important part. Everybody in town already knows what the Chamber’s seal looks like, because it is on the wall of the post office and on the back of every bus ticket. Nobody has to go and ask the Chamber whether a card is genuine; they look at the seal.

That card is a certificate. That is all a certificate is. It is a short written statement by one party about another, saying “this name goes with this lock”, sealed so it cannot be altered.

What the seal actually does, and what it does not#

Be precise about the seal, because almost everyone gets this wrong.

The seal does not make the card true. The seal makes the card unchangeable. If Priya gets hold of Ravi’s card and scratches out “Ravi’s Electricals” and writes “Priya’s Electricals”, the seal no longer fits the words. Anyone checking will see that the impression and the text disagree, and will throw the card away. That is the entire mechanical function of the seal: it welds a particular set of words to a particular author.

Whether the words are true is a completely separate question, and it depends entirely on how careful the Chamber’s clerk was. If the clerk stamped the card without asking for the lease, the card is a perfectly sealed lie. The seal will still check out. Every reader in town will still accept it. This is not a flaw in the design; it is the design. Sealing and checking are different jobs done by different people at different times, and the seal only ever speaks for the sealing.

So a certificate carries two claims that must be kept apart in your head. The first claim is “these words have not been altered since the Chamber wrote them”, and mathematics guarantees that claim absolutely. The second claim is “these words were true when the Chamber wrote them”, and nothing guarantees that claim except procedure, audits and the Chamber’s fear of losing its reputation. Chapter 28 is about the second claim. This chapter is about the words.

A real card, read out loud#

Here is a real one, in plain words. It is a card that, as of August 2026, is sitting behind a very large number of the padlocks on the web. Its holder is called R11 and it belongs to a charity called Let’s Encrypt.

The card says: I was written by the Internet Security Research Group. I am about a holder called R11, which is part of Let’s Encrypt, in the United States. Here is the holder’s padlock shape, a number 2048 binary digits long. I am good from the start of 13 March 2024 until one second before midnight on 12 March 2027. My card number is 8a7d3e13d62f30ef2386bd29076b34f8. And then four extra notes: this holder may write cards for other people; but the cards it writes may not themselves write cards for anyone else; this holder’s padlock may be used to seal cards and cancellation lists, and nothing else; and if you want my author’s own card, it is kept at a place called x1.i.lencr.org.

Every one of those lines is doing a job. The dates stop a card outliving the shop. The card number lets exactly one card be cancelled without cancelling every card the Chamber ever wrote. The note about writing cards is what separates a shop from a branch office of the Chamber. The note about what the padlock may be used for stops a card written for one purpose being waved at somebody expecting another. And the pointer to the author’s own card exists because the reader may not be holding it.

Why the card looks like a committee designed it#

It did. And that is the point worth carrying away from the plain half.

Imagine the card had started out as just two lines: a name and a padlock shape. Now walk forward through the years and watch the complaints arrive.

A shop closes down, and its card is still in circulation two years later, so somebody starts using the old padlock. The Chamber adds a start date and an end date.

Two shops are both called Ravi’s Electricals, in different towns. The Chamber starts writing the full address on the card, not just the name.

A customer looking for “the shop at 14 Market Road” cannot match it against a card that says “Ravi’s Electricals”, even though they are the same shop. The Chamber adds a list of every name the shop is known by, and tells readers to check that list and nothing else.

One clever shopkeeper realizes that his card is sealed by the Chamber, and that readers only ever look at whether the seal is the Chamber’s. So he starts writing his own cards for other shops, sealing them with his own padlock, and handing out a little bundle: my card from the Chamber, plus this card I wrote. Readers accept the bundle. The Chamber adds a box on every card: may this holder write cards? yes or no, and readers are told they must look at that box. This is not a story. It is exactly what happened in August 2002, and we will do it ourselves later in this chapter with real software.

A card written so a shop could collect registered post gets waved at a bank manager as proof of identity for a loan. The Chamber adds a line: what this card is good for, and readers are told to refuse a card presented for a purpose not on the list.

A second Chamber opens in the next district, with a different seal, and one shop holds a card from each. Readers now have to work out which seal to compare against. The Chamber starts printing a short fingerprint of its own seal on every card it writes, so a reader can pick the right one immediately.

Do that for thirty years and you get X.509. Nothing in it is decoration. Every field is a fence built at the edge of a hole somebody already fell into.

Where the plain version stops being true#

There is no clerk, and nobody looks at the card#

The picture of a customer squinting at a seal is comfortable and wrong. No human being reads a certificate. A piece of software reads it, in a few hundred microseconds, while a page is loading, and the software’s opinion is final and invisible. If the software decides the certificate is fine, you see a page. If it decides otherwise, you see a warning that most people click through.

The honest version: the reader is a certificate verification routine inside a browser, an operating system or a language library, and it is a large, old, heavily patched piece of code. The rules it applies come from a specification (RFC 5280), a set of industry rules (the CA/Browser Forum Baseline Requirements) and a pile of local decisions its authors made. Different readers apply different subsets. A certificate that one reader accepts, another rejects. That is not a rare edge case; it is a routine operational fact, and chapter 27 shows several examples.

“This name goes with this key” hides which name#

In the shop story, the name was “Ravi’s Electricals, 14 Market Road”, and a customer knew what they were looking for. On the internet, a single machine may answer to a dozen names, some of which the certificate’s author has never seen, and the name the client cares about is the one the user typed - which may be a hostname, or an IP address, or a name with a wildcard star standing in for a label.

The honest version: a certificate does not contain “the name”. It contains a structured set of names of several different types, and the rule for deciding whether a given name the client wanted matches any of them is a written algorithm with sharp edges. Getting that algorithm wrong has produced a long line of security bugs, which is why it now has its own specification, RFC 9525, published in November 2023 to replace RFC 6125 of March 2011.

Sealed does not mean current#

A seal fixes the words. It cannot fix them to the present. The moment a card leaves the Chamber’s office it starts to age, and nothing in the card itself knows whether the shop has since burned down or the padlock has been copied.

The honest version: a certificate is a statement about a moment in the past, carrying an expiry date chosen at issue. Cancelling one before its expiry requires a completely separate mechanism, run by the issuer, that the reader has to go and consult - and those mechanisms work badly enough that the industry’s main response has been to shorten the expiry instead. Chapter 30 is about revocation and why it mostly does not work.

The card and the padlock are not attached#

We drew the card as though the padlock were glued to it. It is not. A certificate contains a copy of the public key, not the key itself in any physical sense, and anybody who has ever seen the certificate can make more copies. Certificates are public objects. They are broadcast in the clear at the start of every connection and published in public logs.

The honest version: holding a certificate proves nothing whatsoever. Anyone can download Google’s certificate right now. What matters is proving you hold the matching private key, and that proof is a separate act - a signature over something fresh, made during the handshake. Chapter 29 shows the exact message that does it. A certificate on its own is a claim, not a credential.

The “yes or no” boxes are only as good as the reader#

We said the Chamber added a box saying whether the holder may write cards, and that readers must check it. Both halves of that sentence are promises, and only the first half is under the Chamber’s control.

The honest version: every constraint in a certificate is advisory unless the verifier enforces it. A certificate can say in the strongest possible terms that its holder is not a certificate authority, and if the verifying code never looks at that field, the constraint does nothing at all. This is not hypothetical. The single most famous certificate bug in history is exactly this: the field was present, correctly set, and ignored.

One card, many meanings#

Finally, the plain story implies that a certificate has one meaning that all readers agree on. They do not. The same file means “a valid web server identity” to one program, “an untrusted stranger” to another that has a different set of Chambers on its wall, and “expired” to a third whose clock is wrong.

The honest version: a certificate has no meaning by itself. Meaning is produced by a verifier applying a policy, with a trust anchor set, at a particular time. Change the anchor set, the policy or the clock, and the same bytes change verdict. Keep this in mind for the rest of the chapter: we are reading a document, and documents do not decide anything.

The technical version#

The three-part envelope#

An X.509 certificate is defined in ASN.1, a notation for describing data structures, and its outermost shape has been the same since 1988. RFC 5280, “Internet X.509 Public Key Infrastructure Certificate and Certificate Revocation List (CRL) Profile”, published in May 2008, gives it in section 4.1 as:

Certificate  ::=  SEQUENCE  {
     tbsCertificate       TBSCertificate,
     signatureAlgorithm   AlgorithmIdentifier,
     signatureValue       BIT STRING  }

Three parts, and only three. The names are worth saying out loud because they carry the entire security argument.

tbsCertificate is “to be signed”. It is the statement: every field the issuer is asserting, including the subject name, the public key, the validity dates and all the extensions. This is the body of the letter.

signatureAlgorithm names the algorithm the issuer used, for example sha256WithRSAEncryption, so the reader knows how to check the signature.

signatureValue is the signature itself, a bit string, computed over the encoded bytes of tbsCertificate and nothing else.

That last clause is the one to memorize. The signature covers the body only. It does not cover the outer signatureAlgorithm field, and it does not cover itself, which would be circular. Everything a verifier is entitled to believe lives inside tbsCertificate. Anything outside it is a hint that the verifier must not rely on.

Now, a subtlety that looks like sloppy design and is in fact a fence. The algorithm is named twice: once inside tbsCertificate, in a field RFC 5280 calls signature (section 4.1.2.3), and once outside, in signatureAlgorithm (section 4.1.1.2). The inner copy is protected by the signature; the outer copy is not. RFC 5280 requires the two to contain the same value, and the CA/Browser Forum Baseline Requirements, in the certificate profiles introduced by ballot SC062 (adopted 22 April 2023, effective 15 September 2023), tighten this to “the encoded value MUST be byte-for-byte identical to the tbsCertificate signature”. The reason is that an attacker who can edit the unprotected outer copy could try to persuade a verifier to check the signature with a weaker algorithm than the one the issuer actually used. Comparing the two copies closes that door.

Here is the whole object as a picture.

  Certificate (a SEQUENCE)
  +----------------------------------------------+
  |  tbsCertificate                              |
  |    version, serialNumber, signature,         |
  |    issuer, validity, subject,                |
  |    subjectPublicKeyInfo, extensions [3]      |  <-- signed
  +----------------------------------------------+
  |  signatureAlgorithm  (a copy of the above)   |  <-- not signed
  +----------------------------------------------+
  |  signatureValue      (BIT STRING)            | <- signature
  +----------------------------------------------+

  signatureValue = Sign(issuer private key,
                        DER bytes of tbsCertificate)

DER and PEM: why the bytes have to be exactly these bytes#

A signature is over bytes. So before anything can be signed, the structure has to become a definite string of bytes, and there must be exactly one way to do it. If two encoders produced different bytes for the same certificate, a signature made over one would fail over the other.

The encoding is DER, the Distinguished Encoding Rules, defined in ITU-T Recommendation X.690. DER is a restricted form of BER, the Basic Encoding Rules; the restriction is precisely that every value has one and only one legal encoding. Booleans that are false are omitted where a DEFAULT allows it, lengths use the shortest possible form, set elements are sorted. “Distinguished” means canonical.

Everything in DER is a triple: a tag saying what type this is, a length, and that many bytes of content. Structures nest by putting triples inside the content of other triples. That is the whole scheme.

Take a real file. ISRG Root X1 is the root certificate of the Internet Security Research Group, the charity behind Let’s Encrypt; on a Debian-family Linux it ships in the system trust store. Convert it to raw DER and look at the start:

openssl x509 -in /etc/ssl/certs/ISRG_Root_X1.pem \
        -outform DER -out isrg.der
od -A d -t x1 -N 32 isrg.der
0000000 30 82 05 6b 30 82 03 53 a0 03 02 01 02 02 11 00
0000016 82 10 cf b0 d2 40 e3 59 44 63 e0 bb 63 82 8b 00

Read it. Byte 0 is 30, the tag for SEQUENCE: this is the outer Certificate. Byte 1 is 82, which has its top bit set, so it is a long-form length saying “the next 2 bytes are the length”. Those bytes are 05 6b, which is 1387. So the content is 1387 bytes and the header was 4, giving 1391 bytes in total. Check it against the file:

$ ls -l isrg.der
-rw-r--r-- 1 root root 1391 ... isrg.der

Exactly 1391. The arithmetic is not a coincidence; it is the format.

Byte 4 starts the next triple: 30 82 03 53, another SEQUENCE, 0x0353 = 851 bytes long. That is tbsCertificate. Then a0 03 02 01 02: tag a0 is context-specific 0, the [0] EXPLICIT wrapper around the version, 3 bytes long, containing 02 01 02 - an INTEGER, 1 byte, value 2. Version 2 in the encoding means version 3 in human speech, because the enumeration starts at zero. Then 02 11 00 82 10 cf ...: an INTEGER, 17 bytes, whose first byte is 00. That leading zero is there because DER integers are signed two’s complement, the real first byte 82 has its top bit set, and without the pad the serial number would be negative. RFC 5280 section 4.1.2.2 requires serial numbers to be positive.

You do not have to do this by hand. OpenSSL will walk the tree for you:

openssl asn1parse -in /etc/ssl/certs/ISRG_Root_X1.pem -i
    0:d=0  hl=4 l=1387 cons: SEQUENCE
    4:d=1  hl=4 l= 851 cons:  SEQUENCE
    8:d=2  hl=2 l=   3 cons:   cont [ 0 ]
   10:d=3  hl=2 l=   1 prim:    INTEGER           :02
   13:d=2  hl=2 l=  17 prim:   INTEGER
                          :8210CFB0D240E3594463E0BB63828B00
   32:d=2  hl=2 l=  13 cons:   SEQUENCE
   34:d=3  hl=2 l=   9 prim:    OBJECT
                          :sha256WithRSAEncryption
   45:d=3  hl=2 l=   0 prim:    NULL
   47:d=2  hl=2 l=  79 cons:   SEQUENCE
   49:d=3  hl=2 l=  11 cons:    SET
   51:d=4  hl=2 l=   9 cons:     SEQUENCE
   53:d=5  hl=2 l=   3 prim:      OBJECT   :countryName
   58:d=5  hl=2 l=   2 prim:      PRINTABLESTRING   :US

Two lines above have been wrapped to fit the page; the tool prints them unbroken. Column one is the byte offset, hl is the header length, l is the content length, d is the depth. You are looking at the actual file.

That is DER. The second half of this subsection is the wrapper you will actually see in files, because DER is binary and binary does not survive email, configuration files or copy and paste. The wrapper is base64 of the DER, split into lines, with a labelled header and footer:

-----BEGIN CERTIFICATE-----
MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw
TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh
... 27 further lines ...
-----END CERTIFICATE-----

The arithmetic again, on the same real file. The DER is 1391 bytes. Base64 turns every 3 bytes into 4 characters, rounding up, so 1391 bytes become ceil(1391 / 3) times 4 = 464 times 4 = 1856 characters. At 64 characters per line that is exactly 29 lines, plus the BEGIN and END lines, giving 31 lines in the file. Count them: wc -l on the real file returns 31.

The name PEM stands for Privacy Enhanced Mail, a secure email scheme specified in RFC 1421 through RFC 1424 in February 1993 that never took hold. The protocol died; its container format outlived it by thirty years and is now the default way certificates are stored, shipped and pasted into support tickets. The format was finally written down properly, long after everyone was already using it, in RFC 7468, “Textual Encodings of PKIX, PKCS, and CMS Structures”, April 2015.

Two practical notes. First, the label matters: CERTIFICATE means a DER X.509 certificate, PRIVATE KEY means a PKCS#8 private key, CERTIFICATE REQUEST means a PKCS#10 request. Software keys off the label, and a file labelled wrongly will be rejected even if the bytes are fine. Second, a PEM file may contain several blocks one after another; that is how a server is usually given a leaf certificate followed by its intermediates. Converting between the two forms is one command each way:

openssl x509 -in cert.pem -outform DER -out cert.der
openssl x509 -in cert.der -inform DER -out cert.pem

The first line turns the text form into the binary form; the second turns it back.

The body: seven fields that matter and two that do not#

Inside tbsCertificate, RFC 5280 section 4.1.2 defines:

TBSCertificate  ::=  SEQUENCE  {
     version         [0]  EXPLICIT Version DEFAULT v1,
     serialNumber         CertificateSerialNumber,
     signature            AlgorithmIdentifier,
     issuer               Name,
     validity             Validity,
     subject              Name,
     subjectPublicKeyInfo SubjectPublicKeyInfo,
     issuerUniqueID  [1]  IMPLICIT UniqueIdentifier OPTIONAL,
     subjectUniqueID [2]  IMPLICIT UniqueIdentifier OPTIONAL,
     extensions      [3]  EXPLICIT Extensions OPTIONAL }

version is 0, 1 or 2 in the encoding, meaning v1, v2 or v3. Version 1 is the original 1988 certificate: no extensions at all, just names and a key. Version 2 added the two unique identifier fields. Version 3 added the extensions field, and with it everything that makes a modern certificate usable. The relevant editions of ITU-T Recommendation X.509 are the first, approved November 1988, the second, November 1993, and the third, August 1997, which carries version 3. Every publicly trusted TLS certificate today is v3; the Baseline Requirements require it in every profile.

serialNumber is a positive integer chosen by the issuer, unique among the certificates that issuer has written. It is what a revocation list points at. RFC 5280 section 4.1.2.2 says conforming CAs must not use serial numbers longer than 20 octets, and that certificate users must be able to handle 20. The Baseline Requirements go further: the serial number must be non-sequential, greater than zero, under 2 to the power 159, and must contain at least 64 bits of output from a cryptographically secure random number generator.

That 64-bit randomness rule is a scar with a date on it. In December 2008, at the 25th Chaos Communication Congress, Alexander Sotirov, Marc Stevens, Jacob Appelbaum, Arjen Lenstra, David Molnar, Dag Arne Osvik and Benne de Weger presented a working rogue certificate authority certificate, built by exploiting a collision in the MD5 hash function. Their attack needed to predict the contents of the certificate the CA would issue - including its serial number, which the CA in question assigned sequentially. Unpredictable serial numbers do not fix a broken hash function, but they make the class of attack that needs a predictable certificate body enormously harder. The rule stayed.

signature is the inner copy of the algorithm identifier discussed above.

issuer and subject are both of type Name: who wrote the certificate, and who it is about. They get their own subsection below.

validity is a pair of times:

Validity ::= SEQUENCE {
     notBefore      Time,
     notAfter       Time }

Time ::= CHOICE {
     utcTime        UTCTime,
     generalTime    GeneralizedTime }

RFC 5280 section 4.1.2.5 requires dates through the year 2049 to be encoded as UTCTime, which has a two-digit year, and dates in 2050 or later as GeneralizedTime, which has four. A reader must handle both. In the ISRG Root X1 dump above the two times appear as 150604110438Z and 350604110438Z: 4 June 2015 at 11:04:38 UTC, and the same instant in 2035. The two-digit year rule is that 50 to 99 means 1950 to 1999 and 00 to 49 means 2000 to 2049, which is a Y2K-era compromise that will need attention around 2049.

There is also a convention, not a rule, for certificates with no meaningful expiry: notAfter is set to 99991231235959Z, which RFC 5280 describes as the way to say the certificate has no well-defined expiration date.

subjectPublicKeyInfo is the payload. It is an algorithm identifier plus the key itself as a bit string. For RSA the key is a SEQUENCE of modulus and exponent; for elliptic curve keys it is a point on a named curve. This is the thing the whole document exists to bind a name to.

issuerUniqueID and subjectUniqueID are the two fields that do not matter. They came in with version 2 to disambiguate reused directory names, and RFC 5280 recommends conforming CAs not generate them. You will effectively never see them. They are worth knowing about only so that you recognize the [1] and [2] tags if you ever meet one.

extensions is a sequence of triples: an OID naming the extension, a boolean called critical, and an octet string holding the extension’s own DER. The critical flag is the cleverest piece of design in the format. It means: if you do not understand this extension, you must reject this certificate. Without it, adding a new restriction would be useless, because old software would ignore it and carry on. With it, a CA can add a constraint and be sure that any verifier which does not understand the constraint will fail closed rather than open.

Names: distinguished names, RDNs, and the retirement of CN#

A Name in X.509 is not a string. It is a path through a directory tree, because X.509 was born as part of X.500, a 1988 plan for a global distributed directory of everything. That plan did not happen. Its naming scheme survived.

Name ::= RDNSequence
RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
RelativeDistinguishedName ::= SET OF AttributeTypeAndValue
AttributeTypeAndValue ::= SEQUENCE {
     type   AttributeType,      -- an OID
     value  AttributeValue }

Read outward. A distinguished name, or DN, is an ordered sequence of relative distinguished names, or RDNs. Each RDN is an unordered set of attribute-and-value pairs, where the attribute is an object identifier. Almost every RDN in practice contains exactly one pair, which makes the SET look like pointless machinery, but the SET is there because X.500 allowed a directory node to be identified by several attributes at once.

The attributes you will actually see:

Attribute OID Meaning
countryName (C) 2.5.4.6 Two-letter country code
organizationName (O) 2.5.4.10 Organization name
commonName (CN) 2.5.4.3 Free-text name
organizationalUnit (OU) 2.5.4.11 Department, now removed

The Baseline Requirements pin the encoding of each: commonName, for instance, must use UTF8String or PrintableString and is limited to 64 characters. That PrintableString type is a restricted character set inherited from telex-era standards; it has no lower-case restriction but does exclude, among other things, the underscore and the ampersand. ISRG Root X1’s name attributes are PrintableString, as the asn1parse dump above shows.

The organizationalUnit attribute is a small, complete example of the chapter’s thesis running backwards: a field removed because it went wrong. OU was free-form text that no CA had any way to verify, so it filled up with marketing claims and, in some incidents, outright falsehoods. CA/Browser Forum ballot SC047, “Sunset subject:organizationalUnitName”, adopted 30 June 2021, began its removal from publicly trusted TLS certificates.

Now the big one: why the Common Name is no longer where a hostname lives.

For most of the 1990s and 2000s, a web server certificate said which site it was for by putting the hostname in the subject’s commonName: CN=www. example.com. It worked, roughly. It was also wrong in four separate ways.

First, CN is not typed. It is a free-text field whose declared meaning is “the name of the thing”, and a directory name for a person, a printer and a web server all land in the same field with nothing to tell them apart. RFC 9525 puts it bluntly: the Common Name RDN must not be used to identify a service, because it is not strongly typed and therefore suffers from ambiguities in interpretation.

Second, a DN may contain more than one CN, and the specification does not say which one wins. RFC 2818, “HTTP Over TLS”, May 2000, told implementers to use “the (most specific) Common Name”, which is not a definition anyone can implement identically.

Third, a certificate for a machine with several names needed several CNs or several certificates, and neither worked well.

Fourth, and worst, free text invites parsing bugs. In July 2009, at Black Hat USA, Moxie Marlinspike demonstrated the null-prefix attack: request a certificate for a name containing an embedded null byte, such as a CN reading www.paypal.com followed by a zero byte and then an attacker-controlled domain. The CA’s validation logic saw the attacker’s domain at the end and approved it; the client’s C string handling saw the name stop at the null byte and matched www.paypal.com. The two readers disagreed about where the name ended, and a strongly typed field would not have let them.

The replacement was already in the specification. RFC 2818 said that if a subjectAltName extension of type dNSName is present, that must be used as the identity, and the CN was only a fallback. RFC 6125, March 2011, deprecated the CN fallback. RFC 9525, November 2023, removed it. The Baseline Requirements mark commonName as NOT RECOMMENDED in subscriber certificates, and require that if it is present at all it must contain a character-for-character copy of one of the values already in the subjectAltName extension - it may add nothing.

Browsers moved on their own timetable. Chrome 58, released in April 2017, removed support for commonName matching entirely, and a wave of internal certificates that had never bothered with a SAN broke on the same afternoon. Firefox had already done the same. As of August 2026 no mainstream TLS client will match a hostname against a CN.

Subject Alternative Name#

The subjectAltName extension, RFC 5280 section 4.2.1.6, OID 2.5.29.17, is where identity actually lives. It is a sequence of GeneralName, which is a CHOICE of nine alternatives:

Tag Name type Used for TLS?
[0] otherName No
[1] rfc822Name No, email only
[2] dNSName Yes
[6] uniformResourceId No
[7] iPAddress Yes

The Baseline Requirements permit exactly two of the nine in a publicly trusted TLS server certificate: dNSName and iPAddress. Every other type - otherName, rfc822Name, x400Address, directoryName, ediPartyName, uniformResourceIdentifier, registeredID - is forbidden. The extension must be present, and must contain at least one dNSName or iPAddress.

Encoding details that trip people up:

A dNSName is an IA5String holding the name in ASCII form. An internationalized name must appear in its punycode form, the xn-- encoding, not as Unicode. There is no trailing dot: example.com, never example.com.. The Baseline Requirements state this explicitly.

An iPAddress is not text. It is a raw octet string: 4 bytes for IPv4, 16 for IPv6. The address 203.0.113.10 is the four bytes cb 00 71 0a. Tools print it back as dotted decimal, which hides how it is stored. Public CAs may not put reserved addresses in one; the range 203.0.113.0/24 used in this chapter’s examples is TEST-NET-3 from RFC 5737, reserved for documentation, so no public CA would issue for it. Our own CA later in this chapter will, because our own CA has no rules.

Criticality. RFC 5280 says that if the subject field is an empty sequence, the subjectAltName extension must be marked critical, because otherwise the certificate would name nobody in a way an old verifier must respect. The Baseline Requirements state the rule in both directions: critical if the subject is empty, and not critical otherwise. In practice almost every web certificate has a non-empty subject and a non-critical SAN.

Wildcards. A dNSName may begin with a single asterisk label. The matching rules, from RFC 9525, are narrow and worth learning exactly:

  1. There is only one wildcard character.
  2. It appears only as the complete content of the leftmost label.
  3. It matches exactly one label, never zero labels and never more than one.

Partial wildcards such as w*.example.com are not allowed, and neither is *.*.example.com. Worked through:

Certificate has Client wants Match
*.example.com a.example.com Yes
*.example.com example.com No
*.example.com a.b.example.com No
*.b.example.com a.b.example.com Yes

The second row is the one that catches people. A wildcard certificate for *.example.com does not cover example.com itself; the bare name has to be listed separately, which is why real wildcard certificates almost always carry both entries.

On top of the matching rules there is an issuance rule. Baseline Requirements section 3.2.2.6 requires a CA, before issuing a wildcard certificate, to determine whether the part after the asterisk is registry-controlled or a public suffix, and to refuse unless the applicant controls the whole namespace. The specification’s own examples are that a CA must not issue *.com or *.local but may issue *.example.com. Without that rule, one certificate could impersonate an entire top-level domain.

Key usage and extended key usage#

Two extensions restrict what the certified key may be used for, and they are not the same thing.

keyUsage, RFC 5280 section 4.2.1.3, OID 2.5.29.15, is a bit string with nine named positions:

KeyUsage ::= BIT STRING {
     digitalSignature        (0),
     nonRepudiation          (1),
     keyEncipherment         (2),
     dataEncipherment        (3),
     keyAgreement            (4),
     keyCertSign             (5),
     cRLSign                 (6),
     encipherOnly            (7),
     decipherOnly            (8) }

These describe cryptographic operations, not applications. keyCertSign is the important one for this chapter: it says the key may be used to verify signatures on certificates. RFC 5280 states the tie to basic constraints directly - if the CA boolean is not asserted, the keyCertSign bit must not be asserted either. The extension is normally marked critical, and the Baseline Requirements require it to be critical when present.

extendedKeyUsage, section 4.2.1.12, OID 2.5.29.37, is a different idea: a list of object identifiers naming purposes.

ExtKeyUsageSyntax ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId
KeyPurposeId ::= OBJECT IDENTIFIER
Purpose OID In a TLS leaf
serverAuth 1.3.6.1.5.5.7.3.1 MUST
clientAuth 1.3.6.1.5.5.7.3.2 MAY
codeSigning 1.3.6.1.5.5.7.3.3 MUST NOT
emailProtection 1.3.6.1.5.5.7.3.4 MUST NOT

The right-hand column is from Baseline Requirements section 7.1.2.7.10. The same table also forbids timeStamping (1.3.6.1.5.5.7.3.8), OCSPSigning (1.3.6.1.5.5.7.3.9) and the wildcard anyExtendedKeyUsage (2.5.29.37.0). The prohibition on anyExtendedKeyUsage matters: it exists so that a certificate cannot opt out of the whole mechanism by claiming every purpose at once.

When both extensions are present, RFC 5280 requires them to be processed independently, and the certificate may only be used for a purpose consistent with both. If no purpose satisfies both, the certificate must not be used for anything.

What a mismatch breaks, concretely:

An RSA leaf certificate with only the keyEncipherment bit set will work in a TLS 1.2 handshake using an RSA key transport cipher suite, and will fail in TLS 1.3. TLS 1.3 always authenticates the server with a signature - the CertificateVerify message - so it needs digitalSignature. The Baseline Requirements say this in their own words: digitalSignature is required for use with modern protocols such as TLS 1.3, while keyEncipherment may be asserted to support older protocols. A certificate issued in 2014 with the old bit pattern and renewed unchanged is a real and recurring cause of “works on the old server, fails on the new one”.

An elliptic curve leaf must assert digitalSignature and, under the current profile, should not assert keyAgreement. An ECDSA certificate is never used to encrypt anything, so keyEncipherment on an EC key is simply meaningless and is forbidden.

A certificate with extendedKeyUsage listing only emailProtection, presented as a web server certificate, is rejected by every browser with an error meaning “this certificate is not valid for this use”. The signature is fine. The chain is fine. The purpose is wrong, and that is enough.

One honest note on scope. RFC 5280 defines extendedKeyUsage for the certificate it appears in. It does not define what it means for a CA certificate to carry an EKU - whether that constrains the certificates the CA may issue. Treating a CA’s EKU as a constraint on its children, usually called EKU chaining, is an implementation behaviour that Microsoft’s verifier adopted early and that other verifiers have since implemented in varying degrees. The Baseline Requirements now lean on it: their definition of a technically constrained subordinate CA uses extended key usage and name constraints together to limit what a subordinate may issue. So: the extension is a standard, its presence in leaf certificates is required by industry rules, and its inheritance down a chain is a widely implemented convention rather than something RFC 5280 mandates.

Basic constraints, the CA bit, and August 2002#

BasicConstraints ::= SEQUENCE {
     cA                      BOOLEAN DEFAULT FALSE,
     pathLenConstraint       INTEGER (0..MAX) OPTIONAL }

Two fields, RFC 5280 section 4.2.1.9, OID 2.5.29.19. The cA boolean says whether this certificate’s public key may verify signatures on other certificates. pathLenConstraint, meaningful only when cA is true, gives the maximum number of further CA certificates that may follow this one in a chain; zero means this CA may issue leaf certificates and no further CAs.

Note the DEFAULT FALSE. Under DER, a boolean equal to its default is omitted entirely, so a certificate that is not a CA either omits the extension or includes it with an empty sequence as its value. “Absent” and “false” are the same statement.

The Baseline Requirements are unambiguous for subscriber certificates: cA must be FALSE and pathLenConstraint must not be present. Where present the extension must be critical.

Now the history, because this extension is the reason the whole chapter has its thesis.

On 5 August 2002, a Bugtraq post titled “IE SSL Vulnerability” appeared, signed Mike Benham - the researcher later widely known as Moxie Marlinspike. The finding was one sentence long in substance: Internet Explorer does not check the Basic Constraints. The consequence he drew from it was the sentence that made the disclosure famous: anyone with a valid CA-signed certificate for any domain can generate a valid CA-signed certificate for any other domain. He noted that IE 5, 5.5 and, mostly, 6 were affected, and that Netscape 4.x and Mozilla were not, and that when the attack ran no warnings were given and no dialogs were shown.

Read that carefully. The attack needed no CA compromise, no stolen key, no cryptographic break. It needed one legitimately purchased certificate for one domain you actually own. You then use that certificate’s private key to sign a new certificate for any name you like, and hand the victim both. The victim’s software walks up the chain: the new certificate is signed by your certificate, your certificate is signed by a trusted CA, therefore trusted. The one check that would have stopped it - is this middle certificate allowed to sign certificates? - was not being made.

Microsoft published Security Bulletin MS02-050, “Certificate Validation Flaw Could Enable Identity Spoofing”, on 4 September 2002, tracked as CAN-2002-0862. The bulletin’s own description of the cause is exact: the APIs within CryptoAPI that construct and validate certificate chains - CertGetCertificateChain, CertVerifyCertificateChainPolicy and WinVerifyTrust - do not check the Basic Constraints field. The fix, in Microsoft’s words, ensures that intermediate certificates are not treated as a certificate authority unless the Basic Constraint extension is present with the value of CA set to TRUE. The bulletin was revised repeatedly over the following fourteen months, and a variant of the same problem was tracked separately as CAN-2002-1183.

The lesson is not that Microsoft wrote a bug. The lesson is that a constraint written into a document does nothing until a verifier reads it, and that the gap between “the specification says” and “the code checks” is where security actually lives. Nine years later the same omission appeared in a different stack: CVE-2011-0228 records that the Data Security component in Apple iOS before 4.2.10 and 4.3.x before 4.3.5 does not check the basicConstraints parameter during validation of X.509 certificate chains. Same field, same omission, different decade.

Doing it ourselves, and watching a verifier refuse#

Talk is cheap. Build the attack.

We need a private certificate authority, a normal server certificate issued by it, and then a second certificate signed by that server certificate’s key. Everything below was run with OpenSSL 3.0.13, and the outputs are real.

First, a root:

openssl req -x509 -newkey rsa:2048 -nodes \
  -keyout root.key -out root.crt -days 3650 -sha256 \
  -subj "/C=IN/O=KedByte Demo/CN=KedByte Demo Root" \
  -addext "basicConstraints=critical,CA:TRUE" \
  -addext "keyUsage=critical,keyCertSign,cRLSign"

Then an ordinary leaf for a shop, with a proper set of extensions. The extension file is worth reading on its own, because it is the profile of a modern web certificate written out in four lines:

basicConstraints=critical,CA:FALSE
keyUsage=critical,digitalSignature
extendedKeyUsage=serverAuth
subjectAltName=DNS:shop.example,DNS:www.shop.example,
  DNS:*.api.shop.example,IP:203.0.113.10
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid

The subjectAltName line is one line in the real file; it is broken here to fit the page. Issue it:

openssl req -newkey rsa:2048 -nodes -keyout shop.key \
  -out shop.csr -subj "/CN=shop.example"
openssl x509 -req -in shop.csr -CA root.crt -CAkey root.key \
  -CAcreateserial -out shop.crt -days 90 -sha256 \
  -extfile leaf.ext

And read it back:

Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            4c:a7:03:7c:87:30:77:b6:d9:74:ef:77:56:fa:9a:cc:
            6b:f2:c3:e4
        Signature Algorithm: sha256WithRSAEncryption
        Issuer: C = IN, O = KedByte Demo,
                CN = KedByte Demo Root
        Validity
            Not Before: Aug 17 23:08:26 2026 GMT
            Not After : Nov 15 23:08:26 2026 GMT
        Subject: CN = shop.example
        X509v3 extensions:
            X509v3 Basic Constraints: critical
                CA:FALSE
            X509v3 Key Usage: critical
                Digital Signature
            X509v3 Extended Key Usage:
                TLS Web Server Authentication
            X509v3 Subject Alternative Name:
                DNS:shop.example, DNS:www.shop.example,
                DNS:*.api.shop.example,
                IP Address:203.0.113.10
            X509v3 Subject Key Identifier:
                AA:0C:62:BD:6B:60:90:19:62:1B:3F:D2:E4:87:
                86:E6:25:98:F0:E9
            X509v3 Authority Key Identifier:
                CE:8F:AC:3A:0C:57:BC:A7:BD:96:5A:B8:A0:5C:
                DB:6A:F9:1F:D5:74

Long values are wrapped here; OpenSSL prints them on single lines. Note the serial number: 20 bytes, which is the maximum RFC 5280 allows, generated at random by the -CAcreateserial flag.

Now the 2002 attack. We take shop.crt and its private key - which in the real scenario is simply a certificate we bought for a domain we own - and we sign a brand new certificate for a bank we do not own:

openssl req -newkey rsa:2048 -nodes -keyout bank.key \
  -out bank.csr -subj "/CN=bank.example"
openssl x509 -req -in bank.csr -CA shop.crt -CAkey shop.key \
  -CAcreateserial -out bank.crt -days 90 -sha256 \
  -extfile bank.ext

OpenSSL signs it without complaint, because signing is just arithmetic. The resulting file is a real certificate that really was signed by shop.example’s key. Verify that claim independently, in Python, using the certificate’s own tbsCertificate bytes:

from cryptography import x509
from cryptography.hazmat.primitives.asymmetric import padding

bank = x509.load_pem_x509_certificate(open('bank.crt','rb').read())
shop = x509.load_pem_x509_certificate(open('shop.crt','rb').read())
shop.public_key().verify(bank.signature,
                         bank.tbs_certificate_bytes,
                         padding.PKCS1v15(),
                         bank.signature_hash_algorithm)
print("RSA signature over tbsCertificate: VALID")
RSA signature over tbsCertificate: VALID

The mathematics is perfect. In 2002, that was the end of the story and you had a working impersonation of any site on the internet. Today:

openssl verify -CAfile root.crt -untrusted shop.crt bank.crt
CN = shop.example
error 79 at 1 depth lookup: invalid CA certificate
CN = shop.example
error 32 at 1 depth lookup: key usage does not
      include certificate signing
error bank.crt: verification failed

Two independent refusals, at depth 1, which is the shop certificate. Error 79 is basic constraints: cA is FALSE, so this certificate may not be a link in a chain. Error 32 is key usage: the keyCertSign bit is not set, so this key may not verify a certificate signature. Either alone would be fatal. Modern verifiers check both, because defence in depth is what you build after the first check turns out to have been missing for four years.

That is the chapter’s thesis, executed on a real machine in under a minute.

Key identifiers, and how a verifier finds the parent#

Two more extensions exist purely to make the verifier’s search cheap.

subjectKeyIdentifier, section 4.2.1.2, OID 2.5.29.14, is a short value derived from the certificate’s own public key. RFC 5280 gives two common methods: the 160-bit SHA-1 hash of the subjectPublicKey bit string, or a four-bit type field 0100 followed by the least significant 60 bits of that hash. Method one is what almost everything uses. It is checkable:

Take the certificate’s DER SubjectPublicKeyInfo, pull out the BIT STRING value, strip the leading unused-bits octet, and hash what is left. Call that byte string content:

import hashlib
print(':'.join(f'{b:02X}'
      for b in hashlib.sha1(content).digest()))
79:B4:59:E6:7B:B6:E5:E4:01:73:80:08:88:C8:1A:58:F6:E9:9B:6E

That is the exact value printed as the Subject Key Identifier of ISRG Root X1 by openssl x509 -text. The derivation is not a guess; it reproduces the field.

authorityKeyIdentifier, section 4.2.1.1, OID 2.5.29.35, is the mirror image: it names the key that signed this certificate.

AuthorityKeyIdentifier ::= SEQUENCE {
   keyIdentifier             [0] KeyIdentifier           OPTIONAL,
   authorityCertIssuer       [1] GeneralNames            OPTIONAL,
   authorityCertSerialNumber [2] CertificateSerialNumber OPTIONAL }

In practice only keyIdentifier is used, and it holds the issuer’s subjectKeyIdentifier. In the Let’s Encrypt R11 certificate the authority key identifier is 79:B4:59:E6:7B:B6:E5:E4:01:73:80:08:88:C8:1A:58:F6:E9:9B:6E - the same twenty bytes we just computed from ISRG Root X1’s public key. That is the link, made visible.

Two warnings. First, these identifiers are hints, not proof. A verifier that finds a candidate parent by matching AKI to SKI must still check the signature; an attacker can put any AKI they like in a certificate they mint. Second, a certificate may have several valid parents, and the correct algorithm is a search with backtracking, not a lookup. That algorithm, and the ways implementations disagree about it, is chapter 27.

A small live change worth noting: the Baseline Requirements now mark subjectKeyIdentifier as NOT RECOMMENDED in subscriber certificates, while authorityKeyIdentifier remains required. A leaf certificate has no children, so publishing an identifier for its own key serves nobody and only adds bytes.

Reading a real certificate, field by field#

Here is the command every practitioner types a hundred times a year:

openssl x509 -in r11.pem -noout -text

-in names the file, -noout suppresses re-printing the PEM, -text asks for the human-readable dump. Add -inform DER if the file is binary. Add -fingerprint -sha256 for the hash of the whole certificate.

The subject of the dump is Let’s Encrypt’s R11 intermediate, obtained from Let’s Encrypt’s own published certificate files. Its SHA-256 fingerprint is 59:1E:9C:E6:C8:63:D3:A0:79:E9:FA:BE:14:78:C7:33: followed by 9A:26:B2:12:69:DD:E7:95:21:13:61:02:4A:E3:1A:44, which you can compare against the published value before believing anything below.

Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            8a:7d:3e:13:d6:2f:30:ef:23:86:bd:29:07:6b:34:f8
        Signature Algorithm: sha256WithRSAEncryption
        Issuer: C = US,
                O = Internet Security Research Group,
                CN = ISRG Root X1
        Validity
            Not Before: Mar 13 00:00:00 2024 GMT
            Not After : Mar 12 23:59:59 2027 GMT
        Subject: C = US, O = Let's Encrypt, CN = R11
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)
                Modulus:
                    00:ba:87:bc:5c:1b:00:39:cb:ca:0a:cd:d4:
                    67:10:f9:01:3c:a5:4e:a5:61:cb:26:ca:52:
                    ... 220 further bytes ...
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Key Usage: critical
                Digital Signature, Certificate Sign, CRL Sign
            X509v3 Extended Key Usage:
                TLS Web Client Authentication,
                TLS Web Server Authentication
            X509v3 Basic Constraints: critical
                CA:TRUE, pathlen:0
            X509v3 Subject Key Identifier:
                C5:CF:46:A4:EA:F4:C3:C0:7A:6C:95:C4:2D:B0:
                5E:92:2F:26:E3:B9
            X509v3 Authority Key Identifier:
                79:B4:59:E6:7B:B6:E5:E4:01:73:80:08:88:C8:
                1A:58:F6:E9:9B:6E
            Authority Information Access:
                CA Issuers - URI at host x1.i.lencr.org
            X509v3 Certificate Policies:
                Policy: 2.23.140.1.2.1
            X509v3 CRL Distribution Points:
                Full Name:
                  URI at host x1.c.lencr.org
    Signature Algorithm: sha256WithRSAEncryption
    Signature Value:
        4e:e2:89:5d:0a:03:1c:90:38:d0:f5:1f:f9:71:5c:f8:
        ... 240 further bytes ...

Long lines are wrapped, the modulus and signature are truncated where marked, and the two web addresses are given as hostnames because this book prints no web addresses. Everything else is verbatim. Now walk it.

Version: 3 (0x2) - the encoded integer is 2, meaning version 3. Required.

Serial Number - sixteen bytes, non-sequential, comfortably over the 64 bits of randomness the Baseline Requirements demand and comfortably under the 20 octets RFC 5280 allows.

Signature Algorithm: sha256WithRSAEncryption - this is the inner copy, inside tbsCertificate. The outer copy at the bottom of the dump reads the same, as it must.

Issuer - a distinguished name with three RDNs: country US, organization Internet Security Research Group, common name ISRG Root X1. To find the parent, a verifier looks for a certificate whose subject is byte-for-byte this name. Byte-for-byte, not “looks the same”: the Baseline Requirements require the issuer field to be byte-for-byte identical to the subject field of the issuing CA, because DER comparison is how the match is actually done.

Validity - three years less one second, which is normal for an intermediate. Note that notAfter is 23:59:59, not midnight; that one-second gap is a convention that keeps validity periods from being computed as a day longer than intended. Subscriber certificates live under a much shorter ceiling, on a schedule that chapter 28 covers.

Subject - country US, organization Let’s Encrypt, common name R11. There is no subjectAltName in this certificate at all, because a CA certificate does not identify a service. Its name is a name, not a hostname.

Subject Public Key Info - RSA, 2048 bits, public exponent 65537. This is the key the certificates below it will be signed with.

Key Usage: critical - Digital Signature, Certificate Sign, CRL Sign - three bits. Certificate Sign is keyCertSign, the bit that makes this a working CA. CRL Sign lets the same key sign revocation lists. Digital Signature is present so that the same key can sign OCSP responses directly. The extension is critical, so any verifier that cannot understand key usage must reject the certificate outright.

Extended Key Usage: TLS Web Client Authentication, TLS Web Server Authentication - the two purposes this CA’s descendants are for. Under the technically constrained CA rules, an EKU list here bounds what the subordinate may be used for.

Basic Constraints: critical - CA:TRUE, pathlen:0 - the two fields that matter most in the whole file. CA:TRUE makes this a certificate authority. pathlen:0 says zero further CA certificates may appear below it, so R11 may issue end-entity certificates and may not issue another intermediate. Also critical.

Subject Key Identifier and Authority Key Identifier - R11’s own key fingerprint, and the fingerprint of the key that signed it. The second value is identical to ISRG Root X1’s subject key identifier, computed earlier in this chapter from the root’s public key.

Authority Information Access - where to fetch the issuer’s own certificate if you do not have it. This is the field that lets a misconfigured server sometimes still work, because clients fetch the missing intermediate themselves. Chapter 27 explains why relying on that is a bad idea.

Certificate Policies: 2.23.140.1.2.1 - a CA/Browser Forum reserved policy identifier. That specific arc means domain-validated: the CA checked control of the domain and nothing about the organization behind it. The organization validated arc is 2.23.140.1.2.2 and the individual validated arc is 2.23.140.1.2.3.

CRL Distribution Points - where the revocation list lives.

Signature Value - 256 bytes of RSA signature, matching the 2048-bit key of the issuer, computed over the DER of everything in the Data section above.

For comparison, here are four real certificates side by side, all read with the same command on the same day:

Certificate Key DER bytes
ISRG Root X1 RSA 4096 1391
ISRG Root X2 EC P-384 543
Let’s Encrypt R11 RSA 2048 1290
Let’s Encrypt E6 EC P-384 698

The size difference is not cosmetic. Every one of these is sent on every handshake that uses it, and the elliptic curve root is 543 bytes against the RSA root’s 1391 for the same security claim. Their validity windows differ too:

Certificate Not before Not after
ISRG Root X1 2015-06-04 2035-06-04
ISRG Root X2 2020-09-04 2040-09-17
Let’s Encrypt R11 2024-03-13 2027-03-12
Let’s Encrypt E6 2024-03-13 2027-03-12

Roots live for twenty years because replacing one means updating every trust store on earth. Intermediates live for three because replacing one means telling a few thousand server operators. Leaf certificates now live for months, and are getting shorter.

The profile of a modern leaf, in one place#

The Baseline Requirements, at version 2.2.9 as of 6 August 2026, specify the subscriber certificate profile in section 7.1.2.7. Collapsed to its essentials:

Extension Presence Critical
subjectAltName MUST see note
extKeyUsage MUST No
authorityKeyIdentifier MUST No
certificatePolicies MUST No
keyUsage SHOULD Yes
basicConstraints MAY Yes
nameConstraints MUST NOT -
subjectKeyIdentifier NOT RECOMMENDED No

The note on subjectAltName is the criticality rule given earlier: critical only when the subject is an empty sequence. The presence of nameConstraints in a leaf is forbidden outright, because name constraints are a CA-level control and mean nothing on a certificate with no children.

Two more rules from the same document that people trip over. The certificate policies extension must assert exactly one reserved policy identifier and must not assert anyPolicy. And a certificate that carries no OCSP pointer in its authority information access must carry a CRL distribution point instead - the status information has to be reachable somehow.

Finally, the ceiling on validity, which has been falling steadily and which this chapter records because a reader in 2027 will need to know where they are on the schedule. Baseline Requirements section 6.3.2, as of version 2.2.9:

Issued on or after Issued before Max validity
- 2026-03-15 398 days
2026-03-15 2027-03-15 200 days
2027-03-15 2029-03-15 100 days
2029-03-15 - 47 days

As of August 2026 we are in the second row: a subscriber certificate issued today may not exceed 200 days, and should not exceed 199. The schedule comes from ballot SC081, “Introduce Schedule of Reducing Validity and Data Reuse Periods”, adopted 11 April 2025 and effective 16 May 2025. Why the industry chose shorter lifetimes over working revocation is chapter 30’s subject.

A short history of the fields#

Set out as dates, the format’s growth is easy to see.

Year What happened
1978 Kohnfelder names the idea
1988 X.509 first edition, v1
1993 X.509 second edition, v2
1997 X.509 third edition, v3
1999 RFC 2459, first PKIX profile
2002 IE ignores basic constraints
2008 RFC 5280, the current profile
2023 RFC 9525 retires the CN

The first row deserves a sentence. The word “certificate”, in this sense, comes from Loren M. Kohnfelder’s 1978 bachelor’s thesis at the Massachusetts Institute of Technology, “Towards a practical public-key cryptosystem”, written in the Department of Electrical Engineering and Computer Science. Public key cryptography was two years old. Kohnfelder’s contribution was to notice that the hard part was not the maths but the distribution, and to propose a signed record binding a name to a key. Everything in this chapter is a footnote to that idea, and the forty-eight years since have been spent discovering, one incident at a time, what else the record has to say.

26.98 Common wrong ideas#

Wrong: A certificate proves a website is safe or legitimate. Right: A certificate is a signed statement that a particular name goes with a particular public key, checked to whatever standard the issuer applied - for the vast majority of certificates, that standard is only “somebody demonstrated control of this domain name”, which a criminal who registers a domain can also do.

Wrong: The certificate contains the private key, so it must be kept secret. Right: A certificate contains only the public key, and is broadcast in the clear at the start of every connection and published in public transparency logs; the private key lives in a separate file that never leaves the server, and holding a certificate without that key proves nothing.

Wrong: The hostname a browser checks is the Common Name in the subject. Right: The hostname is checked against dNSName and iPAddress entries in the subjectAltName extension only; RFC 9525 of November 2023 states that the Common Name RDN must not be used to identify a service, and Chrome removed the fallback in version 58 in April 2017.

Wrong: A wildcard certificate for *.example.com also covers example.com. Right: A wildcard matches exactly one label and only in the leftmost position, so *.example.com covers a.example.com but not example.com and not a.b.example.com; the bare name must be listed as its own dNSName entry, which is why real wildcard certificates carry both.

Wrong: If a certificate says CA:FALSE then it cannot be used to sign other certificates. Right: Nothing physically prevents it - the private key will sign anything you give it, and the resulting signature is mathematically valid; what stops the attack is the verifier reading the basic constraints extension, which Internet Explorer failed to do until September 2002 and Apple iOS failed to do until 2011.

Wrong: Key usage and extended key usage are two names for the same restriction. Right: Key usage is a bit string naming cryptographic operations such as digitalSignature and keyCertSign, extended key usage is a list of object identifiers naming purposes such as serverAuth, and RFC 5280 requires both to be satisfied independently, so a certificate can pass one and fail the other.

Wrong: PEM and DER are different certificate formats. Right: They are the same certificate: DER is the canonical binary encoding defined in ITU-T X.690, and PEM is that identical byte string base64-encoded between BEGIN and END lines as standardized in RFC 7468, so converting between them changes not one bit of the certificate itself.

Wrong: The authority key identifier tells the verifier which certificate signed this one. Right: It is a hint that speeds up the search for candidate parents, nothing more; an attacker can write any value they like into a certificate they mint, so the verifier must still check the signature cryptographically, and a single certificate may legitimately have several valid parents.

Wrong: Certificates are complicated because standards committees enjoy complexity. Right: Almost every field in a modern certificate profile can be traced to a specific failure with a date attached - unpredictable serial numbers to the 2008 MD5 rogue CA demonstration, the SAN requirement to the ambiguity and parsing attacks against Common Name, the basic constraints check to August 2002 - and removing any of them reopens the hole it closed.

26.99 Chapter summary in 20 lines#

  1. A certificate is a signed statement that binds a name to a public key, and nothing more than that.
  2. Its signature guarantees that the words have not been altered, not that the words were ever true.
  3. An X.509 certificate has exactly three top-level parts: tbsCertificate, signatureAlgorithm and signatureValue.
  4. The signature is computed over the DER encoding of tbsCertificate alone, so only fields inside that structure may be relied upon.
  5. The signature algorithm is recorded twice, inside and outside the signed body, and the two copies must match byte for byte.
  6. DER, defined in ITU-T X.690, gives every value exactly one legal encoding, which is what makes signing a structure possible at all.
  7. PEM is that same byte string in base64 between BEGIN and END lines, standardized in RFC 7468 of April 2015, and changes nothing about the certificate.
  8. The body carries version, serial number, algorithm, issuer, validity, subject, public key and extensions.
  9. Serial numbers must be positive, at most 20 octets, and under the Baseline Requirements must contain at least 64 bits of output from a secure random generator.
  10. Validity dates before 2050 are encoded as UTCTime with a two-digit year and later dates as GeneralizedTime, per RFC 5280 section 4.1.2.5.
  11. A distinguished name is an ordered sequence of relative distinguished names, each an unordered set of typed attribute values identified by object identifiers.
  12. The Common Name was retired as a hostname carrier because it is untyped, repeatable, and was successfully attacked with embedded null bytes in 2009.
  13. Hostnames now live only in the subjectAltName extension, as dNSName or iPAddress entries, and iPAddress entries are raw octets rather than text.
  14. A wildcard may appear only as the entire leftmost label, appears only once, and matches exactly one label.
  15. Key usage names cryptographic operations as a bit string; extended key usage names purposes as object identifiers; both must be satisfied.
  16. Basic constraints carries the CA boolean and an optional path length, and it is the field that separates an end-entity certificate from an authority.
  17. Internet Explorer did not check basic constraints until Microsoft published MS02-050 on 4 September 2002, after Bugtraq disclosure on 5 August 2002.
  18. Subject and authority key identifiers are search hints that link a child to its parent, and a verifier must still check the signature itself.
  19. The command openssl x509 -in file -noout -text prints every field discussed in this chapter, and reading its output fluently is the practical skill the chapter exists to give.
  20. Every field in the profile is a fence built at the edge of a hole somebody already fell into, which is why the format looks the way it does.

Chapter sources: ITU-T Recommendation X.509, first edition November 1988, second edition November 1993, third edition August 1997, current edition October 2019; ITU-T Recommendation X.690 for the Distinguished Encoding Rules; RFC 5280, “Internet X.509 Public Key Infrastructure Certificate and Certificate Revocation List (CRL) Profile”, May 2008, in particular sections 4.1, 4.1.2.2, 4.1.2.5, 4.2.1.1, 4.2.1.2, 4.2.1.3, 4.2.1.6, 4.2.1.9, 4.2.1.12 and 4.2.2.1; RFC 2459, January 1999, and RFC 3280, April 2002, its predecessors; RFC 2818, “HTTP Over TLS”, May 2000, now obsoleted by RFC 9110; RFC 6125, March 2011, obsoleted by RFC 9525, “Service Identity in TLS”, November 2023; RFC 7468, “Textual Encodings of PKIX, PKCS, and CMS Structures”, April 2015; RFC 1421 through 1424, February 1993, for the origin of the PEM container; RFC 5737 for the documentation address ranges; CA/Browser Forum Baseline Requirements for the Issuance and Management of Publicly-Trusted TLS Server Certificates, version 2.2.9, effective 6 August 2026, sections 3.2.2.6, 6.3.2, 7.1.2.7 with its subsections 7.1.2.7.6 through 7.1.2.7.12, 7.1.4.2, 7.1.4.3 and 7.1.6.1, and ballots 62, SC047, SC062 and SC081; Mike Benham (Moxie Marlinspike), “IE SSL Vulnerability”, Bugtraq, 5 August 2002; Microsoft Security Bulletin MS02-050, “Certificate Validation Flaw Could Enable Identity Spoofing”, 4 September 2002, CAN-2002-0862 and the later variant CAN-2002-1183; CVE-2011-0228 for the same omission in Apple iOS before 4.2.10 and 4.3.5; Sotirov, Stevens, Appelbaum, Lenstra, Molnar, Osvik and de Weger, “MD5 considered harmful today”, 25th Chaos Communication Congress, December 2008; Moxie Marlinspike’s null-prefix certificate work presented at Black Hat USA, July 2009; the Chrome 58 deprecations note on removing commonName matching, 2017; Loren M. Kohnfelder, “Towards a practical public-key cryptosystem”, B.S. thesis, Massachusetts Institute of Technology, Department of Electrical Engineering and Computer Science, 1978. All certificate dumps were produced with OpenSSL 3.0.13 in August 2026 against ISRG Root X1 from a Debian system trust store and the published Let’s Encrypt R11 and E6 intermediate files.