错误信息
Failed to read asymmetric key
Node.js crypto — e.g. code ERR_OSSL_ASN1_WRONG_TAG
含义
createPublicKey()(或任何以 DER 形式接收公钥的调用,例如 crypto.verify())收到的字节,其 ASN.1 结构与你声明的类型不符——例如声明了 type: "spki",而这些字节实际上是 SEC1 EC 私钥。OpenSSL 解析到足以确定标签不对的程度后就停止了。(createPrivateKey() 和标签有误的 PEM 会用 OpenSSL 自己的措辞报告同类不匹配,例如“error:068000A8:asn1 encoding routines::wrong tag”。)随附的错误码(ERR_OSSL_ASN1_WRONG_TAG 及同类错误码)指出的是 ASN.1 层面的不匹配。DECODER routines 的“unsupported”错误表示根本没有找到任何可解析的内容;与之不同,这个错误表示这些字节能被识别出来,但其结构不是所声明类型应有的结构。
原因
声明的类型与字节内容不符
常见DER 世界里有好几种容器:SPKI 用于公钥,PKCS#8 用于私钥,SEC1 用于旧式 EC 私钥,PKCS#1 用于旧式 RSA 密钥。为 SEC1 或 PKCS#8 私钥、或者为整张证书声明 type: "spki",会立即触发标签检查失败。
Base64 没有解码,或被解码了两次
常见用 format: "der" 传入 base64 文本(于是 OpenSSL 把 ASCII 当作 ASN.1 解析),或者对包含头尾行的完整 PEM 执行 Buffer.from(pem, "base64"),都会产生一堆标签错误的混乱字节。
传入的是原始 EC 点,而不是密钥结构
偶见65 字节的未压缩点(0x04‖X‖Y)不是 DER——它们是放在 SPKI 内部的载荷。直接把它们传给 createPublicKey 会失败;必须先封装,或者通过 JWK/WebCrypto 的 raw 导入方式导入。
修复方法
- 1.
先识别结构,再如实声明
asn1parse 会打印外层结构。SPKI 以一个包含 AlgorithmIdentifier 的 SEQUENCE 开头;PKCS#8 以版本号 INTEGER 0 开头;SEC1 EC 密钥则以 INTEGER 1 开头。
bash openssl asn1parse -inform der -in key.der | head -5 - 2.
让 Node 选项与容器格式对应
确定了容器格式之后,选项该怎么对应就是机械的事情了。
js // SPKI public key createPublicKey({ key: der, format: "der", type: "spki" }); // PKCS#8 private key createPrivateKey({ key: der, format: "der", type: "pkcs8" }); // SEC1 (BEGIN EC PRIVATE KEY) private key createPrivateKey({ key: der, format: "der", type: "sec1" }); - 3.
在系统边界一次性转换旧式容器
存储时统一使用 PKCS#8/SPKI,这样应用代码就永远不必去猜。
bash openssl pkey -in legacy-ec.pem -out key-pkcs8.pem # any private → PKCS#8 openssl pkey -in key-pkcs8.pem -pubout -out pub-spki.pem # derive SPKI public