From 877960fe043dc75801fd15c97893ab4f2525b974 Mon Sep 17 00:00:00 2001
From: Les Hazlewood <121180+lhazlewood@users.noreply.github.com>
Date: Thu, 28 Apr 2022 12:11:36 -0400
Subject: [PATCH] Added additional guards for JVM CVE-2022-21449 per review,
accompanied by corresponding regression tests (#733)
---
CHANGELOG.md | 45 +++++--
README.md | 10 +-
.../jsonwebtoken/impl/DefaultJwtBuilder.java | 15 +--
.../jsonwebtoken/impl/DefaultJwtParser.java | 34 +----
.../impl/crypto/EllipticCurveProvider.java | 53 ++++++--
.../EllipticCurveSignatureValidator.java | 58 ++++++---
.../impl/crypto/EllipticCurveSigner.java | 9 +-
.../groovy/io/jsonwebtoken/JwtsTest.groovy | 67 ++++++++++
.../crypto/EllipticCurveProviderTest.groovy | 28 ++++
...EllipticCurveSignatureValidatorTest.groovy | 122 ++++++++++--------
.../crypto/EllipticCurveSignerTest.groovy | 24 ++--
11 files changed, 310 insertions(+), 155 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 480216e5..f3aabe54 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,32 @@
## Release Notes
+### 0.11.5
+
+This patch release adds additional security guards against an ECDSA bug in Java SE versions 15-15.0.6, 17-17.0.2, and 18
+([CVE-2022-21449](https://nvd.nist.gov/vuln/detail/CVE-2022-21449)) in addition to the guards added in the JJWT 0.11.3
+release. This patch allows JJWT users using those JVM versions to upgrade to JJWT 0.11.5, even if they are unable to
+upgrade their JVM to patched/fixed JVM version in a timely manner. Note: if your application does not use these JVM
+versions, you are not exposed to the JVM vulnerability.
+
+Note that the CVE is not a bug within JJWT itself - it is a bug within the above listed JVM versions, and the
+JJWT 0.11.5 release adds additional precautions within JJWT in case an application team is not able to upgrade
+their JVM in a timely manner.
+
+However, even with these additional JJWT security guards, the root cause of the issue is the JVM, so it **strongly
+recommended** to upgrade your JVM to version
+15.0.7, 17.0.3, or 18.0.1 or later to ensure the bug does not surface elsewhere in your application code or any other
+third party library in your application that may not contain similar security guards.
+
+Issues included in this patch are listed in the [JJWT 0.11.5 milestone](https://github.com/jwtk/jjwt/milestone/26?closed=1).
+
+#### Credits
+
+Thank you to [Neil Madden](https://neilmadden.blog), the security researcher that first discovered the JVM
+vulnerability as covered in his [Psychic Signatures in Java](https://neilmadden.blog/2022/04/19/psychic-signatures-in-java/)
+blog post. Neil worked directly with the JJWT team to provide these additional guards, beyond what was in the JJWT 0.11.3
+release, and we're grateful for his help and collaboration in reviewing our fixes and for the additional tests he
+provided the JJWT team.
+
### 0.11.4
This patch release:
@@ -20,18 +47,14 @@ Issues included in this patch are listed in the [JJWT 0.11.4 milestone](https://
### 0.11.3
This patch release adds security guards against an ECDSA bug in Java SE versions 15-15.0.6, 17-17.0.2, and 18
-([CVE-2022-21449](https://nvd.nist.gov/vuln/detail/CVE-2022-21449)). This patch allows JJWT users using those JVM
-versions to upgrade to JJWT 0.11.3, even if they are unable to upgrade their JVM to patched/fixed JVM version in a
-timely manner. Note: if your application does not use these JVM versions, you are not exposed to the JVM vulnerability.
+([CVE-2022-21449](https://nvd.nist.gov/vuln/detail/CVE-2022-21449)). Note: if your application does not use these
+JVM versions, you are not exposed to the JVM vulnerability.
-Note that the CVE is not a bug within JJWT itself - it is a bug within the above listed JVM versions, and the
-JJWT 0.11.3 release adds additional precautions within JJWT in case an application team is not able to upgrade
-their JVM in a timely manner.
-
-However, even with these additional JJWT security guards, the root cause of the issue is the JVM, so it **strongly
-recommended** to upgrade your JVM to version
-15.0.7, 17.0.3, or 18.0.1 or later to ensure the bug does not surface elsewhere in your application code or any other
-third party library in your application that may not contain similar security guards.
+Note that the CVE is not a bug within JJWT itself - it is a bug within the above listed JVM versions. However, even
+with these additional JJWT security guards, the root cause of the issue is the JVM, so it **strongly
+recommended** to upgrade your JVM to version 15.0.7, 17.0.3, or 18.0.1 or later to ensure the bug does not surface
+elsewhere in your application code or any other third party library in your application that may not contain similar
+security guards.
Issues included in this patch are listed in the [JJWT 0.11.3 milestone](https://github.com/jwtk/jjwt/milestone/24).
diff --git a/README.md b/README.md
index 06ca77f2..a56ba10b 100644
--- a/README.md
+++ b/README.md
@@ -580,15 +580,15 @@ for any RSA key, the requirement is the RSA key (modulus) length in bits MUST be
#### Elliptic Curve
-JWT Elliptic Curve signature algorithms `ES256`, `ES384`, and `ES512` all require a minimum key length
-(aka an Elliptic Curve order bit length) that is _at least_ as many bits as the algorithm signature's individual
+JWT Elliptic Curve signature algorithms `ES256`, `ES384`, and `ES512` all require a key length
+(aka an Elliptic Curve order bit length) equal to the algorithm signature's individual
`R` and `S` components per [RFC 7512 Section 3.4](https://tools.ietf.org/html/rfc7518#section-3.4). This means:
-* `ES256` requires that you use a private key that is at least 256 bits (32 bytes) long.
+* `ES256` requires that you use a private key that is exactly 256 bits (32 bytes) long.
-* `ES384` requires that you use a private key that is at least 384 bits (48 bytes) long.
+* `ES384` requires that you use a private key that is exactly 384 bits (48 bytes) long.
-* `ES512` requires that you use a private key that is at least 512 bits (64 bytes) long.
+* `ES512` requires that you use a private key that is exactly 521 bits (65 or 66 bytes) long (depending on format).
#### Creating Safe Keys
diff --git a/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtBuilder.java b/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtBuilder.java
index 2c7ab117..c57e5e0a 100644
--- a/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtBuilder.java
+++ b/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtBuilder.java
@@ -15,21 +15,11 @@
*/
package io.jsonwebtoken.impl;
-import io.jsonwebtoken.Claims;
-import io.jsonwebtoken.CompressionCodec;
-import io.jsonwebtoken.Header;
-import io.jsonwebtoken.JwsHeader;
-import io.jsonwebtoken.JwtBuilder;
-import io.jsonwebtoken.JwtParser;
-import io.jsonwebtoken.SignatureAlgorithm;
+import io.jsonwebtoken.*;
import io.jsonwebtoken.impl.crypto.DefaultJwtSigner;
import io.jsonwebtoken.impl.crypto.JwtSigner;
import io.jsonwebtoken.impl.lang.LegacyServices;
-import io.jsonwebtoken.io.Decoders;
-import io.jsonwebtoken.io.Encoder;
-import io.jsonwebtoken.io.Encoders;
-import io.jsonwebtoken.io.SerializationException;
-import io.jsonwebtoken.io.Serializer;
+import io.jsonwebtoken.io.*;
import io.jsonwebtoken.lang.Assert;
import io.jsonwebtoken.lang.Collections;
import io.jsonwebtoken.lang.Strings;
@@ -120,6 +110,7 @@ public class DefaultJwtBuilder implements JwtBuilder {
Assert.notNull(key, "Key argument cannot be null.");
Assert.notNull(alg, "SignatureAlgorithm cannot be null.");
alg.assertValidSigningKey(key); //since 0.10.0 for https://github.com/jwtk/jjwt/issues/334
+ createSigner(alg, key); // since 0.11.5: fail fast if key cannot be used for alg.
this.algorithm = alg;
this.key = key;
return this;
diff --git a/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParser.java b/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParser.java
index 591433f3..1070acce 100644
--- a/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParser.java
+++ b/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParser.java
@@ -15,27 +15,7 @@
*/
package io.jsonwebtoken.impl;
-import io.jsonwebtoken.ClaimJwtException;
-import io.jsonwebtoken.Claims;
-import io.jsonwebtoken.Clock;
-import io.jsonwebtoken.CompressionCodec;
-import io.jsonwebtoken.CompressionCodecResolver;
-import io.jsonwebtoken.ExpiredJwtException;
-import io.jsonwebtoken.Header;
-import io.jsonwebtoken.IncorrectClaimException;
-import io.jsonwebtoken.InvalidClaimException;
-import io.jsonwebtoken.Jws;
-import io.jsonwebtoken.JwsHeader;
-import io.jsonwebtoken.Jwt;
-import io.jsonwebtoken.JwtHandler;
-import io.jsonwebtoken.JwtHandlerAdapter;
-import io.jsonwebtoken.JwtParser;
-import io.jsonwebtoken.MalformedJwtException;
-import io.jsonwebtoken.MissingClaimException;
-import io.jsonwebtoken.PrematureJwtException;
-import io.jsonwebtoken.SignatureAlgorithm;
-import io.jsonwebtoken.SigningKeyResolver;
-import io.jsonwebtoken.UnsupportedJwtException;
+import io.jsonwebtoken.*;
import io.jsonwebtoken.impl.compression.DefaultCompressionCodecResolver;
import io.jsonwebtoken.impl.crypto.DefaultJwtSignatureValidator;
import io.jsonwebtoken.impl.crypto.JwtSignatureValidator;
@@ -403,13 +383,13 @@ public class DefaultJwtParser implements JwtParser {
throw e;
} catch (InvalidKeyException | IllegalArgumentException e) {
String algName = algorithm.getValue();
- String msg = "The parsed JWT indicates it was signed with the " + algName + " signature " +
- "algorithm, but the specified signing key of type " + key.getClass().getName() +
- " may not be used to validate " + algName + " signatures. Because the specified " +
- "signing key reflects a specific and expected algorithm, and the JWT does not reflect " +
+ String msg = "The parsed JWT indicates it was signed with the '" + algName + "' signature " +
+ "algorithm, but the provided " + key.getClass().getName() + " key may " +
+ "not be used to verify " + algName + " signatures. Because the specified " +
+ "key reflects a specific and expected algorithm, and the JWT does not reflect " +
"this algorithm, it is likely that the JWT was not expected and therefore should not be " +
- "trusted. Another possibility is that the parser was configured with the incorrect " +
- "signing key, but this cannot be assumed for security reasons.";
+ "trusted. Another possibility is that the parser was provided the incorrect " +
+ "signature verification key, but this cannot be assumed for security reasons.";
throw new UnsupportedJwtException(msg, e);
}
diff --git a/impl/src/main/java/io/jsonwebtoken/impl/crypto/EllipticCurveProvider.java b/impl/src/main/java/io/jsonwebtoken/impl/crypto/EllipticCurveProvider.java
index 45ea11d2..15b7f991 100644
--- a/impl/src/main/java/io/jsonwebtoken/impl/crypto/EllipticCurveProvider.java
+++ b/impl/src/main/java/io/jsonwebtoken/impl/crypto/EllipticCurveProvider.java
@@ -19,12 +19,15 @@ import io.jsonwebtoken.JwtException;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.lang.Assert;
import io.jsonwebtoken.lang.Strings;
+import io.jsonwebtoken.security.InvalidKeyException;
import io.jsonwebtoken.security.SignatureException;
+import java.math.BigInteger;
import java.security.Key;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.SecureRandom;
+import java.security.interfaces.ECKey;
import java.security.spec.ECGenParameterSpec;
import java.util.HashMap;
import java.util.Map;
@@ -39,16 +42,43 @@ public abstract class EllipticCurveProvider extends SignatureProvider {
private static final Map EC_CURVE_NAMES = createEcCurveNames();
private static Map createEcCurveNames() {
- Map m = new HashMap(); //alg to ASN1 OID name
+ Map m = new HashMap<>(); //alg to ASN1 OID name
m.put(SignatureAlgorithm.ES256, "secp256r1");
m.put(SignatureAlgorithm.ES384, "secp384r1");
m.put(SignatureAlgorithm.ES512, "secp521r1");
return m;
}
+ protected static String byteSizeString(int bytesLength) {
+ return bytesLength + " bytes (" + (bytesLength * Byte.SIZE) + " bits)";
+ }
+
+ protected final int requiredSignatureByteLength;
+ protected final int fieldByteLength;
+
protected EllipticCurveProvider(SignatureAlgorithm alg, Key key) {
super(alg, key);
Assert.isTrue(alg.isEllipticCurve(), "SignatureAlgorithm must be an Elliptic Curve algorithm.");
+ if (!(key instanceof ECKey)) {
+ String msg = "Elliptic Curve signatures require an ECKey. The provided key of type " +
+ key.getClass().getName() + " is not a " + ECKey.class.getName() + " instance.";
+ throw new InvalidKeyException(msg);
+ }
+ this.requiredSignatureByteLength = getSignatureByteArrayLength(alg);
+ this.fieldByteLength = this.requiredSignatureByteLength / 2;
+
+ ECKey ecKey = (ECKey) key; // can cast here because of the Assert.isTrue assertion above
+ BigInteger order = ecKey.getParams().getOrder();
+ int keyFieldByteLength = (order.bitLength() + 7) / Byte.SIZE; //for ES512 (can be 65 or 66, this ensures 66)
+ int concatByteLength = keyFieldByteLength * 2;
+
+ if (concatByteLength != this.requiredSignatureByteLength) {
+ String msg = "EllipticCurve key has a field size of " +
+ byteSizeString(keyFieldByteLength) + ", but " + alg.name() + " requires a field size of " +
+ byteSizeString(this.fieldByteLength) + " per [RFC 7518, Section 3.4 (validation)]" +
+ "(https://datatracker.ietf.org/doc/html/rfc7518#section-3.4).";
+ throw new InvalidKeyException(msg);
+ }
}
/**
@@ -148,16 +178,15 @@ public abstract class EllipticCurveProvider extends SignatureProvider {
/**
* Returns the expected signature byte array length (R + S parts) for
- * the specified ECDSA algorithm.
+ * the specified ECDSA algorithm. Expected lengths are mandated by
+ * JWA RFC 7518, Section 3.4.
*
* @param alg The ECDSA algorithm. Must be supported and not
* {@code null}.
* @return The expected byte array length for the signature.
* @throws JwtException If the algorithm is not supported.
*/
- public static int getSignatureByteArrayLength(final SignatureAlgorithm alg)
- throws JwtException {
-
+ public static int getSignatureByteArrayLength(final SignatureAlgorithm alg) throws JwtException {
switch (alg) {
case ES256:
return 64;
@@ -180,7 +209,7 @@ public abstract class EllipticCurveProvider extends SignatureProvider {
* @return The ECDSA JWS encoded signature.
* @throws JwtException If the ASN.1/DER signature format is invalid.
*/
- public static byte[] transcodeSignatureToConcat(final byte[] derSignature, int outputLength) throws JwtException {
+ public static byte[] transcodeDERToConcat(final byte[] derSignature, int outputLength) throws JwtException {
if (derSignature.length < 8 || derSignature[0] != 48) {
throw new JwtException("Invalid ECDSA signature format");
@@ -213,9 +242,9 @@ public abstract class EllipticCurveProvider extends SignatureProvider {
rawLen = Math.max(rawLen, outputLength / 2);
if ((derSignature[offset - 1] & 0xff) != derSignature.length - offset
- || (derSignature[offset - 1] & 0xff) != 2 + rLength + 2 + sLength
- || derSignature[offset] != 2
- || derSignature[offset + 2 + rLength] != 2) {
+ || (derSignature[offset - 1] & 0xff) != 2 + rLength + 2 + sLength
+ || derSignature[offset] != 2
+ || derSignature[offset + 2 + rLength] != 2) {
throw new JwtException("Invalid ECDSA signature format");
}
@@ -238,7 +267,7 @@ public abstract class EllipticCurveProvider extends SignatureProvider {
* @return The ASN.1/DER encoded signature.
* @throws JwtException If the ECDSA JWS signature format is invalid.
*/
- public static byte[] transcodeSignatureToDER(byte[] jwsSignature) throws JwtException {
+ public static byte[] transcodeConcatToDER(byte[] jwsSignature) throws JwtException {
try {
return concatToDER(jwsSignature);
} catch (Exception e) { // CVE-2022-21449 guard
@@ -257,10 +286,6 @@ public abstract class EllipticCurveProvider extends SignatureProvider {
i--;
}
- if (i == 0) { // r == 0, JVM bug CVE-2202-21449 guard:
- throw new JwtException("Invalid ECDSA Signature format");
- }
-
int j = i;
if (jwsSignature[rawLen - i] < 0) {
diff --git a/impl/src/main/java/io/jsonwebtoken/impl/crypto/EllipticCurveSignatureValidator.java b/impl/src/main/java/io/jsonwebtoken/impl/crypto/EllipticCurveSignatureValidator.java
index c6765057..d9d3c38c 100644
--- a/impl/src/main/java/io/jsonwebtoken/impl/crypto/EllipticCurveSignatureValidator.java
+++ b/impl/src/main/java/io/jsonwebtoken/impl/crypto/EllipticCurveSignatureValidator.java
@@ -19,16 +19,18 @@ import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.lang.Assert;
import io.jsonwebtoken.security.SignatureException;
-import java.security.InvalidKeyException;
+import java.math.BigInteger;
import java.security.Key;
import java.security.PublicKey;
import java.security.Signature;
+import java.security.interfaces.ECKey;
import java.security.interfaces.ECPublicKey;
+import java.util.Arrays;
public class EllipticCurveSignatureValidator extends EllipticCurveProvider implements SignatureValidator {
private static final String EC_PUBLIC_KEY_REQD_MSG =
- "Elliptic Curve signature validation requires an ECPublicKey instance.";
+ "Elliptic Curve signature validation requires an ECPublicKey instance.";
private static final String DER_ENCODING_SYS_PROPERTY_NAME =
"io.jsonwebtoken.impl.crypto.EllipticCurveSignatureValidator.derEncodingSupported";
@@ -39,24 +41,48 @@ public class EllipticCurveSignatureValidator extends EllipticCurveProvider imple
}
@Override
- public boolean isValid(byte[] data, byte[] signature) {
+ public boolean isValid(byte[] data, byte[] concatSignature) {
Signature sig = createSignatureInstance();
PublicKey publicKey = (PublicKey) key;
try {
- int expectedSize = getSignatureByteArrayLength(alg);
- /*
- * If the expected size is not valid for JOSE, fall back to ASN.1 DER signature IFF the application
- * is configured to do so. This fallback is for backwards compatibility ONLY (to support tokens
- * generated by early versions of jjwt) and backwards compatibility will be removed in a future
- * version of this library. This fallback is only enabled if the system property is set to 'true' due to
- * the risk of CVE-2022-21449 attacks on early JVM versions 15, 17 and 18.
- */
- //TODO: remove for 1.0 (DER-encoding support is not in the JWT RFCs)
+ // mandated per https://datatracker.ietf.org/doc/html/rfc7518#section-3.4 :
+ int requiredConcatByteLength = getSignatureByteArrayLength(alg);
+
byte[] derSignature;
- if (expectedSize != signature.length && signature[0] == 0x30 && "true".equalsIgnoreCase(System.getProperty(DER_ENCODING_SYS_PROPERTY_NAME))) {
- derSignature = signature;
+
+ if (requiredConcatByteLength != concatSignature.length) {
+
+ /*
+ * If the expected size is not valid for JOSE, fall back to ASN.1 DER signature IFF the application
+ * is configured to do so. This fallback is for backwards compatibility ONLY (to support tokens
+ * generated by early versions of jjwt) and backwards compatibility will be removed in a future
+ * version of this library. This fallback is only enabled if the system property is set to 'true' due to
+ * the risk of CVE-2022-21449 attacks on early JVM versions 15, 17 and 18.
+ */
+ // TODO: remove for 1.0 (DER-encoding support is not in the JWT RFCs)
+ if (concatSignature[0] == 0x30 && "true".equalsIgnoreCase(System.getProperty(DER_ENCODING_SYS_PROPERTY_NAME))) {
+ derSignature = concatSignature;
+ } else {
+ String msg = "Provided signature is " + byteSizeString(concatSignature.length) + " but " +
+ alg.name() + " signatures must be exactly " + byteSizeString(requiredConcatByteLength) + " per " +
+ "[RFC 7518, Section 3.4 (validation)](https://datatracker.ietf.org/doc/html/rfc7518#section-3.4).";
+ throw new SignatureException(msg);
+ }
} else {
- derSignature = EllipticCurveProvider.transcodeSignatureToDER(signature);
+
+ //guard for JVM security bug CVE-2022-21449:
+ ECKey ecKey = (ECKey) publicKey; // we can cast here because of the assertions made in the constructor
+ BigInteger order = ecKey.getParams().getOrder();
+ BigInteger r = new BigInteger(1, Arrays.copyOfRange(concatSignature, 0, this.fieldByteLength));
+ BigInteger s = new BigInteger(1, Arrays.copyOfRange(concatSignature, this.fieldByteLength, concatSignature.length));
+ if (r.signum() < 1 || s.signum() < 1 || r.compareTo(order) >= 0 || s.compareTo(order) >= 0) {
+ return false;
+ }
+
+ // Convert from concat to DER encoding since
+ // 1) SHAXXXWithECDSAInP1363Format algorithms are only available on >= JDK 9 and
+ // 2) the SignatureAlgorithm enum JCA alg names are all SHAXXXwithECDSA (which expects DER formatting)
+ derSignature = transcodeConcatToDER(concatSignature);
}
return doVerify(sig, publicKey, data, derSignature);
} catch (Exception e) {
@@ -66,7 +92,7 @@ public class EllipticCurveSignatureValidator extends EllipticCurveProvider imple
}
protected boolean doVerify(Signature sig, PublicKey publicKey, byte[] data, byte[] signature)
- throws InvalidKeyException, java.security.SignatureException {
+ throws java.security.InvalidKeyException, java.security.SignatureException {
sig.initVerify(publicKey);
sig.update(data);
return sig.verify(signature);
diff --git a/impl/src/main/java/io/jsonwebtoken/impl/crypto/EllipticCurveSigner.java b/impl/src/main/java/io/jsonwebtoken/impl/crypto/EllipticCurveSigner.java
index 9aeb1e8b..16c826fb 100644
--- a/impl/src/main/java/io/jsonwebtoken/impl/crypto/EllipticCurveSigner.java
+++ b/impl/src/main/java/io/jsonwebtoken/impl/crypto/EllipticCurveSigner.java
@@ -23,16 +23,15 @@ import java.security.InvalidKeyException;
import java.security.Key;
import java.security.PrivateKey;
import java.security.Signature;
-import java.security.interfaces.ECKey;
public class EllipticCurveSigner extends EllipticCurveProvider implements Signer {
public EllipticCurveSigner(SignatureAlgorithm alg, Key key) {
super(alg, key);
- if (!(key instanceof PrivateKey && key instanceof ECKey)) {
- String msg = "Elliptic Curve signatures must be computed using an EC PrivateKey. The specified key of " +
+ if (!(key instanceof PrivateKey)) {
+ String msg = "Elliptic Curve signatures must be computed using an EC PrivateKey. The specified key of " +
"type " + key.getClass().getName() + " is not an EC PrivateKey.";
- throw new IllegalArgumentException(msg);
+ throw new io.jsonwebtoken.security.InvalidKeyException(msg);
}
}
@@ -54,6 +53,6 @@ public class EllipticCurveSigner extends EllipticCurveProvider implements Signer
Signature sig = createSignatureInstance();
sig.initSign(privateKey);
sig.update(data);
- return transcodeSignatureToConcat(sig.sign(), getSignatureByteArrayLength(alg));
+ return transcodeDERToConcat(sig.sign(), getSignatureByteArrayLength(alg));
}
}
diff --git a/impl/src/test/groovy/io/jsonwebtoken/JwtsTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/JwtsTest.groovy
index c9de8390..009e51e8 100644
--- a/impl/src/test/groovy/io/jsonwebtoken/JwtsTest.groovy
+++ b/impl/src/test/groovy/io/jsonwebtoken/JwtsTest.groovy
@@ -19,10 +19,12 @@ import io.jsonwebtoken.impl.DefaultHeader
import io.jsonwebtoken.impl.DefaultJwsHeader
import io.jsonwebtoken.impl.compression.DefaultCompressionCodecResolver
import io.jsonwebtoken.impl.compression.GzipCompressionCodec
+import io.jsonwebtoken.impl.crypto.EllipticCurveProvider
import io.jsonwebtoken.impl.lang.Services
import io.jsonwebtoken.io.Encoders
import io.jsonwebtoken.io.Serializer
import io.jsonwebtoken.lang.Strings
+import io.jsonwebtoken.security.InvalidKeyException
import io.jsonwebtoken.security.Keys
import io.jsonwebtoken.security.WeakKeyException
import org.junit.Test
@@ -576,6 +578,71 @@ class JwtsTest {
}
}
+ /**
+ * @since 0.11.5
+ */
+ @Test
+ void testBuilderWithEcdsaPublicKey() {
+ def builder = Jwts.builder().setSubject('foo')
+ def pair = Keys.keyPairFor(SignatureAlgorithm.ES256)
+ try {
+ builder.signWith(pair.public, SignatureAlgorithm.ES256) //public keys can't be used to create signatures
+ } catch (InvalidKeyException expected) {
+ String msg = "ECDSA signing keys must be PrivateKey instances."
+ assertEquals msg, expected.getMessage()
+ }
+ }
+
+ /**
+ * @since 0.11.5 as part of testing guards against JVM CVE-2022-21449
+ */
+ @Test
+ void testBuilderWithMismatchedEllipticCurveKeyAndAlgorithm() {
+ def builder = Jwts.builder().setSubject('foo')
+ def pair = Keys.keyPairFor(SignatureAlgorithm.ES384)
+ try {
+ builder.signWith(pair.private, SignatureAlgorithm.ES256) //ES384 keys can't be used to create ES256 signatures
+ } catch (InvalidKeyException expected) {
+ String msg = "EllipticCurve key has a field size of 48 bytes (384 bits), but ES256 requires a " +
+ "field size of 32 bytes (256 bits) per [RFC 7518, Section 3.4 (validation)]" +
+ "(https://datatracker.ietf.org/doc/html/rfc7518#section-3.4)."
+ assertEquals msg, expected.getMessage()
+ }
+ }
+
+ /**
+ * @since 0.11.5 as part of testing guards against JVM CVE-2022-21449
+ */
+ @Test
+ void testParserWithMismatchedEllipticCurveKeyAndAlgorithm() {
+ def pair = Keys.keyPairFor(SignatureAlgorithm.ES256)
+ def jws = Jwts.builder().setSubject('foo').signWith(pair.private).compact()
+ def parser = Jwts.parserBuilder().setSigningKey(Keys.keyPairFor(SignatureAlgorithm.ES384).public).build()
+ try {
+ parser.parseClaimsJws(jws)
+ } catch (UnsupportedJwtException expected) {
+ String msg = 'The parsed JWT indicates it was signed with the \'ES256\' signature algorithm, but ' +
+ 'the provided sun.security.ec.ECPublicKeyImpl key may not be used to verify ES256 signatures. ' +
+ 'Because the specified key reflects a specific and expected algorithm, and the JWT does not ' +
+ 'reflect this algorithm, it is likely that the JWT was not expected and therefore should not ' +
+ 'be trusted. Another possibility is that the parser was provided the incorrect signature ' +
+ 'verification key, but this cannot be assumed for security reasons.'
+ assertEquals msg, expected.getMessage()
+ }
+ }
+
+ /**
+ * @since 0.11.5 as part of testing guards against JVM CVE-2022-21449
+ */
+ @Test(expected=io.jsonwebtoken.security.SignatureException)
+ void testEcdsaInvalidSignatureValue() {
+ def withoutSignature = "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0ZXN0IjoidGVzdCIsImlhdCI6MTQ2NzA2NTgyN30"
+ def invalidEncodedSignature = "_____wAAAAD__________7zm-q2nF56E87nKwvxjJVH_____AAAAAP__________vOb6racXnoTzucrC_GMlUQ"
+ String jws = withoutSignature + '.' + invalidEncodedSignature
+ def keypair = EllipticCurveProvider.generateKeyPair(SignatureAlgorithm.ES256)
+ Jwts.parserBuilder().setSigningKey(keypair.public).build().parseClaimsJws(jws)
+ }
+
//Asserts correct/expected behavior discussed in https://github.com/jwtk/jjwt/issues/20
@Test
void testParseClaimsJwsWithUnsignedJwt() {
diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/crypto/EllipticCurveProviderTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/crypto/EllipticCurveProviderTest.groovy
index 7e61b8f9..ccebf30b 100644
--- a/impl/src/test/groovy/io/jsonwebtoken/impl/crypto/EllipticCurveProviderTest.groovy
+++ b/impl/src/test/groovy/io/jsonwebtoken/impl/crypto/EllipticCurveProviderTest.groovy
@@ -15,7 +15,10 @@
*/
package io.jsonwebtoken.impl.crypto
+
import io.jsonwebtoken.SignatureAlgorithm
+import io.jsonwebtoken.security.InvalidKeyException
+import io.jsonwebtoken.security.Keys
import org.junit.Test
import java.security.KeyPair
@@ -65,4 +68,29 @@ class EllipticCurveProviderTest {
assertEquals ise.message, "SignatureAlgorithm argument must represent an Elliptic Curve algorithm."
}
}
+
+ @Test
+ void testConstructorWithNonEcKey() {
+ def key = Keys.secretKeyFor(SignatureAlgorithm.HS256)
+ try {
+ new EllipticCurveProvider(SignatureAlgorithm.ES256, key) {}
+ } catch (InvalidKeyException expected) {
+ String msg = 'Elliptic Curve signatures require an ECKey. The provided key of type ' +
+ 'javax.crypto.spec.SecretKeySpec is not a java.security.interfaces.ECKey instance.'
+ assertEquals msg, expected.getMessage()
+ }
+ }
+
+ @Test
+ void testConstructorWithInvalidKeyFieldLength() {
+ def keypair = Keys.keyPairFor(SignatureAlgorithm.ES256)
+ try {
+ new EllipticCurveProvider(SignatureAlgorithm.ES384, keypair.public){}
+ } catch (InvalidKeyException expected) {
+ String msg = "EllipticCurve key has a field size of 32 bytes (256 bits), but ES384 requires a " +
+ "field size of 48 bytes (384 bits) per [RFC 7518, Section 3.4 (validation)]" +
+ "(https://datatracker.ietf.org/doc/html/rfc7518#section-3.4)."
+ assertEquals msg, expected.getMessage()
+ }
+ }
}
diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/crypto/EllipticCurveSignatureValidatorTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/crypto/EllipticCurveSignatureValidatorTest.groovy
index 22e8b3a1..51aba2e9 100644
--- a/impl/src/test/groovy/io/jsonwebtoken/impl/crypto/EllipticCurveSignatureValidatorTest.groovy
+++ b/impl/src/test/groovy/io/jsonwebtoken/impl/crypto/EllipticCurveSignatureValidatorTest.groovy
@@ -36,21 +36,23 @@ class EllipticCurveSignatureValidatorTest {
String msg = 'foo'
final InvalidKeyException ex = new InvalidKeyException(msg)
+ def alg = SignatureAlgorithm.ES512
+ def keypair = EllipticCurveProvider.generateKeyPair(alg)
- def v = new EllipticCurveSignatureValidator(SignatureAlgorithm.ES512, EllipticCurveProvider.generateKeyPair().public) {
+ def v = new EllipticCurveSignatureValidator(alg, EllipticCurveProvider.generateKeyPair(alg).public) {
@Override
protected boolean doVerify(Signature sig, PublicKey pk, byte[] data, byte[] signature) throws InvalidKeyException, java.security.SignatureException {
throw ex;
}
}
- byte[] bytes = new byte[16]
- byte[] signature = new byte[16]
- SignatureProvider.DEFAULT_SECURE_RANDOM.nextBytes(bytes)
- SignatureProvider.DEFAULT_SECURE_RANDOM.nextBytes(signature)
+ byte[] data = new byte[32]
+ SignatureProvider.DEFAULT_SECURE_RANDOM.nextBytes(data)
+
+ byte[] signature = new EllipticCurveSigner(alg, keypair.getPrivate()).sign(data)
try {
- v.isValid(bytes, signature)
+ v.isValid(data, signature)
fail();
} catch (SignatureException se) {
assertEquals se.message, 'Unable to verify Elliptic Curve signature using configured ECPublicKey. ' + msg
@@ -80,12 +82,24 @@ class EllipticCurveSignatureValidatorTest {
void legacySignatureCompatDefaultTest() {
def withoutSignature = "eyJhbGciOiJFUzUxMiIsInR5cCI6IkpXVCJ9.eyJ0ZXN0IjoidGVzdCIsImlhdCI6MTQ2NzA2NTgyN30"
def keypair = EllipticCurveProvider.generateKeyPair()
- def signature = Signature.getInstance(SignatureAlgorithm.ES512.jcaName)
+ def alg = SignatureAlgorithm.ES512
+ def signature = Signature.getInstance(alg.jcaName)
def data = withoutSignature.getBytes("US-ASCII")
signature.initSign(keypair.private)
signature.update(data)
def signed = signature.sign()
- assertFalse new EllipticCurveSignatureValidator(SignatureAlgorithm.ES512, keypair.public).isValid(data, signed)
+ def validator = new EllipticCurveSignatureValidator(alg, keypair.public)
+ try {
+ validator.isValid(data, signed)
+ fail()
+ } catch (SignatureException expected) {
+ String signedBytesString = EllipticCurveProvider.byteSizeString(signed.length)
+ String msg = "Unable to verify Elliptic Curve signature using configured ECPublicKey. Provided " +
+ "signature is $signedBytesString but ES512 signatures must be exactly 132 bytes (1056 bits) " +
+ "per [RFC 7518, Section 3.4 (validation)]" +
+ "(https://datatracker.ietf.org/doc/html/rfc7518#section-3.4)." as String
+ assertEquals msg, expected.getMessage()
+ }
}
@Test
@@ -107,54 +121,54 @@ class EllipticCurveSignatureValidatorTest {
@Test // asserts guard for JVM security bug CVE-2022-21449:
void testSignatureAllZeros() {
- try {
- byte[] forgedSig = new byte[64]
- def withoutSignature = "eyJhbGciOiJFUzUxMiIsInR5cCI6IkpXVCJ9.eyJ0ZXN0IjoidGVzdCIsImlhdCI6MTQ2NzA2NTgyN30"
- def keypair = EllipticCurveProvider.generateKeyPair()
- def data = withoutSignature.getBytes("US-ASCII")
- new EllipticCurveSignatureValidator(SignatureAlgorithm.ES256, keypair.public).isValid(data, forgedSig)
- fail("SignatureException expected")
- } catch(SignatureException expected) {
- assertEquals 'Unable to verify Elliptic Curve signature using configured ECPublicKey. Invalid ECDSA signature format.', expected.getMessage()
- }
+ byte[] forgedSig = new byte[64]
+ def withoutSignature = "eyJhbGciOiJFUzUxMiIsInR5cCI6IkpXVCJ9.eyJ0ZXN0IjoidGVzdCIsImlhdCI6MTQ2NzA2NTgyN30"
+ def alg = SignatureAlgorithm.ES256
+ def keypair = EllipticCurveProvider.generateKeyPair(alg)
+ def data = withoutSignature.getBytes("US-ASCII")
+ def validator = new EllipticCurveSignatureValidator(alg, keypair.public)
+ assertFalse validator.isValid(data, forgedSig)
}
@Test // asserts guard for JVM security bug CVE-2022-21449:
void testSignatureRZero() {
- try {
- byte[] r = new byte[32]
- byte[] s = new byte[32]; Arrays.fill(s, Byte.MAX_VALUE)
- byte[] sig = new byte[r.length + s.length]
- System.arraycopy(r, 0, sig, 0, r.length)
- System.arraycopy(s, 0, sig, r.length, s.length)
+ byte[] r = new byte[32]
+ byte[] s = new byte[32]; Arrays.fill(s, Byte.MAX_VALUE)
+ byte[] sig = new byte[r.length + s.length]
+ System.arraycopy(r, 0, sig, 0, r.length)
+ System.arraycopy(s, 0, sig, r.length, s.length)
- def withoutSignature = "eyJhbGciOiJFUzUxMiIsInR5cCI6IkpXVCJ9.eyJ0ZXN0IjoidGVzdCIsImlhdCI6MTQ2NzA2NTgyN30"
- def keypair = EllipticCurveProvider.generateKeyPair()
- def data = withoutSignature.getBytes("US-ASCII")
- new EllipticCurveSignatureValidator(SignatureAlgorithm.ES256, keypair.public).isValid(data, sig)
- fail("SignatureException expected")
- } catch(SignatureException expected) {
- assertEquals 'Unable to verify Elliptic Curve signature using configured ECPublicKey. Invalid ECDSA signature format.', expected.getMessage()
- }
+ def withoutSignature = "eyJhbGciOiJFUzUxMiIsInR5cCI6IkpXVCJ9.eyJ0ZXN0IjoidGVzdCIsImlhdCI6MTQ2NzA2NTgyN30"
+ def keypair = EllipticCurveProvider.generateKeyPair(SignatureAlgorithm.ES256)
+ def data = withoutSignature.getBytes("US-ASCII")
+ def validator = new EllipticCurveSignatureValidator(SignatureAlgorithm.ES256, keypair.public)
+ assertFalse validator.isValid(data, sig)
}
@Test // asserts guard for JVM security bug CVE-2022-21449:
void testSignatureSZero() {
- try {
- byte[] r = new byte[32]; Arrays.fill(r, Byte.MAX_VALUE);
- byte[] s = new byte[32]
- byte[] sig = new byte[r.length + s.length]
- System.arraycopy(r, 0, sig, 0, r.length)
- System.arraycopy(s, 0, sig, r.length, s.length)
+ byte[] r = new byte[32]; Arrays.fill(r, Byte.MAX_VALUE);
+ byte[] s = new byte[32]
+ byte[] sig = new byte[r.length + s.length]
+ System.arraycopy(r, 0, sig, 0, r.length)
+ System.arraycopy(s, 0, sig, r.length, s.length)
- def withoutSignature = "eyJhbGciOiJFUzUxMiIsInR5cCI6IkpXVCJ9.eyJ0ZXN0IjoidGVzdCIsImlhdCI6MTQ2NzA2NTgyN30"
- def keypair = EllipticCurveProvider.generateKeyPair()
- def data = withoutSignature.getBytes("US-ASCII")
- new EllipticCurveSignatureValidator(SignatureAlgorithm.ES256, keypair.public).isValid(data, sig)
- fail("SignatureException expected")
- } catch(SignatureException expected) {
- assertEquals 'Unable to verify Elliptic Curve signature using configured ECPublicKey. Invalid ECDSA signature format.', expected.getMessage()
- }
+ def withoutSignature = "eyJhbGciOiJFUzUxMiIsInR5cCI6IkpXVCJ9.eyJ0ZXN0IjoidGVzdCIsImlhdCI6MTQ2NzA2NTgyN30"
+ def keypair = EllipticCurveProvider.generateKeyPair(SignatureAlgorithm.ES256)
+ def data = withoutSignature.getBytes("US-ASCII")
+ def validator = new EllipticCurveSignatureValidator(SignatureAlgorithm.ES256, keypair.public)
+ assertFalse validator.isValid(data, sig)
+ }
+
+ @Test // asserts guard for JVM security bug CVE-2022-21449:
+ void ecdsaInvalidSignatureValuesTest() {
+ def withoutSignature = "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0ZXN0IjoidGVzdCIsImlhdCI6MTQ2NzA2NTgyN30"
+ def invalidEncodedSignature = "_____wAAAAD__________7zm-q2nF56E87nKwvxjJVH_____AAAAAP__________vOb6racXnoTzucrC_GMlUQ"
+ def keypair = EllipticCurveProvider.generateKeyPair(SignatureAlgorithm.ES256)
+ def data = withoutSignature.getBytes("US-ASCII")
+ def invalidSignature = Decoders.BASE64URL.decode(invalidEncodedSignature)
+ def validator = new EllipticCurveSignatureValidator(SignatureAlgorithm.ES256, keypair.public)
+ assertFalse("Forged signature must not be considered valid.", validator.isValid(data, invalidSignature))
}
@Test
@@ -173,7 +187,7 @@ class EllipticCurveSignatureValidatorTest {
try {
def signature = new byte[257]
SignatureProvider.DEFAULT_SECURE_RANDOM.nextBytes(signature)
- EllipticCurveProvider.transcodeSignatureToDER(signature)
+ EllipticCurveProvider.transcodeConcatToDER(signature)
fail()
} catch (JwtException e) {
assertEquals e.message, 'Invalid ECDSA signature format.'
@@ -184,7 +198,7 @@ class EllipticCurveSignatureValidatorTest {
void invalidDERSignatureToJoseFormatTest() {
def verify = { signature ->
try {
- EllipticCurveProvider.transcodeSignatureToConcat(signature, 132)
+ EllipticCurveProvider.transcodeDERToConcat(signature, 132)
fail()
} catch (JwtException e) {
assertEquals e.message, 'Invalid ECDSA signature format'
@@ -209,14 +223,14 @@ class EllipticCurveSignatureValidatorTest {
def signature = new byte[32]
SignatureProvider.DEFAULT_SECURE_RANDOM.nextBytes(signature)
signature[0] = 0 as byte
- EllipticCurveProvider.transcodeSignatureToDER(signature) //no exception
+ EllipticCurveProvider.transcodeConcatToDER(signature) //no exception
}
@Test
void edgeCaseSignatureToConcatLengthTest() {
try {
def signature = Decoders.BASE64.decode("MIEAAGg3OVb/ZeX12cYrhK3c07TsMKo7Kc6SiqW++4CAZWCX72DkZPGTdCv2duqlupsnZL53hiG3rfdOLj8drndCU+KHGrn5EotCATdMSLCXJSMMJoHMM/ZPG+QOHHPlOWnAvpC1v4lJb32WxMFNz1VAIWrl9Aa6RPG1GcjCTScKjvEE")
- EllipticCurveProvider.transcodeSignatureToConcat(signature, 132)
+ EllipticCurveProvider.transcodeDERToConcat(signature, 132)
fail()
} catch (JwtException e) {
@@ -227,7 +241,7 @@ class EllipticCurveSignatureValidatorTest {
void edgeCaseSignatureToConcatInvalidSignatureTest() {
try {
def signature = Decoders.BASE64.decode("MIGBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA")
- EllipticCurveProvider.transcodeSignatureToConcat(signature, 132)
+ EllipticCurveProvider.transcodeDERToConcat(signature, 132)
fail()
} catch (JwtException e) {
assertEquals e.message, 'Invalid ECDSA signature format'
@@ -238,7 +252,7 @@ class EllipticCurveSignatureValidatorTest {
void edgeCaseSignatureToConcatInvalidSignatureBranchTest() {
try {
def signature = Decoders.BASE64.decode("MIGBAD4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA")
- EllipticCurveProvider.transcodeSignatureToConcat(signature, 132)
+ EllipticCurveProvider.transcodeDERToConcat(signature, 132)
fail()
} catch (JwtException e) {
assertEquals e.message, 'Invalid ECDSA signature format'
@@ -249,7 +263,7 @@ class EllipticCurveSignatureValidatorTest {
void edgeCaseSignatureToConcatInvalidSignatureBranch2Test() {
try {
def signature = Decoders.BASE64.decode("MIGBAj4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA")
- EllipticCurveProvider.transcodeSignatureToConcat(signature, 132)
+ EllipticCurveProvider.transcodeDERToConcat(signature, 132)
fail()
} catch (JwtException e) {
assertEquals e.message, 'Invalid ECDSA signature format'
@@ -260,7 +274,7 @@ class EllipticCurveSignatureValidatorTest {
void verifySwarmTest() {
for (SignatureAlgorithm algorithm : [SignatureAlgorithm.ES256, SignatureAlgorithm.ES384, SignatureAlgorithm.ES512]) {
def withoutSignature = "eyJhbGciOiJFUzUxMiIsInR5cCI6IkpXVCJ9.eyJ0ZXN0IjoidGVzdCIsImlhdCI6MTQ2NzA2NTgyN30"
- def keypair = EllipticCurveProvider.generateKeyPair()
+ def keypair = EllipticCurveProvider.generateKeyPair(algorithm)
def data = withoutSignature.getBytes("US-ASCII")
def signature = new EllipticCurveSigner(algorithm, keypair.private).sign(data)
assert new EllipticCurveSignatureValidator(algorithm, keypair.public).isValid(data, signature)
diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/crypto/EllipticCurveSignerTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/crypto/EllipticCurveSignerTest.groovy
index 97baac2d..d8a27c06 100644
--- a/impl/src/test/groovy/io/jsonwebtoken/impl/crypto/EllipticCurveSignerTest.groovy
+++ b/impl/src/test/groovy/io/jsonwebtoken/impl/crypto/EllipticCurveSignerTest.groovy
@@ -43,13 +43,14 @@ class EllipticCurveSignerTest {
@Test
void testConstructorWithoutECPrivateKey() {
- def key = Keys.secretKeyFor(SignatureAlgorithm.HS256)
+ def pair = Keys.keyPairFor(SignatureAlgorithm.ES256)
try {
- new EllipticCurveSigner(SignatureAlgorithm.ES256, key)
- fail('EllipticCurveSigner should reject non ECPrivateKey instances.')
- } catch (IllegalArgumentException expected) {
- assertEquals expected.message, "Elliptic Curve signatures must be computed using an EC PrivateKey. The specified key of " +
- "type " + key.getClass().getName() + " is not an EC PrivateKey."
+ new EllipticCurveSigner(SignatureAlgorithm.ES256, pair.public)
+ fail('EllipticCurveSigner should reject public ECKey instances.')
+ } catch (io.jsonwebtoken.security.InvalidKeyException expected) {
+ String msg = 'Elliptic Curve signatures must be computed using an EC PrivateKey. The specified key of ' +
+ 'type sun.security.ec.ECPublicKeyImpl is not an EC PrivateKey.'
+ assertEquals(msg, expected.getMessage())
}
}
@@ -59,7 +60,6 @@ class EllipticCurveSignerTest {
SignatureAlgorithm alg = SignatureAlgorithm.ES256
KeyPair kp = Keys.keyPairFor(alg)
- PublicKey publicKey = kp.getPublic()
PrivateKey privateKey = kp.getPrivate()
String msg = 'foo'
@@ -87,14 +87,15 @@ class EllipticCurveSignerTest {
@Test
void testDoSignWithJoseSignatureFormatException() {
- KeyPair kp = EllipticCurveProvider.generateKeyPair()
+ SignatureAlgorithm alg = SignatureAlgorithm.ES256
+ KeyPair kp = EllipticCurveProvider.generateKeyPair(alg)
PublicKey publicKey = kp.getPublic();
PrivateKey privateKey = kp.getPrivate();
String msg = 'foo'
final JwtException ex = new JwtException(msg)
- def signer = new EllipticCurveSigner(SignatureAlgorithm.ES256, privateKey) {
+ def signer = new EllipticCurveSigner(alg, privateKey) {
@Override
protected byte[] doSign(byte[] data) throws InvalidKeyException, java.security.SignatureException, JwtException {
throw ex
@@ -116,14 +117,15 @@ class EllipticCurveSignerTest {
@Test
void testDoSignWithJdkSignatureException() {
- KeyPair kp = EllipticCurveProvider.generateKeyPair()
+ SignatureAlgorithm alg = SignatureAlgorithm.ES256
+ KeyPair kp = EllipticCurveProvider.generateKeyPair(alg)
PublicKey publicKey = kp.getPublic();
PrivateKey privateKey = kp.getPrivate();
String msg = 'foo'
final java.security.SignatureException ex = new java.security.SignatureException(msg)
- def signer = new EllipticCurveSigner(SignatureAlgorithm.ES256, privateKey) {
+ def signer = new EllipticCurveSigner(alg, privateKey) {
@Override
protected byte[] doSign(byte[] data) throws InvalidKeyException, java.security.SignatureException {
throw ex