Сообщение об ошибке
InvalidAccessError: Unable to use this key to verify
Это формулировка Node (для sign — «Unable to use this key to sign», для ключа другого алгоритма — «Key algorithm mismatch»). Браузеры формулируют ошибку иначе (Chrome: «key.usages does not permit this operation», Firefox: «A parameter or an operation is not supported by the underlying object», Safari: «CryptoKey doesn't support verification»), но имя DOMException InvalidAccessError везде одно и то же.
WebCrypto crypto.subtle.sign / verify — browsers & Node
Что это означает
Переданному объекту ключа эта операция не разрешена: её нет в массиве usages ключа, либо у ключа не тот класс (проверка подписи закрытым ключом, подписание открытым), либо ключ относится к другому алгоритму, чем тот, что запрашивает вызов. Сам ключевой материал может быть совершенно корректным — не годятся его разрешения или роль.
Почему это происходит
Операция не была указана в usages при импорте
частоКлючи WebCrypto работают по принципу минимальных привилегий: importKey(..., ["verify"]) создаёт ключ, который может только проверять подписи. Если импортировать ключ с [] или с ["sign"], а затем вызвать verify(), возникает эта ошибка: usages фиксируются при создании ключа, и добавить их позже нельзя.
Перепутаны открытая и закрытая части пары
частоsubtle.sign требует закрытый ключ, subtle.verify — открытый ключ. Передать keyPair.publicKey в sign (или privateKey в verify) — ошибка роли, и API сразу отклоняет такой вызов.
Алгоритм ключа отличается от алгоритма операции
иногдаКлюч ECDH в вызове подписи ECDSA (или наоборот) даёт ошибку даже на той же кривой: WebCrypto привязывает ключи к алгоритму, для которого они созданы, поэтому в схемах «один ключ EC для обоих алгоритмов» ключевой материал нужно импортировать дважды.
Как исправить
- 1.
Сразу укажите все нужные usages
Перечисляйте все нужные операции при генерации или импорте; если один ключ выполняет несколько ролей, импортируйте тот же ключевой материал повторно с другими usages.
js const keyPair = await crypto.subtle.generateKey( { name: "ECDSA", namedCurve: "P-256" }, true, ["sign", "verify"], // privateKey gets "sign", publicKey gets "verify" ); - 2.
Передавайте в каждый вызов нужную часть пары
При отладке смотрите key.type и key.usages: они точно показывают, что разрешено делать этому объекту.
js console.log(key.type, key.usages); // e.g. "public" ["verify"] const sig = await crypto.subtle.sign(alg, keyPair.privateKey, data); const ok = await crypto.subtle.verify(alg, keyPair.publicKey, sig, data);