公钥基础设施(PKI)基础
做TLS双向认证,绕不开PKI。说白了,PKI就是一套管理公钥加密的信任体系。没有它,谁也信不过谁。
我刚开始接触双向认证时,以为只要有证书就行。结果被CA、证书链、CRL这些概念绕得晕头转向。后来才明白,PKI是整个TLS信任的根基。
PKI的核心角色
PKI里最关键的角色就四个:
- 证书颁发机构(CA):签发证书的权威。根CA是最顶层的信任点。
- 注册机构(RA):负责验证申请者身份,CA不直接对接用户,通过RA做初审。
- 证书持有者:拿到证书的一方,比如服务端或客户端。
- 依赖方:验证证书的一方。在TLS双向认证里,双方互为依赖方。
我的一点经验:实际项目里,很多公司自建内部CA用来签发服务器证书和客户端证书。这样既省钱,又方便管理。但根证书的私钥一定要保护好——一旦泄露,整个信任体系就完了。
数字证书长什么样?
证书不只是公钥的容器。它绑定了公钥和主体信息(域名、公司名、邮箱),还有CA的签名。X.509 v3是最常用的标准格式。
我整理了一张常见字段表:
| 字段 | 说明 | 双向认证中的意义 |
|---|---|---|
| 序列号 | CA分配的唯一编号 | 用于吊销时定位证书 |
| 主体(Subject) | 持有者身份信息 | 服务端用 CN 域名,客户端用 CN 用户名 |
| 公钥 | RSA/ECC 公钥 | 加密和签名验证的基础 |
| 有效期 | 起始和结束时间 | 过期证书必须拒绝,否则有安全隐患 |
| 签发者(Issuer) | 签发该证书的CA | 用于构建证书链 |
| CA签名 | CA用私钥对证书摘要签名 | 保证证书内容未被篡改 |
注意:双向认证时,双方都需要校验对方的证书有效期。我遇到过因为忘记更新客户端证书导致生产环境认证失败的事故,排查了好久才发现是证书过期了。
证书链与信任锚
证书不是单独存在的。它通常是一个链条:
- 根证书:自签名,信任的起点。浏览器或操作系统预装了很多根证书。
- 中间CA证书:由根CA签发,用来签发终端证书。这样做的好处是:根CA私钥可以离线保存,降低泄露风险。
- 终端实体证书:服务器或客户端持有的证书,由中间CA或根CA直接签发。
验证时,依赖方从终端证书开始,逐级向上查找签发者,直到找到信任的根证书。这个过程叫证书链验证。
我曾经踩过的坑:自建CA时,我用根证书直接签发终端证书,省掉了中间CA。结果后来想吊销一批证书,不得不重新签发根证书,导致所有下级证书都得重新签。如果你打算长期运营,建议至少保留一层中间CA。
证书吊销:CRL与OCSP
证书在有效期内也可能被吊销(比如私钥泄露、员工离职)。PKI提供了两种吊销检查机制:
- CRL(证书吊销列表):CA定期发布一个列表,包含所有被吊销证书的序列号。客户端下载列表后离线检查。
- OCSP(在线证书状态协议):实时查询某个证书是否被吊销。比CRL更新及时,但需要联网。
我建议双向认证接口中,优先使用OCSP stapling(由服务端主动携带OCSP响应),既能实时检查,又避免客户端频繁查询造成的性能开销。
SVG图:PKI信任体系结构
下面这张图展示了PKI的层次关系和在TLS双向认证中的交互路径:
实战:用OpenSSL搭建迷你PKI
为了加深理解,我习惯在本地快速建一套测试用PKI。下面是最简步骤:
- 生成根CA密钥和自签名证书
# 生成根CA私钥
openssl genrsa -out ca.key 2048
# 生成自签名根证书
openssl req -x509 -new -nodes -key ca.key -sha256 -days 3650 \
-subj "/C=CN/O=MyLab/CN=MyLab Root CA" -out ca.crt
- 生成中间CA证书
# 中间CA私钥
openssl genrsa -out inter.key 2048
openssl req -new -key inter.key -subj "/C=CN/O=MyLab/CN=MyLab Inter CA" -out inter.csr
# 用根CA签发中间CA证书
openssl x509 -req -in inter.csr -CA ca.crt -CAkey ca.key -CAcreateserial \
-out inter.crt -days 1825 -sha256 -extensions v3_ca
- 签发服务器证书(用于双向认证测试)
# 生成服务器密钥和CSR
openssl genrsa -out server.key 2048
openssl req -new -key server.key -subj "/C=CN/O=MyLab/CN=server.example.com" -out server.csr
# 用中间CA签发
openssl x509 -req -in server.csr -CA inter.crt -CAkey inter.key -CAcreateserial \
-out server.crt -days 365 -sha256
一个小建议:测试时把根证书
ca.crt 导入操作系统的信任存储,这样客户端验证时就不会报“证书未知颁发者”。我在本地常用 security add-trusted-cert(macOS)或 certutil -addstore(Windows/Linux)。
PKI在TLS双向认证中的关键点
- 服务器必须持有由CA签发的证书(不能自签名,除非客户明确信任)。
- 客户端证书同理,且服务端要配置信任的根CA列表。
- 双方都要做证书链校验,不能只检查叶子证书。
- 吊销检查不能忽略——尤其是客户端证书的吊销,员工离职后应立刻吊销其证书。
我曾经遇到一个案例:某个项目使用自签名证书进行双向认证,但只把根证书硬编码在客户端。后来根证书过期,所有客户端都无法连接,只能紧急发布新版本。所以生产环境一定要规划好证书的生命周期管理。
好了,PKI的基础概念就到这。理解了CA、证书链和吊销机制,你就能正确配置TLS双向认证的信任存储了。下一节我们接着讲如何用代码实现完整的手工验证。