mirror of https://github.com/jwtk/jjwt.git
0.11.3 to master (#728)
Merged 0.11.3 patch release into mainline development branch
This commit is contained in:
parent
d91881fbac
commit
b78473262d
51
CHANGELOG.md
51
CHANGELOG.md
|
@ -1,12 +1,61 @@
|
||||||
## Release Notes
|
## Release Notes
|
||||||
|
|
||||||
### 0.11.3 (pending release)
|
### 0.11.4 (pending release)
|
||||||
|
|
||||||
This patch release:
|
This patch release:
|
||||||
|
|
||||||
* Adds additional handling for rare JSON parsing exceptions and wraps them in a `JwtException` to allow the application to handle these conditions as JWT concerns.
|
* Adds additional handling for rare JSON parsing exceptions and wraps them in a `JwtException` to allow the application to handle these conditions as JWT concerns.
|
||||||
* Upgrades the `jjwt-jackson` module's Jackson dependency to `2.12.6.1`.
|
* Upgrades the `jjwt-jackson` module's Jackson dependency to `2.12.6.1`.
|
||||||
|
|
||||||
|
### 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.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
Issues included in this patch are listed in the [JJWT 0.11.3 milestone](https://github.com/jwtk/jjwt/milestone/24).
|
||||||
|
|
||||||
|
#### Backwards Compatibility Warning
|
||||||
|
|
||||||
|
In addition to additional protections against
|
||||||
|
[r or s values of zero in ECDSA signatures](https://neilmadden.blog/2022/04/19/psychic-signatures-in-java/), this
|
||||||
|
release also disables by default legacy DER-encoded signatures that might be included in an ECDSA-signed JWT.
|
||||||
|
(DER-encoded signatures are not supported by the JWT RFC specifications, so they are not frequently encountered.)
|
||||||
|
|
||||||
|
However, if you are using an application that needs to consume such legacy JWTs (either produced by a very
|
||||||
|
early version of JJWT, or a different JWT library), you may re-enable DER-encoded ECDSA signatures by setting the
|
||||||
|
`io.jsonwebtoken.impl.crypto.EllipticCurveSignatureValidator.derEncodingSupported` System property to the _exact_
|
||||||
|
`String` value `true`. For example:
|
||||||
|
|
||||||
|
```java
|
||||||
|
System.setProperty("io.jsonwebtoken.impl.crypto.EllipticCurveSignatureValidator.derEncodingSupported", "true");
|
||||||
|
```
|
||||||
|
|
||||||
|
*BUT BE CAREFUL*: **DO NOT** set this System property if your application may run on one of the vulnerable JVMs
|
||||||
|
noted above (Java SE versions 15-15.0.6, 17-17.0.2, and 18).
|
||||||
|
|
||||||
|
You may safely set this property to a `String` value of `true` on all other versions of the JVM if you need to
|
||||||
|
support these legacy JWTs, *otherwise it is best to ignore (not set) the property entirely*.
|
||||||
|
|
||||||
|
#### 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.
|
||||||
|
|
||||||
|
We'd also like to thank Toshiki Sasazaki, a member of [LINE Corporation](https://linecorp.com)'s Application Security
|
||||||
|
Team as the first person to report the concern directly to the JJWT team, as well as for working with us during testing
|
||||||
|
leading to our conclusions and subsequent 0.11.3 patch release.
|
||||||
|
|
||||||
### 0.11.2
|
### 0.11.2
|
||||||
|
|
||||||
This patch release:
|
This patch release:
|
||||||
|
|
30
README.md
30
README.md
|
@ -264,18 +264,18 @@ If you're building a (non-Android) JDK project, you will want to define the foll
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.jsonwebtoken</groupId>
|
<groupId>io.jsonwebtoken</groupId>
|
||||||
<artifactId>jjwt-api</artifactId>
|
<artifactId>jjwt-api</artifactId>
|
||||||
<version>0.11.2</version>
|
<version>0.11.3</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.jsonwebtoken</groupId>
|
<groupId>io.jsonwebtoken</groupId>
|
||||||
<artifactId>jjwt-impl</artifactId>
|
<artifactId>jjwt-impl</artifactId>
|
||||||
<version>0.11.2</version>
|
<version>0.11.3</version>
|
||||||
<scope>runtime</scope>
|
<scope>runtime</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.jsonwebtoken</groupId>
|
<groupId>io.jsonwebtoken</groupId>
|
||||||
<artifactId>jjwt-jackson</artifactId> <!-- or jjwt-gson if Gson is preferred -->
|
<artifactId>jjwt-jackson</artifactId> <!-- or jjwt-gson if Gson is preferred -->
|
||||||
<version>0.11.2</version>
|
<version>0.11.3</version>
|
||||||
<scope>runtime</scope>
|
<scope>runtime</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<!-- Uncomment this next dependency if you are using JDK 10 or earlier and you also want to use
|
<!-- Uncomment this next dependency if you are using JDK 10 or earlier and you also want to use
|
||||||
|
@ -295,11 +295,11 @@ If you're building a (non-Android) JDK project, you will want to define the foll
|
||||||
|
|
||||||
```groovy
|
```groovy
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation 'io.jsonwebtoken:jjwt-api:0.11.2'
|
compile 'io.jsonwebtoken:jjwt-api:0.11.3'
|
||||||
runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.11.2',
|
runtime 'io.jsonwebtoken:jjwt-impl:0.11.3',
|
||||||
// Uncomment the next line if you want to use RSASSA-PSS (PS256, PS384, PS512) algorithms:
|
// Uncomment the next line if you want to use RSASSA-PSS (PS256, PS384, PS512) algorithms:
|
||||||
//'org.bouncycastle:bcprov-jdk15on:1.60',
|
//'org.bouncycastle:bcprov-jdk15on:1.60',
|
||||||
'io.jsonwebtoken:jjwt-jackson:0.11.2' // or 'io.jsonwebtoken:jjwt-gson:0.11.2' for gson
|
'io.jsonwebtoken:jjwt-jackson:0.11.3' // or 'io.jsonwebtoken:jjwt-gson:0.11.3' for gson
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -315,9 +315,9 @@ Add the dependencies to your project:
|
||||||
|
|
||||||
```groovy
|
```groovy
|
||||||
dependencies {
|
dependencies {
|
||||||
api 'io.jsonwebtoken:jjwt-api:0.11.2'
|
api 'io.jsonwebtoken:jjwt-api:0.11.3'
|
||||||
runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.11.2'
|
runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.11.3'
|
||||||
runtimeOnly('io.jsonwebtoken:jjwt-orgjson:0.11.2') {
|
runtimeOnly('io.jsonwebtoken:jjwt-orgjson:0.11.3') {
|
||||||
exclude group: 'org.json', module: 'json' //provided by Android natively
|
exclude group: 'org.json', module: 'json' //provided by Android natively
|
||||||
}
|
}
|
||||||
// Uncomment the next line if you want to use RSASSA-PSS (PS256, PS384, PS512) algorithms:
|
// Uncomment the next line if you want to use RSASSA-PSS (PS256, PS384, PS512) algorithms:
|
||||||
|
@ -1328,7 +1328,7 @@ scope which is the typical JJWT default). That is:
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.jsonwebtoken</groupId>
|
<groupId>io.jsonwebtoken</groupId>
|
||||||
<artifactId>jjwt-jackson</artifactId>
|
<artifactId>jjwt-jackson</artifactId>
|
||||||
<version>0.11.2</version>
|
<version>0.11.3</version>
|
||||||
<scope>compile</scope> <!-- Not runtime -->
|
<scope>compile</scope> <!-- Not runtime -->
|
||||||
</dependency>
|
</dependency>
|
||||||
```
|
```
|
||||||
|
@ -1337,7 +1337,7 @@ scope which is the typical JJWT default). That is:
|
||||||
|
|
||||||
```groovy
|
```groovy
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation 'io.jsonwebtoken:jjwt-jackson:0.11.2'
|
implementation 'io.jsonwebtoken:jjwt-jackson:0.11.3'
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -1436,7 +1436,7 @@ scope which is the typical JJWT default). That is:
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.jsonwebtoken</groupId>
|
<groupId>io.jsonwebtoken</groupId>
|
||||||
<artifactId>jjwt-gson</artifactId>
|
<artifactId>jjwt-gson</artifactId>
|
||||||
<version>0.11.2</version>
|
<version>0.11.3</version>
|
||||||
<scope>compile</scope> <!-- Not runtime -->
|
<scope>compile</scope> <!-- Not runtime -->
|
||||||
</dependency>
|
</dependency>
|
||||||
```
|
```
|
||||||
|
@ -1445,7 +1445,7 @@ scope which is the typical JJWT default). That is:
|
||||||
|
|
||||||
```groovy
|
```groovy
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation 'io.jsonwebtoken:jjwt-gson:0.11.2'
|
implementation 'io.jsonwebtoken:jjwt-gson:0.11.3'
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>io.jsonwebtoken</groupId>
|
<groupId>io.jsonwebtoken</groupId>
|
||||||
<artifactId>jjwt-root</artifactId>
|
<artifactId>jjwt-root</artifactId>
|
||||||
<version>0.11.3-SNAPSHOT</version>
|
<version>0.11.4-SNAPSHOT</version>
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>io.jsonwebtoken</groupId>
|
<groupId>io.jsonwebtoken</groupId>
|
||||||
<artifactId>jjwt-root</artifactId>
|
<artifactId>jjwt-root</artifactId>
|
||||||
<version>0.11.3-SNAPSHOT</version>
|
<version>0.11.4-SNAPSHOT</version>
|
||||||
<relativePath>../../pom.xml</relativePath>
|
<relativePath>../../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>io.jsonwebtoken</groupId>
|
<groupId>io.jsonwebtoken</groupId>
|
||||||
<artifactId>jjwt-root</artifactId>
|
<artifactId>jjwt-root</artifactId>
|
||||||
<version>0.11.3-SNAPSHOT</version>
|
<version>0.11.4-SNAPSHOT</version>
|
||||||
<relativePath>../../pom.xml</relativePath>
|
<relativePath>../../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>io.jsonwebtoken</groupId>
|
<groupId>io.jsonwebtoken</groupId>
|
||||||
<artifactId>jjwt-root</artifactId>
|
<artifactId>jjwt-root</artifactId>
|
||||||
<version>0.11.3-SNAPSHOT</version>
|
<version>0.11.4-SNAPSHOT</version>
|
||||||
<relativePath>../../pom.xml</relativePath>
|
<relativePath>../../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>io.jsonwebtoken</groupId>
|
<groupId>io.jsonwebtoken</groupId>
|
||||||
<artifactId>jjwt-root</artifactId>
|
<artifactId>jjwt-root</artifactId>
|
||||||
<version>0.11.3-SNAPSHOT</version>
|
<version>0.11.4-SNAPSHOT</version>
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>io.jsonwebtoken</groupId>
|
<groupId>io.jsonwebtoken</groupId>
|
||||||
<artifactId>jjwt-root</artifactId>
|
<artifactId>jjwt-root</artifactId>
|
||||||
<version>0.11.3-SNAPSHOT</version>
|
<version>0.11.4-SNAPSHOT</version>
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@ import io.jsonwebtoken.JwtException;
|
||||||
import io.jsonwebtoken.SignatureAlgorithm;
|
import io.jsonwebtoken.SignatureAlgorithm;
|
||||||
import io.jsonwebtoken.lang.Assert;
|
import io.jsonwebtoken.lang.Assert;
|
||||||
import io.jsonwebtoken.lang.Strings;
|
import io.jsonwebtoken.lang.Strings;
|
||||||
|
import io.jsonwebtoken.security.SignatureException;
|
||||||
|
|
||||||
import java.security.Key;
|
import java.security.Key;
|
||||||
import java.security.KeyPair;
|
import java.security.KeyPair;
|
||||||
|
@ -238,6 +239,15 @@ public abstract class EllipticCurveProvider extends SignatureProvider {
|
||||||
* @throws JwtException If the ECDSA JWS signature format is invalid.
|
* @throws JwtException If the ECDSA JWS signature format is invalid.
|
||||||
*/
|
*/
|
||||||
public static byte[] transcodeSignatureToDER(byte[] jwsSignature) throws JwtException {
|
public static byte[] transcodeSignatureToDER(byte[] jwsSignature) throws JwtException {
|
||||||
|
try {
|
||||||
|
return concatToDER(jwsSignature);
|
||||||
|
} catch (Exception e) { // CVE-2022-21449 guard
|
||||||
|
String msg = "Invalid ECDSA signature format.";
|
||||||
|
throw new SignatureException(msg, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static byte[] concatToDER(byte[] jwsSignature) throws ArrayIndexOutOfBoundsException {
|
||||||
|
|
||||||
int rawLen = jwsSignature.length / 2;
|
int rawLen = jwsSignature.length / 2;
|
||||||
|
|
||||||
|
@ -247,6 +257,10 @@ public abstract class EllipticCurveProvider extends SignatureProvider {
|
||||||
i--;
|
i--;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (i == 0) { // r == 0, JVM bug CVE-2202-21449 guard:
|
||||||
|
throw new JwtException("Invalid ECDSA Signature format");
|
||||||
|
}
|
||||||
|
|
||||||
int j = i;
|
int j = i;
|
||||||
|
|
||||||
if (jwsSignature[rawLen - i] < 0) {
|
if (jwsSignature[rawLen - i] < 0) {
|
||||||
|
@ -273,7 +287,7 @@ public abstract class EllipticCurveProvider extends SignatureProvider {
|
||||||
|
|
||||||
int offset;
|
int offset;
|
||||||
|
|
||||||
final byte derSignature[];
|
final byte[] derSignature;
|
||||||
|
|
||||||
if (len < 128) {
|
if (len < 128) {
|
||||||
derSignature = new byte[2 + 2 + j + 2 + l];
|
derSignature = new byte[2 + 2 + j + 2 + l];
|
||||||
|
|
|
@ -30,6 +30,9 @@ public class EllipticCurveSignatureValidator extends EllipticCurveProvider imple
|
||||||
private static final String EC_PUBLIC_KEY_REQD_MSG =
|
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";
|
||||||
|
|
||||||
public EllipticCurveSignatureValidator(SignatureAlgorithm alg, Key key) {
|
public EllipticCurveSignatureValidator(SignatureAlgorithm alg, Key key) {
|
||||||
super(alg, key);
|
super(alg, key);
|
||||||
Assert.isTrue(key instanceof ECPublicKey, EC_PUBLIC_KEY_REQD_MSG);
|
Assert.isTrue(key instanceof ECPublicKey, EC_PUBLIC_KEY_REQD_MSG);
|
||||||
|
@ -41,14 +44,20 @@ public class EllipticCurveSignatureValidator extends EllipticCurveProvider imple
|
||||||
PublicKey publicKey = (PublicKey) key;
|
PublicKey publicKey = (PublicKey) key;
|
||||||
try {
|
try {
|
||||||
int expectedSize = getSignatureByteArrayLength(alg);
|
int expectedSize = getSignatureByteArrayLength(alg);
|
||||||
/**
|
/*
|
||||||
*
|
* If the expected size is not valid for JOSE, fall back to ASN.1 DER signature IFF the application
|
||||||
* If the expected size is not valid for JOSE, fall back to ASN.1 DER signature.
|
* is configured to do so. This fallback is for backwards compatibility ONLY (to support tokens
|
||||||
* This fallback is for backwards compatibility ONLY (to support tokens generated by previous versions of jjwt)
|
* generated by early versions of jjwt) and backwards compatibility will be removed in a future
|
||||||
* and backwards compatibility will possibly be removed in a future version of this library.
|
* 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.
|
||||||
* **/
|
*/
|
||||||
byte[] derSignature = expectedSize != signature.length && signature[0] == 0x30 ? signature : EllipticCurveProvider.transcodeSignatureToDER(signature);
|
//TODO: remove for 1.0 (DER-encoding support is not in the JWT RFCs)
|
||||||
|
byte[] derSignature;
|
||||||
|
if (expectedSize != signature.length && signature[0] == 0x30 && "true".equalsIgnoreCase(System.getProperty(DER_ENCODING_SYS_PROPERTY_NAME))) {
|
||||||
|
derSignature = signature;
|
||||||
|
} else {
|
||||||
|
derSignature = EllipticCurveProvider.transcodeSignatureToDER(signature);
|
||||||
|
}
|
||||||
return doVerify(sig, publicKey, data, derSignature);
|
return doVerify(sig, publicKey, data, derSignature);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
String msg = "Unable to verify Elliptic Curve signature using configured ECPublicKey. " + e.getMessage();
|
String msg = "Unable to verify Elliptic Curve signature using configured ECPublicKey. " + e.getMessage();
|
||||||
|
|
|
@ -21,7 +21,10 @@ import io.jsonwebtoken.io.Decoders
|
||||||
import io.jsonwebtoken.security.SignatureException
|
import io.jsonwebtoken.security.SignatureException
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
|
||||||
import java.security.*
|
import java.security.InvalidKeyException
|
||||||
|
import java.security.KeyFactory
|
||||||
|
import java.security.PublicKey
|
||||||
|
import java.security.Signature
|
||||||
import java.security.spec.X509EncodedKeySpec
|
import java.security.spec.X509EncodedKeySpec
|
||||||
|
|
||||||
import static org.junit.Assert.*
|
import static org.junit.Assert.*
|
||||||
|
@ -73,8 +76,8 @@ class EllipticCurveSignatureValidatorTest {
|
||||||
verifier("eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzUxMiJ9.eyJ0ZXN0IjoidGVzdCJ9.AV26tERbSEwcoDGshneZmhokg-tAKUk0uQBoHBohveEd51D5f6EIs6cskkgwtfzs4qAGfx2rYxqQXr7LTXCNquKiAJNkTIKVddbPfped3_TQtmHZTmMNiqmWjiFj7Y9eTPMMRRu26w4gD1a8EQcBF-7UGgeH4L_1CwHJWAXGbtu7uMUn")
|
verifier("eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzUxMiJ9.eyJ0ZXN0IjoidGVzdCJ9.AV26tERbSEwcoDGshneZmhokg-tAKUk0uQBoHBohveEd51D5f6EIs6cskkgwtfzs4qAGfx2rYxqQXr7LTXCNquKiAJNkTIKVddbPfped3_TQtmHZTmMNiqmWjiFj7Y9eTPMMRRu26w4gD1a8EQcBF-7UGgeH4L_1CwHJWAXGbtu7uMUn")
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test // asserts guard for JVM security bug CVE-2022-21449:
|
||||||
void legacySignatureCompatTest() {
|
void legacySignatureCompatDefaultTest() {
|
||||||
def withoutSignature = "eyJhbGciOiJFUzUxMiIsInR5cCI6IkpXVCJ9.eyJ0ZXN0IjoidGVzdCIsImlhdCI6MTQ2NzA2NTgyN30"
|
def withoutSignature = "eyJhbGciOiJFUzUxMiIsInR5cCI6IkpXVCJ9.eyJ0ZXN0IjoidGVzdCIsImlhdCI6MTQ2NzA2NTgyN30"
|
||||||
def keypair = EllipticCurveProvider.generateKeyPair()
|
def keypair = EllipticCurveProvider.generateKeyPair()
|
||||||
def signature = Signature.getInstance(SignatureAlgorithm.ES512.jcaName)
|
def signature = Signature.getInstance(SignatureAlgorithm.ES512.jcaName)
|
||||||
|
@ -82,7 +85,76 @@ class EllipticCurveSignatureValidatorTest {
|
||||||
signature.initSign(keypair.private)
|
signature.initSign(keypair.private)
|
||||||
signature.update(data)
|
signature.update(data)
|
||||||
def signed = signature.sign()
|
def signed = signature.sign()
|
||||||
assert new EllipticCurveSignatureValidator(SignatureAlgorithm.ES512, keypair.public).isValid(data, signed)
|
assertFalse new EllipticCurveSignatureValidator(SignatureAlgorithm.ES512, keypair.public).isValid(data, signed)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void legacySignatureCompatWhenEnabledTest() {
|
||||||
|
try {
|
||||||
|
System.setProperty(EllipticCurveSignatureValidator.DER_ENCODING_SYS_PROPERTY_NAME, 'true')
|
||||||
|
def withoutSignature = "eyJhbGciOiJFUzUxMiIsInR5cCI6IkpXVCJ9.eyJ0ZXN0IjoidGVzdCIsImlhdCI6MTQ2NzA2NTgyN30"
|
||||||
|
def keypair = EllipticCurveProvider.generateKeyPair()
|
||||||
|
def signature = Signature.getInstance(SignatureAlgorithm.ES512.jcaName)
|
||||||
|
def data = withoutSignature.getBytes("US-ASCII")
|
||||||
|
signature.initSign(keypair.private)
|
||||||
|
signature.update(data)
|
||||||
|
def signed = signature.sign()
|
||||||
|
assertTrue new EllipticCurveSignatureValidator(SignatureAlgorithm.ES512, keypair.public).isValid(data, signed)
|
||||||
|
} finally {
|
||||||
|
System.clearProperty(EllipticCurveSignatureValidator.DER_ENCODING_SYS_PROPERTY_NAME)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@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)
|
||||||
|
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@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)
|
||||||
|
|
||||||
|
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()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -104,7 +176,7 @@ class EllipticCurveSignatureValidatorTest {
|
||||||
EllipticCurveProvider.transcodeSignatureToDER(signature)
|
EllipticCurveProvider.transcodeSignatureToDER(signature)
|
||||||
fail()
|
fail()
|
||||||
} catch (JwtException e) {
|
} catch (JwtException e) {
|
||||||
assertEquals e.message, 'Invalid ECDSA signature format'
|
assertEquals e.message, 'Invalid ECDSA signature format.'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -132,12 +204,6 @@ class EllipticCurveSignatureValidatorTest {
|
||||||
verify(signature)
|
verify(signature)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
void edgeCaseSignatureLengthTest() {
|
|
||||||
def signature = new byte[1]
|
|
||||||
EllipticCurveProvider.transcodeSignatureToDER(signature)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testPaddedSignatureToDER() {
|
void testPaddedSignatureToDER() {
|
||||||
def signature = new byte[32]
|
def signature = new byte[32]
|
||||||
|
|
137
pom.xml
137
pom.xml
|
@ -17,15 +17,9 @@
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
<parent>
|
|
||||||
<groupId>org.sonatype.oss</groupId>
|
|
||||||
<artifactId>oss-parent</artifactId>
|
|
||||||
<version>7</version>
|
|
||||||
</parent>
|
|
||||||
|
|
||||||
<groupId>io.jsonwebtoken</groupId>
|
<groupId>io.jsonwebtoken</groupId>
|
||||||
<artifactId>jjwt-root</artifactId>
|
<artifactId>jjwt-root</artifactId>
|
||||||
<version>0.11.3-SNAPSHOT</version>
|
<version>0.11.4-SNAPSHOT</version>
|
||||||
<name>JJWT</name>
|
<name>JJWT</name>
|
||||||
<description>JSON Web Token support for the JVM and Android</description>
|
<description>JSON Web Token support for the JVM and Android</description>
|
||||||
<packaging>pom</packaging>
|
<packaging>pom</packaging>
|
||||||
|
@ -40,11 +34,20 @@
|
||||||
<licenses>
|
<licenses>
|
||||||
<license>
|
<license>
|
||||||
<name>Apache License, Version 2.0</name>
|
<name>Apache License, Version 2.0</name>
|
||||||
<url>http://www.apache.org/licenses/LICENSE-2.0</url>
|
<url>https://www.apache.org/licenses/LICENSE-2.0</url>
|
||||||
<distribution>repo</distribution>
|
<distribution>repo</distribution>
|
||||||
</license>
|
</license>
|
||||||
</licenses>
|
</licenses>
|
||||||
|
|
||||||
|
<developers>
|
||||||
|
<developer>
|
||||||
|
<name>Les Hazlewood</name>
|
||||||
|
<email>121180+lhazlewood@users.noreply.github.com</email>
|
||||||
|
<organization>JJWT</organization>
|
||||||
|
<organizationUrl>https://github.com/jwtk/jjwt</organizationUrl>
|
||||||
|
</developer>
|
||||||
|
</developers>
|
||||||
|
|
||||||
<scm>
|
<scm>
|
||||||
<connection>scm:git:https://github.com/jwtk/jjwt.git</connection>
|
<connection>scm:git:https://github.com/jwtk/jjwt.git</connection>
|
||||||
<developerConnection>scm:git:git@github.com:jwtk/jjwt.git</developerConnection>
|
<developerConnection>scm:git:git@github.com:jwtk/jjwt.git</developerConnection>
|
||||||
|
@ -59,8 +62,54 @@
|
||||||
<system>TravisCI</system>
|
<system>TravisCI</system>
|
||||||
<url>https://travis-ci.org/jwtk/jjwt</url>
|
<url>https://travis-ci.org/jwtk/jjwt</url>
|
||||||
</ciManagement>
|
</ciManagement>
|
||||||
|
<distributionManagement>
|
||||||
|
<snapshotRepository>
|
||||||
|
<id>ossrh</id>
|
||||||
|
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
|
||||||
|
</snapshotRepository>
|
||||||
|
<repository>
|
||||||
|
<id>ossrh</id>
|
||||||
|
<url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
|
||||||
|
</repository>
|
||||||
|
</distributionManagement>
|
||||||
|
|
||||||
|
<!-- temporary fix until official release of coverall-maven-plugin with clover support -->
|
||||||
|
<repositories>
|
||||||
|
<repository>
|
||||||
|
<id>ossrh</id>
|
||||||
|
<name>Sonatype Nexus Snapshots</name>
|
||||||
|
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
|
||||||
|
<releases>
|
||||||
|
<enabled>false</enabled>
|
||||||
|
</releases>
|
||||||
|
<snapshots>
|
||||||
|
<enabled>true</enabled>
|
||||||
|
</snapshots>
|
||||||
|
</repository>
|
||||||
|
<repository>
|
||||||
|
<snapshots>
|
||||||
|
<enabled>false</enabled>
|
||||||
|
</snapshots>
|
||||||
|
<id>bintray-jwtk-coveralls-maven-plugin</id>
|
||||||
|
<name>bintray</name>
|
||||||
|
<url>https://dl.bintray.com/jwtk/coveralls-maven-plugin</url>
|
||||||
|
</repository>
|
||||||
|
</repositories>
|
||||||
|
<pluginRepositories>
|
||||||
|
<pluginRepository>
|
||||||
|
<snapshots>
|
||||||
|
<enabled>false</enabled>
|
||||||
|
</snapshots>
|
||||||
|
<id>bintray-jwtk-coveralls-maven-plugin</id>
|
||||||
|
<name>bintray-plugins</name>
|
||||||
|
<url>https://dl.bintray.com/jwtk/coveralls-maven-plugin</url>
|
||||||
|
</pluginRepository>
|
||||||
|
</pluginRepositories>
|
||||||
|
<!-- temporary fix until official release of coverall-maven-plugin with clover support -->
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
<arguments/>
|
||||||
|
|
||||||
<jjwt.root>${basedir}</jjwt.root>
|
<jjwt.root>${basedir}</jjwt.root>
|
||||||
<jjwt.previousVersion>0.10.7</jjwt.previousVersion>
|
<jjwt.previousVersion>0.10.7</jjwt.previousVersion>
|
||||||
|
@ -71,7 +120,6 @@
|
||||||
<gmavenplus.version>1.6.1</gmavenplus.version>
|
<gmavenplus.version>1.6.1</gmavenplus.version>
|
||||||
|
|
||||||
<jdk.version>1.7</jdk.version>
|
<jdk.version>1.7</jdk.version>
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
|
||||||
<buildNumber>${user.name}-${maven.build.timestamp}</buildNumber>
|
<buildNumber>${user.name}-${maven.build.timestamp}</buildNumber>
|
||||||
|
|
||||||
<jackson.version>2.12.6.1</jackson.version>
|
<jackson.version>2.12.6.1</jackson.version>
|
||||||
|
@ -204,6 +252,16 @@
|
||||||
<build>
|
<build>
|
||||||
<pluginManagement>
|
<pluginManagement>
|
||||||
<plugins>
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-release-plugin</artifactId>
|
||||||
|
<version>2.5.3</version>
|
||||||
|
<configuration>
|
||||||
|
<mavenExecutorId>forked-path</mavenExecutorId>
|
||||||
|
<useReleaseProfile>false</useReleaseProfile>
|
||||||
|
<arguments>${arguments} -Possrh</arguments>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.openclover</groupId>
|
<groupId>org.openclover</groupId>
|
||||||
<artifactId>clover-maven-plugin</artifactId>
|
<artifactId>clover-maven-plugin</artifactId>
|
||||||
|
@ -455,10 +513,21 @@
|
||||||
<configuration>
|
<configuration>
|
||||||
<mavenExecutorId>forked-path</mavenExecutorId>
|
<mavenExecutorId>forked-path</mavenExecutorId>
|
||||||
<useReleaseProfile>false</useReleaseProfile>
|
<useReleaseProfile>false</useReleaseProfile>
|
||||||
<arguments>-Psonatype-oss-release -Pdocs -Psign</arguments>
|
<arguments>-Possrh -Pdocs -Psign</arguments>
|
||||||
<autoVersionSubmodules>true</autoVersionSubmodules>
|
<autoVersionSubmodules>true</autoVersionSubmodules>
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.sonatype.plugins</groupId>
|
||||||
|
<artifactId>nexus-staging-maven-plugin</artifactId>
|
||||||
|
<version>1.6.7</version>
|
||||||
|
<extensions>true</extensions>
|
||||||
|
<configuration>
|
||||||
|
<serverId>ossrh</serverId>
|
||||||
|
<nexusUrl>https://oss.sonatype.org/</nexusUrl>
|
||||||
|
<autoReleaseAfterClose>false</autoReleaseAfterClose>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.felix</groupId>
|
<groupId>org.apache.felix</groupId>
|
||||||
<artifactId>maven-bundle-plugin</artifactId>
|
<artifactId>maven-bundle-plugin</artifactId>
|
||||||
|
@ -502,7 +571,6 @@
|
||||||
</plugin>
|
</plugin>
|
||||||
<!-- Temporarily host coveralls SNAPSHOT with clover support locally -->
|
<!-- Temporarily host coveralls SNAPSHOT with clover support locally -->
|
||||||
|
|
||||||
<!-- Override OSS parent to support Java 9 -->
|
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-javadoc-plugin</artifactId>
|
<artifactId>maven-javadoc-plugin</artifactId>
|
||||||
|
@ -615,5 +683,52 @@
|
||||||
</plugins>
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
</profile>
|
</profile>
|
||||||
|
<profile>
|
||||||
|
<id>ossrh</id>
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-source-plugin</artifactId>
|
||||||
|
<version>2.1.2</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>attach-sources</id>
|
||||||
|
<goals>
|
||||||
|
<goal>jar-no-fork</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-javadoc-plugin</artifactId>
|
||||||
|
<version>2.7</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>attach-javadocs</id>
|
||||||
|
<goals>
|
||||||
|
<goal>jar</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-gpg-plugin</artifactId>
|
||||||
|
<version>1.1</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>sign-artifacts</id>
|
||||||
|
<phase>verify</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>sign</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
</profile>
|
||||||
</profiles>
|
</profiles>
|
||||||
</project>
|
</project>
|
||||||
|
|
Loading…
Reference in New Issue