One variable at a time
The lab creates two independent roots, an intermediate signed by the first and fictional end-entity certificates. Every file lives in a temporary directory and is deleted at the end. Start with the passing case: root-a as explicit trust, intermediate as supporting material, sslserver purpose and api.fund.test as name. Then change one variable per test. This sequence attributes the observed difference to the changed material or option rather than replacing root, name and certificate together and not knowing what fixed the failure.
Path construction and trust decisions are separate
Without the intermediate, leaf verification fails in this isolated environment. Adding it through -untrusted allows building the path to root-a. Replacing the anchor with unrelated root-b fails again, even with the intermediate present. A complete supplied chain therefore does not force every client to accept it. In a batch incident, confirm which trust store the process uses and who approves issuers. Copying an entire laptop trust set can broaden scope without resolving ownership of the affected client.
Explicit DNS and IP identities
The experiment leaf includes DNS:api.fund.test and IP:192.0.2.40 in SAN. The correct DNS reference succeeds; wrong.fund.test fails. IP reference.40 succeeds and.41 fails. These tests neither resolve DNS nor contact those addresses: they compare requested identity with the local certificate. Modern RFC 9525 policy requires appropriate SAN identities. OpenSSL documentation also describes Common Name fallback; therefore the lab uses explicit SAN and does not present one success as proof of every client’s complete compliance with that policy.
Purpose and constraints above the leaf
A second certificate permits only clientAuth. The experiment shows acceptance with sslclient and rejection with sslserver. In another case, SAN contains api.other.test and matches the requested name, but the intermediate permits only DNS under.fund.test. The permitted subtree violation identifies a path constraint. Reissuing the same name through the same chain can repeat the problem. Recovery should confirm the CA’s authorized scope and use appropriate issuance while retaining the identity and trust controls defined for the service.
Read evidence and explain the correction
Run the runner and read the chain, identity, purpose and nameConstraint groups. For each failure, identify the changed variable, error and correction that respects policy. Avoid saying only invalid certificate: that summary can lead another team to renew dates when an intermediate is missing, or change trust when the name is wrong. The ticket should contain the OpenSSL version, identified public files, options, result and scope. No private key needs to be attached to explain these verification outcomes.
Move from file to service
The verify command analyzes local certificates. It sends no SNI, negotiates no TLS and does not observe the pair loaded by a process. After correcting material, a change plan still needs to validate activation, relevant clients and functional operation. Revocation checks also depend on their own options and sources; the runner uses neither CRLs nor OCSP. Keep a precise statement of what passed in the report. An offline test is a useful preparation step, not final evidence that an integration recovered.
# From the project root; no network connections
python3 content/labs/tls-paths/run.py
# Runner verification pattern uses disposable local files:
# openssl verify -CAfile root-a.pem -no-CApath -no-CAstore \
# -untrusted intermediate.pem -purpose sslserver \
# -verify_hostname api.fund.test server.pemFictional case: api.other.test matches SAN, but the intermediate CA permits only.fund.test. The team requests a chain authorized for the new name and keeps cutover pending that validation.
Common pitfalls
Do not confuse -untrusted with revocation, supplied chain with approved trust, matching SAN with absence of CA constraints, or verify with a real handshake.
Related topics: Keys, certificates, and trust · Identity, name, and time · Diagnosis with explicit criteria
A matrix changing one variable per test turns generic errors into bounded decisions while keeping presented material separate from client policy.
Reference: OpenSSL verify · BigSavant TLS/certificates 2026-09; selected TLS 1.2/1.3, RFC 9525 identity and OpenSSL 3.5 diagnostics