第4章:数字证书格式——X.509标准,证书字段与签名算法
说起数字证书,你肯定听过X.509这个名字。它到底是什么?
简单来说,X.509就是定义证书长什么样的一套国际标准。就像我们身份证有国标一样,证书也得有个统一的格式,不然不同的系统之间根本没法互认。我记得刚接触PKI(公钥基础设施)时,被各种术语搞得一头雾水。后来亲手解析了一次证书文件,才真正搞明白里面每一段数据是干什么用的。
这一章,我们就一起把X.509证书的“零件”拆开来看。
4.1 X.509标准的前世今生
X.509是国际电信联盟(ITU-T)制定的一个标准。最早是1988年发布的,后来不断更新,现在主流用的是X.509 v3版本。
你可能会问:为什么是v3?因为v1和v2太简单了。v1只有基本字段,v2加了个唯一标识符(没用多久就被淘汰了)。v3引入了“扩展”机制,这才是关键。扩展允许我们在证书里塞入自定义信息,比如证书用途、域名、策略约束等。说白了,v3让证书变得灵活了。
我在项目中遇到过一种情况:一个老系统只支持v1证书,新签发的v3证书它死活不认。最后只能降级签发。所以,了解版本差异在实际工作中很重要。
| 版本 | 特点 | 使用现状 |
|---|---|---|
| v1 (1988) | 基本字段,无扩展 | 极少使用,历史遗留 |
| v2 (1993) | 增加颁发者和主体唯一标识符 | 几乎不再使用 |
| v3 (1996+) | 引入扩展机制 | 事实标准,mTLS和HTTPS都用它 |
4.2 证书结构:到底长什么样?
一个X.509 v3证书,说白了就是一段用ASN.1(抽象语法表示法)编码的数据。你想想看,它包含两个主要部分:证书体(TBSCertificate)和签名值。
证书体是核心,里面装着所有关键信息。签名值则是对证书体的数字签名,用来保证内容没有被篡改。
下面这个表格列出了证书体里的主要字段。我在看证书时,心里会按这个顺序来扫一遍:
| 字段名 | 含义 | 避坑点 |
|---|---|---|
| Version | 证书版本号(0=v1,1=v2,2=v3) | 永远别搞错v3对应的是2 |
| Serial Number | 颁发者分配的唯一整数,最长20字节 | 序列号重复会导致吊销混乱,我见过有人用随机数生成 |
| Signature Algorithm | 签名算法标识符(如 sha256WithRSAEncryption) | 必须与证书体外的算法字段一致 |
| Issuer | 颁发者的DN(Distinguished Name) | DN的编码顺序有讲究,不同CA可能有差异 |
| Validity | 有效期:notBefore和notAfter | UTC时间格式,注意时区转换坑 |
| Subject | 证书持有者的DN | 自签名证书里Subject和Issuer一样 |
| Public Key Info | 公钥算法和公钥值 | ECDSA的曲线参数必须明确指定 |
| Extensions (v3) | 一组扩展项 | Basic Constraints、Key Usage等 |
我的习惯:每次生成自签名证书,我都会用 openssl x509 -text -in cert.pem 把证书打印出来,逐字段检查一遍。尤其是序列号和有效期,踩过坑的人都知道这两项有多重要。
4.3 签名算法:到底怎么签名?
签名算法决定了CA用什么算法来“盖戳”。它由两部分组成:哈希算法和签名算法。
为什么要有哈希?因为直接对整个证书做签名太慢了。先算一个摘要,再对摘要签名,这样效率高很多。
常见的组合有:
- sha256WithRSAEncryption:SHA-256做哈希,RSA做签名。最经典、兼容性最好。我早期做mTLS时基本都用这个。
- ecdsa-with-SHA256:SHA-256做哈希,ECDSA做签名。密钥更短,性能更好,适合移动端和IoT。但我建议注意OpenSSL版本,老版本对ECDSA支持不太好。
- sha256WithRSAandMGF1:RSASSA-PSS,一种更安全的RSA签名方案。说实话目前主流系统还没全面支持,mTLS里用它会遇到兼容性问题。我曾经在跨平台对接时被它坑过——两边库的PSS参数不同,握手直接失败。
注意:签名算法字段在证书里出现两次。一次在证书体里,一次在证书体外面。两个值必须一致。如果它们不一致,证书就是非法的。我见过有人手工修改证书时忘改了,结果验证不通过。
你可能会问:自签名证书用什么算法好?我个人建议:如果只是内部测试和开发环境,用 sha256WithRSAEncryption 就足够了。RSA的兼容性最好,几乎所有库都能处理。如果你想压榨性能,可以试试ECDSA,但要确认你的所有客户端都支持。
核心结论:自签名证书跟CA签发的证书在结构上完全一样,只是Issuer和Subject相同,而且没有上级CA做背书。X.509标准并不区分“谁签的”,只关心“字段对不对”。你签的证书只要符合格式,其他系统就能解析。
4.4 一个完整的证书解析实战
来,我们真的看一个例子。假如你有如下自签名证书(PEM格式):
-----BEGIN CERTIFICATE-----
MIIFazCCA1OgAwIBAgIUV9U7yF0Z...
-----END CERTIFICATE-----
用OpenSSL命令解析:
openssl x509 -in mycert.pem -text -noout
输出会包含:
- Certificate: 显示版本号、序列号、签名算法。
- Issuer: CN = my-ca.test, O = TestLab
- Validity: Not Before: Apr 1 00:00:00 2024 GMT / Not After : Mar 31 23:59:59 2025 GMT
- Subject: CN = my-ca.test, O = TestLab
- Subject Public Key Info: Public Key Algorithm: rsaEncryption / Public-Key: (2048 bit)
- X509v3 extensions: 这里能看到 Basic Constraints: CA:TRUE(自签名根证书必须有这个)
- Signature Algorithm: sha256WithRSAEncryption
- Signature Value: 一串十六进制数
你会注意到,自签名证书的Issuer和Subject完全一样。这也是它被称为“自签名”的原因——自己给自己签名。
下面是这一章的核心知识结构图。它帮你理清X.509证书的层次和关系:
嗯,这张图基本把X.509的结构捋清楚了。证书体(TBSCertificate)包含所有元数据,它会被序列化成一段二进制数据。然后CA用私钥对这个二进制数据做签名,得到Signature Value。最后把证书体和签名值打包到一起,就是完整的证书了。
一句话总结:证书 = 证书体(描述你是谁、你的公钥、有效期等)+ CA对证书体的数字签名(证明这个证书是真的)。
你在网上看到的.PEM或.DER文件,本质上都是按这个结构编码的。解析的时候,解析器先还原证书体,再用CA的公钥验签。验签通过了,才说明这个证书是合法的。
搞明白这个结构之后,你会发现后面学mTLS和证书链就轻松多了。本质上都是在跟这些字段打交道。