Skip to content
ecdsa.com
OpenSSL CLI (openssl s_client / openssl verify)OpenSSL CLI

Error message

verify error:num=20:unable to get local issuer certificate

Also printed as

  • Verify return code: 20 (unable to get local issuer certificate)
  • error 20 at 0 depth lookup: unable to get local issuer certificate

s_client prints "verify error:num=20:…" during the handshake and "Verify return code: 20 (…)" in its summary; openssl verify prints "error 20 at <depth> depth lookup: …". By default s_client continues after verification errors; add -verify_return_error to make it fail.

OpenSSL CLI (openssl s_client / openssl verify) — X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY

What it means

OpenSSL error 20 (X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY): while building the chain, OpenSSL reached a certificate whose issuer it could not find, neither among the certificates the server sent nor in the trusted store. The depth line printed just before it names the certificate whose issuer is missing. This is the same code behind curl's (60), Python's CERTIFICATE_VERIFY_FAILED and Node.js's UNABLE_TO_GET_ISSUER_CERT_LOCALLY.

Why it happens

How to fix it

  1. 1.

    Read the depth lines

    Depth 0 is the server's certificate, higher numbers are the intermediates it sent. The last depth line before the error is the certificate whose issuer is missing.

    bash
    echo | openssl s_client -connect api.example.com:443 -servername api.example.com 2>&1 | grep -E '^depth|verify'
    # depth=1 CN=Example Corp Issuing CA       <- the highest certificate received
    # verify error:num=20:...                   <- its issuer is not in the trust store
  2. 2.

    Test with the expected root

    -CAfile with the correct root (and -verify_return_error to make failures fatal) shows whether that root completes the chain; "Verify return code: 0 (ok)" means it does.

    bash
    # Verify against a specific root (exit code and "Verify return code: 0 (ok)" confirm it)
    echo | openssl s_client -connect api.example.com:443 -servername api.example.com \
      -CAfile corp-root-ca.pem -verify_return_error 2>&1 | grep 'Verify return code'
  3. 3.

    Verify certificate files offline

    Give openssl verify the root as -CAfile and the intermediates as -untrusted; a leaf alone cannot be verified.

    bash
    # Offline: root as trust anchor, intermediate(s) as untrusted helpers
    openssl verify -CAfile corp-root-ca.pem -untrusted intermediate.pem server.pem
  4. 4.

    Install the root into the system store

    When the chain legitimately ends at a company root, add it to the distribution's store; OpenSSL-based tools on the machine then trust it.

    bash
    sudo cp corp-root-ca.pem /usr/local/share/ca-certificates/corp-root-ca.crt
    sudo update-ca-certificates     # openssl reads /etc/ssl/certs by default on Debian/Ubuntu

Related errors

Browse the full signature error database