Build a two-tier certificate chain and break it on purpose

short · 40 min · Objective 1.3

Task

Build a root CA, an intermediate, and a server certificate on your own lab VM, verify the chain, then break it in two different ways and observe how the failures differ. Chain problems are the commonest certificate incident there is, and they are much clearer once you have caused them.

Steps

  1. Make a working directory and a root: generate a key and a self-signed root certificate with openssl req -x509 -newkey rsa:2048 -nodes -keyout root.key -out root.crt -subj '/CN=Lab Root CA' -days 365.
  2. Generate an intermediate key intermediate.key and a CSR, then sign the CSR with the root into intermediate.crt, setting basicConstraints=CA:TRUE,pathlen:0 via an extension file so it is genuinely a CA certificate.
  3. Generate a server key server.key and a CSR server.csr for lab.internal, and sign it with the INTERMEDIATE, not the root, into server.crt. Keep all of these: the hashing capstone signs a release with server.key.
  4. Verify the full chain: openssl verify -CAfile root.crt -untrusted intermediate.crt server.crt.
  5. Break it the first way: verify server.crt against the root alone, without supplying the intermediate. Note the error text.
  6. Break it the second way, without touching server.crt: issue a second certificate from the same CSR that lives for one day -- openssl x509 -req -in server.csr -CA intermediate.crt -CAkey intermediate.key -CAcreateserial -days 1 -out shortlived.crt -- and verify it as it will stand two days from now: openssl verify -attime $(( $(date +%s) + 2*86400 )) -CAfile root.crt -untrusted intermediate.crt shortlived.crt. Note that the error is different, and write both messages into /tmp/chain.md. (Backdating with -days -1 is refused by current OpenSSL: "end date before start date".)

Verify

openssl verify -CAfile root.crt -untrusted intermediate.crt server.crt
openssl x509 -in server.crt -noout -issuer -subject -dates
openssl verify -CAfile root.crt server.crt 2>&1 | grep -ci "unable to get local issuer"
openssl verify -attime $(( $(date +%s) + 2*86400 )) -CAfile root.crt -untrusted intermediate.crt shortlived.crt 2>&1 | grep -ci "certificate has expired"
grep -ciE "expired|issuer" /tmp/chain.md

The first must print server.crt: OK for the good certificate. The second must show the issuer is the intermediate and the subject is your invented name. The third must be non-zero — that specific message is what a missing intermediate looks like, and recognising it saves an afternoon. The fourth must be non-zero too, and it is a different message: an expired certificate is a renewal problem, a missing intermediate is a server configuration problem. The fifth confirms you recorded both failure modes, because they are different findings with different fixes.

Notes

The missing-intermediate failure is the one that reaches production, because it works in the browser of whoever tested it — their browser had already cached the intermediate from another site. The server must send the chain; relying on the client to have it is how a certificate works for you and fails for your customers.

This is an independent study companion for CompTIA Security+ SY0-801 and is not produced by or endorsed by CompTIA.