mirror of https://github.com/jwtk/jjwt.git
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:
parent
b58e1b6dc5
commit
7f662627cc
|
@ -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
|
||||
|
|
11
CHANGELOG.md
11
CHANGELOG.md
|
@ -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:
|
||||
|
|
53
README.md
53
README.md
|
@ -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'
|
||||
}
|
||||
```
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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.");
|
||||
|
|
|
@ -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."
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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.')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
13
pom.xml
|
@ -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>
|
||||
|
|
Loading…
Reference in New Issue