跳到主要内容
AZ Tools

PKCS#12 密钥库检查器

像 `openssl pkcs12 -info` 那样直接从字节读取 PKCS#12 密钥库,全部在浏览器内完成。文件里有一半内容根本不需要密码,所以先把这一半列出来:PFX 版本、MAC 的摘要算法与迭代次数和盐长度,以及每个内容块是明文还是加密、用的是什么算法。OpenSSL 3 写出的文件是 PBES2、AES-256-CBC、PBKDF2-HMAC-SHA256;Java 21 和新版 OpenSSL 直接拒绝加载的文件里,则会看到 pbeWithSHA1And40BitRC2-CBC 这类旧算法。很多时候这一行就是你要的全部答案。输入密码后,工具用 RFC 7292 附录 B 的 PKCS#12 密钥派生(它不是 PBKDF2,也是多数实现最容易写错的地方)校验 MAC,再解密各个包,列出每张证书的主体、颁发者、序列号、有效期、SAN、密钥算法和 SHA-256 指纹,按叶子证书在前的顺序排列,并附上每个包的 friendlyName 与 localKeyID。然后回答人们打开密钥库最想知道的问题:里面有没有私钥,这把私钥是不是叶子证书的私钥。工具从私钥还原出公钥,与证书的 SubjectPublicKeyInfo 逐字节比较,而不是凭别名相同来猜。做不到的是解密旧文件:WebCrypto 没有 RC2、RC4、DES 和 3DES,因此这类密钥库会被明确标为旧式,而不是解析到一半,但它们的 MAC 仍可校验,所以密码对不对依然能判断。此外,工具不会拿证书链去比对任何信任库。

使用方法

  1. 把 .p12 或 .pfx 拖到方框里。结构会立刻显示:不用密码也能看到 MAC 算法、迭代次数,以及保护每个内容块的加密算法。
  2. 如果你在排查导入失败,先看内容块表格。出现 pbeWithSHA1And40BitRC2-CBC 或 3-KeyTripleDES 就说明这是旧式密钥库,这正是 Java 21、OpenSSL 3 和 Windows 拒绝它的原因。
  3. 输入密码并点击解锁。MAC 那一行会同时告诉你密码是否正确,以及文件写出之后有没有被改动过。
  4. 查看「密钥与证书」标签:它把从私钥还原出的公钥和叶子证书的公钥作比较,这才是这个密钥库能不能用于 TLS 的真正判断依据。
  5. 按顺序阅读证书:叶子证书在最前,往上依次是各级颁发者。这里缺少中间证书,正是服务器在访问过的浏览器里正常、在别处却握手失败的典型原因。

常见问题

为什么还没输入密码就能看到算法和 MAC?
因为这些部分本来就没有被加密。PFX 由版本号、authenticated safe 和 MacData 组成,safe 是一串内容块,每个块要么是明文的 SafeContents,要么是 PKCS#7 的 EncryptedData,而后者的 AlgorithmIdentifier 以明文记录了加密算法、盐和迭代次数。真正被保护的只有包里的内容。所以不知道密码也能判断这是不是旧式 RC2 密钥库、迭代次数有多弱、里面有几个块;反过来也说明,不能因为 .p12 带密码就把它当作完全不可读的文件。
提示说密钥库使用了旧算法,我该怎么办?
用 OpenSSL 转换一次即可:先 `openssl pkcs12 -legacy -in old.p12 -nodes -out tmp.pem -passin pass:…`,再 `openssl pkcs12 -export -in tmp.pem -out new.p12`,OpenSSL 3 默认就会写成 PBES2、AES-256-CBC、PBKDF2-HMAC-SHA256。完成后请删除 tmp.pem,它里面是明文私钥。需要 -legacy 是因为 OpenSSL 3 把 RC2、RC4 和单 DES 移到了 legacy provider,Java 也把同样的算法从默认处理中移除了;2015 年前后的设备写出的文件并没有损坏,只是用了如今没人再启用的算法。
MAC 的密码和加密的密码是同一个吗?
原则上可以是两个:RFC 7292 允许完整性 MAC 和机密性加密使用不同的密码,少数企业工具确实这么做。但常见的导出工具都用同一个字符串,所以 MAC 校验失败几乎总是密码错了,而不是文件被篡改。两者派生密钥的方式也不同:MAC 的密钥来自附录 B 的 PKCS#12 派生(ID 为 3),而现代的包加密用的是对密码字节做 PBKDF2。因此,若文件真的用两个密码写成,就可能出现 MAC 通过但解密失败的情况。
.p12 能打开,但里面没有私钥,私钥去哪了?
多半是当初就没有导出。`openssl pkcs12 -export -nokeys`,以及浏览器或 MMC 控制台里大多数「导出证书链」按钮,写出的都是只含 certBag 的纯证书密钥库,它在格式上完全合法。这种文件往往在最糟糕的时刻才被发现:Web 服务器或负载均衡器会毫无怨言地导入它,然后在 TLS 握手时报密钥不匹配。这里的包列表会如实显示有哪些包,所以在部署之前就能看出缺少密钥包。
本地密钥 ID 有什么用?
localKeyID 是把证书包和密钥包配对起来的属性,因为一个密钥库里两者都可能有多个。OpenSSL 用证书公钥的 SHA-1 哈希,Windows 和 Java 各用自己的取值,规范本身并不要求某种固定做法。friendlyName 则是给人看的别名:keytool 列出的、Windows 证书存储里显示的就是它;导入一个 friendlyName 与现有别名冲突的密钥库,就会出现常见的「alias already exists」错误。这里会按包显示这两个值,并标明每个包来自哪一个内容块。
在网页里打开含私钥的密钥库安全吗?
这个页面不会把文件或密码发送到任何地方:解析、MAC 校验、PBKDF2、AES-CBC 解密以及私钥与证书的比对,全部通过 WebCrypto 在你的标签页里运行,密码只存在于组件状态中,关掉页面就没了,localStorage 里只留下文件名。话虽如此,对生产环境的密钥库,最稳妥的习惯仍然是用离线的 `openssl pkcs12 -info` 检查;这个工具适合用于正在排查的文件,而任何要求你上传 .p12 的网页工具都值得怀疑。

相关工具