エラーメッセージ
DataError: Data provided to an operation does not meet requirements
判定には DOMException の名前 DataError を使ってください。メッセージのテキストはランタイムによって異なります。Firefox と Safari は上記の汎用的な文を表示します。Chrome はメッセージを空のままにすることが多く、理由を示すこともあります(「The imported EC key specifies a different curve than requested」)。Node は「Invalid keyData」または「Named curve mismatch」のような具体的な理由を出力します。
WebCrypto crypto.subtle.importKey — browsers & Node
このエラーの意味
importKey(または unwrapKey)が鍵のバイト列を拒否しました。宣言した形式として解析できないか、内容がアルゴリズムのパラメーターと矛盾しています(曲線の誤り、JWK のフィールドの不一致)。WebCrypto で「このバイト列は、宣言どおりの鍵ではない」ことを表すエラーで、鍵オブジェクトが作成される前にスローされます。
発生する理由
形式名がバイト列と一致しない
よくある公開鍵を形式「pkcs8」(秘密鍵用のコンテナー)でインポートしたり、秘密鍵を「spki」でインポートしたりするのは、典型的な取り違えです。名前はわかりにくく、spki = 公開鍵、pkcs8 = 秘密鍵、raw = EC の点そのもの、jwk = JSON オブジェクトです。
PEM テキストがバイナリに変換されていない
よくあるimportKey が受け取るのは PEM テキストではなく、DER の ArrayBuffer です。PEM の文字列を UTF-8 でエンコードして渡したり、BEGIN/END 行と改行を先に取り除かずに base64 デコードしたりすると、構造の解析に失敗するバイト列になります。
鍵とアルゴリズムで曲線が一致しない
ときどきP-256 の SPKI を namedCurve: "P-384" でインポートした場合(Node は「Named curve mismatch」と報告します)や、crv が要求したアルゴリズムと一致しない JWK を使った場合です。バイト列に問題はなく、宣言が間違っています。Firefox はインポート時に SPKI のこのケースをチェックしないため、同じコードが Firefox では通り、Chrome、Safari、Node では失敗することがあります。
不正な raw 形式の点
ときどき形式「raw」では、65 バイトが 0x04 ‖ X ‖ Y であり、かつ (X, Y) が実際に曲線上にある必要があります。Chrome、Firefox、Node は壊れた点をインポート時に拒否しますが、ecdsa.com のテストでは、Safari のエンジンは何の警告もなくインポートしました。圧縮形式の点(0x02/0x03 のプレフィックスが付いた 33 バイト)は、逆方向の移植性の落とし穴です。Chrome、Firefox、Node は受け入れますが、Safari はこのエラーで拒否します。
修正方法
- 1.
PEM → ArrayBuffer の変換を正しく行う
アーマー行(BEGIN/END 行)を取り除き、本体を base64 デコードし、PEM のラベルで形式を選んでください。PUBLIC KEY → spki、PRIVATE KEY → pkcs8 です。
js function pemToArrayBuffer(pem) { const b64 = pem.replace(/-----[^-]+-----/g, "").replace(/\s+/g, ""); return Uint8Array.from(atob(b64), (c) => c.charCodeAt(0)).buffer; } const key = await crypto.subtle.importKey( "spki", pemToArrayBuffer(publicKeyPem), { name: "ECDSA", namedCurve: "P-256" }, false, ["verify"], ); - 2.
JSON の鍵データがあるなら JWK を使う
JWKS エンドポイントは、WebCrypto でそのまま使えるオブジェクトを最初から返します。バイナリ変換は不要で、crv も鍵と一緒に渡されます。
js const key = await crypto.subtle.importKey( "jwk", jwk, { name: "ECDSA", namedCurve: jwk.crv }, false, ["verify"], ); - 3.
バイト列の実体を確認する
下の証明書デコーダーまたは署名検証ツールに鍵を貼り付けてください。どちらも SPKI/PKCS#8/JWK をローカルで解析して実際の曲線と鍵の種類を表示するので、たいていはすぐに不一致の箇所がわかります。