X.509 证书字段全解读:SAN、CN、密钥用途、证书链到底各管什么

· 约 6 分钟 🔏 证书解析

X.509 是一种证书格式标准,HTTPS、mTLS、代码签名、S/MIME、电子邮件加密全在用。但它的字段密密麻麻、术语晦涩——SAN、CN、SKI、AKI、KU、EKU、CRL、OCSP……不弄清楚每个字段干什么,配错证书就会”看起来没问题但客户端就是不认”。这篇把 X.509 的关键字段从语义到坑一次讲透。

一张证书包含什么

一张 X.509 证书本质上是一份结构化数据,CA 用自己的私钥对其签名。核心分三块:

内容作用
TBS Certificate(待签名部分)序列号、签发者、主体、公钥、扩展字段实际信息载体
Signature Algorithmsha256WithRSAEncryption标识签名算法
Signature Value签发者私钥对 TBS 部分的签名防篡改

客户端验证时用签发者的公钥对 Signature Value 解签,再算一遍 TBS 部分的哈希对比——一致就说明未被篡改、确实由该 CA 签发。

主体身份字段:CN 和 SAN

历史上证书绑定域名靠 CN(Common Name)——CN=www.example.com。但 CN 设计上是 Distinguished Name 的一个组成部分(DN 还包含 O 组织、OU 部门、C 国家、L 城市等),语义模糊:同一个 CN 可以是”个人姓名”、“机器名”、“域名”。

RFC 6125(2011 年)正式推荐 SAN(Subject Alternative Name) 作为主体身份的权威来源。Chrome 58(2017 年)、Firefox 48(2016 年)起完全忽略 CN 里的域名信息——只看 SAN

SAN 支持多种类型:

SAN: DNS:example.com,
     DNS:www.example.com,
     DNS:*.api.example.com,
     IP:192.168.1.1,
     email:admin@example.com,
     URI:https://example.com/path

实务规则

  • 申请证书时 SAN 里必须列出所有要保护的域名,包括和 CN 同名的
  • 通配符证书 *.example.com 只匹配一级子域名,不匹配 a.b.example.com
  • 多域名证书(SAN 证书)一张能装几十上百个域名
  • 自签证书测试时同样要带 SAN,否则 curl/Go/Node 客户端报 x509: certificate is not valid for any names

签发者:颁发者 DN 和密钥标识符

签发者信息有两种:

  • Issuer DNCN=Let's Encrypt R3, O=Let's Encrypt, C=US——人类可读
  • Authority Key Identifier(AKI):通常是签发者公钥SHA-1 摘要——机器精确匹配

仅靠 Issuer DN 找不到唯一签发者——同名 CA 可能签发多套证书。AKI 才是构建证书链时的精确指针:本证书的 AKI 应该等于上级证书的 Subject Key Identifier(SKI)

链验证逻辑(简化):

  1. 取叶子证书的 AKI
  2. 在受信库 + bundle 里找 SKI 等于该 AKI 的证书
  3. 找到的就是上级,递归到根

链断了就是 SKI/AKI 对不上——这是 Chain issues: incomplete 的真实原因。

证书链:根、中间、叶子的分工

实际部署是三层结构:

作用寿命
根证书(Root CA)自签名,浏览器/系统内置20-30 年
中间证书(Intermediate CA)根签发的”二级 CA”,实际签用户证书5-10 年
叶子证书(Leaf)服务器/用户实际使用1 年(DV/OV)/ 90 天(Let’s Encrypt)

为什么要中间层:根证书私钥离线保管(HSM、断网机房),几十年才取出用一次签发新中间 CA;中间 CA 在线签具体用户证书。万一中间 CA 私钥泄露,吊销中间 CA 即可,根不动;而根 CA 一旦泄露就是行业级灾难。

HTTPS 服务端必须发完整链:叶子在前、中间紧跟。根可省——浏览器自带。Nginx 配置:

ssl_certificate /etc/ssl/fullchain.pem;   # 叶子 + 中间,按顺序拼
ssl_certificate_key /etc/ssl/privkey.pem;

只配叶子证书的话,桌面 Chrome 可能因为缓存过中间证书而能访问,但手机端、新设备首次访问就会失败——非常隐蔽的坑。

有效期与时钟陷阱

Not Before 生效时间、Not After 过期时间,都是 UTC。客户端用本地系统时钟比对:

  • 时钟回拨到 1970 → 所有证书都”未生效”,HTTPS 全挂
  • 时钟超前 → 当前证书”已过期”
  • 树莓派、IoT 设备无 RTC → NTP 同步前一切证书都不可用

续期节奏

  • 老式 DV/OV 证书:1-2 年
  • Let’s Encrypt:90 天,建议过期前 30 天自动续
  • CA/Browser Forum 趋势:2027 年统一缩到 47 天,2029 年前到 6 天

短期证书是大势所趋——自动化续期比”挑长期证书”更值得投入。

Key Usage 与 Extended Key Usage

证书签了不等于什么都能干。两组扩展字段限制合法用途:

Key Usage(KU) 基础权限位:

  • digitalSignature:用于签名
  • keyEncipherment:用于密钥交换(RSA TLS)
  • keyCertSign:用于签发下级证书(CA 才有)
  • cRLSign:用于签发吊销列表

Extended Key Usage(EKU) 细分用途:

  • serverAuth(1.3.6.1.5.5.7.3.1):HTTPS 服务端
  • clientAuth(1.3.6.1.5.5.7.3.2):mTLS 客户端
  • codeSigning(1.3.6.1.5.5.7.3.3):代码签名
  • emailProtection(1.3.6.1.5.5.7.3.4):S/MIME
  • timeStamping(1.3.6.1.5.5.7.3.8):时间戳服务

实务

  • 浏览器看到 EKU 不含 serverAuth → 直接拒绝,不管其他字段对不对
  • 代码签名证书不能拿去做 HTTPS,CA 也不会签发跨用途证书
  • mTLS 客户端证书必须有 clientAuth

吊销机制:CRL 与 OCSP

证书过期前如果发现私钥泄露、错签、主体作恶等情况,CA 需要提前作废。两种机制:

  • CRL(Certificate Revocation List):CA 定期发布”已吊销证书的序列号清单”,客户端下载比对。问题:CRL 文件越来越大,更新延迟可达数天
  • OCSP(Online Certificate Status Protocol):客户端每次握手时实时查询 CA”这个证书还有效吗”。问题:每次访问都要联网查 CA,慢且暴露用户访问轨迹
  • OCSP Stapling:服务端定期向 CA 取 OCSP 应答(带签名+时间戳),握手时附带发给客户端,避免客户端直连 CA。Nginx 一行 ssl_stapling on; 就开

Chrome 的现状:Chrome 已基本放弃 OCSP,改用 CRLite——把 CRL 压缩成 Bloom filter 推给客户端,不再回 CA。

PEM 与 DER:同一份证书的两种皮

  • DER:纯二进制,文件最小但不能 cat 看
  • PEM:DER 做 base64 + -----BEGIN CERTIFICATE----- 包头,纯文本
-----BEGIN CERTIFICATE-----
MIIDazCCAlOgAwIBAgIUBYPn7xK0g8...
(base64 内容)
-----END CERTIFICATE-----

扩展名约定不是强制):

扩展名通常是
.pem .crtPEM
.derDER
.cer两边都用——必须用 file 命令或看头部判断
.p7b .p7cPKCS#7 容器(含证书链,无私钥)
.pfx .p12PKCS#12 容器(含证书链 + 私钥,加密)

互转

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

混用证书时统一转成 PEM 再操作,省得格式错误抓不到原因。

自签证书的常见坑

测试环境常用自签证书,但配错的概率非常高:

  1. CN 写了域名却没加 SAN → 现代客户端全拒
  2. basicConstraints 缺失 → 客户端不知道这是 CA 还是叶子
  3. 链没补全 → 中间 CA 自签后没把 CA 证书塞进 trust store
  4. EKU 缺 serverAuth → 浏览器静默拒绝

最小可用的自签命令(带 SAN):

openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem \
  -days 365 -nodes -subj "/CN=test.local" \
  -addext "subjectAltName=DNS:test.local,DNS:*.test.local"

测试完别忘了从 trust store 删除——长期挂在那里是个隐患。

一份证书诊断清单

拿到一张证书后,按顺序确认:

  1. 主体:SAN 里有没有要保护的域名?通配符是不是覆盖到位?
  2. 签发链:解析 AKI,看上级 SKI 能不能匹配?bundle 里中间证书全不全?
  3. 有效期:Not Before / Not After,注意时区换算
  4. 算法:签名算法是不是 SHA-256+ RSA-2048+ 或 ECDSA-P256+?仍在用 SHA-1 / RSA-1024 立刻替换
  5. EKU:要做 HTTPS 必须有 serverAuth
  6. 吊销:CRL/OCSP URL 写没写?有没有 OCSP Stapling?

把这六条逐项过一遍,配错证书的概率会降到极低。

❓ 常见问题

浏览器现在到底看 CN 还是 SAN?

只看 SAN,不看 CN。Chrome 58(2017)起完全忽略 CN 里的域名信息,Firefox 48(2016)跟进。原因:CN 字段本质是 Distinguished Name 的一部分,最初不是为域名设计的;同一个 CN 可以被解读成"组织名"、"个人名"、"域名",语义混乱。RFC 6125(2011)已明确推荐 SAN,CN 只作回退。实务:(1) 申请证书时 SAN 里必须列出所有需要保护的域名(包括和 CN 同名的);(2) 仅 CN、SAN 缺失的证书在任何现代浏览器、curl、Go/Node 客户端都会被拒;(3) 自签证书测试时同样要带 SAN,不能省。

看证书的"有效期",到底看哪个时间?

Not Before 和 Not After 两个字段,都看本地系统时钟比对Not Before 是证书生效时间——签发时一般写当前时间,但偶尔会回拨几小时避免客户端时钟超前;Not After 是过期时间。典型坑:(1) 时区——X.509 内部存 UTC,看证书工具默认显示本地时区,别把 +08:00 当成 UTC 算过期;(2) 客户端时钟错乱——树莓派、IoT 设备没 RTC 时启动后时间是 1970,所有证书都是"未生效",HTTPS 全部失败;(3) Let's Encrypt 现在签发周期是 90 天(2024 年起部分证书 6 天),过期前 30 天没自动续就要警惕;(4) 旧设备根证书过期——iPhone 5、老安卓的预置 CA 已停止维护,2030 年大量根证书会集中过期。

一个证书文件里同时装好几张证书是什么东西?

那是证书链(chain / bundle)。HTTPS 服务端必须发完整链:叶子证书 + 所有中间证书。为什么:(1) 浏览器只内置根证书(约 100-200 张);(2) 实际签发用户证书的是中间 CA,根 CA 离线保护、几十年才用一次;(3) 浏览器拿到叶子后必须能"一路连到根"才信。典型错误:(1) Nginx 只配了叶子证书没配中间证书——SSL LabsChain issues: incomplete,部分浏览器(手机端、老设备)直接拒绝;(2) 链顺序错——必须叶子在前、中间在后,根证书可省(浏览器自带);(3) 中间证书过期——根没过期、叶子没过期,但中间过期了仍然全链失效。自检openssl s_client -connect example.com:443 -showcerts 看返回了几张。

PEM 和 DER 的区别?怎么互转?

两种编码、同一份证书DER(Distinguished Encoding Rules)——纯二进制,文件小但不能直接打开看;PEM(Privacy-Enhanced Mail)——把 DER 做 base64 + 加 -----BEGIN CERTIFICATE----- / -----END CERTIFICATE----- 包头,可以放进文本文件、邮件、配置里。扩展名约定(不是强制):(1) .pem / .crt / .cer —— 通常是 PEM;(2) .der / .cer(Windows)—— 通常是 DER;(3) .cer 两边都用,必须用 file 命令或看头部判断。互转openssl x509 -inform PEM -outform DER -in cert.pem -out cert.der 反之亦然。实务:(1) Linux/Nginx/Apache 用 PEM;(2) Windows/Java keystore 用 DER 或 PFX(P12) 包含私钥;(3) 不同形态混用证书时先统一成 PEM 再操作最省心。

证书里的 "Key Usage" 和 "Extended Key Usage" 都写了什么是干嘛的?

限制证书的合法用途——签了不等于什么都能干。Key Usage(KU)是基础权限:digitalSignaturekeyEnciphermentkeyCertSigncRLSign 等。Extended Key Usage(EKU)是细粒度:serverAuth(HTTPS 服务端)、clientAuth(mTLS 客户端)、codeSigning(代码签名)、emailProtection(S/MIME)、timeStamping 等。为什么重要:(1) 浏览器看到 EKU 没 serverAuth 直接拒——即使证书未过期、链完整、域名匹配;(2) mTLS 场景要求客户端证书 EKU 必须含 clientAuth,否则服务端拒绝;(3) 代码签名证书不能拿去做 HTTPS——CA 也不会签发跨用途的证书。自检:解析证书时重点看 EKU,部署到服务器前确认 serverAuth 在场。

🔏 打开 证书解析 X.509/CSR/RSA/EC 公钥解析·SAN/有效期/指纹·PEM/DER 自动识别·本地不上传