Сообщение об ошибке
java.security.InvalidKeyException: No installed provider supports this key: sun.security.rsa.RSAPublicKeyImpl
Также выводится как
- java.security.InvalidKeyException: No installed provider supports this key: sun.security.ec.ECPublicKeyImpl
- java.security.InvalidKeyException: No installed provider supports this key: sun.security.ec.ed.EdDSAPublicKeyImpl
Текст после двоеточия — класс реализации ключа (`sun.security.rsa.RSAPublicKeyImpl`, `sun.security.ec.ECPublicKeyImpl`, `sun.security.ec.ed.EdDSAPublicKeyImpl`, класс Bouncy Castle…). В современных JDK ключ `null` вызывает ошибку раньше, с сообщением «Key must not be null».
Java (JDK) — Signature.initVerify / initSign, Cipher.init
Что это означает
Среди провайдеров JCA не нашлось ни одного, чья реализация запрошенного алгоритма принимает этот объект ключа. С провайдерами по умолчанию это почти всегда означает, что ключ и алгоритм из разных семейств: ключ RSA передан в `SHA256withECDSA`, ключ EC — в `SHA256withRSA`, ключ Ed25519 — в ECDSA. Имя класса в конце показывает, какой ключ пришёл на самом деле.
Почему это происходит
Алгоритм не соответствует типу ключа
частоТипичная ситуация в коде для JWT, который определяет алгоритм JCA по заголовку токена, но использует статически заданный ключ: она возникает после того, как издатель переходит с RS256 на ES256, или когда токены двух издателей приходят к одной проверяющей стороне.
Ключ Ed25519 или X25519 используется как ключ EC
иногдаКлючи Ed25519 — это ключи на эллиптической кривой, но не ключи ECDSA: для них нужен `Signature.getInstance("Ed25519")` (JDK 15+). Ключи X25519 предназначены только для согласования ключей и подписывать вообще не могут.
Объект ключа от незарегистрированного провайдера
иногдаКлючи, созданные провайдером HSM/PKCS#11 или Bouncy Castle, может использовать только этот провайдер. Если он не зарегистрирован (или вы запрашиваете алгоритм у другого провайдера), ни один провайдер не примет ключ.
Как исправить
- 1.
Определяйте алгоритм и сверяйте его с ключом
Явно сопоставьте разрешённые алгоритмы JWS с именами JCA и отклоняйте сочетания, в которых тип ключа не подходит: тогда сбой будет понятной ошибкой политики, а не ошибкой поиска провайдера.
java static Signature verifierFor(String jwsAlg, PublicKey key) throws GeneralSecurityException { String jca = switch (jwsAlg) { case "ES256" -> "SHA256withECDSAinP1363Format"; case "ES384" -> "SHA384withECDSAinP1363Format"; case "RS256" -> "SHA256withRSA"; case "PS256" -> "RSASSA-PSS"; default -> throw new GeneralSecurityException("algorithm not allowed: " + jwsAlg); }; boolean keyFits = jwsAlg.startsWith("ES") ? key instanceof java.security.interfaces.ECPublicKey : key instanceof java.security.interfaces.RSAPublicKey; if (!keyFits) throw new GeneralSecurityException(jwsAlg + " does not match a " + key.getAlgorithm() + " key"); Signature signature = Signature.getInstance(jca); if (jwsAlg.equals("PS256")) { signature.setParameter(new java.security.spec.PSSParameterSpec("SHA-256", "MGF1", java.security.spec.MGF1ParameterSpec.SHA256, 32, 1)); } signature.initVerify(key); return signature; }