第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 v3证书结构图 X.509 v3 证书结构 TBSCertificate 证书体 Version (v3) Serial Number Signature Algorithm Issuer Validity Subject Public Key Info Extensions Basic Constraints Key Usage Subject Alt Name Signature Algorithm sha256WithRSAEncryption Signature Value 0xAB 3F 29 ... (256字节) 自签名证书:Issuer == Subject,且没有上级CA 签发流程 私钥签名 → 输出DER/PEM

嗯,这张图基本把X.509的结构捋清楚了。证书体(TBSCertificate)包含所有元数据,它会被序列化成一段二进制数据。然后CA用私钥对这个二进制数据做签名,得到Signature Value。最后把证书体和签名值打包到一起,就是完整的证书了。

一句话总结:证书 = 证书体(描述你是谁、你的公钥、有效期等)+ CA对证书体的数字签名(证明这个证书是真的)。

你在网上看到的.PEM或.DER文件,本质上都是按这个结构编码的。解析的时候,解析器先还原证书体,再用CA的公钥验签。验签通过了,才说明这个证书是合法的。

搞明白这个结构之后,你会发现后面学mTLS和证书链就轻松多了。本质上都是在跟这些字段打交道。