Mensaje de error
TypeError: Failed to execute 'sign' on 'SubtleCrypto': EcdsaParams: hash: Missing or not an AlgorithmIdentifier
También se muestra como
- TypeError: Failed to execute 'verify' on 'SubtleCrypto': EcdsaParams: hash: Missing or not an AlgorithmIdentifier
- TypeError: Member EcdsaParams.hash is required and must be an instance of (object or DOMString)
- NotSupportedError: Failed to execute 'sign' on 'SubtleCrypto': EcdsaParams: hash: Algorithm: Unrecognized name
Arriba está el texto de Chromium (con `verify` cambia el nombre del método); Safari/WebKit: «Member EcdsaParams.hash is required and must be an instance of (object or DOMString)»; Firefox notifica un `SyntaxError` genérico («An invalid or illegal string was specified»).
WebCrypto SubtleCrypto.sign / verify with ECDSA — algorithm parameter without hash (Chromium / WebKit)
Qué significa
En WebCrypto, ECDSA recibe la función hash en cada operación, no en la clave: `sign` y `verify` necesitan `{ name: "ECDSA", hash: "SHA-256" }`. La llamada pasó un objeto de algoritmo sin `hash` —normalmente el objeto `{ name, namedCurve }` de la generación de la clave—, así que el navegador rechazó los parámetros antes de firmar. (Con las claves RSA ocurre lo contrario: su hash se fija al importarlas). Un hash mal escrito, como `"SHA256"`, falla en cambio con un `NotSupportedError` sobre un nombre no reconocido.
Por qué ocurre
Los parámetros de generación de la clave reutilizados para sign/verify
frecuenteGuardar una única constante `ALG = { name: "ECDSA", namedCurve: "P-256" }` y pasarla a todas partes funciona con `generateKey` e `importKey`, pero `sign` necesita `hash`.
Nombre del hash escrito al estilo de JOSE u OpenSSL
frecuenteLos nombres de WebCrypto son `SHA-256`, `SHA-384` y `SHA-512` (con guion). `SHA256` y `sha256` sin guion, o `ES256`, no se reconocen.
Esperar que la clave lleve el hash
ocasionalEl código portado desde RSA (las claves `RSASSA-PKCS1-v1_5` tienen `hash` en sus parámetros de importación) da por hecho que las claves ECDSA también lo tienen, y no es así.
Cómo solucionarlo
- 1.
Mantener separados los parámetros de la clave y los de la operación
Define un objeto para crear la clave y otro para firmar. Para JWT ES256/ES384/ES512, usa SHA-256/384/512 con P-256/384/521, respectivamente.
js const KEY_ALG = { name: "ECDSA", namedCurve: "P-256" }; // generateKey / importKey const SIGN_ALG = { name: "ECDSA", hash: "SHA-256" }; // sign / verify (ES256) const pair = await crypto.subtle.generateKey(KEY_ALG, false, ["sign", "verify"]); const signature = await crypto.subtle.sign(SIGN_ALG, pair.privateKey, data); // 64 bytes, raw r||s const ok = await crypto.subtle.verify(SIGN_ALG, pair.publicKey, signature, data);