Verify a certificate chain

To verify a certificate against a chain, run `openssl verify -CAfile root-ca.crt -untrusted intermediate.crt certificate.crt`. `-CAfile` names the trusted root, `-untrusted` supplies intermediates that are needed to build the path but are not themselves trusted, and the final argument is the certificate being checked. Output of `certificate.crt: OK` means a complete path to a trusted root was found. To verify against the system trust store instead of a specific root, omit `-CAfile`.

Updated August 19, 2026 Verified against OpenSSL 3.5.7

The command #

Verify against a specific root
openssl verify -CAfile root-ca.crt -untrusted intermediate.crt certificate.crt
Expected output
certificate.crt: OK

Replace these values

PlaceholderWhat to put there
-CAfile root-ca.crtThe trust anchor. Certificates here are treated as trusted.
-untrusted intermediate.crtIntermediates needed to build the path. Not treated as trusted.
certificate.crtThe certificate being verified.

Against the system trust store #

openssl verify -untrusted intermediate.crt certificate.crt

This is the check that matters for a publicly trusted certificate: it asks whether your machine would accept it.

Verifying what a server actually serves #

Better than checking files, because it tests the deployed configuration including whether the intermediates are being sent at all:

openssl s_client -connect example.com:443 -servername example.com </dev/null 2>/dev/null \
| grep "Verify return code"
Expected output
Verify return code: 0 (ok)

Checking the hostname too #

openssl verify validates the chain and says nothing about hostnames. To check both:

openssl verify -CAfile root-ca.crt -untrusted intermediate.crt \
-verify_hostname example.com certificate.crt

Reading the errors #

openssl verify certificate.crt
Expected output
C = US, CN = example.com
error 20 at 0 depth lookup: unable to get local issuer certificate
error certificate.crt: verification failed

The depth number tells you where in the chain the problem is. Depth 0 is the certificate you passed, depth 1 is its issuer, and so on.

Error Meaning Fix
10 Certificate has expired Check the dates
18 Self-signed certificate Self-signed vs CA-signed
19 Self-signed certificate in chain That error
20 Unable to get local issuer certificate That error
21 Unable to verify the first certificate Intermediates missing
24 Invalid CA certificate Issuer lacks CA:TRUE in basic constraints
26 Unsupported certificate purpose Extended key usage does not permit this use

Showing the whole chain that was built #

Useful when verification succeeds but you want to know which path it took:

openssl verify -show_chain -CAfile root-ca.crt -untrusted intermediate.crt certificate.crt
Expected output
certificate.crt: OK
Chain:
depth=0: CN = example.com (untrusted)
depth=1: C = US, O = Example CA, CN = Example Intermediate CA (untrusted)
depth=2: C = US, O = Example CA, CN = Example Root CA

Read it bottom-up. The last entry is the trust anchor; everything above it was validated against the entry below.

Frequently asked questions

What is the difference between -CAfile and -untrusted?
-CAfile supplies certificates you are treating as trust anchors — normally just the root. -untrusted supplies intermediates that are needed to build the path but confer no trust themselves. Passing an intermediate to -CAfile makes verification succeed for the wrong reason, because you have declared the intermediate trusted.
How do I verify against the system trust store?
Omit -CAfile entirely — openssl verify -untrusted intermediate.crt certificate.crt uses the default store. Add -CApath /etc/ssl/certs if your build does not pick it up automatically.
Why does verify succeed but my browser still complains?
openssl verify checks the chain, not the hostname. A certificate can chain perfectly to a trusted root and still be for the wrong hostname. Check the SANs separately, or use -verify_hostname example.com.
Can I verify the chain a live server sends?
Yes, and it is the better test because it checks what is actually deployed rather than what is on disk. Use openssl s_client and read its "Verify return code" line.

References