Hoe je browser een certificaat vertrouwt
Het slotje in je adresbalk ziet eruit als één vinkje, maar je browser heeft er binnen een paar milliseconden een hele reeks controles voor afgewerkt. De server laat een certificaat zien waarop staat dat hij wallieweb.nl is. Dat kan iedereen beweren. De browser vertrouwt het pas als er een ononderbroken keten van handtekeningen loopt naar een partij die hij al kende voordat je op enter drukte.
Hieronder volg je die controle aan de hand van het echte certificaat van deze site, zoals ik het op 24 september 2026 heb opgehaald met openssl s_client -showcerts.
Certificate-bericht: 4 certificaten, 3.404 bytes (TLS 1.3)
leaf 927 B · YE1 655 B · Root YE 682 B · X2 1.140 B
De server stuurt een stapel
Tijdens de TLS 1.3-handshake stuurt de server een Certificate-bericht. Voor wallieweb.nl zitten daar vier certificaten in, samen 3.404 bytes: het certificaat van de site zelf, de intermediate YE1 van Let's Encrypt, en twee certificaten die de nieuwe root ISRG Root YE aan oudere roots koppelen.
De volgorde is geen toeval. Bovenaan staat het certificaat voor deze site, daaronder telkens de partij die het certificaat erboven heeft ondertekend.
Het leaf-certificaat
Het eerste certificaat in de stapel heet het leaf. Hierin staat wat de browser wil weten: voor welke namen het geldt, de publieke sleutel van de server en hoe lang het geldig is. Voor deze site:
- Subject Alternative Names:
wallieweb.nlenwww.wallieweb.nl - sleutel: ECDSA op curve P-256
- geldig van 21 september 2026 07:09 UTC tot 20 december 2026 07:09 UTC, precies 90 dagen
CA:FALSE: met dit certificaat mag je zelf geen certificaten ondertekenen
Een handtekening controleren
Onderaan het leaf staat een handtekening: ecdsa-with-SHA384, gezet door YE1. De browser hasht het ondertekende deel van het certificaat (de tbsCertificate) met SHA-384 en controleert de handtekening met de publieke sleutel uit het YE1-certificaat. Klopt dat, dan heeft YE1 het certificaat uitgegeven en is er onderweg niets aan veranderd.
Daarmee is nog niets bewezen over YE1 zelf. Het vertrouwen schuift alleen een schakel op.
Omhoog door de keten
YE1 is een intermediate: een P-384-sleutel die geldig is tot 2 september 2028, met pathlen:0, zodat er onder YE1 geen andere CA meer kan hangen. YE1 is ondertekend door ISRG Root YE, de root van de nieuwe Generation Y-hiërarchie die Let's Encrypt in september 2025 heeft gegenereerd.
Het probleem is dat Root YE nog niet in de trust stores van browsers en besturingssystemen staat. Daarom stuurt de server een cross-sign mee: een certificaat voor Root YE dat ondertekend is door de oudere ISRG Root X2. Zo hangt de nieuwe root aan een root die al wel bekend is.
De trust store
Hier stopt de keten. ISRG Root X2 staat in de trust store: de lijst roots die met je besturingssysteem of browser is meegeleverd. Op mijn Mac zijn dat er 158, de Chrome Root Store heeft er ongeveer honderd. Een root uit die lijst controleert de browser niet verder: die vertrouwt hij op voorhand. Een root-CA komt pas in die lijst na audits en een beoordeling door het rootprogramma van elke browsermaker.
Het vierde meegestuurde certificaat, X2 ondertekend door ISRG Root X1, is voor oudere systemen die X2 nog niet kennen. Een browser die X2 al vertrouwt, heeft het niet nodig.
Naam en datum
Een geldige keten betekent alleen dat het certificaat echt door Let's Encrypt is uitgegeven. Daarna kijkt de browser of het voor deze site geldt. De hostnaam in de adresbalk moet in de SAN-lijst staan. Het Common Name-veld tellen browsers daarbij al jaren niet meer mee. Ook moet de huidige tijd tussen notBefore en notAfter liggen: op 24 september heeft dit certificaat nog 87 dagen te gaan.
Verder controleert de browser dat het certificaat voor TLS-serverauthenticatie bedoeld is: Extended Key Usage: TLS Web Server Authentication.
Certificate Transparency
In het leaf zitten twee SCT's (Signed Certificate Timestamps): bewijs dat het certificaat vooraf is ingediend bij openbare, append-only logboeken. Voor wallieweb.nl zijn dat Cloudflare Nimbus2026 en Let's Encrypt Willow2027h1, allebei op 21 september om 08:08:21 UTC.
Chrome eist voor een certificaat van maximaal 180 dagen twee SCT's van verschillende logs, van verschillende operators. Het idee erachter is dat een CA geen certificaat voor jouw domein kan uitgeven zonder dat de rest van de wereld dat kan zien.
Breek zelf een schakel
Kies hierboven wat er misgaat en kijk waar de controle faalt. Een verlopen certificaat geeft NET::ERR_CERT_DATE_INVALID. Een naam die niet in de SAN-lijst staat geeft NET::ERR_CERT_COMMON_NAME_INVALID. Eindigt de keten bij een root die de browser niet kent, zoals Root YE zonder cross-sign, dan krijg je NET::ERR_CERT_AUTHORITY_INVALID.
Een ontbrekende intermediate is een lastig geval. Chrome op de desktop en Safari halen YE1 vaak zelf op via de AIA-URL in het leaf, en Firefox heeft alle bekende intermediates vooraf binnengehaald. Android-apps, curl en de meeste andere clients doen dat niet en geven een foutmelding. Het werkt dus op je laptop en faalt in een app.
Wat er verandert
Kortere looptijden. In april 2025 nam het CA/Browser Forum ballot SC-081v3 aan, zonder tegenstemmen. De maximale looptijd van een publiek TLS-certificaat daalt stapsgewijs: 200 dagen vanaf 15 maart 2026, 100 dagen vanaf 15 maart 2027 en 47 dagen vanaf 15 maart 2029. Let's Encrypt gaat verder. Het tlsserver-profiel geeft sinds 13 mei 2026 certificaten van 45 dagen uit, het standaardprofiel gaat op 10 februari 2027 naar 64 dagen en op 16 februari 2028 naar 45 dagen.
Geen OCSP meer. Let's Encrypt heeft zijn OCSP-responders op 6 augustus 2025 uitgezet. Bij OCSP zag de CA bij elke controle welk IP-adres welke site bezocht. Intrekking loopt nu alleen nog via CRL's, voor dit certificaat http://ye1.c.lencr.org/119.crl. Browsers vragen die lijsten niet per bezoek op, maar werken met eigen samengevatte versies: CRLSets in Chrome, CRLite in Firefox. Hoe korter de looptijd, hoe minder er afhangt van intrekking.
Zelf proberen
De hele keten zoals de server hem stuurt:
openssl s_client -connect wallieweb.nl:443 -servername wallieweb.nl -showcerts </dev/null
Eén certificaat in detail, inclusief SAN's, CRL-adres en de SCT's:
openssl s_client -connect wallieweb.nl:443 -servername wallieweb.nl </dev/null 2>/dev/null \
| openssl x509 -noout -text
Wil je de fouten uit de laatste stap zelf zien, bewaar dan de certificaten als leaf.pem en chain.pem en probeer openssl verify -untrusted chain.pem -attime 1797811200 leaf.pem (21 december 2026) of voeg -verify_hostname blog.wallieweb.nl toe. Welke certificaten er ooit voor een domein zijn uitgegeven, zie je op crt.sh, dat de CT-logs doorzoekbaar maakt.
Tot slot
Ik had verwacht dat een certificaat van een site als deze gewoon aan één root zou hangen. In plaats daarvan zie je in de keten een migratie die nog loopt: een nieuwe root die nog niet vertrouwd wordt en daarom door een oudere wordt ondertekend, die op zijn beurt weer door een nog oudere wordt ondertekend. Dat werkt ongemerkt, tot iemand bij het instellen van zijn server een regel vergeet.