Сообщение об ошибке
TypeError: Failed to execute 'sign' on 'SubtleCrypto': EcdsaParams: hash: Missing or not an AlgorithmIdentifier
Также выводится как
- 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
Выше приведён текст Chromium (для `verify` меняется имя метода); Safari/WebKit: «Member EcdsaParams.hash is required and must be an instance of (object or DOMString)»; Firefox выдаёт общую ошибку `SyntaxError` («An invalid or illegal string was specified»).
WebCrypto SubtleCrypto.sign / verify with ECDSA — algorithm parameter without hash (Chromium / WebKit)
Что это означает
В WebCrypto ECDSA получает хеш-функцию для каждой операции, а не для ключа: для `sign` и `verify` нужен `{ name: "ECDSA", hash: "SHA-256" }`. В вызов передан объект алгоритма без `hash` (обычно объект `{ name, namedCurve }`, оставшийся от генерации ключа), поэтому браузер отклонил параметры ещё до подписания. (У ключей RSA всё наоборот: их хеш фиксируется при импорте.) Хеш с опечаткой, например `"SHA256"`, вместо этого приводит к `NotSupportedError` о нераспознанном имени.
Почему это происходит
Параметры генерации ключа повторно используются для sign/verify
частоОдна константа `ALG = { name: "ECDSA", namedCurve: "P-256" }`, которую передают повсюду, подходит для `generateKey` и `importKey`, но для `sign` нужен `hash`.
Имя хеша записано в стиле JOSE или OpenSSL
частоВ WebCrypto имена хешей — `SHA-256`, `SHA-384`, `SHA-512` (с дефисом). `SHA256`, `sha256` без дефиса или `ES256` не распознаются.
Ожидание, что хеш хранится в ключе
иногдаКод, перенесённый с RSA (у ключей `RSASSA-PKCS1-v1_5` параметр `hash` входит в параметры импорта), предполагает, что у ключей ECDSA так же; это не так.
Как исправить
- 1.
Разделяйте параметры ключа и параметры операции
Заведите один объект для создания ключа и другой для подписания. Для JWT с ES256/ES384/ES512 используйте SHA-256/384/512 с P-256/384/521 соответственно.
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);