mirror of https://github.com/jwtk/jjwt.git
Merge pull request #373 from jwtk/375-bc-optional
Ensure BouncyCastle is optional
This commit is contained in:
commit
1520ae8a21
|
@ -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 {
|
||||
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 {
|
||||
|
@ -205,9 +212,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");
|
||||
}
|
||||
|
||||
|
@ -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--;
|
||||
}
|
||||
|
||||
|
|
|
@ -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