Ensured BouncyCastle was optional. Also ensured EllipticCurve algorithms could be used without BouncyCastle since the JDK supports EC by default. Moved RuntimeEnvironment.enableBouncyCastleIfPossible() call out of SignatureAlgorithm into RsaProvider since BC is only necessary for RSASSA-PSS algorithms (PS256, PS384, PS512) and nothing else in JJWT's codebase.

Resolves #372
This commit is contained in:
Les Hazlewood 2018-08-02 15:31:13 -04:00
parent b58e1b6dc5
commit 7f662627cc
18 changed files with 107 additions and 113 deletions

View File

@ -3,13 +3,16 @@
#sudo: required
language: java
jdk:
- openjdk7
- oraclejdk7
- oraclejdk8
- oraclejdk9
- oraclejdk10
- openjdk10
before_install:
- if [ "${TRAVIS_JDK_VERSION}" == "oraclejdk7" ]; then export MAVEN_OPTS="-Dhttps.protocols=TLSv1.2 -Xmx512m -XX:MaxPermSize=128m"; fi
- if [ "${TRAVIS_JDK_VERSION}" == "oraclejdk7" ]; then export JAVA_HOME="/usr/lib/jvm/java-7-oracle"; export PATH="${JAVA_HOME}/bin:${PATH}"; fi
- if [ "${TRAVIS_JDK_VERSION}" == "oraclejdk7" ]; then test ! -d "${JAVA_HOME}" && (curl http://ftp.osuosl.org/pub/funtoo/distfiles/oracle-java/jdk-7u80-linux-x64.tar.gz | sudo tar xz -C /usr/lib/jvm; sudo mv /usr/lib/jvm/jdk1.7.0_80 "${JAVA_HOME}"); fi
- export BUILD_COVERAGE="$([ $TRAVIS_JDK_VERSION == 'oraclejdk8' ] && echo 'true')"
install: true

View File

@ -1,5 +1,16 @@
## Release Notes
### 0.10.1
This is a minor point release that ensures the BouncyCastle dependency is optional and not pulled in as a transitive
dependency into projects.
Internal implementation code (not impacting the JJWT API) and documentation was also updated to reflect that all
Elliptic Curve algorithms are standard on the JDK and do not require Bouncy Castle.
Bouncy Castle is only needed when using PS256, PS384, and PS512 signature algorithms on < JDK 11.
[JDK 11 and later](https://bugs.openjdk.java.net/browse/JDK-8146293) supports these algorithms natively.
### 0.10.0
This is a fairly large feature enhancement release that enables the following:

View File

@ -84,17 +84,17 @@ enforcement.
* HS256: HMAC using SHA-256
* HS384: HMAC using SHA-384
* HS512: HMAC using SHA-512
* ES256: ECDSA using P-256 and SHA-256
* ES384: ECDSA using P-384 and SHA-384
* ES512: ECDSA using P-521 and SHA-512
* RS256: RSASSA-PKCS-v1_5 using SHA-256
* RS384: RSASSA-PKCS-v1_5 using SHA-384
* RS512: RSASSA-PKCS-v1_5 using SHA-512
* PS256: RSASSA-PSS using SHA-256 and MGF1 with SHA-256<sup>1</sup>
* PS384: RSASSA-PSS using SHA-384 and MGF1 with SHA-384<sup>1</sup>
* PS512: RSASSA-PSS using SHA-512 and MGF1 with SHA-512<sup>1</sup>
* ES256: ECDSA using P-256 and SHA-256<sup>1</sup>
* ES384: ECDSA using P-384 and SHA-384<sup>1</sup>
* ES512: ECDSA using P-521 and SHA-512<sup>1</sup>
<sup>1. Requires a compatible JCA Provider (like BouncyCastle) in the runtime classpath.</sup>
<sup>1. Requires JDK 11 or a compatible JCA Provider (like BouncyCastle) in the runtime classpath.</sup>
* Convenience enhancements beyond the specification such as
* Body compression for any large JWT, not just JWEs
* Claims assertions (requiring specific values)
@ -179,22 +179,21 @@ If you're building a (non-Android) JDK project, you will want to define the foll
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.10.0</version>
<version>0.10.1</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.10.0</version>
<version>0.10.1</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>0.10.0</version>
<version>0.10.1</version>
<scope>runtime</scope>
</dependency>
<!-- Uncomment this next dependency if you want to use Elliptic Curve (ES256, ES384, ES512)
or RSASSA-PSS (PS256, PS384, PS512) algorithms:
<!-- Uncomment this next dependency if you want to use RSASSA-PSS (PS256, PS384, PS512) algorithms:
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
@ -205,18 +204,16 @@ If you're building a (non-Android) JDK project, you will want to define the foll
```
Note: The above `jjwt-jackson` dependency requires Jackson 2.x.
<a name="install-jdk-gradle"></a>
#### Gradle
```groovy
dependencies {
compile 'io.jsonwebtoken:jjwt-api:0.10.0'
runtime 'io.jsonwebtoken:jjwt-impl:0.10.0',
// Uncomment the next line if you want to use Elliptic Curve or RSASSA-PSS algorithms:
compile 'io.jsonwebtoken:jjwt-api:0.10.1'
runtime 'io.jsonwebtoken:jjwt-impl:0.10.1',
// Uncomment the next line if you want to use RSASSA-PSS (PS256, PS384, PS512) algorithms:
//'org.bouncycastle:bcprov-jdk15on:1.60',
'io.jsonwebtoken:jjwt-jackson:0.10.0'
'io.jsonwebtoken:jjwt-jackson:0.10.1'
}
```
@ -232,12 +229,12 @@ Add the dependencies to your project:
```groovy
dependencies {
compile 'io.jsonwebtoken:jjwt-api:0.10.0'
runtime 'io.jsonwebtoken:jjwt-impl:0.10.0'
runtime('io.jsonwebtoken:jjwt-orgjson:0.10.0') {
compile 'io.jsonwebtoken:jjwt-api:0.10.1'
runtime 'io.jsonwebtoken:jjwt-impl:0.10.1'
runtime('io.jsonwebtoken:jjwt-orgjson:0.10.1') {
exclude group: 'org.json', module: 'json' //provided by Android natively
}
// Uncomment the next line if you want to use Elliptic Curve or RSASSA-PSS algorithms:
// Uncomment the next line if you want to use RSASSA-PSS (PS256, PS384, PS512) algorithms:
//runtime 'org.bouncycastle:bcprov-jdk15on:1.60'
}
```
@ -433,15 +430,15 @@ key algorithms - identified by the following names:
* `HS256`: HMAC using SHA-256
* `HS384`: HMAC using SHA-384
* `HS512`: HMAC using SHA-512
* `ES256`: ECDSA using P-256 and SHA-256
* `ES384`: ECDSA using P-384 and SHA-384
* `ES512`: ECDSA using P-521 and SHA-512
* `RS256`: RSASSA-PKCS-v1_5 using SHA-256
* `RS384`: RSASSA-PKCS-v1_5 using SHA-384
* `RS512`: RSASSA-PKCS-v1_5 using SHA-512
* `PS256`: RSASSA-PSS using SHA-256 and MGF1 with SHA-256
* `PS384`: RSASSA-PSS using SHA-384 and MGF1 with SHA-384
* `PS512`: RSASSA-PSS using SHA-512 and MGF1 with SHA-512
* `ES256`: ECDSA using P-256 and SHA-256
* `ES384`: ECDSA using P-384 and SHA-384
* `ES512`: ECDSA using P-521 and SHA-512
These are all represented in the `io.jsonwebtoken.SignatureAlgorithm` enum.
@ -549,10 +546,10 @@ KeyPair keyPair = Keys.keyPairFor(SignatureAlgorithm.RS256); //or RS384, RS512,
You use the private key (`keyPair.getPrivate()`) to create a JWS and the public key (`keyPair.getPublic()`) to
parse/verify a JWS.
**NOTE: The `PS256`, `PS384`, `PS512`, `ES256`, `ES384`, and `ES512` algorithms are not provided by the JDK by
default.** If you want to use them, you must enable a JCA provider in the JDK that supports those algorithms
(such as BouncyCastle). See the [Installation](#Installation) section to see how to enable BouncyCastle if you want
to usse these algorithms.
**NOTE: The `PS256`, `PS384`, and `PS512` algorithms require JDK 11 or a compatible JCA Provider
(like BouncyCastle) in the runtime classpath.** If you are using JDK 10 or earlier and you want to use them, see
the [Installation](#Installation) section to see how to enable BouncyCastle. All other algorithms are natively
supported by the JDK.
<a name="jws-create"></a>
### Creating a JWS
@ -1195,7 +1192,7 @@ scope which is the typical JJWT default). That is:
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>0.10.0</version>
<version>0.10.1</version>
<scope>compile</scope> <!-- Not runtime -->
</dependency>
```
@ -1204,7 +1201,7 @@ scope which is the typical JJWT default). That is:
```groovy
dependencies {
compile 'io.jsonwebtoken:jjwt-jackson:0.10.0'
compile 'io.jsonwebtoken:jjwt-jackson:0.10.1'
}
```

View File

@ -21,7 +21,7 @@
<parent>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-root</artifactId>
<version>0.11.0-SNAPSHOT</version>
<version>0.10.1-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -15,7 +15,6 @@
*/
package io.jsonwebtoken;
import io.jsonwebtoken.lang.RuntimeEnvironment;
import io.jsonwebtoken.security.InvalidKeyException;
import io.jsonwebtoken.security.Keys;
import io.jsonwebtoken.security.SignatureException;
@ -74,25 +73,19 @@ public enum SignatureAlgorithm {
RS512("RS512", "RSASSA-PKCS-v1_5 using SHA-512", "RSA", "SHA512withRSA", true, 512, 2048),
/**
* JWA algorithm name for {@code ECDSA using P-256 and SHA-256}. <b>This is not a JDK standard algorithm and
* requires that a JCA provider like BouncyCastle be in the runtime classpath.</b> BouncyCastle will be used
* automatically if found in the runtime classpath.
* JWA algorithm name for {@code ECDSA using P-256 and SHA-256}
*/
ES256("ES256", "ECDSA using P-256 and SHA-256", "ECDSA", "SHA256withECDSA", false, 256, 256),
ES256("ES256", "ECDSA using P-256 and SHA-256", "ECDSA", "SHA256withECDSA", true, 256, 256),
/**
* JWA algorithm name for {@code ECDSA using P-384 and SHA-384}. <b>This is not a JDK standard algorithm and
* requires that a JCA provider like BouncyCastle be in the runtime classpath.</b> BouncyCastle will be used
* automatically if found in the runtime classpath.
* JWA algorithm name for {@code ECDSA using P-384 and SHA-384}
*/
ES384("ES384", "ECDSA using P-384 and SHA-384", "ECDSA", "SHA384withECDSA", false, 384, 384),
ES384("ES384", "ECDSA using P-384 and SHA-384", "ECDSA", "SHA384withECDSA", true, 384, 384),
/**
* JWA algorithm name for {@code ECDSA using P-521 and SHA-512}. <b>This is not a JDK standard algorithm and
* requires that a JCA provider like BouncyCastle be in the runtime classpath.</b> BouncyCastle will be used
* automatically if found in the runtime classpath.
* JWA algorithm name for {@code ECDSA using P-521 and SHA-512}
*/
ES512("ES512", "ECDSA using P-521 and SHA-512", "ECDSA", "SHA512withECDSA", false, 512, 521),
ES512("ES512", "ECDSA using P-521 and SHA-512", "ECDSA", "SHA512withECDSA", true, 512, 521),
/**
* JWA algorithm name for {@code RSASSA-PSS using SHA-256 and MGF1 with SHA-256}. <b>This is not a JDK standard
@ -115,10 +108,6 @@ public enum SignatureAlgorithm {
*/
PS512("PS512", "RSASSA-PSS using SHA-512 and MGF1 with SHA-512", "RSA", "SHA512withRSAandMGF1", false, 512, 2048);
static {
RuntimeEnvironment.enableBouncyCastleIfPossible();
}
//purposefully ordered higher to lower:
private static final List<SignatureAlgorithm> PREFERRED_HMAC_ALGS = Collections.unmodifiableList(Arrays.asList(
SignatureAlgorithm.HS512, SignatureAlgorithm.HS384, SignatureAlgorithm.HS256));

View File

@ -160,17 +160,8 @@ class JwtsTest {
mockStatic(Classes)
//JwtBuilder loads SignatureAlgorithm which in turn uses RuntimeEnvironment which in turn checks for BC:
expect(Classes.isAvailable(eq("org.bouncycastle.jce.provider.BouncyCastleProvider"))).andReturn(false)
replay Classes
def instance = createMock(JwtBuilder)
verify Classes
reset Classes
expect(Classes.newInstance(eq("io.jsonwebtoken.impl.DefaultJwtBuilder"))).andReturn(instance)
replay Classes, instance

View File

@ -121,7 +121,7 @@ class SignatureAlgorithmTest {
@Test
void testIsJdkStandard() {
for (SignatureAlgorithm alg : SignatureAlgorithm.values()) {
if (alg.name().startsWith("ES") || alg.name().startsWith("PS") || alg == SignatureAlgorithm.NONE) {
if (alg.name().startsWith("PS") || alg == SignatureAlgorithm.NONE) {
assertFalse alg.isJdkStandard()
} else {
assertTrue alg.isJdkStandard()

View File

@ -21,7 +21,7 @@
<parent>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-root</artifactId>
<version>0.11.0-SNAPSHOT</version>
<version>0.10.1-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>

View File

@ -21,7 +21,7 @@
<parent>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-root</artifactId>
<version>0.11.0-SNAPSHOT</version>
<version>0.10.1-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>

View File

@ -21,7 +21,7 @@
<parent>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-root</artifactId>
<version>0.11.0-SNAPSHOT</version>
<version>0.10.1-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -21,7 +21,7 @@
<parent>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-root</artifactId>
<version>0.11.0-SNAPSHOT</version>
<version>0.10.1-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
@ -38,11 +38,12 @@
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>

View File

@ -18,11 +18,13 @@ package io.jsonwebtoken.impl.crypto;
import io.jsonwebtoken.JwtException;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.lang.Assert;
import io.jsonwebtoken.lang.Strings;
import java.security.Key;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.SecureRandom;
import java.security.spec.ECGenParameterSpec;
import java.util.HashMap;
import java.util.Map;
@ -85,10 +87,8 @@ public abstract class EllipticCurveProvider extends SignatureProvider {
* Generates a new secure-random key pair of sufficient strength for the specified Elliptic Curve {@link
* SignatureAlgorithm} (must be one of {@code ES256}, {@code ES384} or {@code ES512}) using the specified {@link
* SecureRandom} random number generator. This is a convenience method that immediately delegates to {@link
* #generateKeyPair(String, String, SignatureAlgorithm, SecureRandom)} using {@code "ECDSA"} as the {@code
* jcaAlgorithmName} and {@code "BC"} as the {@code jcaProviderName} since EllipticCurve requires the use of an
* external JCA provider ({@code BC stands for BouncyCastle}. This will work as expected as long as the
* BouncyCastle dependency is in the runtime classpath.
* #generateKeyPair(String, String, SignatureAlgorithm, SecureRandom)} using {@code "EC"} as the {@code
* jcaAlgorithmName}.
*
* @param alg alg the algorithm indicating strength, must be one of {@code ES256}, {@code ES384} or {@code
* ES512}
@ -101,7 +101,7 @@ public abstract class EllipticCurveProvider extends SignatureProvider {
* @see #generateKeyPair(String, String, SignatureAlgorithm, SecureRandom)
*/
public static KeyPair generateKeyPair(SignatureAlgorithm alg, SecureRandom random) {
return generateKeyPair("ECDSA", "BC", alg, random);
return generateKeyPair("EC", null, alg, random);
}
/**
@ -111,8 +111,8 @@ public abstract class EllipticCurveProvider extends SignatureProvider {
*
* @param jcaAlgorithmName the JCA name of the algorithm to use for key pair generation, for example, {@code
* ECDSA}.
* @param jcaProviderName the JCA provider name of the algorithm implementation, for example {@code BC} for
* BouncyCastle.
* @param jcaProviderName the JCA provider name of the algorithm implementation (for example {@code "BC"} for
* BouncyCastle) or {@code null} if the default provider should be used.
* @param alg alg the algorithm indicating strength, must be one of {@code ES256}, {@code ES384} or
* {@code ES512}
* @param random the SecureRandom generator to use during key generation.
@ -128,9 +128,17 @@ public abstract class EllipticCurveProvider extends SignatureProvider {
Assert.notNull(alg, "SignatureAlgorithm argument cannot be null.");
Assert.isTrue(alg.isEllipticCurve(), "SignatureAlgorithm argument must represent an Elliptic Curve algorithm.");
try {
KeyPairGenerator g = KeyPairGenerator.getInstance(jcaAlgorithmName, jcaProviderName);
KeyPairGenerator g;
if (Strings.hasText(jcaProviderName)) {
g = KeyPairGenerator.getInstance(jcaAlgorithmName, jcaProviderName);
} else {
g = KeyPairGenerator.getInstance(jcaAlgorithmName);
}
String paramSpecCurveName = EC_CURVE_NAMES.get(alg);
g.initialize(org.bouncycastle.jce.ECNamedCurveTable.getParameterSpec(paramSpecCurveName), random);
ECGenParameterSpec spec = new ECGenParameterSpec(paramSpecCurveName);
g.initialize(spec, random);
return g.generateKeyPair();
} catch (Exception e) {
throw new IllegalStateException("Unable to generate Elliptic Curve KeyPair: " + e.getMessage(), e);
@ -143,18 +151,19 @@ public abstract class EllipticCurveProvider extends SignatureProvider {
*
* @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 {
switch (alg) {
case ES256: return 64;
case ES384: return 96;
case ES512: return 132;
case ES256:
return 64;
case ES384:
return 96;
case ES512:
return 132;
default:
throw new JwtException("Unsupported Algorithm: " + alg.name());
}
@ -167,9 +176,7 @@ public abstract class EllipticCurveProvider extends SignatureProvider {
*
* @param derSignature The ASN1./DER-encoded. Must not be {@code null}.
* @param outputLength The expected length of the ECDSA JWS signature.
*
* @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 {
@ -220,7 +227,6 @@ public abstract class EllipticCurveProvider extends SignatureProvider {
}
/**
* Transcodes the ECDSA JWS signature into ASN.1/DER format for use by
* the JCA verifier.
@ -228,9 +234,7 @@ public abstract class EllipticCurveProvider extends SignatureProvider {
* @param jwsSignature The JWS signature, consisting of the
* concatenated R and S values. Must not be
* {@code null}.
*
* @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 {
@ -239,7 +243,7 @@ public abstract class EllipticCurveProvider extends SignatureProvider {
int i = rawLen;
while((i > 0) && (jwsSignature[rawLen - i] == 0)) {
while ((i > 0) && (jwsSignature[rawLen - i] == 0)) {
i--;
}

View File

@ -17,6 +17,7 @@ package io.jsonwebtoken.impl.crypto;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.lang.Assert;
import io.jsonwebtoken.lang.RuntimeEnvironment;
import io.jsonwebtoken.security.SignatureException;
import java.security.InvalidAlgorithmParameterException;
@ -54,6 +55,10 @@ public abstract class RsaProvider extends SignatureProvider {
return m;
}
static {
RuntimeEnvironment.enableBouncyCastleIfPossible(); //PS256, PS384, PS512 on <= JDK 10 require BC
}
protected RsaProvider(SignatureAlgorithm alg, Key key) {
super(alg, key);
Assert.isTrue(alg.isRsa(), "SignatureAlgorithm must be an RSASSA or RSASSA-PSS algorithm.");

View File

@ -38,7 +38,7 @@ class EllipticCurveProviderTest {
@Test
void testGenerateKeyPairWithInvalidProviderName() {
try {
EllipticCurveProvider.generateKeyPair("ECDSA", "Foo", SignatureAlgorithm.ES256, null)
EllipticCurveProvider.generateKeyPair("EC", "Foo", SignatureAlgorithm.ES256, null)
fail()
} catch (IllegalStateException ise) {
assertEquals ise.message, "Unable to generate Elliptic Curve KeyPair: no such provider: Foo"
@ -49,7 +49,7 @@ class EllipticCurveProviderTest {
@Test
void testGenerateKeyPairWithNullAlgorithm() {
try {
EllipticCurveProvider.generateKeyPair("ECDSA", "Foo", null, null)
EllipticCurveProvider.generateKeyPair("EC", "Foo", null, null)
fail()
} catch (IllegalArgumentException ise) {
assertEquals ise.message, "SignatureAlgorithm argument cannot be null."
@ -59,7 +59,7 @@ class EllipticCurveProviderTest {
@Test
void testGenerateKeyPairWithNonEllipticCurveAlgorithm() {
try {
EllipticCurveProvider.generateKeyPair("ECDSA", "Foo", SignatureAlgorithm.HS256, null)
EllipticCurveProvider.generateKeyPair("EC", "Foo", SignatureAlgorithm.HS256, null)
fail()
} catch (IllegalArgumentException ise) {
assertEquals ise.message, "SignatureAlgorithm argument must represent an Elliptic Curve algorithm."

View File

@ -19,7 +19,6 @@ import io.jsonwebtoken.JwtException
import io.jsonwebtoken.SignatureAlgorithm
import io.jsonwebtoken.io.Decoders
import io.jsonwebtoken.security.SignatureException
import org.bouncycastle.jce.provider.BouncyCastleProvider
import org.junit.Test
import java.security.*
@ -29,10 +28,6 @@ import static org.junit.Assert.*
class EllipticCurveSignatureValidatorTest {
static {
Security.addProvider(new BouncyCastleProvider())
}
@Test
void testDoVerifyWithInvalidKeyException() {
@ -62,7 +57,7 @@ class EllipticCurveSignatureValidatorTest {
@Test
void ecdsaSignatureComplianceTest() {
def fact = KeyFactory.getInstance("ECDSA", "BC");
def fact = KeyFactory.getInstance("EC");
def publicKey = "MIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQASisgweVL1tAtIvfmpoqvdXF8sPKTV9YTKNxBwkdkm+/auh4pR8TbaIfsEzcsGUVv61DFNFXb0ozJfurQ59G2XcgAn3vROlSSnpbIvuhKrzL5jwWDTaYa5tVF1Zjwia/5HUhKBkcPuWGXg05nMjWhZfCuEetzMLoGcHmtvabugFrqsAg="
def pub = fact.generatePublic(new X509EncodedKeySpec(Decoders.BASE64.decode(publicKey)))
def v = new EllipticCurveSignatureValidator(SignatureAlgorithm.ES512, pub)
@ -82,7 +77,7 @@ class EllipticCurveSignatureValidatorTest {
void legacySignatureCompatTest() {
def withoutSignature = "eyJhbGciOiJFUzUxMiIsInR5cCI6IkpXVCJ9.eyJ0ZXN0IjoidGVzdCIsImlhdCI6MTQ2NzA2NTgyN30"
def keypair = EllipticCurveProvider.generateKeyPair()
def signature = Signature.getInstance(SignatureAlgorithm.ES512.jcaName, "BC")
def signature = Signature.getInstance(SignatureAlgorithm.ES512.jcaName)
def data = withoutSignature.getBytes("US-ASCII")
signature.initSign(keypair.private)
signature.update(data)

View File

@ -47,7 +47,7 @@ class SignatureProviderTest {
@Test
void testCreateSignatureInstanceNoSuchAlgorithmNonStandardAlgorithm() {
def p = new SignatureProvider(SignatureAlgorithm.ES512, EllipticCurveProvider.generateKeyPair().getPublic()) {
def p = new SignatureProvider(SignatureAlgorithm.PS256, RsaProvider.generateKeyPair().getPrivate()) {
@Override
protected Signature getSignatureInstance() throws NoSuchAlgorithmException {
throw new NoSuchAlgorithmException('foo')
@ -65,7 +65,7 @@ class SignatureProviderTest {
@Test
void testCreateSignatureInstanceNoSuchAlgorithmNonStandardAlgorithmWithoutBouncyCastle() {
def p = new SignatureProvider(SignatureAlgorithm.ES512, EllipticCurveProvider.generateKeyPair().getPublic()) {
def p = new SignatureProvider(SignatureAlgorithm.PS256, RsaProvider.generateKeyPair().getPrivate()) {
@Override
protected Signature getSignatureInstance() throws NoSuchAlgorithmException {
throw new NoSuchAlgorithmException('foo')
@ -81,7 +81,7 @@ class SignatureProviderTest {
p.createSignatureInstance()
fail()
} catch (SignatureException se) {
assertTrue se.message.contains('Try including BouncyCastle in the runtime classpath')
assertTrue se.message.contains('This is not a standard JDK algorithm. Try including BouncyCastle in the runtime classpath.')
}
}
}

View File

@ -71,18 +71,21 @@ class KeysImplTest {
KeyPair pair = Keys.keyPairFor(alg);
assertNotNull pair
String asn1oid = "secp${alg.minKeyLength}r1"
int len = alg.minKeyLength
String asn1oid = "secp${len}r1"
String suffix = len == 256 ? ", X9.62 prime${len}v1" : '' //the JDK only adds this extra suffix to the secp256r1 curve name and not secp384r1 or secp521r1 curve names
String jdkParamName = "$asn1oid [NIST P-${len}${suffix}]" as String
PublicKey pub = pair.getPublic()
assert pub instanceof ECPublicKey
assertEquals "ECDSA", pub.algorithm
assertEquals asn1oid, pub.params.name
assertEquals "EC", pub.algorithm
assertEquals jdkParamName, pub.params.name
assertEquals alg.minKeyLength, pub.params.order.bitLength()
PrivateKey priv = pair.getPrivate()
assert priv instanceof ECPrivateKey
assertEquals "ECDSA", priv.algorithm
assertEquals asn1oid, priv.params.name
assertEquals "EC", priv.algorithm
assertEquals jdkParamName, priv.params.name
assertEquals alg.minKeyLength, priv.params.order.bitLength()
} else {

13
pom.xml
View File

@ -25,7 +25,7 @@
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-root</artifactId>
<version>0.11.0-SNAPSHOT</version>
<version>0.10.1-SNAPSHOT</version>
<name>JJWT</name>
<description>JSON Web Token support for the JVM and Android</description>
<packaging>pom</packaging>
@ -121,12 +121,6 @@
<artifactId>jjwt-api</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>${project.version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
@ -147,12 +141,13 @@
<artifactId>json</artifactId>
<version>${orgjson.version}</version>
</dependency>
<!-- Used only during testing for PS256, PS384 and PS512 since JDK <= 10 doesn't support them: -->
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>${bouncycastle.version}</version>
<scope>compile</scope>
<optional>true</optional>
<scope>test</scope>
</dependency>
</dependencies>
</dependencyManagement>