Skip to content
ssldays

Guide

OpenSSL verify certificate chain

Run openssl verify certificate chain against your trust store—validate leaf plus intermediates, then confirm the same path a browser builds on the live hostname.

Updated Apr 10, 2026 807 words

openssl verify certificate chain tests whether a leaf plus its issuing intermediates anchor to a trusted root in your -CAfile store—separate from reading expiry dates alone.

Expiry and trust failures feel similar in browsers but stem from different PKIX checks. A certificate can be within its validity window yet fail verification because the server did not send intermediates, because the wrong root was assumed, or because corporate trust stores differ from Mozilla’s bundle.

DevOps engineers use openssl verify after assembling fullchain.pem, before reloading production, and when debugging customer “not trusted” tickets. This guide walks file-based verification and how to reconcile it with live s_client output.

You need OpenSSL and a current CA bundle (ca-certificates package or Mozilla’s PEM export). Private PKI requires your own trust anchor file.

Use offline verify before reloading customer traffic when you have maintenance windows. Use live s_client immediately after reload to prove the served chain matches the bundle you tested at your desk.

What to check

Verification answers: signature chain integrity, each cert within notBefore/notAfter, basic constraints, and purpose flags. For openssl verify certificate chain, supply the leaf with any intermediates the server should send; do not pass only the leaf unless the issuer is already trusted as a root (rare for public sites).

Cross-check live presentation with -showcerts—verify proves your files are logically consistent; s_client proves strangers receive the same material. When verify passes offline but browsers fail, see Certificate chain incomplete in the browser.

openssl verify certificate chain against Mozilla’s bundle on a laptop does not emulate every mobile trust program. Failure in the field with success locally points to missing intermediates on the wire, not necessarily a wrong trust store on the client.

Step-by-step

Prepare files

Save the leaf as leaf.pem and concatenate intermediates below it in chain.pem, or use the CA’s fullchain.pem without the root (roots live in the trust store, not usually on the wire).

# Example layout after download from CA
# fullchain.pem = leaf + intermediate(s)
cp fullchain.pem ./server-chain.pem

Verify against system trust store (Debian/Ubuntu)

openssl verify -untrusted server-chain.pem leaf.pem

When the leaf is already inside server-chain.pem, split the first cert:

awk 'BEGIN{n=0}/BEGIN CERT/{n++}{if(n==1)print > "leaf.pem"; else if(n>1)print > "int.pem"}' server-chain.pem
openssl verify -CAfile /etc/ssl/certs/ca-certificates.crt -untrusted int.pem leaf.pem

Adjust paths for RHEL (/etc/pki/tls/certs/ca-bundle.crt) or macOS (security find-certificate exports).

Verify with explicit intermediate bundle only

openssl verify -partial_chain -CAfile intermediate.pem leaf.pem

-partial_chain helps when testing modern CA paths where the client already trusts a cross-sign; use carefully so you do not mask missing public intermediates.

Capture live chain and verify offline

HOST=www.example.com
openssl s_client -connect "${HOST}:443" -servername "${HOST}" -showcerts </dev/null 2>/dev/null \
  | awk '/BEGIN CERTIFICATE/,/END CERTIFICATE/{print}' > live-chain.pem

Split live-chain.pem into leaf and untrusted intermediates, then run openssl verify as above. Mismatch with your on-disk bundle pinpoints deployment errors.

OPENSSL_VERBOSE=1 openssl verify -CAfile /etc/ssl/certs/ca-certificates.crt -untrusted int.pem leaf.pem

Messages like certificate has expired versus unable to get local issuer certificate separate date issues from incomplete chains.

After verify succeeds, store the SHA-256 fingerprint of the leaf in your ticket. Live checks later should match that fingerprint exactly when the intended bundle is serving.

How to read the output

leaf.pem: OK means OpenSSL built a path to a trusted anchor using supplied intermediates and the CAfile. Anything else is a failure to paste into tickets.

Message Typical cause
certificate has expired Leaf or intermediate past notAfter
certificate is not yet valid Clock skew or premature deploy
unable to get local issuer certificate Missing intermediate in -untrusted or wrong bundle
self signed certificate in certificate chain Wrong file order or private PKI without custom root
unable to verify the first certificate No issuer data for the leaf

Browser trust may still differ if they ship a different root store or build paths with alternate cross-signs. Verification success on Ubuntu does not guarantee every mobile client, but failure here is a strong signal.

Common mistakes

Verifying only the leaf file without intermediates, then blaming the CA when OpenSSL cannot find the issuer.

Including the root certificate in the server bundle against CA advice—some stacks misbehave; roots belong in trust stores, not always on the wire.

Using an outdated ca-certificates package that lacks a newly trusted ISRG root—verify fails on otherwise valid Let’s Encrypt chains until the OS package updates.

Assuming verify replaces live checks. Load balancers and CDNs may serve a different chain than /etc/nginx/ssl.

Mixing PEM order (leaf after intermediate). Concatenation order should follow leaf-first convention your web server documents.

Shipping verify success to auditors without attaching the untrusted intermediate list. Auditors need to see what you actually configured, not only the OK line.

When to use automation

openssl verify belongs in CI after assembling chains, but production drifts when one node keeps an old bundle. Automate external TLS handshakes that assess trust and expiry together, alerting at 30, 14, 7, and 1 day before notAfter.

Track chain depth and issuer fingerprints over time. ssldays complements offline verify by testing the certificate path users actually receive, including CDN and multi-region differences your workstation verify step never sees.

Scenario walkthrough

A fintech team ran openssl verify certificate chain locally on Friday before a Monday release. Verify returned OK against the system bundle. Monday morning, iOS clients failed because the server omitted an intermediate iOS fetches less aggressively than Ubuntu. Live -showcerts showed only the leaf on the wire. The fix was configuration, not CA reissue, but only live inspection revealed it.

Agencies assemble chain files for clients who self-host WordPress. Contractors deliver cert.pem without intermediates. Verify fails in staging; they add -partial_chain and mistakenly ship to production. Removing -partial_chain and fixing the bundle aligns offline and online behavior before the client’s marketing launch.

Hardware load balancers sometimes require concatenation in vendor-specific order. Operators verify on Linux, paste into a GUI, and the appliance silently truncates. Keeping a verified PEM set plus a screenshot of the GUI fingerprint prevents finger-pointing between networking and platform teams.

Private PKI rotations demand custom CAfiles in verify commands. Scripts that hardcode public bundles falsely alarm during enterprise root migrations. Document which anchor file belongs to which environment variable in CI.

When auditors ask for chain validation evidence, attach verify output, the list of -untrusted files, and a live -showcerts capture. Triple artifacts convince faster than verbal assurance that engineers understand openssl verify certificate chain limits.

Staging versus production discipline

Never point production traffic at a bundle that verified only on a laptop without the same -CAfile set production users inherit. Maintain staging-cafile.pem and production-cafile.pem consciously when you test internal roots.

When staging mimics production chains, automate verify in both pipelines. A common failure mode is lax staging that accepts partial chains while production must serve full paths.

Document permitted -partial_chain use in runbooks. On-call should not discover exceptions buried in shell history during incidents.

Rotate trust stores after OS upgrades that refresh Mozilla bundles. Verify smoke tests catch roots removed or added upstream.

For hybrid cloud, sync verify steps between on-prem jump hosts and cloud build agents. Divergent trust stores cause thrash when Terraform deploys succeed in one continent and fail in another.

Container images that bake outdated ca-certificates packages are a frequent silent failure. Verify in the image build pipeline, not only on the golden host used by one engineer.

When third parties supply .p7b blobs, convert to PEM before verify. OpenSSL commands differ; document conversion in onboarding so contractors do not attach unusable binaries to tickets.

Fail CI when verify errors mention expired intermediates even if the leaf is new. That policy forces correct bundles before merge, aligning with openssl verify certificate chain discipline.

Game days simulating CA distrust events should include verify against both old and new anchors. Practice builds confidence before real distrust bulletins hit mailing lists.

Support for legacy clients may require temporarily serving additional cross-signs. Verify each path you intentionally support; do not rely on lucky path building in one browser brand.

Record OpenSSL verify exit codes in monitoring wrappers. Zero versus nonzero is easier to alert on than parsing multiline error strings in legacy tools.

Partner integrations delivering client certs for mTLS still need server chain verify before blaming partner APIs. Server expiry dominates most B2B outage calls.

Organizational adoption

Platform guilds should demo verify failures live using intentional broken bundles. Seeing unable to get local issuer certificate in a classroom prevents ritual copy-paste without comprehension.

Open-source contributors submitting TLS config changes should attach verify output in pull requests. Maintainers merge faster with cryptographic evidence.

Regulated industries filing change tickets need verify logs archived immutably. WORM storage or signed log links satisfy auditors asking whether chains were tested pre-deploy.

Distros shipping custom CA bundles for nation-state roots complicate verify in those regions. Document regional jump hosts when global teams support localized deployments.

Chaos experiments that temporarily rename fullchain.pem should follow verify in rollback steps. Ensuring OK status returns proves restore completeness, not only HTTP health checks.

Marketing microsites on separate AWS accounts need verify scripts in their own CI tenant. Central platform pipelines never see those buckets unless governance enforces shared templates.

When acquiring startups, import their verify scripts before merging infrastructure. Hidden partial_chain exceptions become technical debt if not cataloged on day one.

Plain-language summary

Chain verification answers whether cryptography lines up from leaf to trusted root. Browsers perform a similar dance with slightly different root stores; offline verify approximates but does not guarantee identical client behavior.

Operations culture improves when verify failures are celebrated in staging. Finding incomplete chains before production beats discovering them via social media.

Documentation should name owners for trust store updates on jump hosts. Mystery anchors cause verify success on one laptop and failure on another during the same incident.

Renewal projects should include verify in definition of done alongside live handshakes. Two green checks reduce rollback arguments.

Auditors unfamiliar with TLS appreciate analogies: the leaf is the employee badge, intermediates are department signatures, roots are HR authority. Verify proves the signatures chain logically.

Partial chain flags are advanced tools, not defaults for public websites. Governance should restrict who may add them to production scripts.

Teaching verify alongside showcerts builds intuition for missing intermediates versus expired dates. New hires troubleshoot faster with both mental models.

Escalations to CAs should include verify output proving local chain assembly, not only live errors customers quote from phones.

Quarterly access reviews for who may edit CAfile bundles on jump hosts reduce mystery trust changes before audits.

Pair verify exercises with reading browser certification paths for the same hostname. Humans learn faster when abstract verify messages map to UI metaphors.

Invest in small lab environments where verify failures are safe to trigger intentionally. Fear of OpenSSL errors decreases when failure is a rehearsed guest, not a stranger.

Document exceptions where private roots are intentional. Future engineers should not waste days chasing public trust on intentionally private names.

Verification success in staging should block production promotion through CI gates the same way unit tests do. Treat chain integrity as release criteria, not optional commentary.

Store verify success artifacts next to change tickets for the same duration you retain incident logs. Future investigations appreciate synchronized evidence trails.

Label CAfile bundles with creation dates and owners in version control. Mystery anchors slow verify debugging during tense bridges.

Frequently asked questions

Why does verify pass but Firefox fails?

Different root programs, cached intermediates, or corporate TLS inspection. Compare -showcerts output to Firefox’s certification path viewer.

Should I use `c_rehash` on my CA directory?

Modern OpenSSL prefers explicit -CAfile bundles. Distribution-maintained bundles are simpler than manual hash symlinks.

Can I verify client certificates?

Yes with openssl verify -purpose ssl-client when building mutual TLS stacks. Server chain verification for HTTPS remains the common case in this guide.

Is `openssl s_client` verification enough?

s_client prints verification return codes at the end (Verify return code: 0 (ok)). That uses the default trust store and confirms live presentation—run it after verify on files passes.

See what the server presents right now

Free live certificate check — no signup.