如何使用Node.js验证CNG密钥生成、C# JwtSecurityTokenHandler签名的ES384算法JWT
根因分析
你遇到的ERR_OSSL_ASN1_WRONG_TAG错误是因为CNG默认导出的EccPublicBlob/EccPrivateBlob属于微软专有密钥格式,不符合Node.js生态依赖的OpenSSL要求的标准ASN.1密钥结构,直接将该格式的内容转PEM会因为结构不匹配触发ASN.1标签校验失败。
解决方案
你需要将CNG生成的ECC密钥导出为OpenSSL可识别的标准SPKI(公钥)/PKCS#8(私钥)格式,.NET Core 3.0+、.NET 5+ 自带相关API可以直接生成符合要求的密钥,无需手动转换格式,具体实现代码如下:
var key = CngKey.Create(CngAlgorithm.ECDsaP384, "keyName", new CngKeyCreationParameters { KeyCreationOptions = CngKeyCreationOptions.OverwriteExistingKey, KeyUsage = CngKeyUsages.AllUsages, ExportPolicy = CngExportPolicies.AllowPlaintextExport, }); using var ecdsa = new ECDsaCng(key); // 导出适配Node.js的标准公钥PEM byte[] publicKeyBytes = ecdsa.ExportSubjectPublicKeyInfo(); string publicKeyPem = Convert.ToBase64String(publicKeyBytes, Base64FormattingOptions.InsertLineBreaks); publicKeyPem = $"-----BEGIN PUBLIC KEY-----\n{publicKeyPem}\n-----END PUBLIC KEY-----"; // 若需要导出私钥给Node.js使用,使用以下代码生成标准PKCS#8格式私钥 byte[] privateKeyBytes = ecdsa.ExportPkcs8PrivateKey(); string privateKeyPem = Convert.ToBase64String(privateKeyBytes, Base64FormattingOptions.InsertLineBreaks); privateKeyPem = $"-----BEGIN PRIVATE KEY-----\n{privateKeyPem}\n-----END PRIVATE KEY-----";
Node.js端验证代码
直接使用上述生成的publicKeyPem即可正常完成验证,不需要额外格式转换:
const jwt = require('jsonwebtoken'); // 公钥直接传入上面C#导出的publicKeyPem字符串即可 const result = jwt.verify(token, publicKeyPem, { algorithms: ['ES384'] });
注意事项
- 如果你使用的是.NET Framework 低版本没有
ExportSubjectPublicKeyInfo/ExportPkcs8PrivateKeyAPI,可以手动拼接SPKI结构:P384算法的SPKI固定前缀为3076301006072A8648CE3D020106052B81040022036200,后续拼接未压缩标识04+ 48字节X坐标 + 48字节Y坐标,整体转Base64后套PEM头尾即可。 - 不要直接将
CngKey.Export(CngKeyBlobFormat.EccPublicBlob)导出的内容转PEM使用,微软专有格式和标准ASN.1结构不兼容,必然触发标签错误。 - JwtSecurityTokenHandler生成的JWT签名默认符合JWS规范,不需要额外转换格式。
内容的提问来源于stack exchange,提问作者Árpád Gál
相关产品推荐
相关产品推荐

