エラーメッセージ
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 の sign 呼び出しで使うと(その逆も同様)、同じ曲線であっても失敗します。WebCrypto は鍵を作成時のアルゴリズムに結び付けるため、「1 つの EC 鍵を両方に使う」設計では、鍵データを 2 回インポートしなければなりません。
修正方法
- 1.
必要になる用途を宣言する
生成時またはインポート時に、使う予定の操作をすべて列挙してください。1 つの鍵で複数の役割を担う場合は、同じ鍵データを用途を変えて再インポートしてください。
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);