Error message
verify error:num=21:unable to verify the first certificate
Also printed as
- Verify return code: 21 (unable to verify the first certificate)
Printed by openssl s_client as "verify error:num=21:…" and "Verify return code: 21 (…)". Node.js reports the same condition as UNABLE_TO_VERIFY_LEAF_SIGNATURE ("unable to verify the first certificate").
OpenSSL CLI (openssl s_client) — X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE
What it means
OpenSSL error 21 (X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE): the chain consists of a single certificate, the server's own, and its issuer could not be found, so not even the leaf's signature can be checked. s_client usually prints error 20 for depth 0 right before it. The cure is almost always on the server: it must send its intermediate certificate.
Why it happens
The server is configured with the leaf certificate only
commoncert.pem instead of fullchain.pem, a certificate pasted into a load balancer without its chain, or a Java keystore entry imported without the issuing CA.
The chain is configured but not sent
occasionalSome servers need the chain in a separate directive or field (old Apache's SSLCertificateChainFile, a cloud load balancer's chain box); a bundle in the wrong place is silently ignored.
The server sends an intermediate that did not issue the leaf
occasionalAfter a CA changes intermediates, an old chain file sends a certificate that is not the leaf's issuer; OpenSSL then cannot use it.
How to fix it
- 1.
Check what the server sends
One certificate whose issuer (i:) is an intermediate CA confirms the problem.
bash openssl s_client -connect api.example.com:443 -servername api.example.com -showcerts </dev/null 2>/dev/null \ | grep -E '^ *[0-9]+ s:|^ *i:' - 2.
Serve leaf + intermediates
Concatenate the leaf and the issuing intermediate(s) in order and configure the server with that file; print the bundle to check the order.
bash # Build the file the server should use: leaf, then intermediates (issuer of each previous one) cat server.pem intermediate.pem > fullchain.pem openssl crl2pkcs7 -nocrl -certfile fullchain.pem | openssl pkcs7 -print_certs -noout # check the order - 3.
Find the correct intermediate
The leaf's Authority Information Access extension names the URL of its issuer certificate; download it, convert to PEM if needed, and add it to the chain file.
bash # Where to download the missing intermediate: the leaf's Authority Information Access URL openssl x509 -in server.pem -noout -ext authorityInfoAccess curl -sS -o intermediate.der http://ca.example.com/issuing-ca.crt openssl x509 -inform der -in intermediate.der -out intermediate.pem