The certificate was renewed, but the browser still showed the old one
Read one certificate in four pieces
Goal
Issue a server certificate from your own CA, and verify the chain, validity period, SAN, and key match each with openssl. Set up an intermediate CA, assemble a fullchain, and record the hostname check results in a table.
Why it matters
A certificate incident is one of four things — the chain is broken, it has expired, the name is different, or the key is not the matching one. The fixes are all different, so you have to read which one it is first. In this lab you create those four situations on purpose and see what the verifier says. In particular, the fact that x509 -req in OpenSSL 3.0 discards the CSR's extensions by default is a trap in which issuance looks successful, so it is better to run into it yourself.
Steps
- Create
/root/pki/ca.keyand the self-signed certificate/root/pki/ca.crt. The subject isCN=Lab Root CAand the validity is 30 days. - Create the server key
/root/pki/server.keyand the CSR/root/pki/server.csr. The subject isCN=www.lab.internal, and the SANs are two entries,DNS:www.lab.internalandDNS:api.lab.internal. - Sign with the CA to create
/root/pki/server.crt. The validity is 3 days, and the SAN must remain in the certificate. - Save the serial number, expiry date, SHA-256 fingerprint, and SAN of
server.crtto/root/pki/04-fields.txt. - Create one more key for comparison,
/root/pki/other.key, and in/root/pki/05-keymatch.txtwrite three lines,cert=,key=, andother=(each the 64-digit sha256 of the public key PEM), plusverdict=match. - In
/root/pki/06-expiry.txt, write the output line ofopenssl x509 -enddateandrenew_within_7d=yes|no. Decide the verdict by the exit code of-checkend 604800. - Create an intermediate CA (
/root/pki/inter.key,/root/pki/inter.crt,CN=Lab Intermediate CA, CA:TRUE) signed by the root, and with that intermediate CA issue the leaf/root/pki/api.crt(key/root/pki/api.key, SANDNS:api.lab.internal). Concatenate the leaf and the intermediate CA in that order to make/root/pki/fullchain.pem. - For
server.crt, write the verification results for the three nameswww.lab.internal,api.lab.internal, andother.lab.internalto/root/pki/08-hostname.txtin the form이름=OK|FAIL(name, then OK or FAIL; use the actual hostname on the left).
Notes
- Key generation:
openssl genrsa -out <파일> 2048(replace the placeholder with the output file path). Self-signing:openssl req -x509 -new -key ... -days ... -subj .... - SAN in a CSR:
openssl req -new ... -addext "subjectAltName=DNS:a,DNS:b". Keeping the extensions at signing time:openssl x509 -req ... -copy_extensions copy. - For the intermediate CA, pass
basicConstraints=critical,CA:TRUE,pathlen:0andkeyUsage=critical,keyCertSign,cRLSignwith-extfile. - Name check:
openssl verify -CAfile ca.crt -verify_hostname <이름> server.crt(replace the placeholder with the hostname to check). - Common mistakes: if you omit
-copy_extensions copyin step 3, issuance succeeds but the SAN disappears. If you sign the leaf directly with the root in step 7, it is not a chain.
Create the root CA
Create /root/pki/ca.key and the self-signed /root/pki/ca.crt (CN=Lab Root CA, 30 days).
If you pass -x509 to req, you get a self-signed certificate instead of a CSR. Check with openssl x509 -text that the issuer and subject are the same and that basicConstraints is CA:TRUE.
A CSR with a SAN
Create /root/pki/server.key and /root/pki/server.csr (CN=www.lab.internal, two SANs).
You can create the key and the CSR in one go with -newkey rsa:2048 -nodes -keyout. Add the SAN with -addext, and check the Subject Alternative Name in openssl req -in server.csr -noout -text.
Issue a 3-day server certificate
Sign with the CA to create /root/pki/server.crt (3 days, SAN preserved).
The skeleton is x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -days 3. If openssl x509 -in server.crt -noout -ext subjectAltName is empty after issuance, the CSR's extensions were discarded — there is an option that carries them over.
Read the identifying values
Save the serial number, expiry date, SHA-256 fingerprint, and SAN of server.crt to /root/pki/04-fields.txt.
You can pass -serial -enddate -fingerprint -sha256 -ext subjectAltName to x509 all at once. The grader recomputes the values from the same certificate and compares them.
Decide whether the keys match
Create /root/pki/other.key, and in /root/pki/05-keymatch.txt write cert=, key=, and other= (the sha256 of the public key PEM) plus verdict=match.
The certificate's public key comes from x509 -pubkey, and the public key of the private key from pkey -pubout, both in the same PEM format. Keep only the 64 digits with | sha256sum | cut -d' ' -f1. The cert and key values must be the same and only other must differ.
Judge expiry with a 7-day window
In /root/pki/06-expiry.txt, write the -enddate output line and renew_within_7d=yes|no.
-checkend 604800 exits with a nonzero code if the certificate expires within 7 days (604800 seconds). Catch it with an if statement and decide yes or no. For a 3-day certificate, the answer is already settled.
Intermediate CA and fullchain
Create an intermediate CA signed by the root (inter.key/inter.crt, CN=Lab Intermediate CA, CA:TRUE), issue the leaf api.crt (SAN api.lab.internal) with it, and then create /root/pki/fullchain.pem in the order leaf + intermediate.
When you sign the intermediate CA's CSR with the root, pass basicConstraints=critical,CA:TRUE,pathlen:0 and keyUsage=critical,keyCertSign,cRLSign in -extfile. Sign the leaf with -CA inter.crt -CAkey inter.key. It is a real chain only if openssl verify -CAfile ca.crt api.crt fails and passes when you add -untrusted inter.crt.
Hostname check table
For server.crt, write the -verify_hostname results for the three names www, api, and other to /root/pki/08-hostname.txt in the form 이름=OK|FAIL (name, then OK or FAIL).
The name check compares against the SAN's dNSName entries. A name that is in the CN but not in the SAN fails. Loop over the three names with for and decide OK or FAIL by the exit code.