两串指纹,一串 64 个字符一串 95 个字符
起因是一条群消息:一份证书指纹是冒号分组、串尾还多一个冒号,另一份从本地文件读出是连续 64 个十六进制字符。两串摆在一起肉眼对不出结果。指纹上叠着三层变量:算哪个对象、用哪种摘要、以哪种写法显示。
摘要对象是整张证书的 DER
指纹是对整张证书的 DER 编码做摘要,不是公钥,也不是 PEM 文本。样本证书解出的 DER 是 1159 字节,包成 Base64 的 PEM 是 1627 字节,两个文件进来的三条指纹逐字符相同;加 BOM(1630 字节)、换 CRLF(1654 字节)、补尾随空白(1635 字节)、把 Base64 挤成一行,四种变形的指纹一个字符都不动。
会动指纹的只有 DER 内部的字节:另一张只差 1 个字节的样本,公钥段 Base64 完全相同、都是 392 字符,SHA-256 却有 62/64 个字符不同,SHA-1 有 39/40 个不同。单独对那 294 字节的公钥信息求 SHA-256,得到第四个串,和三条指纹都不等。
三种摘要、四种写法
结果区的指纹固定三行,MD5、SHA-1、SHA-256,长度是摘要字节数的两倍:32、40、64 个十六进制字符。四种写法可切换:小写无冒号(默认)、大写无冒号,以及对应的冒号分隔版。冒号分组按 1 个字节也就是 2 个十六进制字符一组,串尾不带冒号,所以冒号比组数少 1。
| 摘要 | 十六进制字符 | 摘要字节数 | 冒号写法总字符 | 字节组数 |
|---|---|---|---|---|
| MD5 | 32 | 16 | 47 | 16 |
| SHA-1 | 40 | 20 | 59 | 20 |
| SHA-256 | 64 | 32 | 95 | 32 |
95 等于 64 个十六进制字符加 31 个冒号,是同一条 SHA-256 摘要的两种显示,比对前先切成同一种写法再逐字符比。
图 1|绿段是十六进制字符,灰段是插进去的冒号。
一个文件里可能不止一张
指纹对上之前还得确认对方给的是哪一张。实测 1683 字节的 .p7b 和 2322 字节的 PEM 包 PKCS#7 各给出 2 张,同一张证书重复 50 次写成 81350 字节的文件一次给出 50 张,每张 DER 都是 1159 字节、三条指纹相同。编号只反映排列顺序,不代表角色:那条 2 张的链里第 1 张是 1159 字节,第 2 张只有 462 字节,谁叶子谁根不由位置决定,别拿最后一条当实体证书。
剩余天数那一行,只看到期日
这行只用到期时间减当前时刻,按天四舍五入,于是已过期但不足 12 小时的证书仍然显示「剩余 0 天」;生效时间不参与计算,notBefore 写在 2027-06-01 的证书照样显示「剩余 587 天」,没有尚未生效的提示。时间行跟机器时区:同一张证书在 TZ 为 UTC 给出 2026-09-01 00:00,在 UTC+8 给出 2026-09-01 08:00,后缀都写着「本地时区」,而两种时区算出的剩余天数都是 144 天。
公钥导出的三种写法
结果区还有独立的公钥块,和指纹块是两码事。样本那张 RSA-2048 证书的公钥信息段 294 字节,三种写法实测:含 -----BEGIN PUBLIC KEY----- 头尾的 PEM 450 字符 9 行、每 64 字符换行的 Base64 398 字符 7 行、单行无头尾 392 字符 1 行。这段内容求出的 SHA-256 不覆盖主体、有效期、颁发者和签名,跟证书指纹混用会一直对不上。
位数与序列号两处口径
密钥位数那行,RSA 走模数实际位长,2048 位和 1024 位样本都对得上;椭圆曲线是估算,位串长度减一再乘八取整,于是 P-521 那张显示成「528 位」,真实位长是 521 位,名字仍按 132 字节查表给出 P-521 (secp521r1)。序列号那行的显示宽度等于 INTEGER 内容字节数的两倍,最长那条 42 字符(内容 21 字节),前导 0 会保留(00BFFF 是三个字节)。
能核对到什么,核对不到什么
密钥库那四类后缀 .p12 / .pfx / .jks / .keystore 是命中后缀就拒,跟内容无关——1159 字节的合法 DER 改名成 .p12 一样被弹回来。只有 PRIVATE KEY 或 PUBLIC KEY 的 PEM 会给明确说法,不硬算指纹;证书和私钥写在同一个文件里(3331 字节那份)只出 1 张,私钥块被安静地忽略掉。识别只看内容不看后缀,同一份 PEM 改叫 cert.txt 也照样解析出 1 张。坏输入也给尺寸信息,DER 截掉一半做成 579 字节,报的是「这张证书声明有 1159 字节,但文件只有 579 字节」。
但它不验签名:那张只改了 1 个字节的证书照样解析,指纹照算,17 行字段全部可读,一条告警都没有。「两条指纹一致」只等于「这两份文件是同一张证书」,判断不了链完整不完整,也回答不了这张证书能不能用。
批量是只进不出
一次投 3 个文件,其中 1 个是 65 字节纯文本,结果区显示 2 张,错误条只贴第 1 个失败原因;再投 1 个文件,同一次会话里累加到 3 张而不是替换前面的,想从头开始只能按清空全部。输出端只有指纹三行和公钥各一个复制按钮,一次只显示选中的那一张,没有并排对比也没有导出入口。
图 2|摘要只吃绿色的 1159 字节,三层容器不影响指纹。
Q:一条 64 个字符、一条 95 个字符,怎么判断是不是同一张证书?
95 个字符那条是冒号分组,等于 64 个十六进制字符加 31 个冒号,删掉冒号就还原成同一长度,逐位一样就是同一张证书、同一种摘要。
Q:对方贴来的串末尾多了一个冒号,要紧吗?
冒号分组写法串尾不带冒号,多出来的那个不是工具生成的,多半是复制时手工补的;比对前删掉,或两边都切成无冒号写法重新复制一次。
Q:三条指纹都对上了,能不能说这条链路是安全的?
不能。指纹一致只证明两份文件是同一张证书且用了同一种摘要;被改过 1 个字节的证书,解析、三条指纹和 17 行字段照常给出,没有任何告警,它不做签名校验。
Q:同一张证书,PEM 和 DER 交出来的指纹会不一样吗?
不会。1159 字节的 DER 和 1627 字节的 PEM 给出逐字符相同的三条指纹,加 BOM、换 CRLF、把 Base64 挤成一行也都相同,摘要对象始终是解开外衣后那段 DER。
这场争论最后是这么收的:两串都切成无冒号小写,长度都是 64,逐字符一致,多出来的尾冒号是运维手工补的。样本文件我都丢进本地解析的 证书指纹 页跑了一遍,文件不离开浏览器,四种写法和 openssl 那几条命令逐字符对得上;要先确认对方给的是不是证书文件本身,可以先用 文件信息 看一眼魔数与真实类型。