Сообщение об ошибке
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.Keys[0]` вместо `keys.Key(kid)`, проверяет подпись первым ключом набора. Это работает, пока издатель не опубликует второй ключ.
Заголовок или полезная нагрузка изменены
иногдаПодпись охватывает в точности те байты, что записаны в base64url. Повторная сериализация полезной нагрузки или склейка частей двух токенов ломает проверку.
Расшифрование не тем закрытым ключом
иногдаДля токенов JWE та же ошибка означает, что не удалось распаковать ключ шифрования содержимого или тег аутентификации не прошёл проверку: токен зашифрован для ключа другого получателя.
Как исправить
- 1.
Выберите ключ по kid, затем проверьте утверждения
Найдите в JWKS издателя ровно один ключ по `kid` из заголовка, проверьте подпись, а затем проверьте `iss`, `aud` и `exp` с помощью `Claims.Validate`: сама 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()})