エラーメッセージ
go-jose/go-jose: error in cryptographic primitive
別の表記
- square/go-jose: error in cryptographic primitive
go-jose v2(gopkg.in/square/go-jose.v2 としてインポート)はプレフィックス「square/go-jose:」を使っていましたが、v3 と v4 は「go-jose/go-jose:」を使います。JWE の復号に失敗した場合も、同じエラーが返されます。
go-jose (Go) — jose.ErrCryptoFailure from JSONWebSignature.Verify / jwt.JSONWebToken.Claims
このエラーの意味
go-jose の汎用的な署名(または復号)の失敗を表す `jose.ErrCryptoFailure` です。JWS の解析は成功し、アルゴリズムも許可されていましたが、渡された鍵による署名の検証が失敗しました。go-jose は意図的にこれ以上の情報を示しません。検証者にとって、鍵の誤りとトークンの改変は同じに見えるためです。そのため、調査では常に、どの鍵を渡したのか、トークンが変更されていないかを確認することになります。
発生する理由
鍵が署名者のものではない
よくある別の環境やテナントの鍵か、鍵のローテーションの際に発行者が置き換えた公開鍵です。
kid を使わずに鍵セットを検索している
よくある`keys.Key(kid)` ではなく `keys.Keys[0]` を取得するコードは、セットの最初の鍵で検証します。これは、発行者が 2 つ目の鍵を公開するまでは動作します。
ヘッダーまたはペイロードが変更されている
ときどき署名の対象は、base64url のバイト列そのものです。ペイロードをシリアライズし直したり、2 つのトークンの部分を組み合わせたりすると、検証は失敗します。
誤った秘密鍵で復号している
ときどきJWE トークンの場合、同じエラーは、コンテンツ暗号化鍵をアンラップできなかったか、認証タグの検証に失敗したことを意味します。つまり、トークンは別の受信者の鍵に向けて暗号化されています。
修正方法
- 1.
kid で鍵を選択してからクレームを検証する
ヘッダーの `kid` を使って発行者の JWKS から鍵をちょうど 1 つ特定して検証し、その後 `Claims.Validate` で `iss`、`aud`、`exp` を検証してください。go-jose はクレームを自動ではチェックしません。
go // keys: *jose.JSONWebKeySet fetched from the issuer's jwks_uri parsed, err := jwt.ParseSigned(raw, []jose.SignatureAlgorithm{jose.ES256}) if err != nil { return err } kid := parsed.Headers[0].KeyID matches := keys.Key(kid) // all keys with this kid if len(matches) != 1 { return fmt.Errorf("no unique key for kid %q", kid) } var claims jwt.Claims if err := parsed.Claims(matches[0].Key, &claims); err != nil { return err } return claims.Validate(jwt.Expected{Issuer: "https://issuer.example.com/", AnyAudience: jwt.Audience{"api"}, Time: time.Now()})