本文へスキップ
ecdsa.com
jsonwebtoken / jws / jwa (Node.js)JWT ライブラリ

エラーメッセージ

TypeError: "ES256" signatures must be "64" bytes, saw "71"

別の表記

  • "ES256" signatures must be "64" bytes, saw "70"
  • "ES256" signatures must be "64" bytes, saw "72"
  • "ES384" signatures must be "96" bytes, saw "103"
  • "ES512" signatures must be "132" bytes, saw "139"

「saw」の後の数値は、ES256 では 70〜72 の間で変わります(DER の長さは r と s の先頭ビットに依存します)。ES384 では 96 バイト、ES512 では 132 バイトが想定されます。このエラーは `JsonWebTokenError` ではなく単なる `TypeError` であるため、jsonwebtoken のエラーを対象にした `instanceof` のチェックでは捕捉されません。

jsonwebtoken / jws / jwa (Node.js) — TypeError from ecdsa-sig-formatter

このエラーの意味

トークンの署名セグメントをデコードすると 71 バイトになりますが、ES256 の JWS 署名はちょうど 64 バイト、つまり RFC 7518 §3.4 で定義された、r と s をそのまま連結した r‖s でなければなりません。`0x30` で始まる 70〜72 バイトの値は、同じ署名を ASN.1 DER でエンコードしたもので、OpenSSL、Java、KMS サービス、Node の `crypto.sign()` がデフォルトで出力する形式です。このトークンは、DER から生の形式への変換を省略した署名者が発行したものです。jsonwebtoken は(ecdsa-sig-formatter を介して)検証を行う前にこれを拒否します。

発生する理由

修正方法

  1. 1.

    node:crypto で生の r‖s を出力させる

    `dsaEncoding: "ieee-p1363"` を指定すると、Node は JWS が要求する固定長の形式で出力します。さらに望ましいのは、この処理を代わりに行ってくれる JOSE ライブラリ(jsonwebtoken の `jwt.sign`、jose の `SignJWT`)で署名することです。

    js
    import { sign } from "node:crypto";
    
    const signature = sign("sha256", Buffer.from(signingInput), {
      key: privateKey,
      dsaEncoding: "ieee-p1363", // raw r||s: 64 bytes for P-256, as RFC 7518 §3.4 requires
    });
    const token = signingInput + "." + signature.toString("base64url");
  2. 2.

    トークンを組み立てる前に KMS の DER を変換する

    `ecdsa-sig-formatter`(jws/jwa を介して jsonwebtoken と一緒にインストールされます)は、DER を JOSE の形式に変換します。DER ⇄ raw 変換ツールは両方の形式について r と s を表示するので、変換が正しいかを確認できます。

    js
    import ecdsaSigFormatter from "ecdsa-sig-formatter";
    
    // AWS KMS and Google Cloud KMS return DER; convert once before assembling the JWS.
    const derSignature = Buffer.from(kmsResponse.Signature);
    const joseSignature = ecdsaSigFormatter.derToJose(derSignature, "ES256"); // base64url, 64 bytes decoded
    const token = signingInput + "." + joseSignature;

関連するエラー

署名エラーデータベースをすべて見る