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`.
The command #
openssl verify -CAfile root-ca.crt -untrusted intermediate.crt certificate.crt Expected output
certificate.crt: OK
Replace these values
| Placeholder | What to put there |
|---|---|
-CAfile root-ca.crt | The trust anchor. Certificates here are treated as trusted. |
-untrusted intermediate.crt | Intermediates needed to build the path. Not treated as trusted. |
certificate.crt | The 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?
-CAfilesupplies certificates you are treating as trust anchors — normally just the root.-untrustedsupplies intermediates that are needed to build the path but confer no trust themselves. Passing an intermediate to-CAfilemakes verification succeed for the wrong reason, because you have declared the intermediate trusted.- How do I verify against the system trust store?
- Omit
-CAfileentirely —openssl verify -untrusted intermediate.crt certificate.crtuses the default store. Add-CApath /etc/ssl/certsif your build does not pick it up automatically. - Why does verify succeed but my browser still complains?
openssl verifychecks 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_clientand read its "Verify return code" line.
References
- openssl-verify(1) — -CAfile, -untrusted and the numbered verify errors
- RFC 4158: certification path building — why a verifier can fail to find a path that exists