Pular para o conteúdo
ecdsa.com
jsonwebtoken / jws / jwa (Node.js)Bibliotecas de JWT

Mensagem de erro

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

Também aparece como

  • "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"

O número após “saw” varia entre 70 e 72 para ES256 (o comprimento do DER depende dos bits iniciais de r e s); ES384 espera 96 bytes, e ES512, 132. O erro é um `TypeError` simples, não um `JsonWebTokenError`, então verificações com `instanceof` para os erros do jsonwebtoken não o capturam.

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

O que significa

O segmento de assinatura do token decodifica para 71 bytes, mas uma assinatura JWS ES256 precisa ter exatamente 64 bytes: a concatenação bruta r‖s definida na RFC 7518 §3.4. Um valor de 70 a 72 bytes que começa com `0x30` é a codificação ASN.1 DER da mesma assinatura — o formato que OpenSSL, Java, serviços de KMS e o `crypto.sign()` do Node produzem por padrão. O token foi gerado por um signatário que pulou a conversão de DER para bruto; o jsonwebtoken (por meio do ecdsa-sig-formatter) o rejeita antes de qualquer verificação.

Por que acontece

Como corrigir

  1. 1.

    Pedir r‖s bruto ao node:crypto

    `dsaEncoding: "ieee-p1363"` faz o Node emitir o formato de comprimento fixo que o JWS exige. Melhor ainda: assine com uma biblioteca JOSE (o `jwt.sign` do jsonwebtoken, o `SignJWT` do jose), que faz isso por você.

    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.

    Converter o DER de um KMS antes de montar o token

    O `ecdsa-sig-formatter` (instalado com o jsonwebtoken por meio de jws/jwa) converte DER para o formato JOSE. O conversor DER ⇄ bruto mostra r e s nas duas formas para que você confirme a conversão.

    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;

Erros relacionados

Ver toda a base de erros de assinatura