Mensaje de error
TypeError: "ES256" signatures must be "64" bytes, saw "71"
También se muestra 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"
El número que sigue a «saw» varía entre 70 y 72 para ES256 (la longitud DER depende de los bits iniciales de r y s); ES384 espera 96 bytes y ES512, 132. El error es un `TypeError` simple, no un `JsonWebTokenError`, así que las comprobaciones `instanceof` de errores de jsonwebtoken no lo capturan.
jsonwebtoken / jws / jwa (Node.js) — TypeError from ecdsa-sig-formatter
Qué significa
El segmento de firma del token se decodifica en 71 bytes, pero una firma JWS ES256 debe tener exactamente 64 bytes: la concatenación en bruto r‖s definida en el RFC 7518 §3.4. Un valor de 70 a 72 bytes que empieza por `0x30` es la codificación ASN.1 DER de esa misma firma, el formato que producen por defecto OpenSSL, Java, los servicios KMS y `crypto.sign()` de Node. El token lo generó un firmante que se saltó la conversión de DER a formato en bruto; jsonwebtoken (a través de ecdsa-sig-formatter) lo rechaza antes de cualquier verificación.
Por qué ocurre
Un firmante casero emitió DER
frecuenteEl código que construye el JWT por su cuenta y firma con `crypto.sign("sha256", data, key)` o `createSign().sign(key)` obtiene una salida DER salvo que pase `dsaEncoding: "ieee-p1363"`. El token parece correcto en todas partes hasta que un verificador que cumple el estándar comprueba la longitud.
El token lo firmó un KMS o un HSM
frecuente`Sign` de AWS KMS y `asymmetricSign` de Google Cloud KMS devuelven las firmas ECDSA en DER, así que firmar JWT con ellos requiere un paso de conversión explícito. (Azure Key Vault y `CKM_ECDSA` de PKCS#11 ya devuelven r‖s en bruto: comprueba lo que documenta tu proveedor antes de convertir).
La codificación predeterminada de otro lenguaje
ocasional`SHA256withECDSA` de Java, `sign()` de cryptography en Python, `ecdsa.SignASN1` de Go y la CLI de OpenSSL producen DER. Las bibliotecas hechas para JOSE convierten automáticamente; las llamadas criptográficas genéricas, no.
El segmento de firma está dañado
raraSi la longitud indicada no está en el rango de 70 a 72 (por ejemplo, «saw 2»), el tercer segmento se truncó o se sustituyó; no es que esté codificado de otra forma.
Cómo solucionarlo
- 1.
Pedir a node:crypto r‖s en bruto
`dsaEncoding: "ieee-p1363"` hace que Node emita el formato de longitud fija que exige JWS. Mejor aún, firma con una biblioteca JOSE (`jwt.sign` de jsonwebtoken, `SignJWT` de jose), que lo hace por ti.
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.
Convertir el DER de un KMS antes de montar el token
`ecdsa-sig-formatter` (que se instala con jsonwebtoken a través de jws/jwa) convierte DER al formato JOSE. El conversor DER ⇄ raw muestra r y s en ambas formas para que puedas confirmar la conversión.
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;