TT Lab
开始
学习 学习路径 课程

证书已经续期,浏览器却还显示旧证书

把一张证书拆成四块来读

在 TT Lab 中继续学习

目标

用自建 CA 签发服务器证书,并分别用 openssl 验证证书链、有效期、SAN 和密钥匹配。建立中间 CA 并组装 fullchain,把名称检查的结果整理成表格留下。

为什么重要

证书故障是四者之一——链断了、过期了、名称不同,或者密钥不配对。修复方法各不相同,所以必须先判断是哪一种。本实验会故意制造这四种情况,看验证工具怎么说。尤其是 OpenSSL 3.0 的 x509 -req 默认会丢弃 CSR 的扩展,这是一个看上去签发成功了的陷阱,最好亲身经历一次。

步骤

  1. 创建 /root/pki/ca.key 和自签名证书 /root/pki/ca.crt。主体为 CN=Lab Root CA,有效期 30 天。
  2. 创建服务器密钥 /root/pki/server.key 和 CSR /root/pki/server.csr。主体为 CN=www.lab.internal,SAN 有 DNS:www.lab.internal 和 DNS:api.lab.internal 两个。
  3. 用 CA 签名,创建 /root/pki/server.crt。有效期为 3 天,SAN 必须保留在证书中。
  4. 把 server.crt 的序列号、到期日、SHA-256 指纹和 SAN 保存到 /root/pki/04-fields.txt。
  5. 再创建一把用于对比的密钥 /root/pki/other.key,并在 /root/pki/05-keymatch.txt 中写入 cert=、key=、other= 三行(各为对应公钥 PEM 的 64 位 sha256)和 verdict=match。
  6. 在 /root/pki/06-expiry.txt 中写入 openssl x509 -enddate 的输出行和 renew_within_7d=yes|no。判定依据是 -checkend 604800 的退出码。
  7. 创建中间 CA(/root/pki/inter.key、/root/pki/inter.crt、CN=Lab Intermediate CA、CA:TRUE),由根为它签名,再用这个中间 CA 签发叶子 /root/pki/api.crt(密钥 /root/pki/api.key,SAN DNS:api.lab.internal)。按叶子、中间 CA 的顺序连接,创建 /root/pki/fullchain.pem。
  8. 针对 server.crt,把 www.lab.internal、api.lab.internal、other.lab.internal 三个名称的验证结果,以 이름=OK|FAIL(占位符为名称)的形式写入 /root/pki/08-hostname.txt。

参考

创建根 CA

创建 /root/pki/ca.key 和自签名的 /root/pki/ca.crt(CN=Lab Root CA,30 天)。

给 req 加上 -x509,得到的是自签名证书而不是 CSR。请用 openssl x509 -text 确认签发者与主体相同,并且 basicConstraints 为 CA:TRUE。

带有 SAN 的 CSR

创建 /root/pki/server.key 和 /root/pki/server.csr(CN=www.lab.internal,两个 SAN)。

用 -newkey rsa:2048 -nodes -keyout 可以一次创建密钥和 CSR。SAN 用 -addext 加入,并在 openssl req -in server.csr -noout -text 中确认 Subject Alternative Name。

签发 3 天有效的服务器证书

用 CA 签名,创建 /root/pki/server.crt(3 天,保留 SAN)。

x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -days 3 是基本骨架。签发之后,如果 openssl x509 -in server.crt -noout -ext subjectAltName 的结果是空的,就是 CSR 的扩展被丢弃了——有一个选项可以把它们带过来。

读取标识值

把 server.crt 的序列号、到期日、SHA-256 指纹和 SAN 保存到 /root/pki/04-fields.txt。

可以给 x509 一次性加上 -serial -enddate -fingerprint -sha256 -ext subjectAltName。评分器会从同一张证书重新计算这些值来对照。

判定密钥是否配对

创建 /root/pki/other.key,并在 /root/pki/05-keymatch.txt 中写入 cert=、key=、other=(公钥 PEM 的 sha256)和 verdict=match。

证书的公钥用 x509 -pubkey,私钥的公钥用 pkey -pubout,得到的是相同的 PEM 格式。用 | sha256sum | cut -d' ' -f1 只保留 64 位。cert 和 key 必须相同,只有 other 不同。

以 7 天窗口判定到期

在 /root/pki/06-expiry.txt 中写入 -enddate 的输出行和 renew_within_7d=yes|no。

-checkend 604800 在 7 天(604800 秒)内过期时,会以非 0 的退出码结束。用 if 语句接收它,决定 yes/no。如果是 3 天有效的证书,答案是确定的。

中间 CA 与 fullchain

创建由根签名的中间 CA(inter.key/inter.crt,CN=Lab Intermediate CA,CA:TRUE),用它签发叶子 api.crt(SAN api.lab.internal),然后按叶子加中间 CA 的顺序创建 /root/pki/fullchain.pem。

用根给中间 CA 的 CSR 签名时,请在 -extfile 中给出 basicConstraints=critical,CA:TRUE,pathlen:0 和 keyUsage=critical,keyCertSign,cRLSign。叶子用 -CA inter.crt -CAkey inter.key 签名。openssl verify -CAfile ca.crt api.crt 会失败,而加上 -untrusted inter.crt 后能通过,才是真正的链。

名称检查表

针对 server.crt,把 www、api、other 三个名称的 -verify_hostname 结果,以 이름=OK|FAIL(占位符为名称)的形式写入 /root/pki/08-hostname.txt。

名称检查要与 SAN 的 dNSName 对照。即使 CN 中有,SAN 中没有也会失败。请用 for 遍历这三个名称,并根据退出码决定 OK/FAIL。