3、X.509证书标准:证书结构、版本号、序列号、签名算法、颁发者、有效期、主体、公钥信息、扩展项
X.509 是 PKI 体系的基石。说白了,它就是定义了一张「数字身份证」长什么样、每个字段写什么的标准。我最早接触 X.509 是在做 HTTPS 证书解析的时候,当时被 ASN.1 编码搞得一头雾水。后来才明白,只要把证书的字段结构搞清楚,剩下的就是编码问题了。
这一节,我们就把 X.509 证书的每个字段拆开来看。你想想看,一张证书从签发到验证,每一步都依赖这些字段的正确性。任何一个字段出错,证书链就可能断裂。
3.1 证书结构总览
一张标准的 X.509 v3 证书,包含三个主要部分:
- 证书体(TBSCertificate)—— 真正要签名的数据
- 签名算法标识—— 告诉你怎么验证签名
- 签名值—— 防篡改的保证
我个人习惯把证书体比作「身份证上的信息」,签名值比作「公安局的钢印」。钢印盖上去,信息就不能改了。
3.2 版本号
版本号告诉解析器:这张证书用的是哪个版本的 X.509 标准。目前有三个版本:
| 版本 | 编码值 | 特点 |
|---|---|---|
| v1 | 0 | 最基础,没有扩展项 |
| v2 | 1 | 引入了主体和颁发者唯一标识,但很少用 |
| v3 | 2 | 支持扩展项,现代证书的标准 |
现在你几乎看不到 v1 和 v2 的证书了。我记得有一次在遗留系统里发现一张 v1 的根证书,CA 说用了十几年没换过。嗯,这种证书该换了,没有扩展项意味着很多安全特性都用不了。
3.3 序列号
序列号是 CA 给每张证书分配的唯一编号。它在同一个 CA 下不能重复。我见过一些 CA 用时间戳加随机数生成序列号,也有直接用递增整数的。
序列号有几个关键作用:
- 唯一标识 —— 配合颁发者 DN,可以全局唯一确定一张证书
- 吊销查询 —— CRL 和 OCSP 都靠序列号定位证书
- 日志审计 —— 出了问题,查序列号就能追溯到具体证书
3.4 签名算法
这个字段出现在两个地方:证书体里和证书体外面。为什么重复?
说白了,就是为了安全。证书体里的签名算法告诉验证方「我是用什么算法签的名」,外面的签名算法标识则用于快速定位算法。如果两者不一致,说明证书可能被篡改过。
常见的签名算法组合:
| 算法 OID | 哈希算法 | 签名算法 | 状态 |
|---|---|---|---|
| 1.2.840.113549.1.1.5 | SHA-1 | RSA | 已弃用 |
| 1.2.840.113549.1.1.11 | SHA-256 | RSA | 推荐 |
| 1.2.840.10045.4.3.2 | SHA-256 | ECDSA | 推荐 |
| 1.2.840.10045.4.3.3 | SHA-384 | ECDSA | 推荐 |
我个人习惯优先选 ECDSA 算法。同样的安全强度,密钥更短,签名也小。RSA 4096 的签名有 512 字节,而 ECDSA P-384 的签名只有 96 字节。在证书链较长时,这个差距很明显。
3.5 颁发者
颁发者字段记录的是签发这张证书的 CA 的身份信息。它用 DN(Distinguished Name)表示,包含一系列属性:
- C —— 国家(Country),如 CN
- ST —— 州/省(State/Province)
- L —— 城市(Locality)
- O —— 组织(Organization)
- OU —— 组织单元(Organizational Unit)
- CN —— 通用名称(Common Name)
举个例子,一张由 Let's Encrypt 签发的证书,颁发者 DN 可能是:
C=US, O=Let's Encrypt, CN=R3
你想想看,验证证书链时,子证书的颁发者 DN 必须和父证书的主体 DN 完全一致。我曾经排查过一个证书链验证失败的问题,折腾了半天,发现是颁发者 DN 里多了一个空格。嗯,字符串比较就是这么严格。
3.6 有效期
有效期包含两个时间戳:
- notBefore —— 证书生效时间
- notAfter —— 证书失效时间
格式是 UTC 时间或 GeneralizedTime。我建议你在解析时统一转成 UTC,避免时区问题。
关于有效期,有几个坑要注意:
- 根证书的有效期通常很长(10-20 年),但私钥的轮换周期应该更短
- 中间证书的有效期一般在 5-10 年
- 终端证书现在普遍是 90 天(Apple/Google 推动的短寿命趋势)
- 验证时不仅要检查当前时间是否在有效期内,还要检查证书链上所有证书都有效
我曾经遇到过一个案例:根证书还有 10 年才过期,但中间证书已经过期了。结果所有由这个中间证书签发的终端证书都验证失败。这就是典型的「链上有一环断了」。
3.7 主体
主体字段记录的是证书持有者的身份信息。格式和颁发者一样,也是 DN。对于终端证书,主体通常包含网站域名或用户身份信息。
举个例子,一张百度网站的证书,主体 DN 可能是:
C=CN, ST=Beijing, L=Beijing, O=Beijing Baidu Netcom Science Technology Co., Ltd, CN=baidu.com
这里有个关键点:主体 CN 和 SAN(Subject Alternative Name)的关系。早期浏览器只检查 CN,但现在 CN 已经被弃用了,浏览器只看 SAN 扩展。我建议你签发证书时,把域名同时放在 CN 和 SAN 里,兼容旧系统。
3.8 公钥信息
这是证书的核心——包含证书持有者的公钥和算法信息。结构如下:
SubjectPublicKeyInfo ::= SEQUENCE {
algorithm AlgorithmIdentifier,
subjectPublicKey BIT STRING
}
算法标识符告诉你怎么解析公钥,公钥本身是一个比特串。常见的算法有:
| 算法 | 密钥长度 | 公钥大小 | 推荐场景 |
|---|---|---|---|
| RSA | 2048/4096 | 256/512 字节 | 兼容性要求高 |
| ECDSA | P-256/P-384 | 64/96 字节 | 性能优先 |
| Ed25519 | 256 位 | 32 字节 | 极致性能 |
我个人偏好 ECDSA P-384。为什么?P-256 虽然够用,但 NSA 和 NIST 对 P-384 的安全余量评价更高。Ed25519 性能最好,但有些老旧系统不支持。
3.9 扩展项
扩展项是 v3 证书最强大的特性。它让证书不再只是一个「公钥+身份」的绑定,而是可以携带各种策略和约束信息。
常见的扩展项:
| 扩展项 | OID | 作用 | 关键/非关键 |
|---|---|---|---|
| Basic Constraints | 2.5.29.19 | 标记是否为 CA 证书,以及路径长度 | 关键 |
| Key Usage | 2.5.29.15 | 限制密钥用途(签名、加密等) | 关键 |
| Extended Key Usage | 2.5.29.37 | 限制证书用途(服务器认证、客户端认证等) | 非关键 |
| Subject Alternative Name | 2.5.29.17 | 列出证书适用的域名/IP | 非关键 |
| CRL Distribution Points | 2.5.29.31 | 告诉你去哪里下载 CRL | 非关键 |
| Authority Information Access | 1.3.6.1.5.5.7.1.1 | 提供 OCSP 响应器地址和 CA 证书下载地址 | 非关键 |
我记得有一次帮客户排查证书问题,发现他们的中间证书没有设置 Basic Constraints 扩展。结果浏览器认为这张证书不是 CA 证书,拒绝用它去验证下级证书。这就是典型的「忘了标记自己是 CA」的错误。
3.10 小结
X.509 证书的每个字段都不是随便定义的。版本号决定了能力,序列号保证了唯一性,签名算法和签名值保证了完整性,颁发者和主体建立了信任关系,有效期控制了风险,公钥信息承载了加密能力,扩展项则让证书变得灵活而强大。