Diagnose TLS failures
Diagnose a missing intermediate
Identify an incomplete server chain and verify the same leaf with the required intermediate supplied.
10 minute lesson
This is the sneakiest chain failure because it hides. A server can present a correct leaf but omit the intermediate needed to reach a trusted root. Some clients may hide the mistake because they cached that intermediate from an earlier connection to a different site — browsers do this all the time. So the site works in Chrome, works on your laptop, and fails in curl, in CI, and on a fresh phone.
The tell is exactly that pattern: a TLS failure that only some clients see.
Inspect and verify the presented chain:
openssl s_client -connect app.lab.test:8443 -servername app.lab.test -showcerts -CAfile lab-ca.crt </dev/null
Two parts of the output matter. First, count the certificates in the Certificate chain section. A leaf that was signed by an intermediate, presented alone, looks like this:
Certificate chain
0 s:CN = app.lab.test
i:CN = Practical TLS Lab Intermediate CA
...
verify error:num=20:unable to get local issuer certificate
Verify return code: 20 (unable to get local issuer certificate)
One certificate, and its issuer is an intermediate that never arrived. Error 20 is OpenSSL saying “I have the leaf, but nothing in what the server sent or in my trust store signs it”. Error 21, unable to verify the first certificate, points at the same family of problem.
Second, prove the leaf itself is fine. Save certificate 0 from the -showcerts output as presented.crt, then verify it with the intermediate supplied by hand:
openssl verify -CAfile lab-ca.crt -untrusted lab-intermediate.crt presented.crt
# presented.crt: OK
-untrusted provides certificates that may be used to build the path without being trust anchors themselves. If this returns OK, the diagnosis is settled: the leaf is good, the server’s configuration is incomplete.
The fix belongs on the server, once. Compare the certificates sent by the server with the intended chain, add the intermediate to the server full-chain configuration — the cat leaf intermediate file from earlier in this course — and retest from a clean client that has no cached state.
Do not add the leaf itself to every client trust store. That “fix” multiplies across every client, breaks again at the next renewal, and trains people to click through trust prompts. Repair the server chain and every client heals at the same moment.
Lesson completed