TLS 的安全最终落在一张证书上:你怎么知道对面真的是 example.com?这篇取下 example.com 的证书链,看每一张证书的字段和扩展,亲自用上一级公钥验证每个签名,找到它在信任库里的根,再用几个故意配错的站点看各种验证失败,最后看 SNI 与主机名验证怎么配合。
TLSv1.3,TLS_AES_256_GCM_SHA384;ssl.get_verified_chain() 返回 4 张证书(从叶子到根方向)
[0] 主体 CN=example.com
签发者 C=US, O=SSL Corporation, CN=Cloudflare TLS Issuing ECC CA 3;公钥 EC secp256r1;签名算法 ecdsa-with-SHA256;DER 1002 字节
有效期 2026-09-26 ~ 2026-12-25(共 90 天;现在起还剩 71 天);序列号 0x1eee6aabb521d5e14f…
[1] 主体 C=US, O=SSL Corporation, CN=Cloudflare TLS Issuing ECC CA 3
签发者 C=US, O=SSL Corporation, CN=SSL.com TLS Transit ECC CA R2;公钥 EC secp256r1;签名算法 ecdsa-with-SHA384;DER 742 字节
有效期 2025-05-29 ~ 2035-05-27(共 3649 天;现在起还剩 3146 天);序列号 0x31eee88afb87cd9ef8…
[2] 主体 C=US, O=SSL Corporation, CN=SSL.com TLS Transit ECC CA R2
签发者 C=US, O=SSL Corporation, CN=SSL.com TLS ECC Root CA 2022;公钥 EC secp384r1;签名算法 ecdsa-with-SHA384;DER 824 字节
有效期 2022-10-21 ~ 2037-10-17(共 5474 天;现在起还剩 4020 天);序列号 0x604d8af8d00ba8748b…
[3] 主体 C=US, O=SSL Corporation, CN=SSL.com TLS ECC Root CA 2022
签发者 C=US, O=SSL Corporation, CN=SSL.com TLS ECC Root CA 2022;公钥 EC secp384r1;签名算法 ecdsa-with-SHA384;DER 574 字节
有效期 2022-08-25 ~ 2046-08-19(共 8759 天;现在起还剩 7248 天);序列号 0x1403f5abfb378b1740…
整条链 DER 总计 3142 字节(这是握手时服务器要发的证书数据的量级)叶子由中间 CA 签发,中间 CA 由根签发;越靠近叶子有效期越短(90 天 / 10 年 / 15 年 / 24 年)。
basicConstraints critical=True CA = False
authorityKeyIdentifier critical=False AuthorityKeyIdentifier
authorityInfoAccess critical=False [('caIssuers', 'http://i.cf-i.ssl.com/Cloudflare-TLS-I-E3.cer'), ('OCSP', 'http://o.cf-i.ssl.com')]
subjectAltName critical=False 2 个名字:['example.com', '*.example.com']
certificatePolicies critical=False 2 项
extendedKeyUsage critical=False ['serverAuth']
cRLDistributionPoints critical=False ['http://c.cf-i.ssl.com/ae801ed1c55bb579d79208b0d772acfb8cc3a208.crl']
keyUsage critical=True digital_signature=True,key_encipherment=False
Unknown OID critical=False UnrecognizedExtension
signedCertificateTimestampList critical=False 2 项CA = False、serverAuth、SAN、OCSP / CRL 地址、SCT 等扩展决定证书的用途和附属信息。
[0] 用 [1] 的公钥验证签名:True [1] 用 [2] 的公钥验证签名:True [2] 用 [3] 的公钥验证签名:True 链的最后一张 [3]:主体 == 签发者?True(= 自签名根) 本机 Python 的信任库里有 192 张根 / 受信 CA 证书 链的最后一张的签发者 "C=US, O=SSL Corporation, CN=SSL.com TLS ECC Root CA 2022" 在信任库里:找到 1 张同名的;用它验证最后一张的签名:True 信任库里 EC 根 60 张,RSA 根 132 张;最早到期的 2026-11-27,最晚到期的 2054-12-09
每张证书用上一级公钥验签;根在信任库里找到并验签通过。
expired.badssl.com (证书过期):验证失败 错误码 10:certificate has expired wrong.host.badssl.com (证书是给别的主机名签的):验证失败 错误码 62:Hostname mismatch, certificate is not valid for 'wrong.host.badssl.com'. self-signed.badssl.com (自签名证书):验证失败 错误码 18:self-signed certificate untrusted-root.badssl.com (根不在信任库里):验证失败 错误码 19:self-signed certificate in certificate chain revoked.badssl.com (证书已被吊销):握手成功(TLSv1.2)——没有报错 注意 revoked.badssl.com:证书其实已被吊销,Python 的默认设置却让握手成功——默认不检查吊销(CRL / OCSP),这是常见的盲区
过期 10、主机名 62、自签名 18、未知根 19;吊销默认不检查。
SNI = example.com → 默认验证:通过;不验证时服务器给的证书 SAN:['example.com', '*.example.com'] SNI = www.example.com → 默认验证:通过;不验证时服务器给的证书 SAN:['example.com', '*.example.com'] SNI = example.org → 默认验证:通过;不验证时服务器给的证书 SAN:['example.org', '*.example.org'] SNI = totally-wrong.invalid → 默认验证:握手失败:SSLError [SSL: SSLV3_ALERT_HANDSHAKE_FAILURE] ssl/tls alert handshake;不验证时服务器给的证书 SAN:握手失败:SSLError [SSL: SSLV3_ALERT_HANDSHAKE_FAILURE] ssl/tls alert handshake 完全不发 SNI:握手失败 SSLError [SSL: SSLV3_ALERT_HANDSHAKE_FAILURE] ssl/tls alert handshake 验证由两部分组成:(1)证书链到受信任的根;(2)证书的 SAN 里有我要连的名字(通配符 *.example.com 匹配 www.example.com)。关掉第二项(check_hostname=False)只会得到“链是好的”,而不知道是不是对的站点
SNI 决定给哪张证书,SAN 里要有要连的名字;不认识的 SNI 直接 handshake_failure。