3、证书格式解析:X.509标准、PEM/DER编码、证书字段详解

说到证书格式,我见过不少运维同事在这上面栽跟头。明明证书内容是对的,就因为格式搞混了,折腾半天。今天咱们就把这块彻底理清楚。

3.1 X.509标准:证书的通用语言

X.509是个国际标准,定义了公钥证书的格式。说白了,它就是一套规则,告诉全世界「证书应该长什么样」。你想想看,如果每个厂商都用自己的格式,那不同系统之间怎么互认?

我在项目中遇到过最典型的场景:某银行对接第三方支付,两边证书都是X.509,但扩展字段的理解不一样,结果联调了整整两天。后来发现是标准版本没对齐——一个用的v3,另一个还在用v1。

X.509的三个版本:

  • v1(1988年):基础版本,定义了主体、颁发者、有效期等核心字段
  • v2(1993年):增加了唯一标识符,但实际用得很少
  • v3(1996年至今):引入了扩展字段,支持SAN、密钥用法、CRL分发点等

现在基本都在用v3。如果你看到v1或v2的证书,那大概率是古董设备。

3.2 PEM与DER:两种编码方式

证书内容确定之后,怎么存到文件里?这就涉及到编码了。最常见的两种:PEM和DER。

特性 PEM DER
格式 Base64文本,可读 二进制,不可读
头尾标记 有(-----BEGIN CERTIFICATE-----) 无
文件大小 比DER大约33% 更紧凑
常见后缀 .pem, .crt, .cer, .key .der, .cer
适用场景 Web服务器、邮件客户端、脚本处理 嵌入式设备、Java keystore、Windows系统

我个人习惯:能用PEM就用PEM。为什么?因为出问题的时候,你可以直接cat出来看,DER就只能用openssl x509 -in xxx.der -inform der -text才能看。

小技巧:PEM和DER可以互相转换:

# PEM → DER
openssl x509 -in cert.pem -outform der -out cert.der

# DER → PEM
openssl x509 -in cert.der -inform der -out cert.pem

3.3 证书字段详解:一张证书里到底藏了什么?

好,现在咱们打开一张证书,看看里面到底有什么。我用openssl命令来展示:

openssl x509 -in example.crt -text -noout

输出结果很长,但核心字段就这些:

3.3.1 基础字段

  • Version:版本号,通常是v3(值为2)
  • Serial Number:序列号,CA颁发的唯一标识。我曾经遇到过一个坑:两个证书序列号一样,结果浏览器报证书冲突。后来发现是CA的数据库出了问题。
  • Signature Algorithm:签名算法,比如sha256WithRSAEncryption
  • Issuer:颁发者,也就是CA的信息
  • Validity:有效期,包含Not Before和Not After
  • Subject:主体,证书归属方的信息
  • Subject Public Key Info:公钥信息,包含算法和公钥值

3.3.2 扩展字段(X.509 v3核心)

v3最大的改进就是扩展字段。这些字段决定了证书能干什么、不能干什么。

扩展名称 OID 作用 常见值
Subject Alternative Name (SAN) 2.5.29.17 指定证书适用的域名/IP DNS:example.com, IP:192.168.1.1
Key Usage 2.5.29.15 定义密钥用途 digitalSignature, keyEncipherment
Extended Key Usage (EKU) 2.5.29.37 定义证书用途 serverAuth, clientAuth
Basic Constraints 2.5.29.19 标记是否为CA证书 CA:TRUE, pathLen:0
CRL Distribution Points 2.5.29.31 证书吊销列表获取地址 http://crl.example.com/ca.crl
Authority Information Access (AIA) 1.3.6.1.5.5.7.1.1 CA证书和OCSP地址 http://ocsp.example.com

注意:SAN字段现在非常重要。从Chrome 58开始,浏览器只认SAN里的域名,不再看Common Name(CN)了。我去年帮一个客户排查HTTPS报错,就是因为证书只填了CN,没填SAN,结果Chrome直接报「NET::ERR_CERT_COMMON_NAME_INVALID」。

3.4 证书链与信任模型

单张证书很少单独存在。它通常是一条链:

  • 根证书(Root CA):自签名,信任的起点
  • 中间证书(Intermediate CA):由根证书签发,用于签发终端证书
  • 终端证书(Leaf/Server Cert):实际使用的证书

我画了张图,帮你理解这个结构:

X.509证书链结构图 根证书 (Root CA) 自签名,信任锚点 中间证书 (Intermediate CA) 由根证书签发 终端证书 (Leaf Cert) 由中间证书签发,实际使用 验证流程:终端证书 → 中间证书 → 根证书(信任锚) 任何一环失效,整条链都不被信任

嗯,这里要注意:服务器发送证书时,必须把整条链(除了根证书)都发过去。我见过太多配置只发了终端证书,结果客户端找不到中间证书,直接报错。

3.5 实操:如何查看和验证证书字段

光说不练假把式。咱们来点实际的:

# 查看证书所有字段
openssl x509 -in server.crt -text -noout

# 只查看有效期
openssl x509 -in server.crt -dates -noout

# 只查看主题
openssl x509 -in server.crt -subject -noout

# 只查看SAN
openssl x509 -in server.crt -ext subjectAltName -noout

# 验证证书链
openssl verify -CAfile ca-chain.crt server.crt

我的经验:写自动化脚本时,用-noout配合-subject、-dates这些参数,可以快速提取关键信息。比如监控证书过期时间:

end_date=$(openssl x509 -in server.crt -enddate -noout | cut -d= -f2)
echo "证书过期时间:$end_date"

3.6 常见坑与避坑指南

  • 我曾经遇到过PEM文件里有多余的空格或换行,导致解析失败。解决办法:用openssl x509 -in cert.pem -text先验证一下。
  • 我曾经在Nginx里配了DER格式的证书,结果Nginx只认PEM。后来统一用PEM,省心多了。
  • 我曾经看到有人把私钥和证书混在一个文件里,还以为是证书链。记住:私钥是私钥,证书是证书,别搞混。

重要提醒:永远不要用文本编辑器修改DER文件。DER是二进制的,你改一个字节,整个证书就废了。PEM可以改,但只限于换行格式,内容不能动。

证书格式这块,说白了就是三个东西:标准(X.509)、编码(PEM/DER)、字段(基础+扩展)。搞清楚了,后面配HTTPS、做证书更新,心里就有底了。