Node.js中如何将AWS KMS ECDSA_SHA_256 DER签名转换为JWT兼容的R||S格式
问题根源
你遇到的R/S值出现33字节的问题是DER编码的标准特性:当大整数的最高二进制位为1时,DER会自动添加1字节的0x00前缀避免被解析为负数,而ES256要求的R、S均为32字节无符号整数,只需裁剪掉多余的前导0即可满足要求。
可直接使用的完整实现
无需新增额外依赖,修改原有转换函数即可:
const base64url = require('base64url'); const asn1js = require('asn1js'); const AWS = require('aws-sdk'); const kms = new AWS.KMS(); // Buffer转ArrayBuffer工具函数 function toArrayBuffer(buffer) { return buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength); } // DER编码签名转JWT兼容的R||S base64url格式(仅适配ES256场景) function derToJwtEs256Signature(derSig) { const { result } = asn1js.fromBER(toArrayBuffer(derSig)); const rBuf = Buffer.from(result.valueBlock.value[0].valueBlock.valueHex); const sBuf = Buffer.from(result.valueBlock.value[1].valueBlock.valueHex); // 裁剪前导0,确保R、S严格为32字节 const r = rBuf.length > 32 ? rBuf.subarray(rBuf.length - 32) : rBuf; const s = sBuf.length > 32 ? sBuf.subarray(sBuf.length - 32) : sBuf; return base64url.fromBase64(Buffer.concat([r, s]).toString('base64')); } // 业务逻辑代码 const keyid = "9001e08c-b7bc-4f53-9eca-ec034904cdd5"; const header = { "typ": "JWT", "alg": "ES256", "kid": keyid } const payload = { "sub": "name", "status": "valid", "aud": "name" } exports.handler = async function (event) { payload.iat = Math.floor(Date.now() / 1000); const jwtHeader = base64url(JSON.stringify(header)); const jwtPayload = base64url(JSON.stringify(payload)); const message = Buffer.from(`${jwtHeader}.${jwtPayload}`); const kmsResponse = await kms.sign({ Message: message, KeyId: keyid, SigningAlgorithm: 'ECDSA_SHA_256', MessageType: 'RAW' }).promise(); const jwtSignature = derToJwtEs256Signature(kmsResponse.Signature); return `${jwtHeader}.${jwtPayload}.${jwtSignature}`; }
注意事项
- 以上实现仅适配ES256(P-256曲线+SHA-256)场景,若使用ES384/ES512算法,只需将裁剪的目标字节长度调整为48、64即可
- 转换后的签名严格符合JWT ES256的格式要求,可直接通过所有标准JWT校验库的验证
内容的提问来源于stack exchange,提问作者VIJAYaraaghavan Manoharan
相关产品推荐
相关产品推荐

