公钥密码基础(十一):数字证书、PKI 与公钥信任体系

公钥密码基础(十一):数字证书、PKI 与公钥信任体系

前言

前几篇文章已经建立了公钥密码的算法基础:

  • DH、ECDH 可以让双方计算共享秘密;
  • RSA、ECDSA、SM2 可以生成和验证数字签名;
  • 公钥和私钥通过数学关系绑定在一起。

但实际通信中还有一个更基础的问题:你拿到的公钥到底属于谁?

如果 Alice 收到一个自称属于 Bob 的公钥,仅凭“这个公钥能完成 ECDH”或“这个签名能验证”仍然无法确认它来自 Bob。攻击者可以生成自己的密钥对,把自己的公钥冒充成 Bob 的公钥。数字证书和 PKI(Public Key Infrastructure,公钥基础设施)就是围绕“把身份与公钥绑定,并让验证者能够建立信任链”构建的一整套体系。

本文介绍:

  • X.509 数字证书包含什么;
  • CA、根证书、中间 CA 和终端证书如何组成证书链;
  • TLS 如何使用证书认证服务器并结合 ECDHE 建立会话;
  • CSR、证书签发、撤销和验证分别解决什么问题;
  • CTF、代码审计和故障排查中应该关注哪些证书字段。

证书不是“把公钥加密一下”,PKI 也不是一个单独算法。它是一套把公钥密码、签名、身份管理、证书策略、信任锚和生命周期管理组合起来的系统。

本文以 X.509 和 Web/TLS 场景为主线。不同企业、内网、设备和国密体系可能使用不同的证书策略和算法组合,但基本的信任链思想相同。


一、为什么需要数字证书

1.1 裸公钥无法证明身份

假设 Alice 想与 Bob 建立加密连接。Bob 把公钥 Q B Q_B QB 发给 Alice,Alice 使用它进行 ECDH:

Z = d A Q B Z=d_AQ_B Z=dAQB

如果攻击者 Mallory 在传输过程中替换 Q B Q_B QB,Alice 实际上会与 Mallory 建立共享密钥。Mallory 再与 Bob 建立另一条共享密钥,就能在两条连接之间转发和修改消息。

这个问题不是 ECDH 的数学问题,而是公钥来源认证问题。Alice 需要一种机制确认:

这个公钥确实属于 Bob,或者至少属于 Bob 所代表的域名、组织、设备或服务。


1.2 证书的基本思想

数字证书是一份由受信任签发者对“身份 + 公钥 + 使用限制”进行数字签名的声明。抽象地表示为:

Cert ⁡ = Sign ⁡ C A _ p r i v a t e ( subject , public key , validity , extensions , … ) \operatorname{Cert}=\operatorname{Sign}_{CA\_private}(\text{subject},\text{public key},\text{validity},\text{extensions},\ldots) Cert=SignCA_private(subject,public key,validity,extensions,)

验证者使用 CA 的公钥检查签名。如果 CA 公钥本身已经通过操作系统、浏览器、企业配置或人工方式信任,那么验证者就可以把这种信任传递给证书中的主体公钥。

证书签名只保证证书内容没有被篡改且由对应 CA 私钥签发;它不保证主体本身永远诚实,也不保证证书颁发流程一定没有业务错误。因此 PKI 还需要审核、策略、撤销和监控。


1.3 证书不等于身份本身

证书中的 Subject、域名、组织名称或设备编号是 CA 根据某种验证流程写入的声明。验证者仍然必须按照使用场景检查:

  • 当前连接的主机名是否在证书允许的名称中;
  • 证书是否还在有效期;
  • 用途是否允许当前操作;
  • 签发者是否在信任链中;
  • 私钥持有者是否真的控制对应服务。

“证书签名验证成功”只是证书验证流程中的一个环节,不等于“所有身份检查都成功”。


二、X.509 证书的结构

2.1 证书的三层结构

X.509 证书通常可以抽象成:

Certificate ⁡ = tbsCertificate ⁡ + signatureAlgorithm ⁡ + signatureValue ⁡ \operatorname{Certificate}=\operatorname{tbsCertificate}+\operatorname{signatureAlgorithm}+\operatorname{signatureValue} Certificate=tbsCertificate+signatureAlgorithm+signatureValue

其中:

  • tbsCertificate 是待签名内容,名称来自 “to be signed”;
  • signatureAlgorithm 表示签名算法标识;
  • signatureValue 是签发者对待签名内容生成的签名。

验证者首先按照 ASN.1/DER 规则解析证书,然后使用签发者公钥验证 tbsCertificate 的签名。


2.2 常见字段

TBSCertificate 中常见字段包括:

字段作用
Version证书版本,使用扩展字段时通常为 v3
Serial Number签发者分配的证书序列号
SignatureTBSCertificate 使用的签名算法标识
Issuer签发者名称
ValidityNotBeforeNotAfter 有效期
Subject证书主体名称
SubjectPublicKeyInfo主体公钥和公钥算法
Extensions约束、用途、名称和策略等扩展
Signature签发者对 TBS 的数字签名

外层的签名算法标识通常应与 TBS 中声明的签名算法一致。解析和验证时不能只看字符串名称,还要检查算法参数、哈希算法和密钥类型是否符合策略。


2.3 SubjectPublicKeyInfo

主体公钥通常位于 SubjectPublicKeyInfo 中,它包含:

  1. 公钥算法标识;
  2. 算法参数;
  3. 公钥比特串。

对于 RSA,参数可能涉及模数和公钥指数;对于 ECDSA、ECDH 或 SM2,参数可能涉及曲线标识和点编码。证书中的曲线、点格式和使用方支持的算法必须匹配,不能只提取一段公钥字节就忽略算法参数。


2.4 重要扩展

Basic Constraints

BasicConstraints 用来说明证书是否可以作为 CA,以及可选的路径长度约束:

  • CA=true 表示可以作为 CA 证书使用;
  • CA=false 或缺省通常表示终端实体证书;
  • pathLenConstraint 限制后续 CA 层级数量。

如果把终端证书误当成 CA,或者忽略路径约束,证书链验证就可能出现严重错误。

Key Usage

KeyUsage 限制密钥用途,例如:

  • digitalSignature:数字签名;
  • keyEncipherment:密钥加密;
  • keyAgreement:密钥协商;
  • keyCertSign:签发证书;
  • cRLSign:签发 CRL。

证书即使签名算法正确,当前用途不在 KeyUsage 允许范围内,也不应接受。

Extended Key Usage

ExtendedKeyUsage 进一步描述应用用途,例如:

  • TLS 服务器认证;
  • TLS 客户端认证;
  • 代码签名;
  • 邮件保护;
  • 时间戳。

服务器证书和客户端证书通常具有不同的 EKU。验证器不能看到“证书有效”就把它用于任意协议。

Subject Alternative Name

在 TLS 主机名验证中,应重点检查 Subject Alternative Name(SAN)中的 DNS 名称或 IP 地址。现代验证逻辑通常不应只依赖旧式 Common Name

例如,连接到 api.example.test 时,应检查该主机名是否匹配 SAN 中的允许名称,并正确处理通配符边界、大小写、国际化域名和 IP 地址编码。

Authority Key Identifier 和 Subject Key Identifier

这两个扩展可以帮助构建者匹配证书与签发者密钥,但它们不是签名本身,也不能替代真正的链验证。最终仍要使用候选签发者公钥验证证书签名。

Certificate Policies

企业和高保证场景可能通过证书策略 OID 表示签发用途、审核级别或业务约束。验证者是否强制检查策略,取决于应用和信任模型。


三、CA、根证书与证书链

3.1 根 CA

根 CA 的证书通常是自签名的:

Verify ⁡ R o o t P u b l i c ( Sign ⁡ R o o t P r i v a t e ( T B S ) ) = true \operatorname{Verify}_{RootPublic}(\operatorname{Sign}_{RootPrivate}(TBS))=\text{true} VerifyRootPublic(SignRootPrivate(TBS))=true

但“自签名验证成功”并不能证明根 CA 值得信任。根证书之所以成为信任锚,是因为它被预置到操作系统、浏览器、企业设备、应用配置或硬件中,或者由管理员通过安全流程导入。

因此,根信任是一个配置和治理问题,不是数学公式自动推导出来的。


3.2 中间 CA

实际体系通常不直接用根 CA 为每个网站或设备签发证书,而是:

Root CA → Intermediate CA → Leaf Certificate \text{Root CA}\rightarrow\text{Intermediate CA}\rightarrow\text{Leaf Certificate} Root CAIntermediate CALeaf Certificate

根 CA 离线保护,中间 CA 负责日常签发。这样可以把在线风险限制在中间 CA;如果某个中间 CA 泄露或被错误授权,可以撤销或移除它,而不必替换所有根信任锚。


3.3 终端实体证书

终端证书通常属于:

  • 网站域名;
  • 服务器或客户端设备;
  • 用户;
  • 软件发布者;
  • 邮件地址;
  • 企业内部服务。

终端证书一般不应具有 CA=truekeyCertSign,并应通过 SAN、EKU、KeyUsage 等扩展限制用途。


3.4 证书链的签名关系

假设终端证书由中间 CA 签发,中间 CA 由根 CA 签发:

  1. 使用中间 CA 公钥验证终端证书;
  2. 使用根 CA 公钥验证中间 CA 证书;
  3. 检查中间 CA 的 CA=true、路径长度和 keyCertSign
  4. 检查每张证书的有效期、撤销状态和策略;
  5. 检查终端证书的名称和用途;
  6. 确认链最终连接到本地信任库中的信任锚。

链验证不是简单地“循环验签”。它还包括名称约束、路径约束、策略、用途、时间和撤销状态检查。


3.5 为什么证书链可能有多条

证书可能包含 Authority Key Identifier,服务器也可能发送多个中间证书,信任库中还可能存在交叉签发的 CA。因此验证器可能需要在候选证书中构建一条满足策略的路径。

同一终端证书在不同设备上可能出现不同验证结果,因为:

  • 信任库不同;
  • 根证书版本不同;
  • 系统时间不同;
  • 撤销检查策略不同;
  • 算法策略不同;
  • 服务器发送的中间证书集合不同。

四、证书签发流程与 CSR

4.1 生成密钥对

申请者首先生成私钥和公钥:

Q = d G Q=dG Q=dG

或生成 RSA 密钥对。私钥应在申请者控制的安全环境中生成和保存,CA 通常不需要知道申请者的私钥。


4.2 生成 CSR

CSR(Certificate Signing Request,证书签名请求)通常包含:

  • 申请者公钥;
  • 申请的主体名称或 SAN;
  • 申请属性和扩展请求;
  • 申请者使用对应私钥生成的签名。

抽象地表示为:

CSR ⁡ = Sign ⁡ A p p l i c a n t P r i v a t e ( requested identity , public key , attributes ) \operatorname{CSR}=\operatorname{Sign}_{ApplicantPrivate}(\text{requested identity},\text{public key},\text{attributes}) CSR=SignApplicantPrivate(requested identity,public key,attributes)

CSR 的签名证明“提交者持有与申请公钥对应的私钥”,但不等于 CA 已经验证了域名、组织或个人身份。CA 仍需要执行自己的验证流程。


4.3 CA 审核与签发

CA 根据证书策略执行验证,例如:

  • 域名控制验证;
  • 组织信息验证;
  • 个人或设备身份审核;
  • 企业内部审批;
  • 设备注册或硬件证明。

审核通过后,CA 把批准的身份、公钥、有效期、扩展和序列号编码为 TBS 证书,并使用 CA 私钥签名。


4.4 证书续期与密钥轮换

证书到期不一定意味着私钥泄露,但续期时应考虑是否同时轮换密钥。密钥轮换可以缩短单把私钥的暴露窗口,并避免长期使用同一密钥造成管理风险。

如果私钥疑似泄露,应立即停止使用相关证书,并根据体系的撤销流程处理,而不是等到自然过期。


五、TLS 中证书和公钥密码如何配合

5.1 证书负责认证,ECDHE 负责会话密钥

现代 TLS 通常把两个目标分开:

  • 证书和签名用于证明服务器身份;
  • ECDHE 用于为当前连接生成临时共享秘密;
  • HKDF 等 KDF 从握手秘密派生会话密钥;
  • AEAD 保护应用数据。

因此,服务器证书并不是每个数据包的加密密钥,也不是把整个网页内容直接加密。它主要用于认证握手中的公钥和签名。


5.2 简化的 TLS 握手逻辑

以基于临时椭圆曲线密钥交换的握手为例,可以抽象为:

  1. 客户端发送支持的协议版本、密码套件和临时公钥;
  2. 服务器发送证书链、临时公钥和握手签名;
  3. 客户端验证服务器证书链、域名、用途和有效期;
  4. 客户端使用证书中的公钥验证服务器对握手上下文的签名;
  5. 双方使用各自临时私钥和对方临时公钥计算 ECDH 共享秘密;
  6. 双方通过 KDF 派生握手密钥和应用数据密钥;
  7. 使用 Finished 消息确认双方对握手 transcript 的理解一致;
  8. 后续应用数据使用 AEAD 加密和认证。

证书验证失败、签名验证失败、主机名不匹配或 Finished 校验失败,都不应继续建立连接。


5.3 为什么不能关闭主机名验证

某些开发者只调用“证书签名验证”而不检查当前主机名。这样攻击者即使拿到一个由受信 CA 签发给其他域名的证书,也可能被错误接受。

完整的 TLS 客户端验证通常至少需要:

  • 证书链连接到信任锚;
  • 当前时间在有效期内;
  • SAN 与目标主机名匹配;
  • EKU 允许服务器认证;
  • 签名算法和密钥强度符合策略;
  • 根据策略执行撤销或状态检查;
  • 握手签名和 Finished 校验成功。

六、证书撤销与生命周期

6.1 为什么需要撤销

证书在有效期内也可能失效,例如:

  • 私钥泄露;
  • 域名控制权改变;
  • 证书错误签发;
  • 设备被注销;
  • 员工离职或权限撤销;
  • CA 发现申请材料不真实。

撤销机制用于表达“这张证书在自然到期前已经不应再被信任”。


6.2 CRL

CRL(Certificate Revocation List)是 CA 定期签发的撤销列表,通常包含:

  • 签发者;
  • 更新时间和下次更新时间;
  • 被撤销证书的序列号;
  • 撤销时间和原因;
  • CA 对 CRL 的数字签名。

验证者下载 CRL 后,根据证书序列号判断是否撤销。CRL 的缺点是体积可能较大,更新也可能不够及时。


6.3 OCSP

OCSP 允许验证者针对某张证书向状态服务查询:

  • good;
  • revoked;
  • unknown。

它减少了传输完整 CRL 的需要,但引入了在线查询、隐私、可用性和软失败策略问题。


6.4 OCSP Stapling

在 OCSP Stapling 中,服务器预先从 CA 获取状态响应,并在 TLS 握手中发送。客户端不必直接联系 CA 的 OCSP 服务,既改善隐私,也降低连接时延,但服务器必须及时更新并正确验证 stapled response。


6.5 吊销不是万能的

不同客户端可能采用不同的撤销策略:

  • 严格失败:无法查询状态就拒绝;
  • 软失败:查询失败时继续连接;
  • 使用短有效期证书降低依赖;
  • 由应用、浏览器或企业策略额外处理。

因此,PKI 中的撤销、短周期证书、密钥轮换、监控和事件响应通常需要组合使用。


七、证书验证的完整检查框架

验证一张终端证书时,可以按以下层次排查。

7.1 编码和结构

  • 是否是合法 DER/PEM;
  • ASN.1 长度是否一致;
  • 关键字段是否重复或异常;
  • 外层和 TBS 签名算法是否符合预期;
  • 公钥算法参数是否能被当前实现识别。

7.2 链和信任

  • 是否能找到签发者;
  • 每一级签名是否验证成功;
  • 根是否在本地信任库;
  • 中间证书是否标记为 CA;
  • 路径长度和名称约束是否满足;
  • 是否因为交叉签发出现不同链路径。

7.3 时间和状态

  • 当前时间是否在 NotBeforeNotAfter 之间;
  • 是否检查证书和中间 CA 的撤销状态;
  • 系统时钟是否可信;
  • 是否存在证书尚未生效或已经过期的情况。

7.4 名称和用途

  • SAN 是否匹配目标主机名;
  • 通配符是否只匹配允许的域名层级;
  • IP 地址是否按 IP 类型匹配,而不是当作普通字符串;
  • EKU 是否包含所需用途;
  • KeyUsage 是否允许当前操作;
  • 是否误把客户端证书当作服务器证书。

7.5 密钥和算法策略

  • RSA 模数、ECC 曲线和密钥长度是否满足策略;
  • 签名哈希和公钥算法是否已被禁止;
  • 是否存在弱参数、过时算法或不支持的曲线;
  • 证书中的公钥是否与实际服务端私钥匹配。

八、CTF 与代码审计中的证书排查

8.1 用 OpenSSL 查看证书

在授权的离线环境中,可以先查看证书概要:

openssl x509 -in server.crt -text -noout

重点观察:

  • IssuerSubject
  • Validity
  • Subject Public Key Info
  • X509v3 extensions
  • Subject Alternative Name
  • Key UsageExtended Key Usage
  • Basic Constraints
  • 签名算法和序列号。

8.2 验证证书链

已知根证书和中间证书时,可以使用:

openssl verify \
  -CAfile root-ca.crt \
  -untrusted intermediate-ca.crt \
  server.crt

命令成功不代表应用层所有检查都已完成。还要单独确认主机名、用途、时间和应用策略。

8.3 检查公钥是否匹配私钥

对 RSA,可以比较模数摘要;对 ECC,可以比较公钥点编码。抽象关系是:

Q c e r t i f i c a t e = ? PublicKey ⁡ ( d s e r v e r ) Q_{certificate}\stackrel{?}=\operatorname{PublicKey}(d_{server}) Qcertificate=?PublicKey(dserver)

如果证书公钥和服务端私钥不匹配,握手签名会失败。生产排障中,证书文件、私钥文件和中间链文件经常来自不同部署版本,这是常见故障来源。

8.4 证书题的常见考点

CTF 或审计题可能利用:

  • 证书过期但验证器忽略时间;
  • 主机名不匹配但客户端关闭校验;
  • 伪造的自签名根被错误导入信任库;
  • CA=truekeyCertSign 等约束处理错误;
  • 使用错误的证书链或交叉签发路径;
  • 弱 RSA 密钥、重复素因子或错误 ECC 参数;
  • 只验证证书签名,不验证链和用途;
  • 解析器对 SAN、通配符或 ASN.1 边界处理不一致。

排查时应先明确程序实际验证了哪些字段,不要默认“调用了 verify 函数”就代表完成了完整 PKI 验证。


九、PKI 的信任边界与常见攻击面

9.1 信任任何证书

开发环境中常见的“跳过证书验证”“信任所有根”“忽略主机名”会把攻击者的自签名证书直接变成有效身份。测试开关不能进入生产环境,也不能通过环境变量在不知情的情况下改变安全策略。

9.2 信任锚管理错误

根证书一旦进入信任库,通常可以签发或验证该信任域内的大量证书。因此:

  • 不应把测试根证书部署到生产设备;
  • 企业根证书应有明确的导入、审计和退出流程;
  • 不同业务域不应无边界共享根信任;
  • 应及时删除失效或被滥用的信任锚。

9.3 证书链不等于授权

证书可能证明“某个域名的私钥持有者”,但并不自动证明该主体可以访问某个 API、数据库或管理操作。应用层仍需要用户认证、授权、访问控制和审计。mTLS 证书可以作为客户端身份的一部分,但不能替代业务权限模型。

9.4 私钥保护是 PKI 的核心

CA 体系、证书链和算法都正确,如果终端私钥被复制,攻击者仍然可以冒充主体。高价值 CA 和设备私钥通常需要:

  • HSM 或安全密钥存储;
  • 访问控制和双人审批;
  • 密钥备份与恢复策略;
  • 审计日志;
  • 证书生命周期自动化;
  • 泄露后的撤销和轮换预案。

十、数字证书与公钥密码的关系

可以把整个体系分成四层:

10.1 数学层

RSA、ECDH、ECDSA、SM2 等提供模幂、点乘、签名和密钥交换等数学原语。

10.2 协议层

TLS、S/MIME、IPsec、设备注册协议等规定如何交换公钥、签名握手、派生密钥和保护数据。

10.3 证书层

X.509 证书把身份、公钥、有效期和用途编码起来,由 CA 进行签名。

10.4 治理层

PKI 还包括:

  • 谁可以申请证书;
  • CA 如何验证身份;
  • 哪些根证书受信;
  • 证书多久过期;
  • 私钥如何生成和保存;
  • 泄露后如何撤销和轮换;
  • 谁负责审计和事件响应。

安全事故经常发生在协议和治理层,而不是底层椭圆曲线公式本身。理解这四层,才能看清“证书验证成功”到底说明了什么、没有说明什么。


十一、常见误区

11.1 证书是公钥的加密版本

错误。证书通常是 CA 对包含公钥和身份信息的结构进行数字签名,不是把公钥加密后交给验证者。

11.2 证书签名验证成功就一定安全

错误。还要检查信任链、时间、域名、用途、撤销、算法策略和私钥使用情况。

11.3 Subject 中写了域名就等于主机名匹配

不一定。TLS 主机名验证应按协议和库的规则检查 SAN,不能只读取任意文本字段。

11.4 根证书自签名证明它可信

错误。根证书是信任锚,可信性来自安全配置和治理流程,而不是来自自签名本身。

11.5 证书能替代访问控制

错误。证书可以表达身份或密钥持有关系,但应用仍必须执行授权、最小权限和审计。

11.6 关闭验证只是开发问题

错误。测试代码、调试参数和“临时绕过”一旦进入生产,就会把中间人攻击直接变成可行攻击。


十二、总结

数字证书解决的是“公钥属于谁”的问题,PKI 则把这个问题扩展成一套完整的信任和生命周期体系。

X.509 证书可以抽象为:

Cert ⁡ = Sign ⁡ C A _ p r i v a t e ( 身份 , 公钥 , 有效期 , 用途 , 扩展 ) \operatorname{Cert}=\operatorname{Sign}_{CA\_private}(\text{身份},\text{公钥},\text{有效期},\text{用途},\text{扩展}) Cert=SignCA_private(身份,公钥,有效期,用途,扩展)

验证者需要从终端证书一路构建到本地信任锚,并检查:

  • 每级证书签名;
  • CA 约束和路径长度;
  • 有效期和撤销状态;
  • SAN、KeyUsage 和 EKU;
  • 算法与密钥策略;
  • 当前服务是否真的持有证书对应私钥。

在 TLS 等协议中,证书主要负责身份认证,ECDHE 等算法负责建立临时共享秘密,KDF 派生会话密钥,AEAD 保护应用数据。证书不是单独完成所有安全目标的魔法文件,而是公钥密码、协议和组织信任共同组成的一个环节。

到这里,公钥密码基础系列已经从有限域、RSA、离散对数、ECC、ECDH、ECDSA 和 SM2,延伸到了实际系统中的证书和信任体系。后续学习 TLS、代码签名、mTLS、设备身份和企业 PKI 时,都可以沿着“密钥—签名—证书—信任—生命周期”这条主线继续展开。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Sagittarius_A*

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值