将 AWS KMS ECDSA_SHA_256 签名从 DER 编码的 ASN.1 格式转换为 JWT base64url 编码的 R || NodeJS/Javascript 中的 S 格式

Convert AWS KMS ECDSA_SHA_256 Signature from DER encoded ANS.1 format to JWT base64url encoded R || S format in NodeJS/Javascript

我正在尝试使用 AWS KMS 客户托管密钥在 NodeJS 中使用 ES256 算法创建 JWT 签名。

使用带有加密签名算法的 AWS KMS 创建的签名 ECDSA_SHA_256 未被 JWT 接受 R || S格式。根据 AWS 文档,签名将采用 DER 编码的 ANS X9.62–2005 格式 (https://docs.aws.amazon.com/kms/latest/APIReference/API_Sign.html#API_Sign_ResponseSyntax)。

我尝试使用以下代码在 NodeJS 中使用 ans1js(https://www.npmjs.com/package/asn1js) 将 AWS KMS Sign 转换为 JWT R||S 格式,但是 R 和 S 的长度不一致,而是 32 + 32大多数时候它变化 33。

function toArrayBuffer(buffer) {
    const ab = new ArrayBuffer(buffer.length);
    const view = new Uint8Array(ab);
    for (let i = 0; i < buffer.length; ++i) {
        view[i] = buffer[i];
    }
    return ab;
}

//call this with your signature buffer
function parseBERSignature(sig) {
    const { result } = asn1js.fromBER(toArrayBuffer(sig));

    const part1 = result.valueBlock.value[0];
    const part2 = result.valueBlock.value[1];

    let r = Buffer.from(part1.valueBlock.valueHex);
    let s = Buffer.from(part2.valueBlock.valueHex);

    console.log("R value", r);
    console.log("S value", s);

    console.log("R value", r.toString('base64'));
    console.log("S value", s.toString('base64'));

    console.log("R length", r.length);
    console.log("S length", s.length);

    return base64url.fromBase64(Buffer.concat([r, s]).toString('base64'));

} 

签名创建的完整代码:

const base64url = require('base64url')
const AWS = require('aws-sdk');
const kms = new AWS.KMS();
const asn1js = require('asn1js')

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, context, callback) {
    console.log("Hello, new World");

    payload.iat = Math.floor(Date.now() / 1000);

    console.log("header", header);
    console.log("payload", payload);

    const jwtHeader = base64url(JSON.stringify(header));
    const jwtPayload = base64url(JSON.stringify(payload));

    console.log("jwtHeader", jwtHeader);
    console.log("jwtPayload", jwtPayload);

    const message = Buffer.from(jwtHeader + "." + jwtPayload);

    const messageDigest = createHash(message);

    let kmsResponse = await kms.sign({
        Message: message,
        KeyId: keyid,
        SigningAlgorithm: 'ECDSA_SHA_256',
        MessageType: 'RAW'
    }).promise();

    console.log("Signature RAW", kmsResponse.Signature);
    console.log("Signature String", kmsResponse.Signature.toString());
    console.log("Signature base64", kmsResponse.Signature.toString('base64'));

    let response = parseBERSignature(kmsResponse.Signature);
    console.log("response", response);
    return jwtHeader + "." + jwtPayload + "." + response;

}

将 DER 编码的 ANS 格式转换为 R 的任何 NodeJs Javascript 实现 || S 格式 base64url 编码?

Any NodeJs Javascript implementation to convert the DER encoded ANS format to R || S format base64url encoded?

是的,ecdsa-sig-formatter 将帮助您在格式之间来回转换签名。