エラーメッセージ
Invalid JWK EC key
Node.js crypto — TypeError, code ERR_CRYPTO_INVALID_JWK
このエラーの意味
format: "jwk" を指定した createPublicKey/createPrivateKey が JWK オブジェクトを拒否しました。必須のメンバーがないか、座標をデコードできないか、点(x, y)が指定された曲線上に実際には存在しないかのいずれかです。Node はインポート時に点を検証するため、壊れた座標や途中で切れた座標は、決して署名を検証できない鍵になるのではなく、この時点で検出されます。JWK の入手元が JWKS エンドポイントでも、設定ファイルでも、別のサービスでも、同じチェックが実行されます。このエラーが問題にしているのはオブジェクトであり、伝送経路ではありません。
発生する理由
座標が base64url になっていない
よくあるJWK の x/y/d は、パディングなしの base64url でなければなりません(RFC 7518)。16 進文字列や 10 進の整数は、P-256 で想定される 32 バイトにデコードされません。Node は、ある 1 つの形式に限っては寛容です。+ と / を使い = でパディングした標準の base64 はエラーなくインポートされますが、ブラウザーは同じ JWK を DataError で拒否します。サーバーで動作する鍵でも、クライアントでは失敗することがあるのです。
途中で切れた座標、または壊れた座標
よくある伝送中に文字が欠けたり書き換わったりした座標は別の数値を表すため、点は曲線から外れます。典型的な先頭ゼロのバグ、つまり先頭のバイトがゼロだったためにエンコーダーが 31 バイトしか書き出さない問題は、Node が許容する唯一の切り詰めです。数値自体は変わらないため、鍵はインポートできます。ブラウザーは同じ JWK を拒否する(「should be 32」バイト)ので、いずれにしても修正する価値があります。
crv と鍵データが一致しない
ときどきcrv: "P-256" と記されているのに secp256k1 や P-384 の座標を持つ JWK(手作業で編集した後や、テンプレートをコピーして使い回した後に生じます)は、宣言された曲線上の点を表すことができません。
修正方法
- 1.
インポートする前に JWK の形式を検証する
メンバーとデコード後の長さを確認してください。P-256 では、x と y はそれぞれちょうど 32 バイトにデコードされなければなりません。
js const x = Buffer.from(jwk.x, "base64url"); const y = Buffer.from(jwk.y, "base64url"); console.log(jwk.kty, jwk.crv, x.length, y.length); // EC P-256 32 32 - 2.
短い座標の先頭をゼロで埋める
生成側が先頭のゼロを取り除いていた場合は、JWK を組み立てる前に固定長に戻してください。
js const pad32 = (b) => Buffer.concat([Buffer.alloc(32 - b.length), b]); jwk.x = pad32(Buffer.from(jwk.x, "base64url")).toString("base64url"); jwk.y = pad32(Buffer.from(jwk.y, "base64url")).toString("base64url"); const key = crypto.createPublicKey({ key: jwk, format: "jwk" }); - 3.
信頼できる入手元から取得し直す
座標が検証に通らず、JWK を自分で作成したのでもない場合は、バイト列を修復するのではなく、発行者の JWKS エンドポイントから取得し直してください。大がかりな修復が必要な JWK は、信頼すべきではありません。