# The certificate chain of trust

A certificate chain is the path from the certificate a server presents up to a root certificate already in the client's trust store. Each certificate is signed by the one above it, and verification walks that path until it reaches an anchor it already trusts. The server must send its own certificate **and** every intermediate in between; it must not need to send the root, because a client that does not already have the root would gain nothing by being handed it. A chain missing an intermediate is the most common TLS misconfiguration there is.

Source: https://certguru.io/concepts/certificate-chain/
Last updated: 2026-08-19
Commands verified against OpenSSL 3.5.7.

---

## What verification actually does

When a client connects, the server sends a list of certificates. The client then walks upward:

1. Take the server's certificate. Read its **issuer** name.
2. Find a certificate whose **subject** matches that issuer. Verify the signature with its key.
3. Repeat, moving up one link at a time.
4. Stop when you reach a certificate that is already in the local trust store.

If step 2 ever fails to find a match, verification stops with
[unable to get local issuer certificate](/errors/unable-to-get-local-issuer-certificate/).

*A typical chain, read bottom-up*

```text
Root CA  (in your OS trust store — the server does not send this)
   |  signs
Intermediate CA  (the server must send this)
   |  signs
example.com  (the server's own certificate)
```

## Why intermediates exist at all

Root CA private keys are enormously valuable and are kept offline, often in hardware in a vault. If
a root signed certificates directly, that key would need to be online and in constant use.

So roots sign a small number of **intermediates**, and intermediates do the day-to-day issuing. A
compromised intermediate can be revoked without touching the root — and without every operating
system and browser on earth needing an update. See
[roots vs intermediates](/concepts/root-vs-intermediate-ca/).

## Building the chain file

Leaf first, then upward. This is simple concatenation:

```bash
cat certificate.crt intermediate.crt > fullchain.crt
```

> **Leaf first, root omitted**
>
> Two mistakes account for nearly every broken chain file: putting the intermediate before the leaf,
>   and appending the root. The first breaks strict clients; the second is harmless but adds bytes to
>   every handshake for no benefit.

## Checking what a server sends

*Count the certificates in the handshake*

```bash
openssl s_client -connect example.com:443 -servername example.com -showcerts /dev/null \
  | grep -c "BEGIN CERTIFICATE"
```

Expected output:

```
2
```

One certificate from a publicly trusted site means the intermediate is missing. To see the chain in
detail:

*Read the verdict and the path*

```bash
openssl s_client -connect example.com:443 -servername example.com /dev/null \
  | grep -E "Verify return code|^ *[0-9] s:"
```

Expected output:

```
0 s:CN = example.com
1 s:C = US, O = Example CA, CN = Example Intermediate CA
Verify return code: 0 (ok)
```

## Why browsers hide the problem

Browsers do two things OpenSSL does not:

- **Cache intermediates.** Having seen an intermediate on another site, a browser reuses it.
- **Follow AIA.** The Authority Information Access extension carries a URL for the issuer's
  certificate, and browsers will fetch it.

So a broken chain works in Chrome, on your machine, because you happened to visit another site using
the same CA. It fails for a fresh browser profile, for curl, for your monitoring, and for the API
client your customer wrote. The server is misconfigured in every case.

*Where the missing intermediate can be found*

```bash
openssl x509 -in certificate.crt -noout -text | grep -A1 "Authority Information Access"
```

Expected output:

```
Authority Information Access:
    OCSP - URI:http://ocsp.example-ca.com
    CA Issuers - URI:http://crt.example-ca.com/intermediate.der
```

That file is normally DER — [convert it to PEM](/convert/der-to-pem/) before concatenating.

## Verifying a chain you have on disk

```bash
openssl verify -CAfile root-ca.crt -untrusted intermediate.crt certificate.crt
```

Expected output:

```
certificate.crt: OK
```

Roots go in `-CAfile`, intermediates in `-untrusted`. Putting an intermediate in `-CAfile` makes the
check pass for the wrong reason. See
[verifying a certificate chain](/openssl/verify-certificate-chain/).

## What breaks a chain

| Problem | Symptom |
| --- | --- |
| Intermediate not sent | `unable to get local issuer certificate` |
| Certificates in the wrong order | Fails on strict clients, works on lenient ones |
| An intermediate has expired | Fails even though the leaf is valid for months |
| Root not in the client's trust store | Fails on that client only — typical for private CAs |
| Wrong intermediate for the leaf | Signature verification fails partway up |


## Frequently asked questions

### Should the root certificate be in the chain the server sends?

No. A client that trusts the root already has it, so sending it wastes bytes on every handshake. A client that does not trust it will not start trusting it because the server said so. Send the leaf and the intermediates, and stop there.

### Why does a site work in Chrome but fail with curl?

Browsers repair broken chains. They cache intermediates from previous sites and follow the Authority Information Access URL to fetch a missing one over HTTP. curl and OpenSSL do neither. The chain is genuinely broken in both cases — the browser just hides it.

### Does the order of certificates in the file matter?

Yes. The leaf must come first, then each intermediate walking up toward the root. Some clients tolerate other orders, many do not, and a wrongly ordered file fails for a subset of users, which is unpleasant to diagnose.

### How many intermediates are normal?

One or two. A chain of leaf plus one intermediate is the common case for a publicly trusted certificate; cross-signed setups sometimes add another.


## References

- [RFC 5280: X.509 and CRL profile](https://www.rfc-editor.org/rfc/rfc5280) — the specification every field on a certificate comes from
- [RFC 4158: certification path building](https://www.rfc-editor.org/rfc/rfc4158) — why a verifier can fail to find a path that exists

## Related pages

- https://certguru.io/concepts/root-vs-intermediate-ca/
- https://certguru.io/errors/unable-to-get-local-issuer-certificate/
- https://certguru.io/errors/unable-to-verify-leaf-signature/
- https://certguru.io/errors/pkix-path-building-failed/
- https://certguru.io/openssl/verify-certificate-chain/
- https://certguru.io/platforms/kubernetes-tls-secret/
- https://certguru.io/openssl/get-certificate-from-server/
- https://certguru.io/concepts/self-signed-vs-ca-signed/
- https://certguru.io/errors/x509-signed-by-unknown-authority-go/

--
CertGuru — https://certguru.io
