核心概念
读这页之前,你只需要知道:浏览器和服务器之间用 HTTPS 通信时,服务器会出示一张"数字证书"证明身份。cert-skills 围绕这张证书及其背后的体系做分析。
证书是什么
一张 X.509 证书本质是:CA 用自己的私钥,对"主体 + 公钥 + 一堆属性"做的签名。浏览器信任 CA,所以信任这张证书里声明的公钥;用这个公钥协商出会话密钥,就完成了 HTTPS。
一句话理解
证书 = CA 签名的"公钥身份证"。信任 CA → 信任证书里的公钥 → 用公钥协商会话密钥 → HTTPS 建立。
证书字段速查
| 字段 | 含义 | 谁关心 |
|---|---|---|
| Subject | 主体(CN=app.example.com) | 浏览器匹配主机名 |
| Issuer | 签发者(CN=Let's Encrypt R3) | 追信任链 |
| PublicKey | 公钥 | 协商会话密钥 |
| SAN | 备用名(多域名) | 主机名匹配 |
| NotBefore/NotAfter | 有效期 | 过期判断 |
| KeyUsage | 密钥用法 | 合规检查 |
| SerialNumber | 序列号 | CRL 吊销比对 |
| Signature | 签名 | 验证完整性 |
信任链
证书不是孤立存在的,它挂在一条信任链上:
- 根 CA:自签名,预置在操作系统/浏览器信任库里,是信任的起点。
- 中间 CA:根 CA 不直接签发网站证书,而是签发中间 CA,中间 CA 再签发叶子。这样根 CA 的私钥可以离线保管。
- 叶子证书:你网站实际出示的证书。
verify-chain 就是把这条链一路追到根,检查每一级的签名、有效期、用途约束。check-bundle 则检查服务器是否把中间 CA 一起发出来了——漏发中间证书是常见的部署错误。
TLS 协议层 vs 证书层
这是 cert-skills 最核心的二分法:
- 证书层只看证书本身这个数据结构,不需要联网。
pkg里所有FromCert后缀的函数都属于这一类。 - 协议层必须真的和服务器握手一次,拿到
tls.ConnectionState(协商出的版本、套件、扩展、OCSP staple 等)才能判断。
这就是为什么
analyze ./server.pem(离线)的评分权重和analyze example.com(在线)不同——离线拿不到协议层信息,扣分更保守。详见 安全评分算法。
离线 vs 在线的判定边界
- 能离线:只看
*x509.Certificate的所有字段(签名、密钥、SAN、有效期、序列号、KeyUsage、策略 OID)。 - 必须在线:任何需要
tls.ConnectionState的——版本、套件、漏洞、OCSP staple、HSTS、JARM/JA3。 - CLI 用文件后缀(
.pem/.crt/.cer/.der)自动路由,详见 离线 vs 在线分析。
指纹:证书的"DNA"
cert-skills 有四种指纹,各有用途:
| 指纹 | 算什么 | 用途 |
|---|---|---|
| cert SHA-256 | 整张证书 DER 的 SHA-256 | 证书唯一标识,CT 检索 |
| SPKI SHA-256 | 证书的 SubjectPublicKeyInfo 的 SHA-256 | 证书绑定 / HPKP,公钥换了才变 |
| JARM | 10 个 TLS 探针响应的 SHA-256 | 服务端画像,识别 C2/CDN/VPN |
| JA3/JA3S | ClientHello/ServerHello 字段的 MD5 | 客户端/服务端 Hello 画像 |
为什么 SPKI 比 cert SHA-256 更适合做"证书绑定"?因为证书续期(同公钥、新有效期/新签名)时整张证书变了,但公钥没变——SPKI 不变,绑定不会失效。detect-change 正是用这个区分 renewed(续期)vs replaced(换钥)。
续期 vs 换钥的判定口诀
- 整张证书 SHA-256 变了 + SPKI 没变 →
renewed(续期,正常) - 整张证书 SHA-256 变了 + SPKI 也变 →
replaced(换钥,需警惕)
网络空间测绘的三段式
cert-skills 的测绘能力不是孤立的扫描,而是一条流水线:
这三段对应三个工作流 skill 的核心步骤,详见 网络空间测绘 与 实现原理。
PKI 生命周期
从零建一套私有 CA 体系的完整路径:
关键是 pathLenConstraint:它控制一个中间 CA 下面还能不能继续签中间 CA。0 表示只能签叶子,-1 表示无限制。详见 多层 PKI 与 pathLen。