Перейти к содержимому
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. Это обычный `TypeError`, а не `JsonWebTokenError`, поэтому проверки `instanceof` на ошибки jsonwebtoken его не перехватывают.

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

Что это означает

Сегмент подписи токена декодируется в 71 байт, а подпись JWS для ES256 должна занимать ровно 64 байта: это конкатенация r‖s в формате raw, определённая в RFC 7518, § 3.4. Значение длиной 70–72 байта с первым байтом `0x30` — это та же подпись в кодировке ASN.1 DER: в этом формате подпись по умолчанию выдают OpenSSL, Java, сервисы KMS и `crypto.sign()` в Node. Токен подписан кодом, который пропустил преобразование из DER в raw; jsonwebtoken (через ecdsa-sig-formatter) отклоняет его ещё до какой-либо проверки.

Почему это происходит

Как исправить

  1. 1.

    Запросите у node:crypto формат raw r‖s

    С `dsaEncoding: "ieee-p1363"` Node выдаёт подпись в формате фиксированной длины, которого требует JWS. Ещё лучше подписывать библиотекой JOSE (`jwt.sign` из jsonwebtoken, `SignJWT` из jose): она сделает это за вас.

    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.

    Преобразуйте DER из KMS перед сборкой токена

    `ecdsa-sig-formatter` (устанавливается вместе с jsonwebtoken через jws/jwa) преобразует 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;

Связанные ошибки

Открыть всю базу ошибок подписей