数字证书基础:X.509 证书的里里外外
聊 TLS,绕不开数字证书。说白了,证书就是网络世界里的身份证。你访问一个网站,怎么确定它真的是那个网站,而不是中间人冒充的?靠的就是这张证书。
我刚开始接触 HTTPS 时,总觉得证书就是个加密文件。后来排查过几次证书问题,才真正理解它的结构有多重要。今天咱们就把 X.509 证书拆开看看。
什么是 X.509 证书?
X.509 是国际电信联盟(ITU-T)定义的一个标准。它规定了公钥证书的格式。你平时在浏览器里看到的 SSL/TLS 证书,绝大多数都是 X.509 证书。
你可以把它理解成一个数字信封。里面装着持有人的公钥,还有一堆元数据。谁发的、发给谁的、什么时候过期、怎么验证——全写在这张证书里。
一句话总结:X.509 证书 = 公钥 + 身份信息 + 颁发者签名。三者缺一不可。
证书的组成结构
一张 X.509 v3 证书,包含以下核心字段。我习惯把它们分成三组来看:
| 字段组 | 字段名 | 说明 |
|---|---|---|
| 身份信息 | Subject(主体) | 证书持有者,比如域名 example.com |
| Issuer(颁发者) | 签发这张证书的 CA 名称 | |
| Validity(有效期) | notBefore 和 notAfter,起止时间 | |
| 密码学材料 | Subject Public Key Info | 公钥算法 + 公钥值(RSA/ECC) |
| Signature(签名) | CA 用私钥对证书内容的签名值 | |
| 扩展 | X.509 v3 Extensions | SAN、Key Usage、CA 标志等 |
这里有个坑,我提醒一下:签名不是证书持有者自己签的,是 CA 签的。你想想看,如果自己签自己,那跟伪造有什么区别?CA 的签名,才是信任的锚点。
公钥、签名、颁发者、有效期——逐个拆解
公钥
这是证书的核心资产。TLS 握手时,客户端用证书里的公钥加密一个随机数,服务器用私钥解密。只有持有对应私钥的人,才能完成握手。
公钥算法现在主流是 RSA 2048 位或 ECDSA P-256。我个人更倾向 ECDSA,密钥短、性能好。但很多老系统还在用 RSA,兼容性更好。
签名
CA 把证书里的所有字段(除了签名本身)做一次哈希,然后用 CA 的私钥加密这个哈希值,得到签名。验证时,用 CA 的公钥解密签名,跟重新计算的哈希对比。一致就说明证书没被篡改。
我曾经遇到过一个案例:证书的 Subject 被改了一个字母,但签名没变。客户端验证签名时直接报错。嗯,这就是签名的作用——防篡改。
颁发者
Issuer 字段告诉你是谁签发了这张证书。浏览器拿到证书后,会去本地信任存储里找 Issuer 对应的根证书。找不到?那就报“证书不受信任”。
这里有个常见误区:Issuer 不是域名,是 CA 的名称。比如 Let's Encrypt 的 Issuer 是 "R3"。你可以在证书详情里看到。
有效期
每张证书都有生效时间和失效时间。浏览器在验证时,会检查当前时间是否在有效期内。过期证书直接拒绝。
我记得有一次线上告警,排查了半天,发现是证书过期了。从那以后,我都在证书到期前 30 天设置自动续期提醒。别等到过期再处理,那太被动了。
注意:有效期不是越长越好。业界现在推荐 90 天以内的短寿命证书。原因很简单:万一私钥泄露,短有效期能缩小损失窗口。Let's Encrypt 就是 90 天,自动续期。
证书编码格式:DER 与 PEM
证书在磁盘上怎么存?两种主流格式:DER 和 PEM。我经常看到有人搞混,其实区别很简单。
| 特性 | DER | PEM |
|---|---|---|
| 编码方式 | 二进制(ASN.1 DER) | Base64 文本 |
| 可读性 | 不可读,乱码 | 可读,有头尾标记 |
| 常见后缀 | .der .crt .cer | .pem .crt .cer .key |
| 典型用途 | Windows、Java 密钥库 | OpenSSL、Nginx、Apache |
PEM 格式长这样:
-----BEGIN CERTIFICATE-----
MIIFazCCA1OgAwIBAgIU...
(中间是一长串 Base64 编码)
-----END CERTIFICATE-----
DER 格式就是上面那段 Base64 解码后的原始二进制。你可以在 OpenSSL 里互相转换:
# DER 转 PEM
openssl x509 -in cert.der -inform DER -out cert.pem -outform PEM
# PEM 转 DER
openssl x509 -in cert.pem -inform PEM -out cert.der -outform DER
我个人习惯用 PEM。原因很简单:文本格式,可以 cat 查看,可以复制粘贴,不容易损坏。DER 是二进制,传输出错很难排查。
小技巧:用 openssl x509 -in cert.pem -text -noout 可以查看 PEM 证书的完整内容。包括公钥、签名算法、有效期、扩展字段等。排查问题时,这个命令我几乎天天用。
X.509 证书结构图
下面这张图,把证书的核心结构画出来了。你可以对照着看,每个字段在证书里的位置和关系。
你看,从版本号到扩展,每一段都是明文。唯独最后的签名值,是 CA 用私钥加密的。验证时,浏览器会重新计算前面所有字段的哈希,跟签名值解密后的哈希对比。对得上,证书就是真的。
避坑指南:我踩过的几个坑
- 证书链不完整:我曾经只配置了服务器证书,没配中间证书。结果 Android 手机访问正常,iOS 报错。原因是 iOS 不自动下载中间证书。解决方案:把服务器证书和中间证书合并成一个 .pem 文件。
- SAN 字段缺失:老证书可能只写了 Common Name,没写 Subject Alternative Name。Chrome 58 以后强制要求 SAN。我遇到过客户拿着一张只有 CN 的证书来找我,说 Chrome 报“不安全”。没办法,只能重新签发。
- 编码混淆:有一次我把 DER 格式的证书直接传给了 Nginx,Nginx 报错说“bad PEM”。检查才发现,Nginx 只认 PEM 格式。用 OpenSSL 转一下就好了。
重要提醒:永远不要在生产环境手动修改证书文件。改一个字节,签名就失效了。证书的完整性靠签名保证,不是靠文件权限。如果你需要更新证书,找 CA 重新签发。
好了,X.509 证书的基础就聊到这里。你理解了证书的结构,后面讲证书链验证时,就能明白每一步在做什么。记住:公钥是核心,签名是保障,有效期是约束,编码格式是工具。把这四点吃透,证书这块就稳了。