UnsupportedKeyException changes (#826)

* Changed usages of UnsupportedKeyException to only those where a given key is actually not understood.  Cases where the key is not valid for the current use case was changed to throw InvalidKeyException instead to better indicate validation failure.

* Changed superclass of UnsupportedKeyException to KeyException instead of InvalidKeyException (unsupported means 'I don't know what this key is', whereas InvalidKeyExceptions mean 'the key failed validation'). An unsupported key is not necessarily invalid, it just means we don't know how to handle it.
This commit is contained in:
lhazlewood 2023-09-13 11:54:04 -07:00 committed by GitHub
parent b55f26175c
commit d0d80fe849
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
30 changed files with 119 additions and 157 deletions

View File

@ -20,7 +20,7 @@ package io.jsonwebtoken.security;
* *
* @since JJWT_RELEASE_VERSION * @since JJWT_RELEASE_VERSION
*/ */
public class UnsupportedKeyException extends InvalidKeyException { public class UnsupportedKeyException extends KeyException {
/** /**
* Creates a new instance with the specified explanation message. * Creates a new instance with the specified explanation message.

View File

@ -32,10 +32,10 @@ import io.jsonwebtoken.io.Deserializer;
import io.jsonwebtoken.lang.Assert; import io.jsonwebtoken.lang.Assert;
import io.jsonwebtoken.lang.Collections; import io.jsonwebtoken.lang.Collections;
import io.jsonwebtoken.security.AeadAlgorithm; import io.jsonwebtoken.security.AeadAlgorithm;
import io.jsonwebtoken.security.InvalidKeyException;
import io.jsonwebtoken.security.KeyAlgorithm; import io.jsonwebtoken.security.KeyAlgorithm;
import io.jsonwebtoken.security.Keys; import io.jsonwebtoken.security.Keys;
import io.jsonwebtoken.security.SecureDigestAlgorithm; import io.jsonwebtoken.security.SecureDigestAlgorithm;
import io.jsonwebtoken.security.UnsupportedKeyException;
import javax.crypto.SecretKey; import javax.crypto.SecretKey;
import java.security.Key; import java.security.Key;
@ -237,7 +237,7 @@ public class DefaultJwtParserBuilder implements JwtParserBuilder {
} }
String msg = "JWS verification key must be either a SecretKey (for MAC algorithms) or a PublicKey " + String msg = "JWS verification key must be either a SecretKey (for MAC algorithms) or a PublicKey " +
"(for Signature algorithms)."; "(for Signature algorithms).";
throw new UnsupportedKeyException(msg); throw new InvalidKeyException(msg);
} }
@Override @Override

View File

@ -80,8 +80,7 @@ public class DefaultDynamicJwkBuilder<K extends Key, J extends Jwk<K>>
} }
private static UnsupportedKeyException unsupportedKey(Key key, Exception e) { private static UnsupportedKeyException unsupportedKey(Key key, Exception e) {
String msg = "There is no builder that supports specified key of type " + String msg = "There is no builder that supports specified key [" + KeysBridge.toString(key) + "].";
key.getClass().getName() + " with algorithm '" + key.getAlgorithm() + "'.";
return new UnsupportedKeyException(msg, e); return new UnsupportedKeyException(msg, e);
} }
@ -135,7 +134,7 @@ public class DefaultDynamicJwkBuilder<K extends Key, J extends Jwk<K>>
Assert.notEmpty(chain, "chain cannot be null or empty."); Assert.notEmpty(chain, "chain cannot be null or empty.");
X509Certificate cert = Assert.notNull(chain.get(0), "The first X509Certificate cannot be null."); X509Certificate cert = Assert.notNull(chain.get(0), "The first X509Certificate cannot be null.");
PublicKey key = Assert.notNull(cert.getPublicKey(), "The first X509Certificate's PublicKey cannot be null."); PublicKey key = Assert.notNull(cert.getPublicKey(), "The first X509Certificate's PublicKey cannot be null.");
return this.<A,B>key((A)key).x509CertificateChain(chain); return this.<A, B>key((A) key).x509CertificateChain(chain);
} }
@Override @Override
@ -195,9 +194,9 @@ public class DefaultDynamicJwkBuilder<K extends Key, J extends Jwk<K>>
@Override @Override
public <A extends PublicKey, B extends PrivateKey> PrivateJwkBuilder<B, A, ?, ?, ?> keyPair(KeyPair keyPair) public <A extends PublicKey, B extends PrivateKey> PrivateJwkBuilder<B, A, ?, ?, ?> keyPair(KeyPair keyPair)
throws UnsupportedKeyException { throws UnsupportedKeyException {
A pub = (A)KeyPairs.getKey(keyPair, PublicKey.class); A pub = (A) KeyPairs.getKey(keyPair, PublicKey.class);
B priv = (B)KeyPairs.getKey(keyPair, PrivateKey.class); B priv = (B) KeyPairs.getKey(keyPair, PrivateKey.class);
return this.<A,B>key(priv).publicKey(pub); return this.<A, B>key(priv).publicKey(pub);
} }
@Override @Override

View File

@ -20,11 +20,11 @@ import io.jsonwebtoken.impl.lang.CheckedFunction;
import io.jsonwebtoken.lang.Assert; import io.jsonwebtoken.lang.Assert;
import io.jsonwebtoken.lang.Collections; import io.jsonwebtoken.lang.Collections;
import io.jsonwebtoken.lang.Strings; import io.jsonwebtoken.lang.Strings;
import io.jsonwebtoken.security.InvalidKeyException;
import io.jsonwebtoken.security.MacAlgorithm; import io.jsonwebtoken.security.MacAlgorithm;
import io.jsonwebtoken.security.Password; import io.jsonwebtoken.security.Password;
import io.jsonwebtoken.security.SecretKeyBuilder; import io.jsonwebtoken.security.SecretKeyBuilder;
import io.jsonwebtoken.security.SecureRequest; import io.jsonwebtoken.security.SecureRequest;
import io.jsonwebtoken.security.UnsupportedKeyException;
import io.jsonwebtoken.security.VerifySecureDigestRequest; import io.jsonwebtoken.security.VerifySecureDigestRequest;
import io.jsonwebtoken.security.WeakKeyException; import io.jsonwebtoken.security.WeakKeyException;
@ -131,7 +131,7 @@ final class DefaultMacAlgorithm extends AbstractSecureDigestAlgorithm<SecretKey,
String name = key.getAlgorithm(); String name = key.getAlgorithm();
if (!Strings.hasText(name)) { if (!Strings.hasText(name)) {
String msg = "The " + keyType(signing) + " key's algorithm cannot be null or empty."; String msg = "The " + keyType(signing) + " key's algorithm cannot be null or empty.";
throw new UnsupportedKeyException(msg); throw new InvalidKeyException(msg);
} }
// We can ignore PKCS11 key name assertions for two reasons: // We can ignore PKCS11 key name assertions for two reasons:
@ -141,7 +141,7 @@ final class DefaultMacAlgorithm extends AbstractSecureDigestAlgorithm<SecretKey,
//assert key's jca name is valid if it's a JWA standard algorithm: //assert key's jca name is valid if it's a JWA standard algorithm:
if (!pkcs11Key && isJwaStandard() && !isJwaStandardJcaName(name)) { if (!pkcs11Key && isJwaStandard() && !isJwaStandardJcaName(name)) {
throw new UnsupportedKeyException("The " + keyType(signing) + " key's algorithm '" + name + throw new InvalidKeyException("The " + keyType(signing) + " key's algorithm '" + name +
"' does not equal a valid HmacSHA* algorithm name or PKCS12 OID and cannot be used with " + "' does not equal a valid HmacSHA* algorithm name or PKCS12 OID and cannot be used with " +
getId() + "."); getId() + ".");
} }
@ -151,7 +151,6 @@ final class DefaultMacAlgorithm extends AbstractSecureDigestAlgorithm<SecretKey,
protected void validateKey(Key k, boolean signing) { protected void validateKey(Key k, boolean signing) {
final String keyType = keyType(signing); final String keyType = keyType(signing);
if (k == null) { if (k == null) {
throw new IllegalArgumentException("MAC " + keyType + " key cannot be null."); throw new IllegalArgumentException("MAC " + keyType + " key cannot be null.");
} }
@ -159,12 +158,12 @@ final class DefaultMacAlgorithm extends AbstractSecureDigestAlgorithm<SecretKey,
if (!(k instanceof SecretKey)) { if (!(k instanceof SecretKey)) {
String msg = "MAC " + keyType + " keys must be SecretKey instances. Specified key is of type " + String msg = "MAC " + keyType + " keys must be SecretKey instances. Specified key is of type " +
k.getClass().getName(); k.getClass().getName();
throw new UnsupportedKeyException(msg); throw new InvalidKeyException(msg);
} }
if (k instanceof Password) { if (k instanceof Password) {
String msg = "Passwords are intended for use with key derivation algorithms only."; String msg = "Passwords are intended for use with key derivation algorithms only.";
throw new UnsupportedKeyException(msg); throw new InvalidKeyException(msg);
} }
final SecretKey key = (SecretKey) k; final SecretKey key = (SecretKey) k;

View File

@ -18,11 +18,11 @@ package io.jsonwebtoken.impl.security;
import io.jsonwebtoken.impl.lang.CheckedFunction; import io.jsonwebtoken.impl.lang.CheckedFunction;
import io.jsonwebtoken.lang.Assert; import io.jsonwebtoken.lang.Assert;
import io.jsonwebtoken.security.DecryptionKeyRequest; import io.jsonwebtoken.security.DecryptionKeyRequest;
import io.jsonwebtoken.security.InvalidKeyException;
import io.jsonwebtoken.security.KeyAlgorithm; import io.jsonwebtoken.security.KeyAlgorithm;
import io.jsonwebtoken.security.KeyRequest; import io.jsonwebtoken.security.KeyRequest;
import io.jsonwebtoken.security.KeyResult; import io.jsonwebtoken.security.KeyResult;
import io.jsonwebtoken.security.SecurityException; import io.jsonwebtoken.security.SecurityException;
import io.jsonwebtoken.security.UnsupportedKeyException;
import io.jsonwebtoken.security.WeakKeyException; import io.jsonwebtoken.security.WeakKeyException;
import javax.crypto.Cipher; import javax.crypto.Cipher;
@ -57,13 +57,13 @@ public class DefaultRsaKeyAlgorithm extends CryptoAlgorithm implements KeyAlgori
protected void validate(Key key, boolean encryption) { // true = encryption, false = decryption protected void validate(Key key, boolean encryption) { // true = encryption, false = decryption
if (!RsaSignatureAlgorithm.isRsaAlgorithmName(key)) { if (!RsaSignatureAlgorithm.isRsaAlgorithmName(key)) {
throw new UnsupportedKeyException("Unsupported RSA key algorithm name."); throw new InvalidKeyException("Invalid RSA key algorithm name.");
} }
if (RsaSignatureAlgorithm.isPss(key)) { if (RsaSignatureAlgorithm.isPss(key)) {
String msg = "RSASSA-PSS keys may not be used for " + keyType(encryption) + String msg = "RSASSA-PSS keys may not be used for " + keyType(encryption) +
", only digital signature algorithms."; ", only digital signature algorithms.";
throw new UnsupportedKeyException(msg); throw new InvalidKeyException(msg);
} }
int size = KeysBridge.findBitLength(key); int size = KeysBridge.findBitLength(key);

View File

@ -22,7 +22,7 @@ import io.jsonwebtoken.lang.Assert;
import io.jsonwebtoken.lang.Strings; import io.jsonwebtoken.lang.Strings;
import io.jsonwebtoken.security.EcPrivateJwk; import io.jsonwebtoken.security.EcPrivateJwk;
import io.jsonwebtoken.security.EcPublicJwk; import io.jsonwebtoken.security.EcPublicJwk;
import io.jsonwebtoken.security.UnsupportedKeyException; import io.jsonwebtoken.security.InvalidKeyException;
import java.math.BigInteger; import java.math.BigInteger;
import java.security.KeyFactory; import java.security.KeyFactory;
@ -63,7 +63,7 @@ class EcPrivateJwkFactory extends AbstractEcJwkFactory<ECPrivateKey, EcPrivateJw
return derivePublic(kf, spec); return derivePublic(kf, spec);
} catch (Exception e) { } catch (Exception e) {
String msg = "Unable to derive ECPublicKey from ECPrivateKey: " + e.getMessage(); String msg = "Unable to derive ECPublicKey from ECPrivateKey: " + e.getMessage();
throw new UnsupportedKeyException(msg, e); throw new InvalidKeyException(msg, e);
} }
} }
}); });

View File

@ -21,7 +21,6 @@ import io.jsonwebtoken.impl.lang.RequiredFieldReader;
import io.jsonwebtoken.lang.Assert; import io.jsonwebtoken.lang.Assert;
import io.jsonwebtoken.security.EcPublicJwk; import io.jsonwebtoken.security.EcPublicJwk;
import io.jsonwebtoken.security.InvalidKeyException; import io.jsonwebtoken.security.InvalidKeyException;
import io.jsonwebtoken.security.UnsupportedKeyException;
import java.math.BigInteger; import java.math.BigInteger;
import java.security.KeyFactory; import java.security.KeyFactory;
@ -60,7 +59,7 @@ class EcPublicJwkFactory extends AbstractEcJwkFactory<ECPublicKey, EcPublicJwk>
protected static String getJwaIdByCurve(EllipticCurve curve) { protected static String getJwaIdByCurve(EllipticCurve curve) {
ECCurve c = ECCurve.findByJcaCurve(curve); ECCurve c = ECCurve.findByJcaCurve(curve);
if (c == null) { if (c == null) {
throw new UnsupportedKeyException(UNSUPPORTED_CURVE_MSG); throw new InvalidKeyException(UNSUPPORTED_CURVE_MSG);
} }
return c.getId(); return c.getId();
} }

View File

@ -26,7 +26,6 @@ import io.jsonwebtoken.security.KeyPairBuilder;
import io.jsonwebtoken.security.SecureRequest; import io.jsonwebtoken.security.SecureRequest;
import io.jsonwebtoken.security.SignatureAlgorithm; import io.jsonwebtoken.security.SignatureAlgorithm;
import io.jsonwebtoken.security.SignatureException; import io.jsonwebtoken.security.SignatureException;
import io.jsonwebtoken.security.UnsupportedKeyException;
import io.jsonwebtoken.security.VerifySecureDigestRequest; import io.jsonwebtoken.security.VerifySecureDigestRequest;
import java.math.BigInteger; import java.math.BigInteger;
@ -144,7 +143,7 @@ final class EcSignatureAlgorithm extends AbstractSignatureAlgorithm {
protected void validateKey(Key key, boolean signing) { protected void validateKey(Key key, boolean signing) {
super.validateKey(key, signing); super.validateKey(key, signing);
if (!KEY_ALG_NAMES.contains(KeysBridge.findAlgorithm(key))) { if (!KEY_ALG_NAMES.contains(KeysBridge.findAlgorithm(key))) {
throw new UnsupportedKeyException("Unsupported EC key algorithm name."); throw new InvalidKeyException("Unrecognized EC key algorithm name.");
} }
int size = KeysBridge.findBitLength(key); int size = KeysBridge.findBitLength(key);
if (size < 0) return; // likely PKCS11 or HSM key, can't get the data we need if (size < 0) return; // likely PKCS11 or HSM key, can't get the data we need

View File

@ -39,7 +39,6 @@ import io.jsonwebtoken.security.PublicJwk;
import io.jsonwebtoken.security.Request; import io.jsonwebtoken.security.Request;
import io.jsonwebtoken.security.SecureRequest; import io.jsonwebtoken.security.SecureRequest;
import io.jsonwebtoken.security.SecurityException; import io.jsonwebtoken.security.SecurityException;
import io.jsonwebtoken.security.UnsupportedKeyException;
import javax.crypto.KeyAgreement; import javax.crypto.KeyAgreement;
import javax.crypto.SecretKey; import javax.crypto.SecretKey;
@ -158,12 +157,12 @@ class EcdhKeyAlgorithm extends CryptoAlgorithm implements KeyAlgorithm<PublicKey
String type = key instanceof PublicKey ? "encryption " : "decryption "; String type = key instanceof PublicKey ? "encryption " : "decryption ";
String msg = "Unable to determine JWA-standard Elliptic Curve for " + type + "key [" + String msg = "Unable to determine JWA-standard Elliptic Curve for " + type + "key [" +
KeysBridge.toString(key) + "]"; KeysBridge.toString(key) + "]";
throw new UnsupportedKeyException(msg); throw new InvalidKeyException(msg);
} }
if (curve instanceof EdwardsCurve && ((EdwardsCurve) curve).isSignatureCurve()) { if (curve instanceof EdwardsCurve && ((EdwardsCurve) curve).isSignatureCurve()) {
String msg = curve.getId() + " keys may not be used with ECDH-ES key agreement algorithms per " + String msg = curve.getId() + " keys may not be used with ECDH-ES key agreement algorithms per " +
"https://www.rfc-editor.org/rfc/rfc8037#section-3.1"; "https://www.rfc-editor.org/rfc/rfc8037#section-3.1.";
throw new UnsupportedKeyException(msg); throw new InvalidKeyException(msg);
} }
return Assert.isInstanceOf(AbstractCurve.class, curve, "AbstractCurve instance expected."); return Assert.isInstanceOf(AbstractCurve.class, curve, "AbstractCurve instance expected.");
} }
@ -213,9 +212,9 @@ class EcdhKeyAlgorithm extends CryptoAlgorithm implements KeyAlgorithm<PublicKey
Assert.stateNotNull(curve, "Internal implementation state: Curve cannot be null."); Assert.stateNotNull(curve, "Internal implementation state: Curve cannot be null.");
Class<?> epkClass = curve instanceof ECCurve ? EcPublicJwk.class : OctetPublicJwk.class; Class<?> epkClass = curve instanceof ECCurve ? EcPublicJwk.class : OctetPublicJwk.class;
if (!epkClass.isInstance(epk)) { if (!epkClass.isInstance(epk)) {
String msg = "JWE Header " + DefaultJweHeader.EPK + " value is not a supported Elliptic Curve " + String msg = "JWE Header " + DefaultJweHeader.EPK + " value is not an Elliptic Curve " +
"Public JWK. Value: " + epk; "Public JWK. Value: " + epk;
throw new UnsupportedKeyException(msg); throw new InvalidKeyException(msg);
} }
if (!curve.contains(epk.toKey())) { if (!curve.contains(epk.toKey())) {
String msg = "JWE Header " + DefaultJweHeader.EPK + " value does not represent " + String msg = "JWE Header " + DefaultJweHeader.EPK + " value does not represent " +

View File

@ -16,10 +16,10 @@
package io.jsonwebtoken.impl.security; package io.jsonwebtoken.impl.security;
import io.jsonwebtoken.lang.Assert; import io.jsonwebtoken.lang.Assert;
import io.jsonwebtoken.security.InvalidKeyException;
import io.jsonwebtoken.security.KeyPairBuilder; import io.jsonwebtoken.security.KeyPairBuilder;
import io.jsonwebtoken.security.Request; import io.jsonwebtoken.security.Request;
import io.jsonwebtoken.security.SecureRequest; import io.jsonwebtoken.security.SecureRequest;
import io.jsonwebtoken.security.UnsupportedKeyException;
import io.jsonwebtoken.security.VerifyDigestRequest; import io.jsonwebtoken.security.VerifyDigestRequest;
import java.security.Key; import java.security.Key;
@ -71,7 +71,7 @@ final class EdSignatureAlgorithm extends AbstractSignatureAlgorithm {
if (!curve.isSignatureCurve()) { if (!curve.isSignatureCurve()) {
String msg = curve.getId() + " keys may not be used with " + getId() + " digital signatures per " + String msg = curve.getId() + " keys may not be used with " + getId() + " digital signatures per " +
"https://www.rfc-editor.org/rfc/rfc8037.html#section-3.2"; "https://www.rfc-editor.org/rfc/rfc8037.html#section-3.2";
throw new UnsupportedKeyException(msg); throw new InvalidKeyException(msg);
} }
} }
} }

View File

@ -24,7 +24,6 @@ import io.jsonwebtoken.security.InvalidKeyException;
import io.jsonwebtoken.security.KeyException; import io.jsonwebtoken.security.KeyException;
import io.jsonwebtoken.security.KeyLengthSupplier; import io.jsonwebtoken.security.KeyLengthSupplier;
import io.jsonwebtoken.security.KeyPairBuilder; import io.jsonwebtoken.security.KeyPairBuilder;
import io.jsonwebtoken.security.UnsupportedKeyException;
import java.security.Key; import java.security.Key;
import java.security.PrivateKey; import java.security.PrivateKey;
@ -365,9 +364,8 @@ public class EdwardsCurve extends AbstractCurve implements KeyLengthSupplier {
Assert.notNull(key, "Key cannot be null."); Assert.notNull(key, "Key cannot be null.");
EdwardsCurve curve = findByKey(key); EdwardsCurve curve = findByKey(key);
if (curve == null) { if (curve == null) {
String msg = key.getClass().getName() + " with algorithm '" + key.getAlgorithm() + String msg = "Unrecognized Edwards Curve key: [" + KeysBridge.toString(key) + "]";
"' is not a recognized Edwards Curve key."; throw new InvalidKeyException(msg);
throw new UnsupportedKeyException(msg);
} }
//TODO: assert key exists on discovered curve via equation //TODO: assert key exists on discovered curve via equation
return curve; return curve;

View File

@ -17,7 +17,7 @@ package io.jsonwebtoken.impl.security;
import io.jsonwebtoken.impl.lang.Function; import io.jsonwebtoken.impl.lang.Function;
import io.jsonwebtoken.lang.Assert; import io.jsonwebtoken.lang.Assert;
import io.jsonwebtoken.security.UnsupportedKeyException; import io.jsonwebtoken.security.InvalidKeyException;
import java.security.KeyPair; import java.security.KeyPair;
import java.security.PrivateKey; import java.security.PrivateKey;
@ -41,7 +41,7 @@ final class EdwardsPublicKeyDeriver implements Function<PrivateKey, PublicKey> {
EdwardsCurve curve = EdwardsCurve.findByKey(privateKey); EdwardsCurve curve = EdwardsCurve.findByKey(privateKey);
if (curve == null) { if (curve == null) {
String msg = "Unable to derive Edwards-curve PublicKey for specified PrivateKey: " + KeysBridge.toString(privateKey); String msg = "Unable to derive Edwards-curve PublicKey for specified PrivateKey: " + KeysBridge.toString(privateKey);
throw new UnsupportedKeyException(msg); throw new InvalidKeyException(msg);
} }
byte[] pkBytes = curve.getKeyMaterial(privateKey); byte[] pkBytes = curve.getKeyMaterial(privateKey);

View File

@ -19,11 +19,11 @@ import io.jsonwebtoken.impl.lang.Bytes;
import io.jsonwebtoken.impl.lang.OptionalMethodInvoker; import io.jsonwebtoken.impl.lang.OptionalMethodInvoker;
import io.jsonwebtoken.lang.Assert; import io.jsonwebtoken.lang.Assert;
import io.jsonwebtoken.lang.Strings; import io.jsonwebtoken.lang.Strings;
import io.jsonwebtoken.security.InvalidKeyException;
import io.jsonwebtoken.security.KeySupplier; import io.jsonwebtoken.security.KeySupplier;
import io.jsonwebtoken.security.Password; import io.jsonwebtoken.security.Password;
import io.jsonwebtoken.security.PrivateKeyBuilder; import io.jsonwebtoken.security.PrivateKeyBuilder;
import io.jsonwebtoken.security.SecretKeyBuilder; import io.jsonwebtoken.security.SecretKeyBuilder;
import io.jsonwebtoken.security.UnsupportedKeyException;
import javax.crypto.SecretKey; import javax.crypto.SecretKey;
import java.security.Key; import java.security.Key;
@ -136,10 +136,17 @@ public final class KeysBridge {
public static byte[] getEncoded(Key key) { public static byte[] getEncoded(Key key) {
Assert.notNull(key, "Key cannot be null."); Assert.notNull(key, "Key cannot be null.");
byte[] encoded = findEncoded(key); byte[] encoded;
try {
encoded = key.getEncoded();
} catch (Throwable t) {
String msg = "Cannot obtain required encoded bytes from key [" + KeysBridge.toString(key) + "]: " +
t.getMessage();
throw new InvalidKeyException(msg, t);
}
if (Bytes.isEmpty(encoded)) { if (Bytes.isEmpty(encoded)) {
String msg = key.getClass().getName() + " encoded bytes cannot be null or empty."; String msg = "Missing required encoded bytes for key [" + toString(key) + "].";
throw new UnsupportedKeyException(msg); throw new InvalidKeyException(msg);
} }
return encoded; return encoded;
} }

View File

@ -34,7 +34,7 @@ public abstract class OctetJwkFactory<K extends Key, J extends Jwk<K>> extends A
return super.supports(key) && EdwardsCurve.isEdwards(key); return super.supports(key) && EdwardsCurve.isEdwards(key);
} }
protected EdwardsCurve getCurve(final FieldReadable reader) throws UnsupportedKeyException { protected static EdwardsCurve getCurve(final FieldReadable reader) throws UnsupportedKeyException {
Field<String> field = DefaultOctetPublicJwk.CRV; Field<String> field = DefaultOctetPublicJwk.CRV;
String crvId = reader.get(field); String crvId = reader.get(field);
EdwardsCurve curve = EdwardsCurve.findById(crvId); EdwardsCurve curve = EdwardsCurve.findById(crvId);

View File

@ -23,6 +23,7 @@ import io.jsonwebtoken.lang.Arrays;
import io.jsonwebtoken.lang.Assert; import io.jsonwebtoken.lang.Assert;
import io.jsonwebtoken.lang.Collections; import io.jsonwebtoken.lang.Collections;
import io.jsonwebtoken.lang.Strings; import io.jsonwebtoken.lang.Strings;
import io.jsonwebtoken.security.InvalidKeyException;
import io.jsonwebtoken.security.RsaPrivateJwk; import io.jsonwebtoken.security.RsaPrivateJwk;
import io.jsonwebtoken.security.RsaPublicJwk; import io.jsonwebtoken.security.RsaPublicJwk;
import io.jsonwebtoken.security.UnsupportedKeyException; import io.jsonwebtoken.security.UnsupportedKeyException;
@ -53,6 +54,13 @@ class RsaPrivateJwkFactory extends AbstractFamilyJwkFactory<RSAPrivateKey, RsaPr
); );
private static final String PUBKEY_ERR_MSG = "JwkContext publicKey must be an " + RSAPublicKey.class.getName() + " instance."; private static final String PUBKEY_ERR_MSG = "JwkContext publicKey must be an " + RSAPublicKey.class.getName() + " instance.";
private static final String PUB_EXPONENT_EX_MSG =
"Unable to derive RSAPublicKey from RSAPrivateKey [%s]. Supported keys implement the " +
RSAPrivateCrtKey.class.getName() + " or " + RSAMultiPrimePrivateCrtKey.class.getName() +
" interfaces. If the specified RSAPrivateKey cannot be one of these two, you must explicitly " +
"provide an RSAPublicKey in addition to the RSAPrivateKey, as the " +
"[JWA RFC, Section 6.3.2](https://www.rfc-editor.org/rfc/rfc7518.html#section-6.3.2) " +
"requires public values to be present in private RSA JWKs.";
RsaPrivateJwkFactory() { RsaPrivateJwkFactory() {
super(DefaultRsaPublicJwk.TYPE_VALUE, RSAPrivateKey.class, DefaultRsaPrivateJwk.FIELDS); super(DefaultRsaPublicJwk.TYPE_VALUE, RSAPrivateKey.class, DefaultRsaPrivateJwk.FIELDS);
@ -70,13 +78,7 @@ class RsaPrivateJwkFactory extends AbstractFamilyJwkFactory<RSAPrivateKey, RsaPr
return ((RSAMultiPrimePrivateCrtKey) key).getPublicExponent(); return ((RSAMultiPrimePrivateCrtKey) key).getPublicExponent();
} }
String msg = "Unable to derive RSAPublicKey from RSAPrivateKey implementation [" + String msg = String.format(PUB_EXPONENT_EX_MSG, KeysBridge.toString(key));
key.getClass().getName() + "]. Supported keys implement the " +
RSAPrivateCrtKey.class.getName() + " or " + RSAMultiPrimePrivateCrtKey.class.getName() +
" interfaces. If the specified RSAPrivateKey cannot be one of these two, you must explicitly " +
"provide an RSAPublicKey in addition to the RSAPrivateKey, as the " +
"[JWA RFC, Section 6.3.2](https://www.rfc-editor.org/rfc/rfc7518.html#section-6.3.2) " +
"requires public values to be present in private RSA JWKs.";
throw new UnsupportedKeyException(msg); throw new UnsupportedKeyException(msg);
} }
@ -91,9 +93,8 @@ class RsaPrivateJwkFactory extends AbstractFamilyJwkFactory<RSAPrivateKey, RsaPr
try { try {
return (RSAPublicKey) kf.generatePublic(spec); return (RSAPublicKey) kf.generatePublic(spec);
} catch (Exception e) { } catch (Exception e) {
String msg = "Unable to derive RSAPublicKey from RSAPrivateKey " + ctx + String msg = "Unable to derive RSAPublicKey from RSAPrivateKey " + ctx + ". Cause: " + e.getMessage();
". Cause: " + e.getMessage(); throw new InvalidKeyException(msg);
throw new UnsupportedKeyException(msg);
} }
} }
}); });

View File

@ -19,10 +19,10 @@ import io.jsonwebtoken.impl.lang.CheckedFunction;
import io.jsonwebtoken.lang.Assert; import io.jsonwebtoken.lang.Assert;
import io.jsonwebtoken.lang.Collections; import io.jsonwebtoken.lang.Collections;
import io.jsonwebtoken.lang.Strings; import io.jsonwebtoken.lang.Strings;
import io.jsonwebtoken.security.InvalidKeyException;
import io.jsonwebtoken.security.KeyPairBuilder; import io.jsonwebtoken.security.KeyPairBuilder;
import io.jsonwebtoken.security.SecureRequest; import io.jsonwebtoken.security.SecureRequest;
import io.jsonwebtoken.security.SignatureAlgorithm; import io.jsonwebtoken.security.SignatureAlgorithm;
import io.jsonwebtoken.security.UnsupportedKeyException;
import io.jsonwebtoken.security.VerifySecureDigestRequest; import io.jsonwebtoken.security.VerifySecureDigestRequest;
import io.jsonwebtoken.security.WeakKeyException; import io.jsonwebtoken.security.WeakKeyException;
@ -180,7 +180,7 @@ final class RsaSignatureAlgorithm extends AbstractSignatureAlgorithm {
protected void validateKey(Key key, boolean signing) { protected void validateKey(Key key, boolean signing) {
super.validateKey(key, signing); super.validateKey(key, signing);
if (!isRsaAlgorithmName(key)) { if (!isRsaAlgorithmName(key)) {
throw new UnsupportedKeyException("Unsupported RSA or RSASSA-PSS key algorithm name."); throw new InvalidKeyException("Unrecognized RSA or RSASSA-PSS key algorithm name.");
} }
int size = KeysBridge.findBitLength(key); int size = KeysBridge.findBitLength(key);
if (size < 0) return; // https://github.com/jwtk/jjwt/issues/68 if (size < 0) return; // https://github.com/jwtk/jjwt/issues/68

View File

@ -20,14 +20,13 @@ import io.jsonwebtoken.impl.lang.Bytes;
import io.jsonwebtoken.impl.lang.FieldReadable; import io.jsonwebtoken.impl.lang.FieldReadable;
import io.jsonwebtoken.impl.lang.RequiredFieldReader; import io.jsonwebtoken.impl.lang.RequiredFieldReader;
import io.jsonwebtoken.io.Encoders; import io.jsonwebtoken.io.Encoders;
import io.jsonwebtoken.lang.Arrays;
import io.jsonwebtoken.lang.Assert; import io.jsonwebtoken.lang.Assert;
import io.jsonwebtoken.lang.Strings; import io.jsonwebtoken.lang.Strings;
import io.jsonwebtoken.security.InvalidKeyException;
import io.jsonwebtoken.security.MacAlgorithm; import io.jsonwebtoken.security.MacAlgorithm;
import io.jsonwebtoken.security.MalformedKeyException; import io.jsonwebtoken.security.MalformedKeyException;
import io.jsonwebtoken.security.SecretJwk; import io.jsonwebtoken.security.SecretJwk;
import io.jsonwebtoken.security.SecureDigestAlgorithm; import io.jsonwebtoken.security.SecureDigestAlgorithm;
import io.jsonwebtoken.security.UnsupportedKeyException;
import javax.crypto.SecretKey; import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec; import javax.crypto.spec.SecretKeySpec;
@ -37,42 +36,21 @@ import javax.crypto.spec.SecretKeySpec;
*/ */
class SecretJwkFactory extends AbstractFamilyJwkFactory<SecretKey, SecretJwk> { class SecretJwkFactory extends AbstractFamilyJwkFactory<SecretKey, SecretJwk> {
private static final String ENCODED_UNAVAILABLE_MSG = "SecretKey argument does not have any encoded bytes, or " +
"the key's backing JCA Provider is preventing key.getEncoded() from returning any bytes. It is not " +
"possible to represent the SecretKey instance as a JWK.";
SecretJwkFactory() { SecretJwkFactory() {
super(DefaultSecretJwk.TYPE_VALUE, SecretKey.class, DefaultSecretJwk.FIELDS); super(DefaultSecretJwk.TYPE_VALUE, SecretKey.class, DefaultSecretJwk.FIELDS);
} }
static byte[] getRequiredEncoded(SecretKey key) {
Assert.notNull(key, "SecretKey argument cannot be null.");
byte[] encoded = null;
Exception cause = null;
try {
encoded = key.getEncoded();
} catch (Exception e) {
cause = e;
}
if (Arrays.length(encoded) == 0) {
throw new IllegalArgumentException(ENCODED_UNAVAILABLE_MSG, cause);
}
return encoded;
}
@Override @Override
protected SecretJwk createJwkFromKey(JwkContext<SecretKey> ctx) { protected SecretJwk createJwkFromKey(JwkContext<SecretKey> ctx) {
SecretKey key = Assert.notNull(ctx.getKey(), "JwkContext key cannot be null."); SecretKey key = Assert.notNull(ctx.getKey(), "JwkContext key cannot be null.");
String k; String k;
try { try {
byte[] encoded = getRequiredEncoded(key); byte[] encoded = KeysBridge.getEncoded(key);
k = Encoders.BASE64URL.encode(encoded); k = Encoders.BASE64URL.encode(encoded);
Assert.hasText(k, "k value cannot be null or empty."); Assert.hasText(k, "k value cannot be null or empty.");
} catch (Exception e) { } catch (Throwable t) {
String msg = "Unable to encode SecretKey to JWK: " + e.getMessage(); String msg = "Unable to encode SecretKey to JWK: " + t.getMessage();
throw new UnsupportedKeyException(msg, e); throw new InvalidKeyException(msg, t);
} }
ctx.put(DefaultSecretJwk.K.getId(), k); ctx.put(DefaultSecretJwk.K.getId(), k);

View File

@ -1196,7 +1196,7 @@ class JwtsTest {
// Now for the forgery: simulate an attacker using the RSA public key to sign a token, but // Now for the forgery: simulate an attacker using the RSA public key to sign a token, but
// using it as an HMAC signing key instead of RSA: // using it as an HMAC signing key instead of RSA:
Mac mac = Mac.getInstance('HmacSHA256') Mac mac = Mac.getInstance('HmacSHA256')
byte[] raw = ((RSAPublicKey)publicKey).getModulus().toByteArray() byte[] raw = ((RSAPublicKey) publicKey).getModulus().toByteArray()
if (raw.length > 256) { if (raw.length > 256) {
raw = Arrays.copyOfRange(raw, 1, raw.length) raw = Arrays.copyOfRange(raw, 1, raw.length)
} }
@ -1232,7 +1232,7 @@ class JwtsTest {
// Now for the forgery: simulate an attacker using the RSA public key to sign a token, but // Now for the forgery: simulate an attacker using the RSA public key to sign a token, but
// using it as an HMAC signing key instead of RSA: // using it as an HMAC signing key instead of RSA:
Mac mac = Mac.getInstance('HmacSHA256') Mac mac = Mac.getInstance('HmacSHA256')
byte[] raw = ((RSAPublicKey)publicKey).getModulus().toByteArray() byte[] raw = ((RSAPublicKey) publicKey).getModulus().toByteArray()
if (raw.length > 256) { if (raw.length > 256) {
raw = Arrays.copyOfRange(raw, 1, raw.length) raw = Arrays.copyOfRange(raw, 1, raw.length)
} }
@ -1268,7 +1268,7 @@ class JwtsTest {
// Now for the forgery: simulate an attacker using the Elliptic Curve public key to sign a token, but // Now for the forgery: simulate an attacker using the Elliptic Curve public key to sign a token, but
// using it as an HMAC signing key instead of Elliptic Curve: // using it as an HMAC signing key instead of Elliptic Curve:
Mac mac = Mac.getInstance('HmacSHA256') Mac mac = Mac.getInstance('HmacSHA256')
byte[] raw = ((ECPublicKey)publicKey).getParams().getOrder().toByteArray() byte[] raw = ((ECPublicKey) publicKey).getParams().getOrder().toByteArray()
if (raw.length > 32) { if (raw.length > 32) {
raw = Arrays.copyOfRange(raw, 1, raw.length) raw = Arrays.copyOfRange(raw, 1, raw.length)
} }
@ -1509,10 +1509,10 @@ class JwtsTest {
try { try {
encrypt(pubKey, alg, enc) encrypt(pubKey, alg, enc)
fail() fail()
} catch (UnsupportedKeyException expected) { } catch (InvalidKeyException expected) {
String id = EdwardsCurve.forKey(pubKey).getId() String id = EdwardsCurve.forKey(pubKey).getId()
String msg = id + " keys may not be used with ECDH-ES key " + String msg = id + " keys may not be used with ECDH-ES key " +
"agreement algorithms per https://www.rfc-editor.org/rfc/rfc8037#section-3.1" "agreement algorithms per https://www.rfc-editor.org/rfc/rfc8037#section-3.1."
assertEquals msg, expected.getMessage() assertEquals msg, expected.getMessage()
} }
} }
@ -1544,10 +1544,10 @@ class JwtsTest {
try { try {
decrypt(jwe, key) // invalid signing key decrypt(jwe, key) // invalid signing key
fail() fail()
} catch (UnsupportedKeyException expected) { } catch (InvalidKeyException expected) {
String id = EdwardsCurve.forKey(key).getId() String id = EdwardsCurve.forKey(key).getId()
String msg = id + " keys may not be used with ECDH-ES key " + String msg = id + " keys may not be used with ECDH-ES key " +
"agreement algorithms per https://www.rfc-editor.org/rfc/rfc8037#section-3.1" "agreement algorithms per https://www.rfc-editor.org/rfc/rfc8037#section-3.1."
assertEquals msg, expected.getMessage() assertEquals msg, expected.getMessage()
} }
} }

View File

@ -362,7 +362,7 @@ class DefaultJwtParserBuilderTest {
try { try {
builder.setSigningKey(TestKeys.RS256.pair.private) builder.setSigningKey(TestKeys.RS256.pair.private)
fail() fail()
} catch (UnsupportedKeyException e) { } catch (InvalidKeyException e) {
String msg = 'JWS verification key must be either a SecretKey (for MAC algorithms) or a PublicKey (for Signature algorithms).' String msg = 'JWS verification key must be either a SecretKey (for MAC algorithms) or a PublicKey (for Signature algorithms).'
assertEquals msg, e.getMessage() assertEquals msg, e.getMessage()
} }

View File

@ -64,7 +64,7 @@ class DefaultMacAlgorithmTest {
} }
try { try {
newAlg().digest(request(password)) newAlg().digest(request(password))
} catch (UnsupportedKeyException expected) { } catch (InvalidKeyException expected) {
String msg = 'Passwords are intended for use with key derivation algorithms only.' String msg = 'Passwords are intended for use with key derivation algorithms only.'
assertEquals msg, expected.getMessage() assertEquals msg, expected.getMessage()
} }
@ -89,7 +89,7 @@ class DefaultMacAlgorithmTest {
try { try {
newAlg().digest(request(password)) newAlg().digest(request(password))
} catch (UnsupportedKeyException expected) { } catch (InvalidKeyException expected) {
String msg = 'Passwords are intended for use with key derivation algorithms only.' String msg = 'Passwords are intended for use with key derivation algorithms only.'
assertEquals msg, expected.getMessage() assertEquals msg, expected.getMessage()
} }

View File

@ -16,7 +16,7 @@
package io.jsonwebtoken.impl.security package io.jsonwebtoken.impl.security
import io.jsonwebtoken.Jwts import io.jsonwebtoken.Jwts
import io.jsonwebtoken.security.UnsupportedKeyException import io.jsonwebtoken.security.InvalidKeyException
import io.jsonwebtoken.security.WeakKeyException import io.jsonwebtoken.security.WeakKeyException
import org.junit.Test import org.junit.Test
@ -37,13 +37,13 @@ class DefaultRsaKeyAlgorithmTest {
for (DefaultRsaKeyAlgorithm alg : algs) { for (DefaultRsaKeyAlgorithm alg : algs) {
try { try {
alg.validate(key, true) alg.validate(key, true)
} catch (UnsupportedKeyException e) { } catch (InvalidKeyException e) {
assertEquals 'Unsupported RSA key algorithm name.', e.getMessage() assertEquals 'Invalid RSA key algorithm name.', e.getMessage()
} }
try { try {
alg.validate(key, false) alg.validate(key, false)
} catch (UnsupportedKeyException e) { } catch (InvalidKeyException e) {
assertEquals 'Unsupported RSA key algorithm name.', e.getMessage() assertEquals 'Invalid RSA key algorithm name.', e.getMessage()
} }
} }
} }
@ -65,7 +65,7 @@ class DefaultRsaKeyAlgorithmTest {
replay(key) replay(key)
try { try {
alg.validate(key, true) alg.validate(key, true)
} catch (UnsupportedKeyException expected) { } catch (InvalidKeyException expected) {
String msg = 'RSASSA-PSS keys may not be used for encryption, only digital signature algorithms.' String msg = 'RSASSA-PSS keys may not be used for encryption, only digital signature algorithms.'
assertEquals msg, expected.getMessage() assertEquals msg, expected.getMessage()
} }
@ -81,7 +81,7 @@ class DefaultRsaKeyAlgorithmTest {
replay(key) replay(key)
try { try {
alg.validate(key, true) alg.validate(key, true)
} catch (UnsupportedKeyException expected) { } catch (InvalidKeyException expected) {
String msg = 'RSASSA-PSS keys may not be used for encryption, only digital signature algorithms.' String msg = 'RSASSA-PSS keys may not be used for encryption, only digital signature algorithms.'
assertEquals msg, expected.getMessage() assertEquals msg, expected.getMessage()
} }

View File

@ -16,8 +16,8 @@
package io.jsonwebtoken.impl.security package io.jsonwebtoken.impl.security
import io.jsonwebtoken.Jwts import io.jsonwebtoken.Jwts
import io.jsonwebtoken.security.InvalidKeyException
import io.jsonwebtoken.security.MalformedKeyException import io.jsonwebtoken.security.MalformedKeyException
import io.jsonwebtoken.security.UnsupportedKeyException
import org.junit.Test import org.junit.Test
import java.security.KeyFactory import java.security.KeyFactory
@ -66,7 +66,7 @@ class EcPrivateJwkFactoryTest {
try { try {
factory.derivePublic(context) factory.derivePublic(context)
fail() fail()
} catch (UnsupportedKeyException expected) { } catch (InvalidKeyException expected) {
String msg = 'Unable to derive ECPublicKey from ECPrivateKey: invalid' String msg = 'Unable to derive ECPublicKey from ECPrivateKey: invalid'
assertEquals msg, expected.getMessage() assertEquals msg, expected.getMessage()
} }

View File

@ -18,7 +18,6 @@ package io.jsonwebtoken.impl.security
import io.jsonwebtoken.security.InvalidKeyException import io.jsonwebtoken.security.InvalidKeyException
import io.jsonwebtoken.security.Jwks import io.jsonwebtoken.security.Jwks
import io.jsonwebtoken.security.MalformedKeyException import io.jsonwebtoken.security.MalformedKeyException
import io.jsonwebtoken.security.UnsupportedKeyException
import org.junit.Test import org.junit.Test
import java.security.spec.EllipticCurve import java.security.spec.EllipticCurve
@ -82,7 +81,7 @@ class EcPublicJwkFactoryTest {
try { try {
EcPublicJwkFactory.getJwaIdByCurve(curve) EcPublicJwkFactory.getJwaIdByCurve(curve)
fail() fail()
} catch (UnsupportedKeyException e) { } catch (InvalidKeyException e) {
assertEquals EcPublicJwkFactory.UNSUPPORTED_CURVE_MSG, e.getMessage() assertEquals EcPublicJwkFactory.UNSUPPORTED_CURVE_MSG, e.getMessage()
} }
} }

View File

@ -89,8 +89,8 @@ class EcSignatureAlgorithmTest {
algs().each { algs().each {
try { try {
it.validateKey(key, false) it.validateKey(key, false)
} catch (Exception e) { } catch (InvalidKeyException e) {
String msg = 'Unsupported EC key algorithm name.' String msg = 'Unrecognized EC key algorithm name.'
assertEquals msg, e.getMessage() assertEquals msg, e.getMessage()
} }
} }

View File

@ -23,7 +23,6 @@ import io.jsonwebtoken.impl.DefaultMutableJweHeader
import io.jsonwebtoken.security.DecryptionKeyRequest import io.jsonwebtoken.security.DecryptionKeyRequest
import io.jsonwebtoken.security.InvalidKeyException import io.jsonwebtoken.security.InvalidKeyException
import io.jsonwebtoken.security.Jwks import io.jsonwebtoken.security.Jwks
import io.jsonwebtoken.security.UnsupportedKeyException
import org.junit.Test import org.junit.Test
import java.security.PrivateKey import java.security.PrivateKey
@ -125,9 +124,8 @@ class EcdhKeyAlgorithmTest {
try { try {
alg.getEncryptionKey(request) alg.getEncryptionKey(request)
fail() fail()
} catch (UnsupportedKeyException expected) { } catch (InvalidKeyException expected) {
String msg = "Unable to determine JWA-standard Elliptic Curve for encryption key " + String msg = "Unable to determine JWA-standard Elliptic Curve for encryption key [${KeysBridge.toString(encKey)}]"
"[${KeysBridge.toString(encKey)}]"
assertEquals msg, expected.getMessage() assertEquals msg, expected.getMessage()
} }
} }
@ -142,7 +140,7 @@ class EcdhKeyAlgorithmTest {
try { try {
alg.getDecryptionKey(request) alg.getDecryptionKey(request)
fail() fail()
} catch (UnsupportedKeyException expected) { } catch (InvalidKeyException expected) {
String msg = "Unable to determine JWA-standard Elliptic Curve for decryption key [${KeysBridge.toString(key)}]" String msg = "Unable to determine JWA-standard Elliptic Curve for decryption key [${KeysBridge.toString(key)}]"
assertEquals msg, expected.getMessage() assertEquals msg, expected.getMessage()
} }
@ -173,12 +171,8 @@ class EcdhKeyAlgorithmTest {
try { try {
alg.getDecryptionKey(request) alg.getDecryptionKey(request)
fail() fail()
} catch (UnsupportedKeyException expected) { } catch (InvalidKeyException expected) {
String msg = 'JWE Header \'epk\' (Ephemeral Public Key) value is not a supported Elliptic Curve Public ' + String msg = "JWE Header ${DefaultJweHeader.EPK} value is not an Elliptic Curve Public JWK. Value: ${jwk.toString()}"
'JWK. Value: {kty=RSA, n=vPYf1VSy58i6ic93goenzF5UO9oLxyiTSF64lGFUJ6_MBDydAvY9PS76ymvhUcSrsDUHgb' +
'0arsp6MDXOfZxYHn2C7o39n8-bQ7yS4hQm6kkl8KB5OiOkJFkFjEHrwnqykXygx1VFpcVpbBvxDn640ODEScWyoUUPd4sO' +
'K-esTt4D9-q0PXsXzfRT4eOrnpXHJTan_KK_a-UYmfWPr-xIEPUxnLPCD68mIHoSPAaJiv37SkAWHJ9-fm_DfnYTwTi0rx' +
'e2FRQ1-vkOxe6C2-n1ebsqCZPKr0J_2MfwqP0raxLfyGicxM5ee5RSTTRMCA4UyX5dubZvh2pLoaS8PCZajw, e=AQAB}'
assertEquals msg, expected.getMessage() assertEquals msg, expected.getMessage()
} }
} }
@ -193,12 +187,8 @@ class EcdhKeyAlgorithmTest {
try { try {
alg.getDecryptionKey(request) alg.getDecryptionKey(request)
fail() fail()
} catch (UnsupportedKeyException expected) { } catch (InvalidKeyException expected) {
String msg = 'JWE Header \'epk\' (Ephemeral Public Key) value is not a supported Elliptic Curve Public ' + String msg = "JWE Header ${DefaultJweHeader.EPK} value is not an Elliptic Curve Public JWK. Value: ${jwk.toString()}"
'JWK. Value: {kty=RSA, n=vPYf1VSy58i6ic93goenzF5UO9oLxyiTSF64lGFUJ6_MBDydAvY9PS76ymvhUcSrsDUHgb' +
'0arsp6MDXOfZxYHn2C7o39n8-bQ7yS4hQm6kkl8KB5OiOkJFkFjEHrwnqykXygx1VFpcVpbBvxDn640ODEScWyoUUPd4sO' +
'K-esTt4D9-q0PXsXzfRT4eOrnpXHJTan_KK_a-UYmfWPr-xIEPUxnLPCD68mIHoSPAaJiv37SkAWHJ9-fm_DfnYTwTi0rx' +
'e2FRQ1-vkOxe6C2-n1ebsqCZPKr0J_2MfwqP0raxLfyGicxM5ee5RSTTRMCA4UyX5dubZvh2pLoaS8PCZajw, e=AQAB}'
assertEquals msg, expected.getMessage() assertEquals msg, expected.getMessage()
} }
} }
@ -227,7 +217,7 @@ class EcdhKeyAlgorithmTest {
try { try {
EcdhKeyAlgorithm.assertCurve(key) EcdhKeyAlgorithm.assertCurve(key)
fail() fail()
} catch (UnsupportedKeyException expected) { } catch (InvalidKeyException expected) {
String msg = "Unable to determine JWA-standard Elliptic Curve for decryption key [${KeysBridge.toString(key)}]" String msg = "Unable to determine JWA-standard Elliptic Curve for decryption key [${KeysBridge.toString(key)}]"
assertEquals msg, expected.getMessage() assertEquals msg, expected.getMessage()
} }

View File

@ -17,7 +17,6 @@ package io.jsonwebtoken.impl.security
import io.jsonwebtoken.impl.lang.Bytes import io.jsonwebtoken.impl.lang.Bytes
import io.jsonwebtoken.security.InvalidKeyException import io.jsonwebtoken.security.InvalidKeyException
import io.jsonwebtoken.security.UnsupportedKeyException
import org.junit.Test import org.junit.Test
import java.security.spec.PKCS8EncodedKeySpec import java.security.spec.PKCS8EncodedKeySpec
@ -78,8 +77,8 @@ class EdwardsCurveTest {
def key = new TestKey(algorithm: alg) def key = new TestKey(algorithm: alg)
try { try {
EdwardsCurve.forKey(key) EdwardsCurve.forKey(key)
} catch (UnsupportedKeyException uke) { } catch (InvalidKeyException uke) {
String msg = "${key.getClass().getName()} with algorithm '${alg}' is not a recognized Edwards Curve key." String msg = "Unrecognized Edwards Curve key: [${KeysBridge.toString(key)}]"
assertEquals msg, uke.getMessage() assertEquals msg, uke.getMessage()
} }
} }
@ -251,9 +250,9 @@ class EdwardsCurveTest {
try { try {
it.getKeyMaterial(key) it.getKeyMaterial(key)
fail() fail()
} catch (UnsupportedKeyException uke) { } catch (InvalidKeyException e) {
String msg = "${key.getClass().getName()} encoded bytes cannot be null or empty." String msg = "Missing required encoded bytes for key [${KeysBridge.toString(key)}]."
assertEquals msg, uke.getMessage() assertEquals msg, e.getMessage()
} }
} }
} }

View File

@ -16,7 +16,7 @@
package io.jsonwebtoken.impl.security package io.jsonwebtoken.impl.security
import io.jsonwebtoken.Jwts import io.jsonwebtoken.Jwts
import io.jsonwebtoken.security.UnsupportedKeyException import io.jsonwebtoken.security.InvalidKeyException
import org.junit.Test import org.junit.Test
import static org.junit.Assert.assertEquals import static org.junit.Assert.assertEquals
@ -30,7 +30,7 @@ class EdwardsPublicKeyDeriverTest {
try { try {
EdwardsPublicKeyDeriver.INSTANCE.apply(rsaPrivKey) EdwardsPublicKeyDeriver.INSTANCE.apply(rsaPrivKey)
fail() fail()
} catch (UnsupportedKeyException uke) { } catch (InvalidKeyException uke) {
String expectedMsg = "Unable to derive Edwards-curve PublicKey for specified PrivateKey: ${KeysBridge.toString(rsaPrivKey)}" String expectedMsg = "Unable to derive Edwards-curve PublicKey for specified PrivateKey: ${KeysBridge.toString(rsaPrivKey)}"
assertEquals(expectedMsg, uke.getMessage()) assertEquals(expectedMsg, uke.getMessage())
} }

View File

@ -225,11 +225,12 @@ class JwksTest {
try { try {
Jwks.builder().key(key).build() Jwks.builder().key(key).build()
fail() fail()
} catch (UnsupportedKeyException expected) { } catch (InvalidKeyException expected) {
String expectedMsg = 'Unable to encode SecretKey to JWK: ' + SecretJwkFactory.ENCODED_UNAVAILABLE_MSG String causeMsg = "Missing required encoded bytes for key [${KeysBridge.toString(key)}]."
assertEquals expectedMsg, expected.getMessage() String msg = "Unable to encode SecretKey to JWK: $causeMsg"
assertTrue expected.getCause() instanceof IllegalArgumentException assertEquals msg, expected.message
assertEquals SecretJwkFactory.ENCODED_UNAVAILABLE_MSG, expected.getCause().getMessage() assertTrue expected.getCause() instanceof InvalidKeyException
assertEquals causeMsg, expected.getCause().getMessage()
} }
} }
@ -246,11 +247,12 @@ class JwksTest {
try { try {
Jwks.builder().key(key).build() Jwks.builder().key(key).build()
fail() fail()
} catch (UnsupportedKeyException expected) { } catch (InvalidKeyException expected) {
String expectedMsg = 'Unable to encode SecretKey to JWK: ' + SecretJwkFactory.ENCODED_UNAVAILABLE_MSG String causeMsg = "Cannot obtain required encoded bytes from key [${KeysBridge.toString(key)}]: $encodedMsg"
assertEquals expectedMsg, expected.getMessage() String msg = "Unable to encode SecretKey to JWK: $causeMsg"
assertTrue expected.getCause() instanceof IllegalArgumentException assertEquals msg, expected.message
assertEquals SecretJwkFactory.ENCODED_UNAVAILABLE_MSG, expected.getCause().getMessage() assertTrue expected.getCause() instanceof InvalidKeyException
assertEquals causeMsg, expected.cause.message
assertSame encodedEx, expected.getCause().getCause() assertSame encodedEx, expected.getCause().getCause()
} }
} }
@ -372,7 +374,7 @@ class JwksTest {
try { try {
Jwks.builder().key((PublicKey) key) Jwks.builder().key((PublicKey) key)
} catch (UnsupportedKeyException expected) { } catch (UnsupportedKeyException expected) {
String msg = 'There is no builder that supports specified key of type io.jsonwebtoken.impl.security.TestPublicKey with algorithm \'null\'.' String msg = "There is no builder that supports specified key [${KeysBridge.toString(key)}]."
assertEquals(msg, expected.getMessage()) assertEquals(msg, expected.getMessage())
assertNotNull expected.getCause() // ensure we always retain a cause assertNotNull expected.getCause() // ensure we always retain a cause
} }
@ -402,7 +404,7 @@ class JwksTest {
try { try {
Jwks.builder().key((PrivateKey) key) Jwks.builder().key((PrivateKey) key)
} catch (UnsupportedKeyException expected) { } catch (UnsupportedKeyException expected) {
String msg = 'There is no builder that supports specified key of type io.jsonwebtoken.impl.security.TestPrivateKey with algorithm \'null\'.' String msg = "There is no builder that supports specified key [${KeysBridge.toString(key)}]."
assertEquals(msg, expected.getMessage()) assertEquals(msg, expected.getMessage())
assertNotNull expected.getCause() // ensure we always retain a cause assertNotNull expected.getCause() // ensure we always retain a cause
} }

View File

@ -16,6 +16,7 @@
package io.jsonwebtoken.impl.security package io.jsonwebtoken.impl.security
import io.jsonwebtoken.impl.lang.Converters import io.jsonwebtoken.impl.lang.Converters
import io.jsonwebtoken.security.InvalidKeyException
import io.jsonwebtoken.security.Jwks import io.jsonwebtoken.security.Jwks
import io.jsonwebtoken.security.RsaPrivateJwk import io.jsonwebtoken.security.RsaPrivateJwk
import io.jsonwebtoken.security.UnsupportedKeyException import io.jsonwebtoken.security.UnsupportedKeyException
@ -47,14 +48,7 @@ class RsaPrivateJwkFactoryTest {
Jwks.builder().key(key).build() Jwks.builder().key(key).build()
fail() fail()
} catch (UnsupportedKeyException expected) { } catch (UnsupportedKeyException expected) {
String msg = 'Unable to derive RSAPublicKey from RSAPrivateKey implementation ' + String msg = String.format(RsaPrivateJwkFactory.PUB_EXPONENT_EX_MSG, KeysBridge.toString(key))
'[io.jsonwebtoken.impl.security.RsaPrivateJwkFactoryTest$1]. Supported keys implement the ' +
'java.security.interfaces.RSAPrivateCrtKey or ' +
'java.security.interfaces.RSAMultiPrimePrivateCrtKey interfaces. If the specified RSAPrivateKey ' +
'cannot be one of these two, you must explicitly provide an RSAPublicKey in addition to the ' +
'RSAPrivateKey, as the [JWA RFC, Section 6.3.2]' +
'(https://www.rfc-editor.org/rfc/rfc7518.html#section-6.3.2) requires public values to be ' +
'present in private RSA JWKs.'
assertEquals msg, expected.getMessage() assertEquals msg, expected.getMessage()
} }
} }
@ -121,7 +115,7 @@ class RsaPrivateJwkFactoryTest {
try { try {
Jwks.builder().key(key).build() Jwks.builder().key(key).build()
fail() fail()
} catch (UnsupportedKeyException expected) { } catch (InvalidKeyException expected) {
String prefix = 'Unable to derive RSAPublicKey from RSAPrivateKey {kty=RSA}. Cause: ' String prefix = 'Unable to derive RSAPublicKey from RSAPrivateKey {kty=RSA}. Cause: '
assertTrue expected.getMessage().startsWith(prefix) assertTrue expected.getMessage().startsWith(prefix)
} }

View File

@ -20,7 +20,6 @@ import io.jsonwebtoken.impl.lang.Bytes
import io.jsonwebtoken.impl.lang.CheckedFunction import io.jsonwebtoken.impl.lang.CheckedFunction
import io.jsonwebtoken.lang.Assert import io.jsonwebtoken.lang.Assert
import io.jsonwebtoken.security.InvalidKeyException import io.jsonwebtoken.security.InvalidKeyException
import io.jsonwebtoken.security.UnsupportedKeyException
import io.jsonwebtoken.security.WeakKeyException import io.jsonwebtoken.security.WeakKeyException
import org.junit.Test import org.junit.Test
@ -57,8 +56,8 @@ class RsaSignatureAlgorithmTest {
algs.each { algs.each {
try { try {
it.validateKey(key, false) it.validateKey(key, false)
} catch (Exception e) { } catch (InvalidKeyException e) {
String msg = 'Unsupported RSA or RSASSA-PSS key algorithm name.' String msg = 'Unrecognized RSA or RSASSA-PSS key algorithm name.'
assertEquals msg, e.getMessage() assertEquals msg, e.getMessage()
} }
} }
@ -78,8 +77,8 @@ class RsaSignatureAlgorithmTest {
algs.each { algs.each {
try { try {
it.validateKey(key, false) it.validateKey(key, false)
} catch (UnsupportedKeyException e) { } catch (InvalidKeyException e) {
String msg = 'Unsupported RSA or RSASSA-PSS key algorithm name.' String msg = 'Unrecognized RSA or RSASSA-PSS key algorithm name.'
assertEquals msg, e.getMessage() assertEquals msg, e.getMessage()
} }
} }