From 620cc5d97f394305cb701c440f45a53e2f8abc82 Mon Sep 17 00:00:00 2001 From: lhazlewood <121180+lhazlewood@users.noreply.github.com> Date: Thu, 17 Aug 2023 15:21:54 -0700 Subject: [PATCH] Made Curve and Jwks.CRV part of the public API (#797) * Made Curve concept part of the public API for key generation, and added Jwks.CRV utility class to reference standard curves - Ensured PS256, PS384, and PS512 pem-encoded test key files accurately represented the rsassa-pss algorithmId (OID) with appropriate hash/mgf1 properties. - Removed Jwts.SIG#Ed25519 and Jwts.SIG#Ed448 since they were only there for key generation and those keys can now be generated via the Jwks.CRV#Ed25519 and Jwks.CRV#Ed448 references. - Consolidated duplicate use/key_ops logic for checking sig/sign/verify between SecretJwkFactory and RsaPrivateJwkFactory into JwkContext.isSigUse() - Ensured if JwkContext.isSigUse() is true, and a JWK (from values only) is RSA and RSASSA-PSS is available (JDK 11+ or BC enabled), that the JWK's generated RSAPublicKey and RSAPrivateKey use the RSASSA-PSS algorithm instead of just RSA. - Enforced that RSASSA-PSS keys cannot be used for encryption in the RSA KeyAlgorithm implementation (would be a security risk otherwise). - Enforced that RSA encryption keys cannot be used to create RSASSA-PSS digital signatures (but can verify them) ala the "robustness principle" (to reduce security exposure). - Ensured README.md and JavaReadmeTest reflected Jwks.CRV usage for keypair generation. * Added TestCertificates workaround for https://bugs.openjdk.org/browse/JDK-8242556 * Added JwtX509StringConverter workaround for https://bugs.openjdk.org/browse/JDK-8242556 * Added JwtX509StringConverter workaround for https://bugs.openjdk.org/browse/JDK-8242556 * Reverted to former RsaSignatureAlgorithm logic for PSS key validation (no prevention of rsaEncryption keys with PSS) as RFC 7520 test vectors show using a standard RSA key to compute a PSS signature in https://www.rfc-editor.org/rfc/rfc7520.html#section-4.2.1 * Ensured Jwk tests that used RSASSA-PSS keys (from openssl files) used the BC provider since RSASSA-PSS isn't available natively before JDK 11 * Restored TestCertificates logic needed to address JDK 11 bug during tests https://bugs.openjdk.org/browse/JDK-8213363 (fixed in JDK 12+) --- CHANGELOG.md | 9 +- README.md | 4 +- .../java/io/jsonwebtoken/Identifiable.java | 5 + .../main/java/io/jsonwebtoken/JwtBuilder.java | 10 +- .../io/jsonwebtoken/JwtParserBuilder.java | 2 +- api/src/main/java/io/jsonwebtoken/Jwts.java | 41 ++--- .../java/io/jsonwebtoken/lang/Assert.java | 45 ++++-- .../java/io/jsonwebtoken/security/Curve.java | 41 +++++ .../java/io/jsonwebtoken/security/Jwks.java | 115 +++++++++++++ .../orgjson/io/OrgJsonSerializer.java | 8 +- impl/pom.xml | 2 + .../jsonwebtoken/impl/DefaultJwtBuilder.java | 21 ++- .../impl/DefaultJwtParserBuilder.java | 10 +- .../io/jsonwebtoken/impl/lang/Conditions.java | 2 +- .../impl/security/AbstractEcJwkFactory.java | 1 + .../security/AbstractFamilyJwkFactory.java | 9 +- .../AbstractSecureDigestAlgorithm.java | 4 +- .../security/AbstractSignatureAlgorithm.java | 2 +- .../io/jsonwebtoken/impl/security/Curves.java | 3 +- .../impl/security/DefaultCurve.java | 1 + .../impl/security/DefaultJwkContext.java | 14 ++ .../impl/security/DefaultMacAlgorithm.java | 91 +++++++---- .../impl/security/DefaultRsaKeyAlgorithm.java | 8 + .../impl/security/EcSignatureAlgorithm.java | 59 ++++++- .../impl/security/EdSignatureAlgorithm.java | 22 +-- .../impl/security/EdwardsCurve.java | 8 +- .../impl/security/JwkContext.java | 14 ++ .../impl/security/JwtX509StringConverter.java | 60 +++++-- .../impl/security/KeysBridge.java | 52 ++++++ .../impl/security/NoneSignatureAlgorithm.java | 7 +- .../impl/security/RsaPrivateJwkFactory.java | 2 +- .../impl/security/RsaSignatureAlgorithm.java | 152 ++++++++++++++---- .../impl/security/SecretJwkFactory.java | 30 ++-- .../impl/security/StandardCurves.java | 27 ++++ .../StandardSecureDigestAlgorithms.java | 74 +++++---- .../groovy/io/jsonwebtoken/JwksCRVTest.groovy | 37 +++++ .../groovy/io/jsonwebtoken/JwtsTest.groovy | 58 ++++--- .../impl/DefaultJwtBuilderTest.groovy | 62 +++++-- .../impl/DefaultJwtParserBuilderTest.groovy | 11 ++ .../impl/security/DefaultJwkParserTest.groovy | 43 +++-- .../security/DefaultMacAlgorithmTest.groovy | 68 +++++++- .../DefaultRsaKeyAlgorithmTest.groovy | 35 ++++ .../security/EcSignatureAlgorithmTest.groovy | 34 +++- .../security/EdSignatureAlgorithmTest.groovy | 73 ++++----- .../impl/security/EdwardsCurveTest.groovy | 21 ++- .../impl/security/Issue542Test.groovy | 14 +- .../impl/security/JwksTest.groovy | 30 ++-- .../JwtX509StringConverterTest.groovy | 77 +++++++-- .../security/PrivateConstructorsTest.groovy | 1 + .../security/RsaSignatureAlgorithmTest.groovy | 116 +++++++++++-- ...StandardSecureDigestAlgorithmsTest.groovy} | 17 +- .../impl/security/TestCertificates.groovy | 110 ++++++++----- .../impl/security/TestKeys.groovy | 53 +++--- .../impl/security/TestRSAKey.groovy | 22 +-- .../jsonwebtoken/security/JwtsSigTest.groovy | 59 ------- .../jsonwebtoken/security/KeysImplTest.groovy | 5 +- .../io/jsonwebtoken/security/KeysTest.groovy | 28 ++-- .../security/StandardAlgorithmsTest.groovy | 12 ++ .../jsonwebtoken/impl/security/PS256.crt.pem | 41 ++--- .../jsonwebtoken/impl/security/PS256.key.pem | 53 +++--- .../impl/security/PS256.pkcs1.key.pem | 44 ++++- .../jsonwebtoken/impl/security/PS256.pub.pem | 27 +++- .../jsonwebtoken/impl/security/PS384.crt.pem | 52 +++--- .../jsonwebtoken/impl/security/PS384.key.pem | 77 ++++----- .../impl/security/PS384.pkcs1.key.pem | 56 ++++++- .../jsonwebtoken/impl/security/PS384.pub.pem | 29 +++- .../jsonwebtoken/impl/security/PS512.crt.pem | 63 ++++---- .../jsonwebtoken/impl/security/PS512.key.pem | 101 ++++++------ .../impl/security/PS512.pkcs1.key.pem | 68 +++++++- .../jsonwebtoken/impl/security/PS512.pub.pem | 32 +++- .../io/jsonwebtoken/impl/security/README.md | 35 ++-- .../impl/security/RS256.pkcs1.key.pem | 44 ++++- .../jsonwebtoken/impl/security/RS256.pub.pem | 26 ++- .../impl/security/RS384.pkcs1.key.pem | 56 ++++++- .../jsonwebtoken/impl/security/RS384.pub.pem | 28 +++- .../impl/security/RS512.pkcs1.key.pem | 68 +++++++- .../jsonwebtoken/impl/security/RS512.pub.pem | 31 +++- .../impl/security/rsa2048.crt.pem | 36 ----- .../impl/security/rsa2048.key.pem | 44 ----- .../impl/security/rsa2048.pkcs1.key.pem | 43 ----- .../impl/security/rsa2048.pub.pem | 25 --- .../impl/security/rsa3072.crt.pem | 41 ----- .../impl/security/rsa3072.key.pem | 56 ------- .../impl/security/rsa3072.pkcs1.key.pem | 55 ------- .../impl/security/rsa3072.pub.pem | 27 ---- .../impl/security/rsa4096.crt.pem | 47 ------ .../impl/security/rsa4096.key.pem | 68 -------- .../impl/security/rsa4096.pkcs1.key.pem | 67 -------- .../impl/security/rsa4096.pub.pem | 30 ---- .../io/jsonwebtoken/all/JavaReadmeTest.java | 4 +- 90 files changed, 2133 insertions(+), 1282 deletions(-) create mode 100644 api/src/main/java/io/jsonwebtoken/security/Curve.java create mode 100644 impl/src/main/java/io/jsonwebtoken/impl/security/StandardCurves.java create mode 100644 impl/src/test/groovy/io/jsonwebtoken/JwksCRVTest.groovy rename impl/src/{main/java/io/jsonwebtoken/impl/security/Curve.java => test/groovy/io/jsonwebtoken/impl/security/StandardSecureDigestAlgorithmsTest.groovy} (59%) delete mode 100644 impl/src/test/groovy/io/jsonwebtoken/security/JwtsSigTest.groovy mode change 120000 => 100644 impl/src/test/resources/io/jsonwebtoken/impl/security/PS256.pkcs1.key.pem mode change 120000 => 100644 impl/src/test/resources/io/jsonwebtoken/impl/security/PS256.pub.pem mode change 120000 => 100644 impl/src/test/resources/io/jsonwebtoken/impl/security/PS384.pkcs1.key.pem mode change 120000 => 100644 impl/src/test/resources/io/jsonwebtoken/impl/security/PS384.pub.pem mode change 120000 => 100644 impl/src/test/resources/io/jsonwebtoken/impl/security/PS512.pkcs1.key.pem mode change 120000 => 100644 impl/src/test/resources/io/jsonwebtoken/impl/security/PS512.pub.pem mode change 120000 => 100644 impl/src/test/resources/io/jsonwebtoken/impl/security/RS256.pkcs1.key.pem mode change 120000 => 100644 impl/src/test/resources/io/jsonwebtoken/impl/security/RS256.pub.pem mode change 120000 => 100644 impl/src/test/resources/io/jsonwebtoken/impl/security/RS384.pkcs1.key.pem mode change 120000 => 100644 impl/src/test/resources/io/jsonwebtoken/impl/security/RS384.pub.pem mode change 120000 => 100644 impl/src/test/resources/io/jsonwebtoken/impl/security/RS512.pkcs1.key.pem mode change 120000 => 100644 impl/src/test/resources/io/jsonwebtoken/impl/security/RS512.pub.pem delete mode 100644 impl/src/test/resources/io/jsonwebtoken/impl/security/rsa2048.crt.pem delete mode 100644 impl/src/test/resources/io/jsonwebtoken/impl/security/rsa2048.key.pem delete mode 100644 impl/src/test/resources/io/jsonwebtoken/impl/security/rsa2048.pkcs1.key.pem delete mode 100644 impl/src/test/resources/io/jsonwebtoken/impl/security/rsa2048.pub.pem delete mode 100644 impl/src/test/resources/io/jsonwebtoken/impl/security/rsa3072.crt.pem delete mode 100644 impl/src/test/resources/io/jsonwebtoken/impl/security/rsa3072.key.pem delete mode 100644 impl/src/test/resources/io/jsonwebtoken/impl/security/rsa3072.pkcs1.key.pem delete mode 100644 impl/src/test/resources/io/jsonwebtoken/impl/security/rsa3072.pub.pem delete mode 100644 impl/src/test/resources/io/jsonwebtoken/impl/security/rsa4096.crt.pem delete mode 100644 impl/src/test/resources/io/jsonwebtoken/impl/security/rsa4096.key.pem delete mode 100644 impl/src/test/resources/io/jsonwebtoken/impl/security/rsa4096.pkcs1.key.pem delete mode 100644 impl/src/test/resources/io/jsonwebtoken/impl/security/rsa4096.pub.pem diff --git a/CHANGELOG.md b/CHANGELOG.md index 679fe9cf1..8caca1d1c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -186,8 +186,7 @@ deprecate some concepts, or in some cases, completely break backwards compatibil * `io.jsonwebtoken.JwtParser` is now immutable. All mutation/modification methods (setters, etc) deprecated 4 years - ago have been removed. All parser configuration requires using the `JwtParserBuilder` (i.e. - `Jwts.parser()`). + ago have been removed. All parser configuration requires using the `JwtParserBuilder`. * Similarly, `io.jsonwebtoken.Jwts`'s `parser()` method deprecated 4 years ago has been changed to now return a @@ -195,6 +194,12 @@ deprecate some concepts, or in some cases, completely break backwards compatibil removed as it is now redundant. +* The `JwtParserBuilder` no longer supports `PrivateKey`s for signature verification. This was an old + legacy behavior scheduled for removal years ago, and that change is now complete. For various cryptographic/security + reasons, asymmetric public/private key signatures should always be created with `PrivateKey`s and verified with + `PublicKey`s. + + * `io.jsonwebtoken.CompressionCodec` implementations are no longer discoverable via `java.util.ServiceLoader` due to runtime performance problems with the JDK's `ServiceLoader` implementation per https://github.com/jwtk/jjwt/issues/648. Custom implementations should be made available to the `JwtParser` via diff --git a/README.md b/README.md index dffa0c0db..a975b3128 100644 --- a/README.md +++ b/README.md @@ -3477,7 +3477,7 @@ Example creating and parsing an Edwards Elliptic Curve (Ed25519, Ed448, X25519, `OctetPublicJwk` interface names): ```java -PublicKey key = Jwts.SIG.Ed25519.keyPair().build().getPublic(); +PublicKey key = Jwks.CRV.Ed25519.keyPair().build().getPublic(); OctetPublicJwk jwk = builder().octetKey(key).idFromThumbprint().build(); assert jwk.getId().equals(jwk.thumbprint().toString()); @@ -3499,7 +3499,7 @@ Example creating and parsing an Edwards Elliptic Curve (Ed25519, Ed448, X25519, `OctetPrivateJwk` and `OctetPublicJwk` interface names): ```java -KeyPair pair = Jwts.SIG.Ed448.keyPair().build(); +KeyPair pair = Jwks.CRV.Ed448.keyPair().build(); PublicKey pubKey = pair.getPublic(); PrivateKey privKey = pair.getPrivate(); diff --git a/api/src/main/java/io/jsonwebtoken/Identifiable.java b/api/src/main/java/io/jsonwebtoken/Identifiable.java index 9d2cc8d92..2cccc04ab 100644 --- a/api/src/main/java/io/jsonwebtoken/Identifiable.java +++ b/api/src/main/java/io/jsonwebtoken/Identifiable.java @@ -40,6 +40,11 @@ * parameter value. * * + * {@link io.jsonwebtoken.security.Curve Curve} + * JWK's {@code crv} (Curve) + * parameter value. + * + * * {@link io.jsonwebtoken.io.CompressionAlgorithm CompressionAlgorithm} * JWE protected header's * {@code zip} (Compression Algorithm) diff --git a/api/src/main/java/io/jsonwebtoken/JwtBuilder.java b/api/src/main/java/io/jsonwebtoken/JwtBuilder.java index 53f87cc32..26db68ba1 100644 --- a/api/src/main/java/io/jsonwebtoken/JwtBuilder.java +++ b/api/src/main/java/io/jsonwebtoken/JwtBuilder.java @@ -527,14 +527,8 @@ public interface JwtBuilder extends ClaimsMutator { * * EdECKey7 * instanceof {@link PrivateKey} - * 256 - * {@link Jwts.SIG#Ed25519 Ed25519} - * - * - * EdECKey7 - * instanceof {@link PrivateKey} - * 456 - * {@link Jwts.SIG#Ed448 Ed448} + * 256 || 456 + * {@link Jwts.SIG#EdDSA EdDSA} * * * diff --git a/api/src/main/java/io/jsonwebtoken/JwtParserBuilder.java b/api/src/main/java/io/jsonwebtoken/JwtParserBuilder.java index 2d0f7238c..3ad82b6e2 100644 --- a/api/src/main/java/io/jsonwebtoken/JwtParserBuilder.java +++ b/api/src/main/java/io/jsonwebtoken/JwtParserBuilder.java @@ -328,7 +328,7 @@ public interface JwtParserBuilder extends Builder { * {@link #verifyWith(SecretKey)} for type safety, to reflect accurate naming of the concept, and for name * congruence with the {@link #decryptWith(SecretKey)} method.

* - *

This method merely delegates directly to {@link #verifyWith(SecretKey)}.

+ *

This method merely delegates directly to {@link #verifyWith(SecretKey) or {@link #verifyWith(PublicKey)}}.

* * @param key the algorithm-specific signature verification key to use to verify all encountered JWS digital * signatures. diff --git a/api/src/main/java/io/jsonwebtoken/Jwts.java b/api/src/main/java/io/jsonwebtoken/Jwts.java index 26ae06714..89ae3661b 100644 --- a/api/src/main/java/io/jsonwebtoken/Jwts.java +++ b/api/src/main/java/io/jsonwebtoken/Jwts.java @@ -21,6 +21,7 @@ import io.jsonwebtoken.lang.Registry; import io.jsonwebtoken.security.AeadAlgorithm; import io.jsonwebtoken.security.KeyAlgorithm; +import io.jsonwebtoken.security.KeyPairBuilderSupplier; import io.jsonwebtoken.security.MacAlgorithm; import io.jsonwebtoken.security.Password; import io.jsonwebtoken.security.SecretKeyAlgorithm; @@ -293,33 +294,25 @@ private SIG() { public static final SignatureAlgorithm ES512 = Jwts.get(REGISTRY, "ES512"); /** - * {@code EdDSA} signature algorithm as defined by - * RFC 8037, Section 3.1. This algorithm - * requires either {@code Ed25519} or {@code Ed448} Edwards Curve keys. - *

This algorithm requires at least JDK 15 or a compatible JCA Provider (like BouncyCastle) in the runtime + * {@code EdDSA} signature algorithm defined by + * RFC 8037, Section 3.1 that requires + * either {@code Ed25519} or {@code Ed448} Edwards Elliptic Curve1 keys. + * + *

KeyPair Generation

+ * + *

This instance's {@link KeyPairBuilderSupplier#keyPair() keyPair()} builder creates {@code Ed448} keys, + * and is essentially an alias for + * {@link io.jsonwebtoken.security.Jwks.CRV Jwks.CRV}.{@link io.jsonwebtoken.security.Jwks.CRV#Ed448 Ed448}.{@link KeyPairBuilderSupplier#keyPair() keyPair()}.

+ * + *

If you would like to generate an {@code Ed25519} {@code KeyPair} for use with the {@code EdDSA} algorithm, + * you may use the + * {@link io.jsonwebtoken.security.Jwks.CRV Jwks.CRV}.{@link io.jsonwebtoken.security.Jwks.CRV#Ed25519 Ed25519}.{@link KeyPairBuilderSupplier#keyPair() keyPair()} + * builder instead.

+ * + *

1This algorithm requires at least JDK 15 or a compatible JCA Provider (like BouncyCastle) in the runtime * classpath.

*/ public static final SignatureAlgorithm EdDSA = Jwts.get(REGISTRY, "EdDSA"); - - /** - * {@code EdDSA} signature algorithm using Curve {@code Ed25519} as defined by - * RFC 8037, Section 3.1. This algorithm - * requires {@code Ed25519} Edwards Curve keys to create signatures. This is a convenience alias for - * {@link #EdDSA} that defaults key generation to {@code Ed25519} keys. - *

This algorithm requires at least JDK 15 or a compatible JCA Provider (like BouncyCastle) in the runtime - * classpath.

- */ - public static final SignatureAlgorithm Ed25519 = Jwts.get(REGISTRY, "Ed25519"); - - /** - * {@code EdDSA} signature algorithm using Curve {@code Ed448} as defined by - * RFC 8037, Section 3.1. This algorithm - * requires {@code Ed448} Edwards Curve keys to create signatures. This is a convenience alias for - * {@link #EdDSA} that defaults key generation to {@code Ed448} keys. - *

This algorithm requires at least JDK 15 or a compatible JCA Provider (like BouncyCastle) in the runtime - * classpath.

- */ - public static final SignatureAlgorithm Ed448 = Jwts.get(REGISTRY, "Ed448"); } /** diff --git a/api/src/main/java/io/jsonwebtoken/lang/Assert.java b/api/src/main/java/io/jsonwebtoken/lang/Assert.java index da11e2394..85ff14fa0 100644 --- a/api/src/main/java/io/jsonwebtoken/lang/Assert.java +++ b/api/src/main/java/io/jsonwebtoken/lang/Assert.java @@ -351,7 +351,7 @@ public static void notEmpty(Map map) { * Assert that the provided object is an instance of the provided class. *
Assert.instanceOf(Foo.class, foo);
* - * @param the type of instance expected + * @param the type of instance expected * @param clazz the required class * @param obj the object to check * @return the expected instance of type {@code T} @@ -423,35 +423,56 @@ public static void isAssignable(Class superType, Class subType, String message) * an {@link IllegalArgumentException} with the given message if not. * * @param the type of argument - * @param requirement the integer that {@code value} must be greater than * @param value the value to check + * @param requirement the requirement that {@code value} must be greater than * @param msg the message to use for the {@code IllegalArgumentException} if thrown. * @return {@code value} if greater than the specified {@code requirement}. * @since JJWT_RELEASE_VERSION */ - public static T eq(T requirement, T value, String msg) { - notNull(requirement, "requirement cannot be null."); - notNull(value, "value cannot be null."); - if (!requirement.equals(value)) { + public static > T eq(T value, T requirement, String msg) { + if (compareTo(value, requirement) != 0) { throw new IllegalArgumentException(msg); } return value; } + private static > int compareTo(T value, T requirement) { + notNull(value, "value cannot be null."); + notNull(requirement, "requirement cannot be null."); + return value.compareTo(requirement); + } + /** * Asserts that a specified {@code value} is greater than the given {@code requirement}, throwing * an {@link IllegalArgumentException} with the given message if not. * + * @param the type of value to check and return if the requirement is met * @param value the value to check - * @param requirement the integer that {@code value} must be greater than + * @param requirement the requirement that {@code value} must be greater than * @param msg the message to use for the {@code IllegalArgumentException} if thrown. * @return {@code value} if greater than the specified {@code requirement}. * @since JJWT_RELEASE_VERSION */ - public static Integer gt(Integer value, Integer requirement, String msg) { - notNull(value, "value cannot be null."); - notNull(requirement, "requirement cannot be null."); - if (!(value > requirement)) { + public static > T gt(T value, T requirement, String msg) { + if (!(compareTo(value, requirement) > 0)) { + throw new IllegalArgumentException(msg); + } + return value; + } + + /** + * Asserts that a specified {@code value} is less than or equal to the given {@code requirement}, throwing + * an {@link IllegalArgumentException} with the given message if not. + * + * @param the type of value to check and return if the requirement is met + * @param value the value to check + * @param requirement the requirement that {@code value} must be greater than + * @param msg the message to use for the {@code IllegalArgumentException} if thrown. + * @return {@code value} if greater than the specified {@code requirement}. + * @since JJWT_RELEASE_VERSION + */ + public static > T lte(T value, T requirement, String msg) { + if (compareTo(value, requirement) > 0) { throw new IllegalArgumentException(msg); } return value; @@ -495,7 +516,7 @@ public static void state(boolean expression) { * * @param value value to assert is not null * @param msg exception message to use if {@code value} is null - * @param value type + * @param value type * @return the non-null value * @throws IllegalStateException with the specified {@code msg} if {@code value} is null. * @since JJWT_RELEASE_VERSION diff --git a/api/src/main/java/io/jsonwebtoken/security/Curve.java b/api/src/main/java/io/jsonwebtoken/security/Curve.java new file mode 100644 index 000000000..d78e67ccc --- /dev/null +++ b/api/src/main/java/io/jsonwebtoken/security/Curve.java @@ -0,0 +1,41 @@ +/* + * Copyright © 2022 jsonwebtoken.io + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jsonwebtoken.security; + +import io.jsonwebtoken.Identifiable; + +/** + * A cryptographic Elliptic Curve for use with digital signature or key agreement algorithms. + * + *

Curve Identifier

+ * + *

This interface extends {@link Identifiable}; the value returned from {@link #getId()} will + * be used as the JWK + * crv value.

+ * + *

KeyPair Generation

+ * + *

A secure-random KeyPair of sufficient strength on the curve may be obtained with its {@link #keyPair()} builder.

+ * + *

Standard Implementations

+ * + *

Constants for all JWA standard Curves are available via the {@link Jwks.CRV} registry.

+ * + * @see Jwks.CRV + * @since JJWT_RELEASE_VERSION + */ +public interface Curve extends Identifiable, KeyPairBuilderSupplier { +} diff --git a/api/src/main/java/io/jsonwebtoken/security/Jwks.java b/api/src/main/java/io/jsonwebtoken/security/Jwks.java index 22cfc2616..6c0ef613f 100644 --- a/api/src/main/java/io/jsonwebtoken/security/Jwks.java +++ b/api/src/main/java/io/jsonwebtoken/security/Jwks.java @@ -44,6 +44,121 @@ private Jwks() { private static final String PARSERBUILDER_CLASSNAME = "io.jsonwebtoken.impl.security.DefaultJwkParserBuilder"; + /** + * Constants for all standard Elliptic Curves in the {@code JSON Web Key Elliptic Curve Registry} + * defined by RFC 7518, Section 7.6 + * (for Weierstrass Elliptic Curves) and + * RFC 8037, Section 5 (for Edwards Elliptic Curves). + * Each standard algorithm is available as a + * ({@code public static final}) constant for direct type-safe reference in application code. For example: + *
+     * Jwks.CRV.P256.keyPair().build();
+ *

They are also available together as a {@link Registry} instance via the {@link #get()} method.

+ * + * @see #get() + * @since JJWT_RELEASE_VERSION + */ + public static final class CRV { + + private static final String IMPL_CLASSNAME = "io.jsonwebtoken.impl.security.StandardCurves"; + private static final Registry REGISTRY = Classes.newInstance(IMPL_CLASSNAME); + + /** + * Returns a registry of all standard Elliptic Curves in the {@code JSON Web Key Elliptic Curve Registry} + * defined by RFC 7518, Section 7.6 + * (for Weierstrass Elliptic Curves) and + * RFC 8037, Section 5 (for Edwards Elliptic Curves). + * + * @return a registry of all standard Elliptic Curves in the {@code JSON Web Key Elliptic Curve Registry}. + */ + public static Registry get() { + return REGISTRY; + } + + /** + * {@code P-256} Elliptic Curve defined by + * RFC 7518, Section 6.2.1.1 + * using the native Java JCA {@code secp256r1} algorithm. + * + * @see Java Security Standard Algorithm Names + */ + public static final Curve P256 = get().forKey("P-256"); + + /** + * {@code P-384} Elliptic Curve defined by + * RFC 7518, Section 6.2.1.1 + * using the native Java JCA {@code secp384r1} algorithm. + * + * @see Java Security Standard Algorithm Names + */ + public static final Curve P384 = get().forKey("P-384"); + + /** + * {@code P-521} Elliptic Curve defined by + * RFC 7518, Section 6.2.1.1 + * using the native Java JCA {@code secp521r1} algorithm. + * + * @see Java Security Standard Algorithm Names + */ + public static final Curve P521 = get().forKey("P-521"); + + /** + * {@code Ed25519} Elliptic Curve defined by + * RFC 8037, Section 3.1 + * using the native Java JCA {@code Ed25519}1 algorithm. + * + *

1 Requires Java 15 or a compatible JCA Provider (like BouncyCastle) in the runtime + * classpath. If on Java 14 or earlier, BouncyCastle will be used automatically if found in the runtime + * classpath.

+ * + * @see Java Security Standard Algorithm Names + */ + public static final Curve Ed25519 = get().forKey("Ed25519"); + + /** + * {@code Ed448} Elliptic Curve defined by + * RFC 8037, Section 3.1 + * using the native Java JCA {@code Ed448}1 algorithm. + * + *

1 Requires Java 15 or a compatible JCA Provider (like BouncyCastle) in the runtime + * classpath. If on Java 14 or earlier, BouncyCastle will be used automatically if found in the runtime + * classpath.

+ * + * @see Java Security Standard Algorithm Names + */ + public static final Curve Ed448 = get().forKey("Ed448"); + + /** + * {@code X25519} Elliptic Curve defined by + * RFC 8037, Section 3.2 + * using the native Java JCA {@code X25519}1 algorithm. + * + *

1 Requires Java 11 or a compatible JCA Provider (like BouncyCastle) in the runtime + * classpath. If on Java 10 or earlier, BouncyCastle will be used automatically if found in the runtime + * classpath.

+ * + * @see Java Security Standard Algorithm Names + */ + public static final Curve X25519 = get().forKey("X25519"); + + /** + * {@code X448} Elliptic Curve defined by + * RFC 8037, Section 3.2 + * using the native Java JCA {@code X448}1 algorithm. + * + *

1 Requires Java 11 or a compatible JCA Provider (like BouncyCastle) in the runtime + * classpath. If on Java 10 or earlier, BouncyCastle will be used automatically if found in the runtime + * classpath.

+ * + * @see Java Security Standard Algorithm Names + */ + public static final Curve X448 = get().forKey("X448"); + + //prevent instantiation + private CRV() { + } + } + /** * Various (but not all) * IANA Hash diff --git a/extensions/orgjson/src/main/java/io/jsonwebtoken/orgjson/io/OrgJsonSerializer.java b/extensions/orgjson/src/main/java/io/jsonwebtoken/orgjson/io/OrgJsonSerializer.java index c46ee2507..8ad80f1f4 100644 --- a/extensions/orgjson/src/main/java/io/jsonwebtoken/orgjson/io/OrgJsonSerializer.java +++ b/extensions/orgjson/src/main/java/io/jsonwebtoken/orgjson/io/OrgJsonSerializer.java @@ -84,7 +84,7 @@ private Object toJSONInstance(Object object) { } if (object instanceof Supplier) { - object = ((Supplier)object).get(); + object = ((Supplier) object).get(); } if (object instanceof JSONObject || object instanceof JSONArray @@ -163,6 +163,12 @@ private JSONArray toJSONArray(Collection c) { return array; } + /** + * Serializes the specified org.json instance a byte array. + * + * @param o the org.json instance to serialize + * @return the JSON byte array + */ @SuppressWarnings("WeakerAccess") //for testing protected byte[] toBytes(Object o) { String s; diff --git a/impl/pom.xml b/impl/pom.xml index 887ce37d6..4a4b43cd6 100644 --- a/impl/pom.xml +++ b/impl/pom.xml @@ -31,6 +31,8 @@ ${basedir}/.. + + -Xdoclint:none diff --git a/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtBuilder.java b/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtBuilder.java index 85f64f0f9..cfeeb186a 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtBuilder.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtBuilder.java @@ -27,6 +27,7 @@ import io.jsonwebtoken.impl.security.DefaultKeyRequest; import io.jsonwebtoken.impl.security.DefaultSecureRequest; import io.jsonwebtoken.impl.security.Pbes2HsAkwAlgorithm; +import io.jsonwebtoken.impl.security.StandardSecureDigestAlgorithms; import io.jsonwebtoken.io.CompressionAlgorithm; import io.jsonwebtoken.io.Decoders; import io.jsonwebtoken.io.Encoder; @@ -49,6 +50,7 @@ import io.jsonwebtoken.security.SecureRequest; import io.jsonwebtoken.security.SecurityException; import io.jsonwebtoken.security.SignatureException; +import io.jsonwebtoken.security.UnsupportedKeyException; import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; @@ -179,10 +181,21 @@ public JwtBuilder setHeaderParam(String name, Object value) { return this.headerBuilder.add(name, value).and(); } - @SuppressWarnings("unchecked") // TODO: remove for 1.0 + @SuppressWarnings({"unchecked", "deprecation"}) // TODO: remove for 1.0 protected static SecureDigestAlgorithm forSigningKey(K key) { - @SuppressWarnings("deprecation") io.jsonwebtoken.SignatureAlgorithm alg = io.jsonwebtoken.SignatureAlgorithm.forSigningKey(key); - return (SecureDigestAlgorithm) Jwts.SIG.get().forKey(alg.getValue()); + Assert.notNull(key, "Key cannot be null."); + SecureDigestAlgorithm alg = StandardSecureDigestAlgorithms.findBySigningKey(key); + if (alg == null) { + String msg = "Unable to determine a suitable MAC or Signature algorithm for the specified key using " + + "available heuristics: either the key size is too weak be used with available algorithms, or the " + + "key size is unavailable (e.g. if using a PKCS11 or HSM (Hardware Security Module) key store). " + + "If you are using a PKCS11 or HSM keystore, consider using the " + + "JwtBuilder.signWith(Key, SecureDigestAlgorithm) method instead."; + throw new UnsupportedKeyException(msg); + } + return alg; + // io.jsonwebtoken.SignatureAlgorithm dalg = io.jsonwebtoken.SignatureAlgorithm.forSigningKey(key); + //return (SecureDigestAlgorithm) Jwts.SIG.get().forKey(dalg.getValue()); } @Override @@ -195,7 +208,7 @@ public JwtBuilder signWith(Key key) throws InvalidKeyException { @Override public JwtBuilder signWith(K key, final SecureDigestAlgorithm alg) throws InvalidKeyException { Assert.notNull(key, "Key argument cannot be null."); - if (key instanceof PublicKey) { // it's always wrong to try to create signatures with PublicKeys: + if (key instanceof PublicKey) { // it's always wrong/insecure to try to create signatures with PublicKeys: throw new IllegalArgumentException(PUB_KEY_SIGN_MSG); } // Implementation note: Ordinarily Passwords should not be used to create secure digests because they usually diff --git a/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParserBuilder.java b/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParserBuilder.java index 795293693..b776d235b 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParserBuilder.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParserBuilder.java @@ -35,6 +35,7 @@ import io.jsonwebtoken.security.KeyAlgorithm; import io.jsonwebtoken.security.Keys; import io.jsonwebtoken.security.SecureDigestAlgorithm; +import io.jsonwebtoken.security.UnsupportedKeyException; import javax.crypto.SecretKey; import java.security.Key; @@ -229,7 +230,14 @@ public JwtParserBuilder setSigningKey(String base64EncodedSecretKey) { @Override public JwtParserBuilder setSigningKey(final Key key) { - return verifyWith(key); + if (key instanceof SecretKey) { + return verifyWith((SecretKey) key); + } else if (key instanceof PublicKey) { + return verifyWith((PublicKey) key); + } + String msg = "JWS verification key must be either a SecretKey (for MAC algorithms) or a PublicKey " + + "(for Signature algorithms)."; + throw new UnsupportedKeyException(msg); } @Override diff --git a/impl/src/main/java/io/jsonwebtoken/impl/lang/Conditions.java b/impl/src/main/java/io/jsonwebtoken/impl/lang/Conditions.java index 4a90e457d..759406311 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/lang/Conditions.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/lang/Conditions.java @@ -82,7 +82,7 @@ public boolean test() { Object value = null; try { value = supplier.get(); - } catch (Exception ignored) { + } catch (Throwable ignored) { } return value != null; } diff --git a/impl/src/main/java/io/jsonwebtoken/impl/security/AbstractEcJwkFactory.java b/impl/src/main/java/io/jsonwebtoken/impl/security/AbstractEcJwkFactory.java index 8e8526676..0f5e81cfd 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/security/AbstractEcJwkFactory.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/security/AbstractEcJwkFactory.java @@ -19,6 +19,7 @@ import io.jsonwebtoken.impl.lang.Converters; import io.jsonwebtoken.impl.lang.Field; import io.jsonwebtoken.io.Encoders; +import io.jsonwebtoken.security.Curve; import io.jsonwebtoken.security.Jwk; import io.jsonwebtoken.security.UnsupportedKeyException; diff --git a/impl/src/main/java/io/jsonwebtoken/impl/security/AbstractFamilyJwkFactory.java b/impl/src/main/java/io/jsonwebtoken/impl/security/AbstractFamilyJwkFactory.java index 5842786f9..69f6e38ac 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/security/AbstractFamilyJwkFactory.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/security/AbstractFamilyJwkFactory.java @@ -18,6 +18,7 @@ import io.jsonwebtoken.impl.lang.CheckedFunction; import io.jsonwebtoken.impl.lang.Field; import io.jsonwebtoken.lang.Assert; +import io.jsonwebtoken.lang.Strings; import io.jsonwebtoken.security.InvalidKeyException; import io.jsonwebtoken.security.Jwk; import io.jsonwebtoken.security.KeyException; @@ -73,8 +74,14 @@ protected K generateKey(final JwkContext ctx, final CheckedFunction ctx) { + String jcaName = KeysBridge.findAlgorithm(ctx.getKey()); + return Strings.hasText(jcaName) ? jcaName : getId(); + } + protected T generateKey(final JwkContext ctx, final Class type, final CheckedFunction fn) { - JcaTemplate template = new JcaTemplate(getId(), ctx.getProvider(), ctx.getRandom()); + String jcaName = getKeyFactoryJcaName(ctx); + JcaTemplate template = new JcaTemplate(jcaName, ctx.getProvider(), ctx.getRandom()); return template.withKeyFactory(new CheckedFunction() { @Override public T apply(KeyFactory instance) { diff --git a/impl/src/main/java/io/jsonwebtoken/impl/security/AbstractSecureDigestAlgorithm.java b/impl/src/main/java/io/jsonwebtoken/impl/security/AbstractSecureDigestAlgorithm.java index 7fd369e59..6c4d7ef7c 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/security/AbstractSecureDigestAlgorithm.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/security/AbstractSecureDigestAlgorithm.java @@ -41,7 +41,7 @@ protected static String keyType(boolean signing) { @Override public final byte[] digest(SecureRequest request) throws SecurityException { Assert.notNull(request, "Request cannot be null."); - final S key = Assert.notNull(request.getKey(), "Request key cannot be null."); + final S key = Assert.notNull(request.getKey(), "Signing key cannot be null."); Assert.notEmpty(request.getPayload(), "Request content cannot be null or empty."); try { validateKey(key, true); @@ -60,7 +60,7 @@ public final byte[] digest(SecureRequest request) throws SecurityExce @Override public final boolean verify(VerifySecureDigestRequest request) throws SecurityException { Assert.notNull(request, "Request cannot be null."); - final V key = Assert.notNull(request.getKey(), "Request key cannot be null."); + final V key = Assert.notNull(request.getKey(), "Verification key cannot be null."); Assert.notEmpty(request.getPayload(), "Request content cannot be null or empty."); Assert.notEmpty(request.getDigest(), "Request signature byte array cannot be null or empty."); try { diff --git a/impl/src/main/java/io/jsonwebtoken/impl/security/AbstractSignatureAlgorithm.java b/impl/src/main/java/io/jsonwebtoken/impl/security/AbstractSignatureAlgorithm.java index a5ce3b043..eb5ecde9b 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/security/AbstractSignatureAlgorithm.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/security/AbstractSignatureAlgorithm.java @@ -33,7 +33,7 @@ abstract class AbstractSignatureAlgorithm extends AbstractSecureDigestAlgorithm< private static final String KEY_TYPE_MSG_PATTERN = "{0} {1} keys must be {2}s (implement {3}). Provided key type: {4}."; - protected AbstractSignatureAlgorithm(String id, String jcaName) { + AbstractSignatureAlgorithm(String id, String jcaName) { super(id, jcaName); } diff --git a/impl/src/main/java/io/jsonwebtoken/impl/security/Curves.java b/impl/src/main/java/io/jsonwebtoken/impl/security/Curves.java index 19617ab39..553da5b79 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/security/Curves.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/security/Curves.java @@ -21,6 +21,7 @@ import io.jsonwebtoken.lang.Assert; import io.jsonwebtoken.lang.Collections; import io.jsonwebtoken.lang.Registry; +import io.jsonwebtoken.security.Curve; import java.security.spec.EllipticCurve; import java.util.Collection; @@ -33,7 +34,7 @@ public final class Curves { private static final Collection EC_CURVES = Collections.setOf((ECCurve) P_256, (ECCurve) P_384, (ECCurve) P_521); - private static final Collection VALUES = new LinkedHashSet<>(); + static final Collection VALUES = new LinkedHashSet<>(); static { VALUES.addAll(EC_CURVES); diff --git a/impl/src/main/java/io/jsonwebtoken/impl/security/DefaultCurve.java b/impl/src/main/java/io/jsonwebtoken/impl/security/DefaultCurve.java index 7e5195897..5d566ff06 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/security/DefaultCurve.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/security/DefaultCurve.java @@ -17,6 +17,7 @@ import io.jsonwebtoken.lang.Assert; import io.jsonwebtoken.lang.Strings; +import io.jsonwebtoken.security.Curve; import io.jsonwebtoken.security.KeyPairBuilder; import java.security.Provider; diff --git a/impl/src/main/java/io/jsonwebtoken/impl/security/DefaultJwkContext.java b/impl/src/main/java/io/jsonwebtoken/impl/security/DefaultJwkContext.java index 9b73a063b..35eb79f81 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/security/DefaultJwkContext.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/security/DefaultJwkContext.java @@ -209,6 +209,20 @@ public JwkContext setPublicKeyUse(String use) { return this; } + @Override + public boolean isSigUse() { + // Even though 'use' is for PUBLIC KEY use (as defined in RFC 7515), RFC 7520 shows secret keys with + // 'use' values, so we'll account for that as well: + if ("sig".equals(getPublicKeyUse())) { + return true; + } + Set ops = getOperations(); + if (Collections.isEmpty(ops)) { + return false; + } + return ops.contains("sign") || ops.contains("verify"); + } + @Override public K getKey() { return this.key; diff --git a/impl/src/main/java/io/jsonwebtoken/impl/security/DefaultMacAlgorithm.java b/impl/src/main/java/io/jsonwebtoken/impl/security/DefaultMacAlgorithm.java index 1fd7c0291..ab68df413 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/security/DefaultMacAlgorithm.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/security/DefaultMacAlgorithm.java @@ -29,39 +29,51 @@ import javax.crypto.Mac; import javax.crypto.SecretKey; import java.security.Key; +import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.Locale; +import java.util.Map; import java.util.Set; /** * @since JJWT_RELEASE_VERSION */ -public class DefaultMacAlgorithm extends AbstractSecureDigestAlgorithm implements MacAlgorithm { +final class DefaultMacAlgorithm extends AbstractSecureDigestAlgorithm implements MacAlgorithm { - private final int minKeyBitLength; //in bits + private static final String HS256_OID = "1.2.840.113549.2.9"; + private static final String HS384_OID = "1.2.840.113549.2.10"; + private static final String HS512_OID = "1.2.840.113549.2.11"; private static final Set JWA_STANDARD_IDS = new LinkedHashSet<>(Collections.of("HS256", "HS384", "HS512")); - // PKCS12 OIDs are added to these lists per https://bugs.openjdk.java.net/browse/JDK-8243551 - private static final Set HS256_JCA_NAMES = new LinkedHashSet<>(Collections.of("HMACSHA256", "1.2.840.113549.2.9")); - private static final Set HS384_JCA_NAMES = new LinkedHashSet<>(Collections.of("HMACSHA384", "1.2.840.113549.2.10")); - private static final Set HS512_JCA_NAMES = new LinkedHashSet<>(Collections.of("HMACSHA512", "1.2.840.113549.2.11")); + static final DefaultMacAlgorithm HS256 = new DefaultMacAlgorithm(256); + static final DefaultMacAlgorithm HS384 = new DefaultMacAlgorithm(384); + static final DefaultMacAlgorithm HS512 = new DefaultMacAlgorithm(512); - private static final Set VALID_HS256_JCA_NAMES; - private static final Set VALID_HS384_JCA_NAMES; + private static final Map JCA_NAME_MAP; static { - VALID_HS384_JCA_NAMES = new LinkedHashSet<>(HS384_JCA_NAMES); - VALID_HS384_JCA_NAMES.addAll(HS512_JCA_NAMES); - VALID_HS256_JCA_NAMES = new LinkedHashSet<>(HS256_JCA_NAMES); - VALID_HS256_JCA_NAMES.addAll(VALID_HS384_JCA_NAMES); + JCA_NAME_MAP = new LinkedHashMap<>(6); + + // In addition to JCA names, PKCS12 OIDs are added to these per + // https://bugs.openjdk.java.net/browse/JDK-8243551 as well: + JCA_NAME_MAP.put(HS256.getJcaName().toUpperCase(Locale.ENGLISH), HS256); // for case-insensitive lookup + JCA_NAME_MAP.put(HS256_OID, HS256); + + JCA_NAME_MAP.put(HS384.getJcaName().toUpperCase(Locale.ENGLISH), HS384); + JCA_NAME_MAP.put(HS384_OID, HS384); + + JCA_NAME_MAP.put(HS512.getJcaName().toUpperCase(Locale.ENGLISH), HS512); + JCA_NAME_MAP.put(HS512_OID, HS512); } - public DefaultMacAlgorithm(int digestBitLength) { + private final int minKeyBitLength; //in bits + + private DefaultMacAlgorithm(int digestBitLength) { this("HS" + digestBitLength, "HmacSHA" + digestBitLength, digestBitLength); } - public DefaultMacAlgorithm(String id, String jcaName, int minKeyBitLength) { + DefaultMacAlgorithm(String id, String jcaName, int minKeyBitLength) { super(id, jcaName); Assert.isTrue(minKeyBitLength > 0, "minKeyLength must be greater than zero."); this.minKeyBitLength = minKeyBitLength; @@ -76,10 +88,36 @@ private boolean isJwaStandard() { return JWA_STANDARD_IDS.contains(getId()); } - private boolean isJwaStandardJcaName(String jcaName) { - return VALID_HS256_JCA_NAMES.contains(jcaName.toUpperCase(Locale.ENGLISH)); + private static boolean isJwaStandardJcaName(String jcaName) { + String key = jcaName.toUpperCase(Locale.ENGLISH); + return JCA_NAME_MAP.containsKey(key); } + static MacAlgorithm findByKey(Key key) { + + String alg = KeysBridge.findAlgorithm(key); + if (!Strings.hasText(alg)) { + return null; + } + + String upper = alg.toUpperCase(Locale.ENGLISH); + MacAlgorithm mac = JCA_NAME_MAP.get(upper); + if (mac == null) { + return null; + } + + // even though we found a standard alg based on the JCA name, we need to confirm that the key length is + // sufficient if the encoded key bytes are available: + byte[] encoded = KeysBridge.findEncoded(key); + long size = Bytes.bitLength(encoded); + if (size >= mac.getKeyBitLength()) { + return mac; + } + + return null; // couldn't find a suitable match + } + + @Override public SecretKeyBuilder key() { return new DefaultSecretKeyBuilder(getJcaName(), getKeyBitLength()); @@ -91,11 +129,11 @@ protected void validateKey(Key k, boolean signing) { final String keyType = keyType(signing); if (k == null) { - throw new IllegalArgumentException("Signature " + keyType + " key cannot be null."); + throw new IllegalArgumentException("MAC " + keyType + " key cannot be null."); } if (!(k instanceof SecretKey)) { - String msg = "MAC " + keyType(signing) + " keys must be SecretKey instances. Specified key is of type " + + String msg = "MAC " + keyType + " keys must be SecretKey instances. Specified key is of type " + k.getClass().getName(); throw new InvalidKeyException(msg); } @@ -116,24 +154,13 @@ protected void validateKey(Key k, boolean signing) { "HmacSHA* algorithm name or PKCS12 OID and cannot be used with " + id + "."); } - byte[] encoded = null; - - // https://github.com/jwtk/jjwt/issues/478 - // - // Some KeyStore implementations (like Hardware Security Modules and later versions of Android) will not allow - // applications or libraries to obtain the secret key's encoded bytes. In these cases, key length assertions - // cannot be made, so we'll need to skip the key length checks if so. - try { - encoded = key.getEncoded(); - } catch (Exception ignored) { - } + int size = KeysBridge.findBitLength(key); - // We can only perform length validation if key.getEncoded() is not null or does not throw an exception + // We can only perform length validation if key bit length is available // per https://github.com/jwtk/jjwt/issues/478 and https://github.com/jwtk/jjwt/issues/619 // so return early if we can't: - if (encoded == null) return; + if (size < 0) return; - int size = (int) Bytes.bitLength(encoded); if (size < this.minKeyBitLength) { String msg = "The " + keyType + " key's size is " + size + " bits which " + "is not secure enough for the " + id + " algorithm."; diff --git a/impl/src/main/java/io/jsonwebtoken/impl/security/DefaultRsaKeyAlgorithm.java b/impl/src/main/java/io/jsonwebtoken/impl/security/DefaultRsaKeyAlgorithm.java index e7e5928c9..79f7db1d5 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/security/DefaultRsaKeyAlgorithm.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/security/DefaultRsaKeyAlgorithm.java @@ -22,6 +22,7 @@ import io.jsonwebtoken.security.KeyRequest; import io.jsonwebtoken.security.KeyResult; import io.jsonwebtoken.security.SecurityException; +import io.jsonwebtoken.security.UnsupportedKeyException; import io.jsonwebtoken.security.WeakKeyException; import javax.crypto.Cipher; @@ -56,6 +57,13 @@ private static String keyType(boolean encryption) { } protected void validate(Key key, boolean encryption) { // true = encryption, false = decryption + + if (RsaSignatureAlgorithm.isPss(key)) { + String msg = "RSASSA-PSS keys may not be used for " + keyType(encryption) + + ", only digital signature algorithms."; + throw new UnsupportedKeyException(msg); + } + // Some PKCS11 providers and HSMs won't expose the RSAKey interface, so we have to check to see if we can cast // If so, we can provide additional safety checks: if (key instanceof RSAKey) { diff --git a/impl/src/main/java/io/jsonwebtoken/impl/security/EcSignatureAlgorithm.java b/impl/src/main/java/io/jsonwebtoken/impl/security/EcSignatureAlgorithm.java index b5d65603c..c8df1a8fd 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/security/EcSignatureAlgorithm.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/security/EcSignatureAlgorithm.java @@ -19,9 +19,11 @@ import io.jsonwebtoken.impl.lang.Bytes; import io.jsonwebtoken.impl.lang.CheckedFunction; import io.jsonwebtoken.lang.Assert; +import io.jsonwebtoken.lang.Strings; import io.jsonwebtoken.security.InvalidKeyException; import io.jsonwebtoken.security.KeyPairBuilder; import io.jsonwebtoken.security.SecureRequest; +import io.jsonwebtoken.security.SignatureAlgorithm; import io.jsonwebtoken.security.SignatureException; import io.jsonwebtoken.security.VerifySecureDigestRequest; @@ -33,19 +35,28 @@ import java.security.interfaces.ECKey; import java.security.spec.ECGenParameterSpec; import java.util.Arrays; +import java.util.LinkedHashMap; +import java.util.Locale; +import java.util.Map; // @since JJWT_RELEASE_VERSION -public class EcSignatureAlgorithm extends AbstractSignatureAlgorithm { +final class EcSignatureAlgorithm extends AbstractSignatureAlgorithm { private static final String REQD_ORDER_BIT_LENGTH_MSG = "orderBitLength must equal 256, 384, or 521."; private static final String DER_ENCODING_SYS_PROPERTY_NAME = "io.jsonwebtoken.impl.crypto.EllipticCurveSignatureValidator.derEncodingSupported"; + private static final String ES256_OID = "1.2.840.10045.4.3.2"; + private static final String ES384_OID = "1.2.840.10045.4.3.3"; + private static final String ES512_OID = "1.2.840.10045.4.3.4"; + private final ECGenParameterSpec KEY_PAIR_GEN_PARAMS; private final int orderBitLength; + private final String OID; + /** * JWA EC (concat formatted) length in bytes for this instance's {@link #orderBitLength}. */ @@ -89,9 +100,51 @@ private static boolean isSupportedOrderBitLength(int orderBitLength) { return orderBitLength == 256 || orderBitLength == 384 || orderBitLength == 521; } - public EcSignatureAlgorithm(int orderBitLength) { + static final EcSignatureAlgorithm ES256 = new EcSignatureAlgorithm(256, ES256_OID); + static final EcSignatureAlgorithm ES384 = new EcSignatureAlgorithm(384, ES384_OID); + static final EcSignatureAlgorithm ES512 = new EcSignatureAlgorithm(521, ES512_OID); + + private static final Map ALGS_BY_OID; + + static { + ALGS_BY_OID = new LinkedHashMap<>(3); + ALGS_BY_OID.put(ES256_OID, ES256); + ALGS_BY_OID.put(ES384_OID, ES384); + ALGS_BY_OID.put(ES512_OID, ES512); + } + + static SignatureAlgorithm findByKey(Key key) { + + String algName = KeysBridge.findAlgorithm(key); + if (!Strings.hasText(algName)) { + return null; + } + algName = algName.toUpperCase(Locale.ENGLISH); + + SignatureAlgorithm alg = ALGS_BY_OID.get(algName); + if (alg != null) { + return alg; + } + + if ("EC".equalsIgnoreCase(algName) || "ECDSA".equalsIgnoreCase(algName)) { + // some PKCS11 keystores and HSMs won't expose the RSAKey interface, so we can't assume it: + final int bitLength = KeysBridge.findBitLength(key); // returns -1 if we're unable to find out + if (bitLength == ES512.orderBitLength) { + return ES512; + } else if (bitLength == ES384.orderBitLength) { + return ES384; + } else if (bitLength == ES256.orderBitLength) { + return ES256; + } + } + + return null; + } + + private EcSignatureAlgorithm(int orderBitLength, String oid) { super("ES" + shaSize(orderBitLength), "SHA" + shaSize(orderBitLength) + "withECDSA"); Assert.isTrue(isSupportedOrderBitLength(orderBitLength), REQD_ORDER_BIT_LENGTH_MSG); + this.OID = Assert.hasText(oid, "Invalid OID."); String curveName = "secp" + orderBitLength + "r1"; this.KEY_PAIR_GEN_PARAMS = new ECGenParameterSpec(curveName); this.orderBitLength = orderBitLength; @@ -142,7 +195,7 @@ public byte[] apply(Signature sig) throws Exception { }); } - protected boolean isValidRAndS(PublicKey key, byte[] concatSignature) { + boolean isValidRAndS(PublicKey key, byte[] concatSignature) { if (key instanceof ECKey) { //Some PKCS11 providers and HSMs won't expose the ECKey interface, so we have to check first ECKey ecKey = (ECKey) key; BigInteger order = ecKey.getParams().getOrder(); diff --git a/impl/src/main/java/io/jsonwebtoken/impl/security/EdSignatureAlgorithm.java b/impl/src/main/java/io/jsonwebtoken/impl/security/EdSignatureAlgorithm.java index c9d68b18a..14cb6baa2 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/security/EdSignatureAlgorithm.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/security/EdSignatureAlgorithm.java @@ -23,25 +23,27 @@ import io.jsonwebtoken.security.VerifyDigestRequest; import java.security.Key; +import java.security.PrivateKey; -public class EdSignatureAlgorithm extends AbstractSignatureAlgorithm { +final class EdSignatureAlgorithm extends AbstractSignatureAlgorithm { private static final String ID = "EdDSA"; private final EdwardsCurve preferredCurve; - public EdSignatureAlgorithm() { + static final EdSignatureAlgorithm INSTANCE = new EdSignatureAlgorithm(); + + static boolean isSigningKey(PrivateKey key) { + EdwardsCurve curve = EdwardsCurve.findByKey(key); + return curve != null && curve.isSignatureCurve(); + } + + private EdSignatureAlgorithm() { super(ID, ID); this.preferredCurve = EdwardsCurve.Ed448; // EdDSA is not available natively until JDK 15, so try to load BC as a backup provider if possible: setProvider(this.preferredCurve.getProvider()); - } - - public EdSignatureAlgorithm(EdwardsCurve preferredCurve) { - super(ID, preferredCurve.getJcaName()); - this.preferredCurve = Assert.notNull(preferredCurve, "preferredCurve cannot be null."); - Assert.isTrue(preferredCurve.isSignatureCurve(), "EdwardsCurve must be a signature curve, not a key agreement curve."); - setProvider(preferredCurve.getProvider()); + Assert.isTrue(this.preferredCurve.isSignatureCurve(), "Must be signature curve, not key agreement curve."); } @Override @@ -74,7 +76,7 @@ protected void validateKey(Key key, boolean signing) { EdwardsCurve curve = EdwardsCurve.findByKey(key); if (curve != null && !curve.isSignatureCurve()) { String msg = curve.getId() + " keys may not be used with " + getId() + " digital signatures per " + - "https://www.rfc-editor.org/rfc/rfc8037#section-3.2"; + "https://www.rfc-editor.org/rfc/rfc8037.html#section-3.2"; throw new UnsupportedKeyException(msg); } } diff --git a/impl/src/main/java/io/jsonwebtoken/impl/security/EdwardsCurve.java b/impl/src/main/java/io/jsonwebtoken/impl/security/EdwardsCurve.java index b5cd00ac2..fe32bfaa8 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/security/EdwardsCurve.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/security/EdwardsCurve.java @@ -281,14 +281,14 @@ protected byte[] doGetKeyMaterial(Key key) { int keyLen = 0; if (encoded[i] == 0x05) { // NULL terminator, next should be zero byte indicator int unusedBytes = encoded[++i]; - Assert.eq(0, unusedBytes, "OID NULL terminator should indicate zero unused bytes."); + Assert.eq(unusedBytes, 0, "OID NULL terminator should indicate zero unused bytes."); i++; } if (encoded[i] == 0x03) { // DER bit stream, Public Key i++; keyLen = encoded[i++]; int unusedBytes = encoded[i++]; - Assert.eq(0, unusedBytes, "BIT STREAM should not indicate unused bytes."); + Assert.eq(unusedBytes, 0, "BIT STREAM should not indicate unused bytes."); keyLen--; } else if (encoded[i] == 0x04) { // DER octet sequence, Private Key. Key length follows as next byte. i++; @@ -298,10 +298,10 @@ protected byte[] doGetKeyMaterial(Key key) { keyLen = encoded[i++]; // next byte is length } } - Assert.eq(this.encodedKeyByteLength, keyLen, "Invalid key length."); + Assert.eq(keyLen, this.encodedKeyByteLength, "Invalid key length."); byte[] result = Arrays.copyOfRange(encoded, i, i + keyLen); keyLen = Bytes.length(result); - Assert.eq(this.encodedKeyByteLength, keyLen, "Invalid key length."); + Assert.eq(keyLen, this.encodedKeyByteLength, "Invalid key length."); return result; } diff --git a/impl/src/main/java/io/jsonwebtoken/impl/security/JwkContext.java b/impl/src/main/java/io/jsonwebtoken/impl/security/JwkContext.java index 1f8d70272..8a86c6be7 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/security/JwkContext.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/security/JwkContext.java @@ -53,6 +53,20 @@ public interface JwkContext extends Identifiable, Map setPublicKeyUse(String use); + /** + * Returns {@code true} if relevant context values indicate JWK use with MAC or digital signature algorithms, + * {@code false} otherwise. Specifically {@code true} is only returned if either: + *
    + *
  • "sig".equals({@link #getPublicKeyUse()}), OR
  • + *
  • {@link #getOperations()} is not empty and contains either "sign" or "verify"
  • + *
+ *

otherwise {@code false}.

+ * + * @return {@code true} if relevant context values indicate JWK use with MAC or digital signature algorithms, + * {@code false} otherwise. + */ + boolean isSigUse(); + K getKey(); JwkContext setKey(K key); diff --git a/impl/src/main/java/io/jsonwebtoken/impl/security/JwtX509StringConverter.java b/impl/src/main/java/io/jsonwebtoken/impl/security/JwtX509StringConverter.java index 9d1e5c913..1bb33509d 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/security/JwtX509StringConverter.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/security/JwtX509StringConverter.java @@ -15,16 +15,20 @@ */ package io.jsonwebtoken.impl.security; +import io.jsonwebtoken.impl.lang.Bytes; +import io.jsonwebtoken.impl.lang.CheckedFunction; +import io.jsonwebtoken.impl.lang.Conditions; import io.jsonwebtoken.impl.lang.Converter; import io.jsonwebtoken.io.Decoders; import io.jsonwebtoken.io.Encoders; -import io.jsonwebtoken.lang.Arrays; import io.jsonwebtoken.lang.Assert; +import io.jsonwebtoken.lang.Strings; +import io.jsonwebtoken.security.SecurityException; import java.io.ByteArrayInputStream; import java.io.InputStream; +import java.security.Provider; import java.security.cert.CertificateEncodingException; -import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; @@ -44,32 +48,60 @@ public String applyTo(X509Certificate cert) { der = cert.getEncoded(); } catch (CertificateEncodingException e) { String msg = "Unable to access X509Certificate encoded bytes necessary to perform DER " + - "Base64-encoding. Certificate: {" + cert + "}. Cause: " + e.getMessage(); + "Base64-encoding. Certificate: {" + cert + "}. Cause: " + e.getMessage(); throw new IllegalArgumentException(msg, e); } - if (Arrays.length(der) == 0) { + if (Bytes.isEmpty(der)) { String msg = "X509Certificate encoded bytes cannot be null or empty. Certificate: {" + cert + "}."; throw new IllegalArgumentException(msg); } return Encoders.BASE64.encode(der); } - //visible for testing - protected CertificateFactory newCertificateFactory() throws CertificateException { - return CertificateFactory.getInstance("X.509"); + // visible for testing + protected X509Certificate toCert(final byte[] der, Provider provider) throws SecurityException { + JcaTemplate template = new JcaTemplate("X.509", provider); + final InputStream is = new ByteArrayInputStream(der); + return template.withCertificateFactory(new CheckedFunction() { + @Override + public X509Certificate apply(CertificateFactory cf) throws Exception { + return (X509Certificate) cf.generateCertificate(is); + } + }); } @Override public X509Certificate applyFrom(String s) { Assert.hasText(s, "X.509 Certificate encoded string cannot be null or empty."); + byte[] der = null; try { - byte[] der = Decoders.BASE64.decode(s); //RFC requires Base64, not Base64Url - CertificateFactory cf = newCertificateFactory(); - InputStream stream = new ByteArrayInputStream(der); - return (X509Certificate) cf.generateCertificate(stream); - } catch (Exception e) { - String msg = "Unable to convert Base64 String '" + s + "' to X509Certificate instance. Cause: " + e.getMessage(); - throw new IllegalArgumentException(msg, e); + der = Decoders.BASE64.decode(s); //RFC requires Base64, not Base64Url + return toCert(der, null); + } catch (final Throwable t) { + + // Some JDK implementations don't support RSASSA-PSS certificates: + // + // https://bugs.openjdk.org/browse/JDK-8242556 + // + // Oracle only backported this fix to JDK 8u271+, 11.0.9+, and 15+, so we'll try to fall back to + // BC (which can read the files correctly) on JDK 9, 10, 12, 13, and 14: + String causeMsg = t.getMessage(); + Provider bc = null; + if (!Bytes.isEmpty(der) && // Base64 decoding succeeded, so we can continue to try + Strings.hasText(causeMsg) && causeMsg.contains(RsaSignatureAlgorithm.PSS_OID)) { + // OID in exception message, so odds are high that the default provider doesn't support X.509 + // certificates with a PSS_OID `AlgorithmId`. But BC does, so try to obtain that if we can: + bc = Providers.findBouncyCastle(Conditions.TRUE); + } + if (bc != null) { + try { + return toCert(der, bc); + } catch (Throwable ignored) { + // ignore this - we want to report the original exception to the caller + } + } + String msg = "Unable to convert Base64 String '" + s + "' to X509Certificate instance. Cause: " + causeMsg; + throw new IllegalArgumentException(msg, t); } } } diff --git a/impl/src/main/java/io/jsonwebtoken/impl/security/KeysBridge.java b/impl/src/main/java/io/jsonwebtoken/impl/security/KeysBridge.java index eac7ccb9a..6a9d59da6 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/security/KeysBridge.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/security/KeysBridge.java @@ -17,11 +17,15 @@ import io.jsonwebtoken.impl.lang.Bytes; import io.jsonwebtoken.lang.Assert; +import io.jsonwebtoken.lang.Strings; import io.jsonwebtoken.security.Password; import io.jsonwebtoken.security.UnsupportedKeyException; +import javax.crypto.SecretKey; import java.security.Key; import java.security.PublicKey; +import java.security.interfaces.ECKey; +import java.security.interfaces.RSAKey; @SuppressWarnings({"unused"}) // reflection bridge class for the io.jsonwebtoken.security.Keys implementation public final class KeysBridge { @@ -34,6 +38,20 @@ public static Password password(char[] password) { return new PasswordSpec(password); } + public static String findAlgorithm(Key key) { + return key != null ? Strings.clean(key.getAlgorithm()) : null; + } + + /** + * Returns the specified key's available encoded bytes, or {@code null} if not available. + * + *

Some KeyStore implementations - like Hardware Security Modules, PKCS11 key stores, and later versions + * of Android - will not allow applications or libraries to obtain a key's encoded bytes. In these cases, + * this method will return null.

+ * + * @param key the key to inspect + * @return the specified key's available encoded bytes, or {@code null} if not available. + */ public static byte[] findEncoded(Key key) { Assert.notNull(key, "Key cannot be null."); byte[] encoded = null; @@ -44,6 +62,40 @@ public static byte[] findEncoded(Key key) { return encoded; } + /** + * Returns the specified key's key length (in bits) if possible, or {@code -1} if unable to determine the length. + * + *

Some KeyStore implementations - like Hardware Security Modules, PKCS11 key stores, and later versions + * of Android - will not allow applications or libraries to determine a key's length. In these cases, + * this method will return {@code -1} to indicate the length could not be determined.

+ * + * @param key the key to inspect + * @return the specified key's key length in bits, or {@code -1} if unable to determine length. + */ + public static int findBitLength(Key key) { + if (key instanceof SecretKey) { + SecretKey sk = (SecretKey) key; + if ("RAW".equals(sk.getFormat())) { + byte[] encoded = findEncoded(key); + if (encoded != null) { + long len = Bytes.bitLength(encoded); + return Assert.lte(len, (long) Integer.MAX_VALUE, "Excessive key bit length.").intValue(); + } + } + } else if (key instanceof RSAKey) { + return ((RSAKey) key).getModulus().bitLength(); + } else if (key instanceof ECKey) { + return ((ECKey) key).getParams().getOrder().bitLength(); + } else { + //try to see if Edwards key: + EdwardsCurve curve = EdwardsCurve.findByKey(key); + if (curve != null) { + return curve.getKeyBitLength(); + } + } + return -1; // unable to determine + } + public static byte[] getEncoded(Key key) { Assert.notNull(key, "Key cannot be null."); byte[] encoded = findEncoded(key); diff --git a/impl/src/main/java/io/jsonwebtoken/impl/security/NoneSignatureAlgorithm.java b/impl/src/main/java/io/jsonwebtoken/impl/security/NoneSignatureAlgorithm.java index 79a95cd8f..1eed99cee 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/security/NoneSignatureAlgorithm.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/security/NoneSignatureAlgorithm.java @@ -23,10 +23,15 @@ import java.security.Key; -public class NoneSignatureAlgorithm implements SecureDigestAlgorithm { +final class NoneSignatureAlgorithm implements SecureDigestAlgorithm { private static final String ID = "none"; + static final SecureDigestAlgorithm INSTANCE = new NoneSignatureAlgorithm(); + + private NoneSignatureAlgorithm() { + } + @Override public String getId() { return ID; diff --git a/impl/src/main/java/io/jsonwebtoken/impl/security/RsaPrivateJwkFactory.java b/impl/src/main/java/io/jsonwebtoken/impl/security/RsaPrivateJwkFactory.java index 4e55d5802..a8b03a90d 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/security/RsaPrivateJwkFactory.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/security/RsaPrivateJwkFactory.java @@ -196,7 +196,7 @@ protected RsaPrivateJwk createJwkFromValues(JwkContext ctx) { if (ctx.containsKey(DefaultRsaPrivateJwk.OTHER_PRIMES_INFO.getId())) { List otherPrimes = reader.get(DefaultRsaPrivateJwk.OTHER_PRIMES_INFO); RSAOtherPrimeInfo[] arr = new RSAOtherPrimeInfo[Collections.size(otherPrimes)]; - otherPrimes.toArray(arr); + arr = otherPrimes.toArray(arr); spec = new RSAMultiPrimePrivateCrtKeySpec(modulus, publicExponent, privateExponent, firstPrime, secondPrime, firstCrtExponent, secondCrtExponent, firstCrtCoefficient, arr); } else { diff --git a/impl/src/main/java/io/jsonwebtoken/impl/security/RsaSignatureAlgorithm.java b/impl/src/main/java/io/jsonwebtoken/impl/security/RsaSignatureAlgorithm.java index 8e2f692e8..95620a5f4 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/security/RsaSignatureAlgorithm.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/security/RsaSignatureAlgorithm.java @@ -18,9 +18,12 @@ import io.jsonwebtoken.impl.lang.CheckedFunction; import io.jsonwebtoken.impl.lang.CheckedSupplier; import io.jsonwebtoken.impl.lang.Conditions; -import io.jsonwebtoken.security.InvalidKeyException; +import io.jsonwebtoken.lang.Assert; +import io.jsonwebtoken.lang.Collections; +import io.jsonwebtoken.lang.Strings; import io.jsonwebtoken.security.KeyPairBuilder; import io.jsonwebtoken.security.SecureRequest; +import io.jsonwebtoken.security.SignatureAlgorithm; import io.jsonwebtoken.security.VerifySecureDigestRequest; import io.jsonwebtoken.security.WeakKeyException; @@ -32,43 +35,78 @@ import java.security.spec.AlgorithmParameterSpec; import java.security.spec.MGF1ParameterSpec; import java.security.spec.PSSParameterSpec; +import java.util.LinkedHashMap; +import java.util.Locale; +import java.util.Map; +import java.util.Set; /** * @since JJWT_RELEASE_VERSION */ -public class RsaSignatureAlgorithm extends AbstractSignatureAlgorithm { +final class RsaSignatureAlgorithm extends AbstractSignatureAlgorithm { + + // Defined in https://www.rfc-editor.org/rfc/rfc8017#appendix-A.1: + //private static final String RSA_ENC_OID = "1.2.840.113549.1.1.1"; // RFC 8017's "rsaEncryption" + + // Defined in https://www.rfc-editor.org/rfc/rfc8017#appendix-A.2.3: + static final String PSS_JCA_NAME = "RSASSA-PSS"; + static final String PSS_OID = "1.2.840.113549.1.1.10"; // RFC 8017's "id-RSASSA-PSS" + + // Defined in https://www.rfc-editor.org/rfc/rfc8017#appendix-A.2.4: + private static final String RS256_OID = "1.2.840.113549.1.1.11"; // RFC 8017's "sha256WithRSAEncryption" + private static final String RS384_OID = "1.2.840.113549.1.1.12"; // RFC 8017's "sha384WithRSAEncryption" + private static final String RS512_OID = "1.2.840.113549.1.1.13"; // RFC 8017's "sha512WithRSAEncryption" + + private static final Set PSS_ALG_NAMES = Collections.setOf(PSS_JCA_NAME, PSS_OID); - private static final String PSS_JCA_NAME = "RSASSA-PSS"; private static final int MIN_KEY_BIT_LENGTH = 2048; - private static AlgorithmParameterSpec pssParamFromSaltBitLength(int saltBitLength) { - MGF1ParameterSpec ps = new MGF1ParameterSpec("SHA-" + saltBitLength); - int saltByteLength = saltBitLength / Byte.SIZE; + private static AlgorithmParameterSpec pssParamSpec(int digestBitLength) { + MGF1ParameterSpec ps = new MGF1ParameterSpec("SHA-" + digestBitLength); + int saltByteLength = digestBitLength / Byte.SIZE; return new PSSParameterSpec(ps.getDigestAlgorithm(), "MGF1", ps, saltByteLength, 1); } + private static SignatureAlgorithm rsaSsaPss(int digestBitLength) { + return new RsaSignatureAlgorithm(digestBitLength, pssParamSpec(digestBitLength)); + } + + static final SignatureAlgorithm RS256 = new RsaSignatureAlgorithm(256); + static final SignatureAlgorithm RS384 = new RsaSignatureAlgorithm(384); + static final SignatureAlgorithm RS512 = new RsaSignatureAlgorithm(512); + static final SignatureAlgorithm PS256 = rsaSsaPss(256); + static final SignatureAlgorithm PS384 = rsaSsaPss(384); + static final SignatureAlgorithm PS512 = rsaSsaPss(512); + + private static final Map PKCSv15_ALGS; + + static { + PKCSv15_ALGS = new LinkedHashMap<>(); + PKCSv15_ALGS.put(RS256_OID, RS256); + PKCSv15_ALGS.put(RS384_OID, RS384); + PKCSv15_ALGS.put(RS512_OID, RS512); + } + private final int preferredKeyBitLength; private final AlgorithmParameterSpec algorithmParameterSpec; - public RsaSignatureAlgorithm(String name, String jcaName, int preferredKeyBitLength, AlgorithmParameterSpec algParam) { + private RsaSignatureAlgorithm(String name, String jcaName, int digestBitLength, AlgorithmParameterSpec paramSpec) { super(name, jcaName); - if (preferredKeyBitLength < MIN_KEY_BIT_LENGTH) { - String msg = "preferredKeyBitLength must be greater than the JWA mandatory minimum key length of " + - MIN_KEY_BIT_LENGTH; - throw new IllegalArgumentException(msg); - } - this.preferredKeyBitLength = preferredKeyBitLength; - this.algorithmParameterSpec = algParam; + this.preferredKeyBitLength = digestBitLength * Byte.SIZE; // RSA invariant + // invariant since this is a protected constructor: + Assert.state(this.preferredKeyBitLength >= MIN_KEY_BIT_LENGTH); + this.algorithmParameterSpec = paramSpec; } - public RsaSignatureAlgorithm(int digestBitLength, int preferredKeyBitLength) { - this("RS" + digestBitLength, "SHA" + digestBitLength + "withRSA", preferredKeyBitLength, null); + private RsaSignatureAlgorithm(int digestBitLength) { + this("RS" + digestBitLength, "SHA" + digestBitLength + "withRSA", digestBitLength, null); } - public RsaSignatureAlgorithm(int digestBitLength, int preferredKeyBitLength, int pssSaltBitLength) { - this("PS" + digestBitLength, PSS_JCA_NAME, preferredKeyBitLength, pssParamFromSaltBitLength(pssSaltBitLength)); - // PSS is not available natively until JDK 11, so try to load BC as a backup provider if possible on <= JDK 10: + // RSASSA-PSS constructor + private RsaSignatureAlgorithm(int digestBitLength, AlgorithmParameterSpec paramSpec) { + this("PS" + digestBitLength, PSS_JCA_NAME, digestBitLength, paramSpec); + // RSASSA-PSS is not available natively until JDK 11, so try to load BC as a backup provider if possible: setProvider(Providers.findBouncyCastle(Conditions.notExists(new CheckedSupplier() { @Override public Signature get() throws Exception { @@ -77,23 +115,73 @@ public Signature get() throws Exception { }))); } + static SignatureAlgorithm findByKey(Key key) { + + String algName = KeysBridge.findAlgorithm(key); + if (!Strings.hasText(algName)) { + return null; + } + algName = algName.toUpperCase(Locale.ENGLISH); // for checking against name Sets + + // some PKCS11 keystores and HSMs won't expose the RSAKey interface, so we can't assume it: + final int bitLength = KeysBridge.findBitLength(key); // returns -1 if we're unable to find out + + if (PSS_ALG_NAMES.contains(algName)) { // generic RSASSA-PSS names, check for key lengths: + // even though we found an RSASSA-PSS key, we need to confirm that the key length is + // sufficient if the encoded key bytes are available: + if (bitLength >= 4096) { + return PS512; + } else if (bitLength >= 3072) { + return PS384; + } else if (bitLength >= MIN_KEY_BIT_LENGTH) { + return PS256; + } + } + + // unable to resolve/recommend an RSASSA-PSS alg, so try PKCS v 1.5 algs by OID: + SignatureAlgorithm alg = PKCSv15_ALGS.get(algName); + if (alg != null) { + return alg; + } + + if ("RSA".equals(algName)) { + if (bitLength >= 4096) { + return RS512; + } else if (bitLength >= 3072) { + return RS384; + } else if (bitLength >= MIN_KEY_BIT_LENGTH) { + return RS256; + } + } + + return null; + } + + static boolean isPss(Key key) { + String alg = KeysBridge.findAlgorithm(key); + return PSS_ALG_NAMES.contains(alg); + } + @Override public KeyPairBuilder keyPair() { - return new DefaultKeyPairBuilder("RSA", this.preferredKeyBitLength) + final String jcaName = this.algorithmParameterSpec != null ? PSS_JCA_NAME : "RSA"; + + //TODO: JDK 8 or later, for RSASSA-PSS, use the following instead of what is below: + // + // AlgorithmParameterSpec keyGenSpec = new RSAKeyGenParameterSpec(this.preferredKeyBitLength, + // RSAKeyGenParameterSpec.F4, this.algorithmParameterSpec); + // return new DefaultKeyPairBuilder(jcaName, keyGenSpec).provider(getProvider()).random(Randoms.secureRandom()); + // + + return new DefaultKeyPairBuilder(jcaName, this.preferredKeyBitLength) .provider(getProvider()) .random(Randoms.secureRandom()); } @Override protected void validateKey(Key key, boolean signing) { - - // https://github.com/jwtk/jjwt/issues/68 - if (signing && !(key instanceof PrivateKey)) { - String msg = "Asymmetric key signatures must be created with PrivateKeys. The specified key is of type: " + - key.getClass().getName(); - throw new InvalidKeyException(msg); - } - + super.validateKey(key, signing); + // https://github.com/jwtk/jjwt/issues/68 : // Some PKCS11 providers and HSMs won't expose the RSAKey interface, so we have to check to see if we can cast // If so, we can provide additional safety checks: if (key instanceof RSAKey) { @@ -105,8 +193,8 @@ protected void validateKey(Key key, boolean signing) { String msg = "The " + keyType(signing) + " key's size is " + size + " bits which is not secure " + "enough for the " + id + " algorithm. The JWT JWA Specification (RFC 7518, Section " + section + ") states that RSA keys MUST have a size >= " + MIN_KEY_BIT_LENGTH + " bits. " + - "Consider using the Jwts.SIG." + id + ".generateKeyPair() " + "method to create a " + - "key pair guaranteed to be secure enough for " + id + ". See " + + "Consider using the Jwts.SIG." + id + ".keyPair() builder to create a " + + "KeyPair guaranteed to be secure enough for " + id + ". See " + "https://tools.ietf.org/html/rfc7518#section-" + section + " for more information."; throw new WeakKeyException(msg); } @@ -130,10 +218,6 @@ public byte[] apply(Signature sig) throws Exception { @Override protected boolean doVerify(final VerifySecureDigestRequest request) { - final Key key = request.getKey(); - if (key instanceof PrivateKey) { //legacy support only TODO: remove for 1.0 - return super.messageDigest(request); - } return jca(request).withSignature(new CheckedFunction() { @Override public Boolean apply(Signature sig) throws Exception { diff --git a/impl/src/main/java/io/jsonwebtoken/impl/security/SecretJwkFactory.java b/impl/src/main/java/io/jsonwebtoken/impl/security/SecretJwkFactory.java index a223f68a2..89d6541fd 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/security/SecretJwkFactory.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/security/SecretJwkFactory.java @@ -22,7 +22,6 @@ import io.jsonwebtoken.io.Encoders; import io.jsonwebtoken.lang.Arrays; import io.jsonwebtoken.lang.Assert; -import io.jsonwebtoken.lang.Collections; import io.jsonwebtoken.lang.Strings; import io.jsonwebtoken.security.MacAlgorithm; import io.jsonwebtoken.security.MalformedKeyException; @@ -87,7 +86,12 @@ private static void assertKeyBitLength(byte[] bytes, MacAlgorithm alg) { if (bitLen != requiredBitLen) { // Implementors note: Don't print out any information about the `bytes` value itself - size, // content, etc., as it is considered secret material: - String msg = "Secret JWK " + AbstractJwk.ALG + " value is '" + alg.getId() + "', but the " + DefaultSecretJwk.K + " length does not equal the '" + alg.getId() + "' length requirement of " + Bytes.bitsMsg(requiredBitLen) + ". This discrepancy could be the result of an algorithm " + "substitution attack or simply an erroneously constructed JWK. In either case, it is likely " + "to result in unexpected or undesired security consequences."; + String msg = "Secret JWK " + AbstractJwk.ALG + " value is '" + alg.getId() + + "', but the " + DefaultSecretJwk.K + " length does not equal the '" + alg.getId() + + "' length requirement of " + Bytes.bitsMsg(requiredBitLen) + + ". This discrepancy could be the result of an algorithm " + + "substitution attack or simply an erroneously constructed JWK. In either case, it is likely " + + "to result in unexpected or undesired security consequences."; throw new MalformedKeyException(msg); } } @@ -107,21 +111,15 @@ protected SecretJwk createJwkFromValues(JwkContext ctx) { assertKeyBitLength(bytes, (MacAlgorithm) alg); } } - if (!Strings.hasText(jcaName) && - ("sig".equalsIgnoreCase(ctx.getPublicKeyUse()) || // [1] - (!Collections.isEmpty(ctx.getOperations()) && ctx.getOperations().contains("sign")))) { // [2] - // [1] Even though 'use' is for PUBLIC KEY use (as defined in RFC 7515), RFC 7520 shows secret keys with - // 'use' values, so we'll account for that as well - // - // [2] operations values are case-sensitive, so we don't need to test for upper/lowercase "sign" values - - // The only JWA SecretKey signature algorithms are HS256, HS384, HS512, so choose based on bit length: - jcaName = "HmacSHA" + Bytes.bitLength(bytes); - } - if (jcaName == null) { // not an HS* algorithm, no signature "use", no "sign" key op, so default to encryption: - jcaName = AesAlgorithm.KEY_ALG_NAME; + if (!Strings.hasText(jcaName)) { + if (ctx.isSigUse()) { + // The only JWA SecretKey signature algorithms are HS256, HS384, HS512, so choose based on bit length: + jcaName = "HmacSHA" + Bytes.bitLength(bytes); + } else { // not an HS* algorithm, and all standard AeadAlgorithms use AES keys: + jcaName = AesAlgorithm.KEY_ALG_NAME; + } } - + Assert.stateNotNull(jcaName, "jcaName cannot be null (invariant)"); SecretKey key = new SecretKeySpec(bytes, jcaName); ctx.setKey(key); return new DefaultSecretJwk(ctx); diff --git a/impl/src/main/java/io/jsonwebtoken/impl/security/StandardCurves.java b/impl/src/main/java/io/jsonwebtoken/impl/security/StandardCurves.java new file mode 100644 index 000000000..cb56da87b --- /dev/null +++ b/impl/src/main/java/io/jsonwebtoken/impl/security/StandardCurves.java @@ -0,0 +1,27 @@ +/* + * Copyright © 2023 jsonwebtoken.io + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jsonwebtoken.impl.security; + +import io.jsonwebtoken.impl.lang.DelegatingRegistry; +import io.jsonwebtoken.impl.lang.IdRegistry; +import io.jsonwebtoken.security.Curve; + +@SuppressWarnings("unused") // used via reflection in io.jsonwebtoken.Jwks.CRV +public final class StandardCurves extends DelegatingRegistry { + public StandardCurves() { + super(new IdRegistry<>("Elliptic Curve", Curves.VALUES, false)); + } +} diff --git a/impl/src/main/java/io/jsonwebtoken/impl/security/StandardSecureDigestAlgorithms.java b/impl/src/main/java/io/jsonwebtoken/impl/security/StandardSecureDigestAlgorithms.java index 8d27751a5..fb518a29e 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/security/StandardSecureDigestAlgorithms.java +++ b/impl/src/main/java/io/jsonwebtoken/impl/security/StandardSecureDigestAlgorithms.java @@ -18,51 +18,57 @@ import io.jsonwebtoken.impl.lang.DelegatingRegistry; import io.jsonwebtoken.impl.lang.IdRegistry; import io.jsonwebtoken.lang.Collections; +import io.jsonwebtoken.security.Password; import io.jsonwebtoken.security.SecureDigestAlgorithm; +import javax.crypto.SecretKey; +import java.security.Key; +import java.security.PrivateKey; + @SuppressWarnings("unused") // used via reflection in io.jsonwebtoken.Jwts.SIG public final class StandardSecureDigestAlgorithms extends DelegatingRegistry> { - private static final EdSignatureAlgorithm Ed25519 = new EdSignatureAlgorithm(EdwardsCurve.Ed25519); - private static final EdSignatureAlgorithm Ed448 = new EdSignatureAlgorithm(EdwardsCurve.Ed448); - public StandardSecureDigestAlgorithms() { super(new IdRegistry<>("JWS Digital Signature or MAC", Collections.of( - new NoneSignatureAlgorithm(), - new DefaultMacAlgorithm(256), - new DefaultMacAlgorithm(384), - new DefaultMacAlgorithm(512), - new RsaSignatureAlgorithm(256, 2048), - new RsaSignatureAlgorithm(384, 3072), - new RsaSignatureAlgorithm(512, 4096), - new RsaSignatureAlgorithm(256, 2048, 256), - new RsaSignatureAlgorithm(384, 3072, 384), - new RsaSignatureAlgorithm(512, 4096, 512), - new EcSignatureAlgorithm(256), - new EcSignatureAlgorithm(384), - new EcSignatureAlgorithm(521), - new EdSignatureAlgorithm() + NoneSignatureAlgorithm.INSTANCE, + DefaultMacAlgorithm.HS256, + DefaultMacAlgorithm.HS384, + DefaultMacAlgorithm.HS512, + RsaSignatureAlgorithm.RS256, + RsaSignatureAlgorithm.RS384, + RsaSignatureAlgorithm.RS512, + RsaSignatureAlgorithm.PS256, + RsaSignatureAlgorithm.PS384, + RsaSignatureAlgorithm.PS512, + EcSignatureAlgorithm.ES256, + EcSignatureAlgorithm.ES384, + EcSignatureAlgorithm.ES512, + EdSignatureAlgorithm.INSTANCE ), false)); } - @Override - public SecureDigestAlgorithm get(Object id) { - String key = (String) id; // could throw ClassCastException, which is allowed per Map 'get' contract - if (EdwardsCurve.Ed448.getId().equalsIgnoreCase(key)) { - return Ed448; - } else if (EdwardsCurve.Ed25519.getId().equalsIgnoreCase(key)) { - return Ed25519; - } - return super.get(key); - } + @SuppressWarnings("unchecked") + public static SecureDigestAlgorithm findBySigningKey(K key) { + + SecureDigestAlgorithm alg = null; // null value means no suitable match - @Override - public SecureDigestAlgorithm forKey(String id) throws IllegalArgumentException { - if (EdwardsCurve.Ed448.getId().equalsIgnoreCase(id)) { - return Ed448; - } else if (EdwardsCurve.Ed25519.getId().equalsIgnoreCase(id)) { - return Ed25519; + if (key instanceof SecretKey && !(key instanceof Password)) { + + alg = DefaultMacAlgorithm.findByKey(key); + + } else if (key instanceof PrivateKey) { + + PrivateKey pk = (PrivateKey) key; + + alg = RsaSignatureAlgorithm.findByKey(pk); + if (alg == null) { + alg = EcSignatureAlgorithm.findByKey(pk); + } + if (alg == null && EdSignatureAlgorithm.isSigningKey(pk)) { + alg = EdSignatureAlgorithm.INSTANCE; + } } - return super.forKey(id); + + return (SecureDigestAlgorithm) alg; } } diff --git a/impl/src/test/groovy/io/jsonwebtoken/JwksCRVTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/JwksCRVTest.groovy new file mode 100644 index 000000000..b423d5c3d --- /dev/null +++ b/impl/src/test/groovy/io/jsonwebtoken/JwksCRVTest.groovy @@ -0,0 +1,37 @@ +/* + * Copyright © 2023 jsonwebtoken.io + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.jsonwebtoken + +import io.jsonwebtoken.impl.security.Curves +import io.jsonwebtoken.impl.security.EdwardsCurve +import io.jsonwebtoken.security.Jwks +import org.junit.Test + +import static org.junit.Assert.assertSame + +class JwksCRVTest { + + @Test + void testInstances() { + assertSame Curves.P_256, Jwks.CRV.P256 + assertSame Curves.P_384, Jwks.CRV.P384 + assertSame Curves.P_521, Jwks.CRV.P521 + assertSame EdwardsCurve.X25519, Jwks.CRV.X25519 + assertSame EdwardsCurve.X448, Jwks.CRV.X448 + assertSame EdwardsCurve.Ed25519, Jwks.CRV.Ed25519 + assertSame EdwardsCurve.Ed448, Jwks.CRV.Ed448 + } +} diff --git a/impl/src/test/groovy/io/jsonwebtoken/JwtsTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/JwtsTest.groovy index 61a4c8791..8fe83c190 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/JwtsTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/JwtsTest.groovy @@ -36,6 +36,8 @@ import java.security.Key import java.security.KeyPair import java.security.PrivateKey import java.security.PublicKey +import java.security.interfaces.ECPublicKey +import java.security.interfaces.RSAPublicKey import static org.junit.Assert.* @@ -614,21 +616,6 @@ class JwtsTest { testRsa(Jwts.SIG.PS512) } - @Test - void testRSA256WithPrivateKeyValidation() { - testRsa(Jwts.SIG.RS256, true) - } - - @Test - void testRSA384WithPrivateKeyValidation() { - testRsa(Jwts.SIG.RS384, true) - } - - @Test - void testRSA512WithPrivateKeyValidation() { - testRsa(Jwts.SIG.RS512, true) - } - @Test void testES256() { testEC(Jwts.SIG.ES256) @@ -651,12 +638,12 @@ class JwtsTest { @Test void testEd25519() { - testEC(Jwts.SIG.Ed25519) + testEC(Jwts.SIG.EdDSA, TestKeys.forAlgorithm(Jwks.CRV.Ed25519).pair) } @Test void testEd448() { - testEC(Jwts.SIG.Ed448) + testEC(Jwts.SIG.EdDSA, TestKeys.forAlgorithm(Jwks.CRV.Ed448).pair) } @Test @@ -1211,16 +1198,20 @@ class JwtsTest { // Now for the forgery: simulate an attacker using the RSA public key to sign a token, but // using it as an HMAC signing key instead of RSA: Mac mac = Mac.getInstance('HmacSHA256') - mac.init(new SecretKeySpec(publicKey.getEncoded(), 'HmacSHA256')) + byte[] raw = ((RSAPublicKey)publicKey).getModulus().toByteArray() + if (raw.length > 256) { + raw = Arrays.copyOfRange(raw, 1, raw.length) + } + mac.init(new SecretKeySpec(raw, 'HmacSHA256')) byte[] signatureBytes = mac.doFinal(compact.getBytes(Charset.forName('US-ASCII'))) String encodedSignature = Encoders.BASE64URL.encode(signatureBytes) //Finally, the forged token is the header + body + forged signature: String forged = compact + encodedSignature - // Assert that the server (that should always use the private key) does not recognized the forged token: + // Assert that the server does not recognized the forged token: try { - Jwts.parser().setSigningKey(privateKey).build().parse(forged) + Jwts.parser().verifyWith(privateKey).build().parse(forged) fail("Forged token must not be successfully parsed.") } catch (UnsupportedJwtException expected) { assertTrue expected.getMessage().startsWith('The parsed JWT indicates it was signed with the') @@ -1243,7 +1234,11 @@ class JwtsTest { // Now for the forgery: simulate an attacker using the RSA public key to sign a token, but // using it as an HMAC signing key instead of RSA: Mac mac = Mac.getInstance('HmacSHA256') - mac.init(new SecretKeySpec(publicKey.getEncoded(), 'HmacSHA256')) + byte[] raw = ((RSAPublicKey)publicKey).getModulus().toByteArray() + if (raw.length > 256) { + raw = Arrays.copyOfRange(raw, 1, raw.length) + } + mac.init(new SecretKeySpec(raw, 'HmacSHA256')) byte[] signatureBytes = mac.doFinal(compact.getBytes(Charset.forName('US-ASCII'))) String encodedSignature = Encoders.BASE64URL.encode(signatureBytes) @@ -1275,7 +1270,11 @@ class JwtsTest { // Now for the forgery: simulate an attacker using the Elliptic Curve public key to sign a token, but // using it as an HMAC signing key instead of Elliptic Curve: Mac mac = Mac.getInstance('HmacSHA256') - mac.init(new SecretKeySpec(publicKey.getEncoded(), 'HmacSHA256')) + byte[] raw = ((ECPublicKey)publicKey).getParams().getOrder().toByteArray() + if (raw.length > 32) { + raw = Arrays.copyOfRange(raw, 1, raw.length) + } + mac.init(new SecretKeySpec(raw, 'HmacSHA256')) byte[] signatureBytes = mac.doFinal(compact.getBytes(Charset.forName('US-ASCII'))) String encodedSignature = Encoders.BASE64URL.encode(signatureBytes) @@ -1566,7 +1565,7 @@ class JwtsTest { return Jwts.parser().decryptWith(key).build().parseClaimsJwe(jwe) } - static void testRsa(io.jsonwebtoken.security.SignatureAlgorithm alg, boolean verifyWithPrivateKey = false) { + static void testRsa(io.jsonwebtoken.security.SignatureAlgorithm alg) { KeyPair kp = TestKeys.forAlgorithm(alg).pair PublicKey publicKey = kp.getPublic() @@ -1576,12 +1575,7 @@ class JwtsTest { String jwt = Jwts.builder().claims().add(claims).and().signWith(privateKey, alg).compact() - def key = publicKey - if (verifyWithPrivateKey) { - key = privateKey - } - - def token = Jwts.parser().verifyWith(key).build().parse(jwt) + def token = Jwts.parser().verifyWith(publicKey).build().parse(jwt) assertEquals([alg: alg.getId()], token.header) assertEquals(claims, token.payload) @@ -1603,8 +1597,11 @@ class JwtsTest { } static void testEC(io.jsonwebtoken.security.SignatureAlgorithm alg, boolean verifyWithPrivateKey = false) { + testEC(alg, TestKeys.forAlgorithm(alg).pair, verifyWithPrivateKey) + } + + static void testEC(io.jsonwebtoken.security.SignatureAlgorithm alg, KeyPair pair, boolean verifyWithPrivateKey = false) { - KeyPair pair = TestKeys.forAlgorithm(alg).pair PublicKey publicKey = pair.getPublic() PrivateKey privateKey = pair.getPrivate() @@ -1621,6 +1618,7 @@ class JwtsTest { assertEquals([alg: alg.getId()], token.header) assertEquals(claims, token.payload) + } } diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtBuilderTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtBuilderTest.groovy index de39adb9e..069c2dca2 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtBuilderTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtBuilderTest.groovy @@ -21,14 +21,15 @@ import io.jsonwebtoken.Jwts import io.jsonwebtoken.SignatureAlgorithm import io.jsonwebtoken.impl.lang.Services import io.jsonwebtoken.impl.security.Randoms +import io.jsonwebtoken.impl.security.TestKey import io.jsonwebtoken.impl.security.TestKeys import io.jsonwebtoken.io.* import io.jsonwebtoken.security.* import org.junit.Before import org.junit.Test -import javax.crypto.KeyGenerator import java.nio.charset.StandardCharsets +import java.security.MessageDigest import java.security.Provider import java.security.SecureRandom @@ -314,20 +315,56 @@ class DefaultJwtBuilderTest { @Test void testSignWithKeyOnly() { - def b = new DefaultJwtBuilder() - b.header().keyId('a') - b.setPayload('foo') + builder.subject("Joe") // make Claims JWS - def key = KeyGenerator.getInstance('HmacSHA256').generateKey() + for (SecureDigestAlgorithm alg : Jwts.SIG.get().values()) { + if (alg.equals(Jwts.SIG.NONE)) { // skip + continue; + } + def key, vkey + if (alg instanceof KeyPairBuilderSupplier) { + def keyPair = alg.keyPair().build() + key = keyPair.private + vkey = keyPair.public + } else { // MAC + key = ((MacAlgorithm) alg).key().build() + vkey = key + } - b.signWith(key) - String s1 = b.compact() + def parser = Jwts.parser().verifyWith(vkey).build() - //ensure matches same result with specified algorithm: - b.signWith(key, SignatureAlgorithm.HS256) - String s2 = b.compact() + String s1 = builder.signWith(key).compact() + def jws = parser.parseClaimsJws(s1) - assertEquals s1, s2 + String s2 = builder.signWith(key, alg).compact() + def jws2 = parser.parseClaimsJws(s2) + + // signatures differ across duplicate operations for some algorithms, so we can't do + // assertEquals jws, jws2 (since those .equals implementations use the signature) + // So we check for header and payload equality instead, and check the signature when we can: + assertEquals jws.getHeader(), jws2.getHeader() + assertEquals jws2.getPayload(), jws2.getPayload() + // ES* and PS* signatures are nondeterministic and differ on each sign operation, even for identical + // input, so we can't assert signature equality for them. But we can with the others: + if (!alg.id.startsWith('ES') && !alg.id.startsWith('PS')) { + assertTrue MessageDigest.isEqual(jws.getDigest(), jws2.getDigest()) + } + } + } + + @Test + void testSignWithKeyOnlyUsingUnsupportedKey() { + try { + builder.signWith(new TestKey(algorithm: 'foo')) + fail() + } catch (UnsupportedKeyException expected) { + String msg = 'Unable to determine a suitable MAC or Signature algorithm for the specified key using ' + + 'available heuristics: either the key size is too weak be used with available algorithms, or ' + + 'the key size is unavailable (e.g. if using a PKCS11 or HSM (Hardware Security Module) key ' + + 'store). If you are using a PKCS11 or HSM keystore, consider using the ' + + 'JwtBuilder.signWith(Key, SecureDigestAlgorithm) method instead.' + assertEquals msg, expected.getMessage() + } } @Test @@ -337,7 +374,8 @@ class DefaultJwtBuilderTest { new DefaultJwtBuilder().signWith(SignatureAlgorithm.ES256, bytes); fail() } catch (IllegalArgumentException iae) { - assertEquals "Key bytes may only be specified for HMAC signatures. If using RSA or Elliptic Curve, use the signWith(SignatureAlgorithm, Key) method instead.", iae.message + assertEquals "Key bytes may only be specified for HMAC signatures. If using RSA or " + + "Elliptic Curve, use the signWith(SignatureAlgorithm, Key) method instead.", iae.message } } diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtParserBuilderTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtParserBuilderTest.groovy index 100564620..b243a5579 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtParserBuilderTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/DefaultJwtParserBuilderTest.groovy @@ -357,6 +357,17 @@ class DefaultJwtParserBuilderTest { } } + @Test + void testSetSigningKeyWithPrivateKey() { + try { + builder.setSigningKey(TestKeys.RS256.pair.private) + fail() + } catch (UnsupportedKeyException e) { + String msg = 'JWS verification key must be either a SecretKey (for MAC algorithms) or a PublicKey (for Signature algorithms).' + assertEquals msg, e.getMessage() + } + } + static class TestCompressionCodec implements CompressionCodec { String id diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/DefaultJwkParserTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/DefaultJwkParserTest.groovy index 5543528ef..175e8c613 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/DefaultJwkParserTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/DefaultJwkParserTest.groovy @@ -26,6 +26,7 @@ import org.junit.Test import java.nio.charset.StandardCharsets import java.security.Key +import java.security.Provider import static org.junit.Assert.* @@ -35,12 +36,8 @@ class DefaultJwkParserTest { void testKeys() { Set keys = new LinkedHashSet<>() - TestKeys.HS.each { keys.add(it) } - TestKeys.RSA.each { - keys.add(it.pair.public) - keys.add(it.pair.private) - } - TestKeys.EC.each { + TestKeys.SECRET.each { keys.add(it) } + TestKeys.ASYM.each { keys.add(it.pair.public) keys.add(it.pair.private) } @@ -48,7 +45,13 @@ class DefaultJwkParserTest { def serializer = Services.loadFirst(Serializer) for (Key key : keys) { //noinspection GroovyAssignabilityCheck - def jwk = Jwks.builder().key(key).build() + Provider provider = null // assume default, but switch if key requires it + if (key.getClass().getName().startsWith("org.bouncycastle.")) { + // No native JVM support for the key, so we need to enable BC: + provider = Providers.findBouncyCastle(Conditions.TRUE) + } + //noinspection GroovyAssignabilityCheck + def jwk = Jwks.builder().provider(provider).key(key).build() def data = serializer.serialize(jwk) String json = new String(data, StandardCharsets.UTF_8) def parsed = Jwks.parser().build().parse(json) @@ -61,29 +64,37 @@ class DefaultJwkParserTest { Set keys = new LinkedHashSet<>() TestKeys.HS.each { keys.add(it) } - TestKeys.RSA.each { - keys.add(it.pair.public) - keys.add(it.pair.private) - } - TestKeys.EC.each { + TestKeys.ASYM.each { keys.add(it.pair.public) keys.add(it.pair.private) } def serializer = Services.loadFirst(Serializer) - def provider = Providers.findBouncyCastle(Conditions.TRUE) + def provider = Providers.findBouncyCastle(Conditions.TRUE) //always used for (Key key : keys) { //noinspection GroovyAssignabilityCheck - def jwk = Jwks.builder().key(key).build() + def jwk = Jwks.builder().provider(provider).key(key).build() def data = serializer.serialize(jwk) String json = new String(data, StandardCharsets.UTF_8) - def parsed = Jwks.parser().provider(provider).build().parse(json) + def parsed = Jwks.parser().build().parse(json) assertEquals jwk, parsed - assertSame provider, parsed.@context.@provider + //assertSame provider, parsed.@context.@provider } } + @Test + void testParseWithProvider() { + def provider = Providers.findBouncyCastle(Conditions.TRUE) + def jwk = Jwks.builder().provider(provider).key(TestKeys.HS256).build() + def serializer = Services.loadFirst(Serializer) + def data = serializer.serialize(jwk) + String json = new String(data, StandardCharsets.UTF_8) + def parsed = Jwks.parser().provider(provider).build().parse(json) + assertEquals jwk, parsed + assertSame provider, parsed.@context.@provider + } + @Test void testDeserializationFailure() { def parser = new DefaultJwkParser(null, Services.loadFirst(Deserializer)) { diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/DefaultMacAlgorithmTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/DefaultMacAlgorithmTest.groovy index b2ace2f1c..83b751b33 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/DefaultMacAlgorithmTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/DefaultMacAlgorithmTest.groovy @@ -22,7 +22,7 @@ import javax.crypto.spec.SecretKeySpec import java.nio.charset.StandardCharsets import java.security.Key -import static org.junit.Assert.assertEquals +import static org.junit.Assert.* class DefaultMacAlgorithmTest { @@ -164,4 +164,70 @@ class DefaultMacAlgorithmTest { assertEquals 'The signing key\'s size is 192 bits which is not secure enough for the foo algorithm. The foo algorithm requires keys to have a size >= 256 bits.', expected.getMessage() } } + + @Test + void testFindByKeyWithNoAlgorithm() { + assertNull DefaultMacAlgorithm.findByKey(new TestSecretKey()) + } + + @Test + void testFindByKeyInvalidAlgorithm() { + assertNull DefaultMacAlgorithm.findByKey(new TestSecretKey(algorithm: 'foo')) + } + + @Test + void testFindByKey() { + for(def mac : DefaultMacAlgorithm.JCA_NAME_MAP.values()) { + def key = mac.key().build() + assertSame mac, DefaultMacAlgorithm.findByKey(key) + } + } + + @Test + void testFindByKeyNull() { + assertNull DefaultMacAlgorithm.findByKey(null) + } + + @Test + void testFindByNonSecretKey() { + assertNull DefaultMacAlgorithm.findByKey(TestKeys.RS256.pair.public) + } + + @Test + void testFindByWeakKey() { + for(def mac : DefaultMacAlgorithm.JCA_NAME_MAP.values()) { + def key = mac.key().build() + def encoded = new byte[key.getEncoded().length - 1] // one byte less than required + def weak = new TestSecretKey(algorithm: key.getAlgorithm(), format: key.getFormat(), encoded: encoded) + assertSame mac, DefaultMacAlgorithm.findByKey(key) + assertNull DefaultMacAlgorithm.findByKey(weak) + } + } + + @Test + void testFindByLargerThanExpectedKey() { + for(def mac : DefaultMacAlgorithm.JCA_NAME_MAP.values()) { + def key = mac.key().build() + def encoded = new byte[key.getEncoded().length + 1] // one byte less than required + def strong = new TestSecretKey(algorithm: key.getAlgorithm(), format: key.getFormat(), encoded: encoded) + assertSame mac, DefaultMacAlgorithm.findByKey(strong) + } + } + + @Test + void testFindByKeyOid() { + for(def mac : DefaultMacAlgorithm.JCA_NAME_MAP.values()) { + def key = mac.key().build() + def alg = key.getAlgorithm() + if (alg.endsWith('256')) { + alg = DefaultMacAlgorithm.HS256_OID + } else if (alg.endsWith('384')) { + alg = DefaultMacAlgorithm.HS384_OID + } else { + alg = DefaultMacAlgorithm.HS512_OID + } + def oidKey = new TestSecretKey(algorithm: alg, format: 'RAW', encoded: key.getEncoded()) + assertSame mac, DefaultMacAlgorithm.findByKey(oidKey) + } + } } diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/DefaultRsaKeyAlgorithmTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/DefaultRsaKeyAlgorithmTest.groovy index e243887b4..4a2d4d573 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/DefaultRsaKeyAlgorithmTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/DefaultRsaKeyAlgorithmTest.groovy @@ -16,6 +16,7 @@ package io.jsonwebtoken.impl.security import io.jsonwebtoken.Jwts +import io.jsonwebtoken.security.UnsupportedKeyException import io.jsonwebtoken.security.WeakKeyException import org.junit.Test @@ -40,10 +41,43 @@ class DefaultRsaKeyAlgorithmTest { } } + @Test + void testPssKey() { + for (DefaultRsaKeyAlgorithm alg : algs) { + RSAPublicKey key = createMock(RSAPublicKey) + expect(key.getAlgorithm()).andReturn(RsaSignatureAlgorithm.PSS_JCA_NAME) + replay(key) + try { + alg.validate(key, true) + } catch (UnsupportedKeyException expected) { + String msg = 'RSASSA-PSS keys may not be used for encryption, only digital signature algorithms.' + assertEquals msg, expected.getMessage() + } + verify(key) + } + } + + @Test + void testPssOidKey() { + for (DefaultRsaKeyAlgorithm alg : algs) { + RSAPublicKey key = createMock(RSAPublicKey) + expect(key.getAlgorithm()).andReturn(RsaSignatureAlgorithm.PSS_OID) + replay(key) + try { + alg.validate(key, true) + } catch (UnsupportedKeyException expected) { + String msg = 'RSASSA-PSS keys may not be used for encryption, only digital signature algorithms.' + assertEquals msg, expected.getMessage() + } + verify(key) + } + } + @Test void testWeakEncryptionKey() { for (DefaultRsaKeyAlgorithm alg : algs) { RSAPublicKey key = createMock(RSAPublicKey) + expect(key.getAlgorithm()).andReturn("RSA") expect(key.getModulus()).andReturn(BigInteger.ONE) replay(key) try { @@ -65,6 +99,7 @@ class DefaultRsaKeyAlgorithmTest { void testWeakDecryptionKey() { for (DefaultRsaKeyAlgorithm alg : algs) { RSAPrivateKey key = createMock(RSAPrivateKey) + expect(key.getAlgorithm()).andReturn("RSA") expect(key.getModulus()).andReturn(BigInteger.ONE) replay(key) try { diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/EcSignatureAlgorithmTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/EcSignatureAlgorithmTest.groovy index 8854443aa..278e3f616 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/EcSignatureAlgorithmTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/EcSignatureAlgorithmTest.groovy @@ -48,16 +48,44 @@ class EcSignatureAlgorithmTest { @Test void testConstructorWithWeakKeyLength() { try { - new EcSignatureAlgorithm(128) + new EcSignatureAlgorithm(128, 'foo') } catch (IllegalArgumentException iae) { String msg = 'orderBitLength must equal 256, 384, or 521.' assertEquals msg, iae.getMessage() } } + @Test + void testFindByNoAlgKey() { + assertNull EcSignatureAlgorithm.findByKey(new TestKey()) + } + + @Test + void testFindOidKeys() { + for(def alg : EcSignatureAlgorithm.ALGS_BY_OID.values()) { + String name = "${alg.getId()}_OID" + String oid = EcSignatureAlgorithm.metaClass.getAttribute(EcSignatureAlgorithm, name) as String + assertEquals oid, alg.OID + def key = new TestKey(algorithm: oid) + assertSame alg, EcSignatureAlgorithm.findByKey(key) + } + } + + @Test + void testFindByWeakKey() { + ECPublicKey key = createMock(ECPublicKey) + ECParameterSpec spec = createMock(ECParameterSpec) + expect(key.getAlgorithm()).andStubReturn("EC") + expect(key.getParams()).andStubReturn(spec) + expect(spec.getOrder()).andStubReturn(BigInteger.ONE) + replay key, spec + assertNull EcSignatureAlgorithm.findByKey(key) + verify key, spec + } + @Test void testValidateKeyWithoutEcKey() { - def key = createMock(PublicKey) + PublicKey key = createMock(PublicKey) replay key algs().each { it.validateKey(key, false) @@ -68,7 +96,7 @@ class EcSignatureAlgorithmTest { @Test void testIsValidRAndSWithoutEcKey() { - def key = createMock(PublicKey) + PublicKey key = createMock(PublicKey) replay key algs().each { it.isValidRAndS(key, Bytes.EMPTY) diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/EdSignatureAlgorithmTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/EdSignatureAlgorithmTest.groovy index 6f1f8f65f..fe6bcbd82 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/EdSignatureAlgorithmTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/EdSignatureAlgorithmTest.groovy @@ -17,7 +17,6 @@ package io.jsonwebtoken.impl.security import io.jsonwebtoken.Jwts import io.jsonwebtoken.UnsupportedJwtException -import io.jsonwebtoken.security.SignatureAlgorithm import io.jsonwebtoken.security.SignatureException import org.junit.Test @@ -28,41 +27,30 @@ import static org.junit.Assert.* class EdSignatureAlgorithmTest { - static List algs = [Jwts.SIG.EdDSA, Jwts.SIG.Ed25519, Jwts.SIG.Ed448] as List + static EdSignatureAlgorithm alg = Jwts.SIG.EdDSA as EdSignatureAlgorithm @Test void testJcaName() { - assertEquals Jwts.SIG.EdDSA.getId(), Jwts.SIG.EdDSA.getJcaName() - assertEquals EdwardsCurve.Ed25519.getId(), Jwts.SIG.Ed25519.getJcaName() - assertEquals EdwardsCurve.Ed448.getId(), Jwts.SIG.Ed448.getJcaName() + // the JWT RFC id and the JDK standard name appen to be the same: + assertEquals alg.getId(), alg.getJcaName() } @Test void testId() { - //There is only one signature algorithm ID defined for Edwards curve keys per - // https://www.rfc-editor.org/rfc/rfc8037#section-3.1 and - // https://www.rfc-editor.org/rfc/rfc8037#section-5 - // - // As such, the Ed25519 and Ed448 SignatureAlgorithm instances _must_ reflect the same ID since that's the - // only one recognized by the spec. They are effectively just aliases of EdDSA but have the added - // functionality of generating Ed25519 and Ed448 keys, that's the only difference. - for (EdSignatureAlgorithm alg : algs) { - assertEquals Jwts.SIG.EdDSA.getId(), alg.getId() // all aliases of EdDSA per the RFC spec - } + // https://www.rfc-editor.org/rfc/rfc8037#section-3.1: + assertEquals 'EdDSA', alg.getId() } @Test void testKeyPairBuilder() { - algs.each { - def pair = it.keyPair().build() - assertNotNull pair.public - assertTrue pair.public instanceof PublicKey - String alg = pair.public.getAlgorithm() - assertTrue Jwts.SIG.EdDSA.getId().equals(alg) || alg.equals(it.preferredCurve.getId()) - - alg = pair.private.getAlgorithm() - assertTrue Jwts.SIG.EdDSA.getId().equals(alg) || alg.equals(it.preferredCurve.getId()) - } + def pair = alg.keyPair().build() + assertNotNull pair.public + assertTrue pair.public instanceof PublicKey + String algName = pair.public.getAlgorithm() + assertTrue alg.getId().equals(algName) || algName.equals(alg.preferredCurve.getId()) + + algName = pair.private.getAlgorithm() + assertTrue alg.getId().equals(algName) || algName.equals(alg.preferredCurve.getId()) } /** @@ -71,46 +59,44 @@ class EdSignatureAlgorithmTest { @Test void testGetAlgorithmJcaNameWhenCantFindCurve() { def key = new TestKey(algorithm: 'foo') - algs.each { - def payload = [0x00] as byte[] - def req = new DefaultSecureRequest(payload, null , null, key) - assertEquals it.getJcaName(), it.getJcaName(req) - } + def payload = [0x00] as byte[] + def req = new DefaultSecureRequest(payload, null, null, key) + assertEquals alg.getJcaName(), alg.getJcaName(req) } @Test void testEd25519SigVerifyWithEd448() { - testIncorrectVerificationKey(Jwts.SIG.Ed25519, TestKeys.Ed25519.pair.private, TestKeys.Ed448.pair.public) + testIncorrectVerificationKey(TestKeys.Ed25519.pair.private, TestKeys.Ed448.pair.public) } @Test void testEd25519SigVerifyWithX25519() { - testInvalidVerificationKey(Jwts.SIG.Ed25519, TestKeys.Ed25519.pair.private, TestKeys.X25519.pair.public) + testInvalidVerificationKey(TestKeys.Ed25519.pair.private, TestKeys.X25519.pair.public) } @Test void testEd25519SigVerifyWithX448() { - testInvalidVerificationKey(Jwts.SIG.Ed25519, TestKeys.Ed25519.pair.private, TestKeys.X448.pair.public) + testInvalidVerificationKey(TestKeys.Ed25519.pair.private, TestKeys.X448.pair.public) } @Test void testEd448SigVerifyWithEd25519() { - testIncorrectVerificationKey(Jwts.SIG.Ed448, TestKeys.Ed448.pair.private, TestKeys.Ed25519.pair.public) + testIncorrectVerificationKey(TestKeys.Ed448.pair.private, TestKeys.Ed25519.pair.public) } @Test void testEd448SigVerifyWithX25519() { - testInvalidVerificationKey(Jwts.SIG.Ed448, TestKeys.Ed448.pair.private, TestKeys.X25519.pair.public) + testInvalidVerificationKey(TestKeys.Ed448.pair.private, TestKeys.X25519.pair.public) } @Test void testEd448SigVerifyWithX448() { - testInvalidVerificationKey(Jwts.SIG.Ed448, TestKeys.Ed448.pair.private, TestKeys.X448.pair.public) + testInvalidVerificationKey(TestKeys.Ed448.pair.private, TestKeys.X448.pair.public) } - static void testIncorrectVerificationKey(SignatureAlgorithm alg, PrivateKey priv, PublicKey pub) { + static void testIncorrectVerificationKey(PrivateKey priv, PublicKey pub) { try { - testSig(alg, priv, pub) + testSig(priv, pub) fail() } catch (SignatureException expected) { // SignatureException message can differ depending on JDK version and if BC is enabled or not: @@ -124,20 +110,21 @@ class EdSignatureAlgorithmTest { } } - static void testInvalidVerificationKey(SignatureAlgorithm alg, PrivateKey priv, PublicKey pub) { + static void testInvalidVerificationKey(PrivateKey priv, PublicKey pub) { try { - testSig(alg, priv, pub) + testSig(priv, pub) fail() } catch (UnsupportedJwtException expected) { def cause = expected.getCause() def keyCurve = EdwardsCurve.forKey(pub) - String expectedMsg = "${keyCurve.getId()} keys may not be used with EdDSA digital signatures per https://www.rfc-editor.org/rfc/rfc8037#section-3.2" + String expectedMsg = "${keyCurve.getId()} keys may not be used with EdDSA digital signatures per " + + "https://www.rfc-editor.org/rfc/rfc8037.html#section-3.2" assertEquals expectedMsg, cause.getMessage() } } - static void testSig(SignatureAlgorithm alg, PrivateKey signing, PublicKey verification) { - String jwt = Jwts.builder().setIssuer('me').setAudience('you').signWith(signing, alg).compact() + static void testSig(PrivateKey signing, PublicKey verification) { + String jwt = Jwts.builder().issuer('me').audience('you').signWith(signing, alg).compact() def token = Jwts.parser().verifyWith(verification).build().parseClaimsJws(jwt) assertEquals([alg: alg.getId()], token.header) assertEquals 'me', token.getPayload().getIssuer() diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/EdwardsCurveTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/EdwardsCurveTest.groovy index 9def66ca5..988de47c2 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/EdwardsCurveTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/EdwardsCurveTest.groovy @@ -57,11 +57,6 @@ class EdwardsCurveTest { assertFalse EdwardsCurve.isEdwards(null) } - @Test - void testFindByNullKey() { - assertNull EdwardsCurve.findByKey(null) - } - @Test void testForKeyNonEdwards() { def alg = 'foo' @@ -74,6 +69,22 @@ class EdwardsCurveTest { } } + @Test + void testFindByKey() { // happy path test + for(def alg : EdwardsCurve.VALUES) { + def keyPair = alg.keyPair().build() + def pub = keyPair.public + def priv = keyPair.private + assertSame alg, EdwardsCurve.findByKey(pub) + assertSame alg, EdwardsCurve.findByKey(priv) + } + } + + @Test + void testFindByNullKey() { + assertNull EdwardsCurve.findByKey(null) + } + @Test void testFindByKeyUsingEncoding() { curves.each { diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/Issue542Test.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/Issue542Test.groovy index f38333d31..41f97399c 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/Issue542Test.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/Issue542Test.groovy @@ -40,9 +40,9 @@ class Issue542Test { private static String PS512_0_10_7 = 'eyJhbGciOiJQUzUxMiJ9.eyJpc3MiOiJqb2UifQ.r6sisG-FVaMoIJacMSdYZLWFBVoT6bXmf3X3humLZqzoGfsRw3q9-wJ2oIiR4ua2L_mPnJqyPcjFWoXLUzw-URFSyQEAX_S2mWTBn7avCFsmJUh2fMkplG0ynbIHCqReRDl3moQGallbl-SYgArSRI2HbpVt05xsVbk3BmxB8N8buKbBPfUqwZMicRqNpHxoOc-IXaClc7y93gFNfGBMEwXn2nK_ZFXY03pMBL_MHVsJprPmtGfQw0ZZUv29zZbZTkRb6W6bRCi3jIP8sBMnYDqG3_Oyz9sF74IeOoD9sCpgAuRnrSAXhEb3tr1uBwyT__DOI1ZdT8QGFiRRNpUZDm7g4ub7njhXQ6ppkEY6kEKCCoxSq5sAh6EzZQgAfbpKNXy5VIu8s1nR-iJ8GDpeTcpLRhbX8havNzWjc-kSnU95_D5NFoaKfIjofKideVU46lUdCk-m7q8mOoFz8UEK1cXq3t7ay2jLG_sNvv7oZPe2TC4ovQGiQP0Mt446XBuIvyXSvygD3_ACpRSfpAqVoP7Ce98NkV2QCJxYNX1cZ4Zj4HrNoNWMx81TFoyU7RoUhj4tHcgBt_3_jbCO0OCejwswAFhwYRXP3jXeE2QhLaN1QJ7p97ly8WxjkBRac3I2WAeJhOM4CWhtgDmHAER9571MWp-7n4h4bnx9tXXfV7k' private static Map JWS_0_10_7_VALUES = [ - (Jwts.SIG.PS256): PS256_0_10_7, - (Jwts.SIG.PS384): PS384_0_10_7, - (Jwts.SIG.PS512): PS512_0_10_7 + (Jwts.SIG.RS256): PS256_0_10_7, + (Jwts.SIG.RS384): PS384_0_10_7, + (Jwts.SIG.RS512): PS512_0_10_7 ] /** @@ -50,10 +50,7 @@ class Issue542Test { */ @Test void testRsaSsaPssBackwardsCompatibility() { - - def algs = [Jwts.SIG.PS256, Jwts.SIG.PS384, Jwts.SIG.PS512] - - for (alg in algs) { + for (alg in JWS_0_10_7_VALUES.keySet()) { PublicKey key = TestKeys.forAlgorithm(alg).pair.public String jws = JWS_0_10_7_VALUES[alg] def token = Jwts.parser().verifyWith(key).build().parseClaimsJws(jws) @@ -66,8 +63,7 @@ class Issue542Test { * class. This method implementation was retained only to demonstrate how they were created for future reference. */ static void main(String[] args) { - def algs = [Jwts.SIG.PS256, Jwts.SIG.PS384, Jwts.SIG.PS512] - for (alg in algs) { + for (alg in JWS_0_10_7_VALUES.keySet()) { PrivateKey privateKey = TestKeys.forAlgorithm(alg).pair.private String jws = Jwts.builder().setIssuer('joe').signWith(privateKey, alg).compact() println "private static String ${alg.getId()}_0_10_7 = '$jws'" diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/JwksTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/JwksTest.groovy index af441a46a..b968c47ce 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/JwksTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/JwksTest.groovy @@ -16,6 +16,7 @@ package io.jsonwebtoken.impl.security import io.jsonwebtoken.Jwts +import io.jsonwebtoken.impl.lang.Conditions import io.jsonwebtoken.impl.lang.Converters import io.jsonwebtoken.io.Decoders import io.jsonwebtoken.io.Encoders @@ -23,10 +24,7 @@ import io.jsonwebtoken.security.* import org.junit.Test import javax.crypto.SecretKey -import java.security.MessageDigest -import java.security.PrivateKey -import java.security.PublicKey -import java.security.SecureRandom +import java.security.* import java.security.cert.X509Certificate import java.security.interfaces.ECKey import java.security.interfaces.ECPublicKey @@ -186,7 +184,7 @@ class JwksTest { for (def alg : algs) { //get test cert: - X509Certificate cert = TestCertificates.readTestCertificate(alg) + X509Certificate cert = TestKeys.forAlgorithm(alg).cert def builder = Jwks.builder().chain(Arrays.asList(cert)) if (number == 1) { @@ -255,19 +253,26 @@ class JwksTest { @Test void testAsymmetricJwks() { - Collection algs = Jwts.SIG.get().values().findAll({ it instanceof SignatureAlgorithm }) as Collection + Collection algs = Jwts.SIG.get().values() + .findAll({ it instanceof SignatureAlgorithm }) as Collection - for (def alg : algs) { + for (SignatureAlgorithm alg : algs) { def pair = alg.keyPair().build() PublicKey pub = pair.getPublic() PrivateKey priv = pair.getPrivate() + Provider provider = null // assume default + if (pub.getClass().getName().startsWith("org.bouncycastle.")) { + // No native JVM support for the key, so we need to enable BC: + provider = Providers.findBouncyCastle(Conditions.TRUE) + } + // test individual keys - PublicJwk pubJwk = Jwks.builder().key(pub).publicKeyUse("sig").build() + PublicJwk pubJwk = Jwks.builder().provider(provider).key(pub).publicKeyUse("sig").build() assertEquals pub, pubJwk.toKey() - def builder = Jwks.builder().key(priv).publicKeyUse('sig') + def builder = Jwks.builder().provider(provider).key(priv).publicKeyUse('sig') if (alg instanceof EdSignatureAlgorithm) { // We haven't implemented EdDSA public-key derivation yet, so public key is required builder.publicKey(pub) @@ -282,12 +287,13 @@ class JwksTest { assertEquals priv, jwkPair.getPrivate() // test pair + builder = Jwks.builder().provider(provider) if (pub instanceof ECKey) { - builder = Jwks.builder().ecKeyPair(pair) + builder = builder.ecKeyPair(pair) } else if (pub instanceof RSAKey) { - builder = Jwks.builder().rsaKeyPair(pair) + builder = builder.rsaKeyPair(pair) } else { - builder = Jwks.builder().octetKeyPair(pair) + builder = builder.octetKeyPair(pair) } privJwk = builder.publicKeyUse("sig").build() as PrivateJwk assertEquals priv, privJwk.toKey() diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/JwtX509StringConverterTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/JwtX509StringConverterTest.groovy index db17aca3e..8020174fb 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/JwtX509StringConverterTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/JwtX509StringConverterTest.groovy @@ -16,11 +16,14 @@ package io.jsonwebtoken.impl.security import io.jsonwebtoken.impl.lang.Bytes +import io.jsonwebtoken.io.Encoders +import io.jsonwebtoken.security.SecurityException +import org.junit.Before import org.junit.Test +import java.security.Provider import java.security.cert.CertificateEncodingException import java.security.cert.CertificateException -import java.security.cert.CertificateFactory import java.security.cert.X509Certificate import static org.easymock.EasyMock.* @@ -28,6 +31,13 @@ import static org.junit.Assert.* class JwtX509StringConverterTest { + private JwtX509StringConverter converter + + @Before + void setUp() { + converter = JwtX509StringConverter.INSTANCE + } + @Test void testApplyToThrowsEncodingException() { @@ -38,12 +48,11 @@ class JwtX509StringConverterTest { replay cert try { - JwtX509StringConverter.INSTANCE.applyTo(cert) + converter.applyTo(cert) fail() } catch (IllegalArgumentException expected) { - String expectedMsg = 'Unable to access X509Certificate encoded bytes necessary to perform DER ' + - 'Base64-encoding. Certificate: {EasyMock for class java.security.cert.X509Certificate}. ' + - 'Cause: ' + ex.getMessage() + String expectedMsg = "Unable to access X509Certificate encoded bytes necessary to perform DER " + + "Base64-encoding. Certificate: {${cert}}. Cause: " + ex.getMessage() assertSame ex, expected.getCause() assertEquals expectedMsg, expected.getMessage() } @@ -59,7 +68,7 @@ class JwtX509StringConverterTest { replay cert try { - JwtX509StringConverter.INSTANCE.applyTo(cert) + converter.applyTo(cert) fail() } catch (IllegalArgumentException expected) { String expectedMsg = 'X509Certificate encoded bytes cannot be null or empty. Certificate: ' + @@ -71,12 +80,13 @@ class JwtX509StringConverterTest { } @Test - void testApplyFromThrowsCertificateException() { - - def converter = new JwtX509StringConverter() { + void testApplyFromBadBase64() { + final CertificateException ex = new CertificateException('nope') + converter = new JwtX509StringConverter() { @Override - protected CertificateFactory newCertificateFactory() throws CertificateException { - throw new CertificateException("nope") + protected X509Certificate toCert(byte[] der, Provider provider) throws SecurityException { + assertNull provider // ensures not called twice (no fallback) because der bytes aren't available + throw ex } } @@ -87,6 +97,51 @@ class JwtX509StringConverterTest { } catch (IllegalArgumentException expected) { String expectedMsg = "Unable to convert Base64 String '$s' to X509Certificate instance. Cause: nope" assertEquals expectedMsg, expected.getMessage() + assertSame ex, expected.getCause() + } + } + + @Test + void testApplyFromRsaSsaPssCertStringWithSuccessfulBCRetry() { + final CertificateException ex = new CertificateException("nope: ${RsaSignatureAlgorithm.PSS_OID}") + converter = new JwtX509StringConverter() { + @Override + protected X509Certificate toCert(byte[] der, Provider provider) throws SecurityException { + if (provider == null) { + throw ex // first time called, throw ex (simulates JVM parse failure) + } else { // this time BC is available: + assertNotNull provider + return super.toCert(der, provider) + } + } + } + + def cert = TestKeys.RS256.cert + def validBase64 = Encoders.BASE64.encode(cert.getEncoded()) + assertEquals cert, converter.applyFrom(validBase64) + } + + @Test + void testApplyFromRsaSsaPssCertStringWithFailedBCRetry() { + final String exMsg = "nope: ${RsaSignatureAlgorithm.PSS_OID}" + final CertificateException ex = new CertificateException(exMsg) + converter = new JwtX509StringConverter() { + @Override + protected X509Certificate toCert(byte[] der, Provider provider) throws SecurityException { + throw ex // ensure fails first and second time + } + } + + def cert = TestKeys.RS256.cert + def validBase64 = Encoders.BASE64.encode(cert.getEncoded()) + + try { + converter.applyFrom(validBase64) + fail() + } catch (IllegalArgumentException expected) { + String expectedMsg = "Unable to convert Base64 String '$validBase64' to X509Certificate instance. Cause: ${exMsg}" + assertEquals expectedMsg, expected.getMessage() + assertSame ex, expected.getCause() } } } diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/PrivateConstructorsTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/PrivateConstructorsTest.groovy index 6684cb7d5..93aeaa65d 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/PrivateConstructorsTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/PrivateConstructorsTest.groovy @@ -34,6 +34,7 @@ class PrivateConstructorsTest { new Jwts.ENC() new Jwts.KEY() new Jwts.ZIP() + new Jwks.CRV() new Jwks.HASH() } } diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/RsaSignatureAlgorithmTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/RsaSignatureAlgorithmTest.groovy index 10e765b01..46bff77dc 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/RsaSignatureAlgorithmTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/RsaSignatureAlgorithmTest.groovy @@ -16,10 +16,12 @@ package io.jsonwebtoken.impl.security import io.jsonwebtoken.Jwts +import io.jsonwebtoken.impl.lang.CheckedFunction import io.jsonwebtoken.security.InvalidKeyException import io.jsonwebtoken.security.WeakKeyException import org.junit.Test +import java.security.KeyPair import java.security.KeyPairGenerator import java.security.PublicKey import java.security.interfaces.RSAPrivateKey @@ -30,15 +32,13 @@ import static org.junit.Assert.* class RsaSignatureAlgorithmTest { - static Collection algs() { - return Jwts.SIG.get().values().findAll({ - it.id.startsWith("RS") || it.id.startsWith("PS") - }) as Collection - } + static final Collection algs = Jwts.SIG.get().values().findAll({ + it instanceof RsaSignatureAlgorithm + }) as Collection @Test void testKeyPairBuilder() { - algs().each { + algs.each { def pair = it.keyPair().build() assertNotNull pair.public assertTrue pair.public instanceof RSAPublicKey @@ -48,16 +48,11 @@ class RsaSignatureAlgorithmTest { } } - @Test(expected = IllegalArgumentException) - void testWeakPreferredKeyLength() { - new RsaSignatureAlgorithm(256, 1024) //must be >= 2048 - } - @Test void testValidateKeyWithoutRsaKey() { PublicKey key = createMock(PublicKey) replay key - algs().each { + algs.each { it.validateKey(key, false) //no exception - can't check for RSAKey fields (e.g. PKCS11 or HSM key) } @@ -72,7 +67,9 @@ class RsaSignatureAlgorithmTest { Jwts.SIG.RS256.digest(request) fail() } catch (InvalidKeyException e) { - assertTrue e.getMessage().startsWith("Asymmetric key signatures must be created with PrivateKeys. The specified key is of type: ") + String expected = "RS256 signing keys must be PrivateKeys (implement java.security.PrivateKey). " + + "Provided key type: ${key.getClass().getName()}." + assertEquals expected, e.getMessage() } } @@ -80,15 +77,102 @@ class RsaSignatureAlgorithmTest { void testValidateSigningKeyWeakKey() { def gen = KeyPairGenerator.getInstance("RSA") gen.initialize(1024) //too week for any JWA RSA algorithm - def pair = gen.generateKeyPair() + def rsaPair = gen.generateKeyPair() + + def provider = RsaSignatureAlgorithm.PS256.getProvider() // in case BC was loaded + def pssPair = new JcaTemplate(RsaSignatureAlgorithm.PSS_JCA_NAME, provider) + .withKeyPairGenerator(new CheckedFunction() { + @Override + KeyPair apply(KeyPairGenerator generator) throws Exception { + generator.initialize(1024) + return generator.generateKeyPair() + } + }) - def request = new DefaultSecureRequest(new byte[1], null, null, pair.getPrivate()) - Jwts.SIG.get().values().findAll({ it.id.startsWith('RS') || it.id.startsWith('PS') }).each { + algs.each { + def pair = it.getId().startsWith("PS") ? pssPair : rsaPair + def request = new DefaultSecureRequest(new byte[1], null, null, pair.getPrivate()) try { it.digest(request) fail() } catch (WeakKeyException expected) { + String id = it.getId() + String section = id.startsWith('PS') ? '3.5' : '3.3' + String msg = "The signing key's size is 1024 bits which is not secure enough for the ${it.getId()} " + + "algorithm. The JWT JWA Specification (RFC 7518, Section ${section}) states that RSA keys " + + "MUST have a size >= 2048 bits. Consider using the Jwts.SIG.${id}.keyPair() " + + "builder to create a KeyPair guaranteed to be secure enough for ${id}. See " + + "https://tools.ietf.org/html/rfc7518#section-${section} for more information." + assertEquals msg, expected.getMessage() } } } + + @Test + void testFindByKeyWithNoAlgorithm() { + assertNull RsaSignatureAlgorithm.findByKey(new TestPrivateKey()) + } + + @Test + void testFindByKeyInvalidAlgorithm() { + assertNull DefaultMacAlgorithm.findByKey(new TestPrivateKey(algorithm: 'foo')) + } + + @Test + void testFindByKey() { + for (def alg : algs) { + def pair = TestKeys.forAlgorithm(alg).pair + assertSame alg, RsaSignatureAlgorithm.findByKey(pair.public) + assertSame alg, RsaSignatureAlgorithm.findByKey(pair.private) + } + } + + @Test + void testFindByKeyNull() { + assertNull RsaSignatureAlgorithm.findByKey(null) + } + + @Test + void testFindByNonAsymmetricKey() { + assertNull RsaSignatureAlgorithm.findByKey(TestKeys.HS256) + } + + @Test + void testFindByWeakKey() { + for (def alg : algs) { + def pair = TestKeys.forAlgorithm(alg).pair + byte[] mag = new byte[255] // one byte less than 256 (2048 bits) which is the minimum + Randoms.secureRandom().nextBytes(mag) + def modulus = new BigInteger(1, mag) + //def modulus = pair.public.modulus + def weakPub = new TestRSAKey(pair.public); weakPub.modulus = modulus + def weakPriv = new TestRSAKey(pair.private); weakPriv.modulus = modulus + assertNull RsaSignatureAlgorithm.findByKey(weakPub) + assertNull RsaSignatureAlgorithm.findByKey(weakPriv) + } + } + + @Test + void testFindByLargerThanExpectedKey() { + for (def alg : algs) { + def pair = TestKeys.forAlgorithm(alg).pair + def mag = new byte[(alg.preferredKeyBitLength / Byte.SIZE) + 1] // one byte more than required + Randoms.secureRandom().nextBytes(mag) + def modulus = new BigInteger(1, mag) + def strongPub = new TestRSAKey(pair.public); strongPub.modulus = modulus + def strongPriv = new TestRSAKey(pair.private); strongPriv.modulus = modulus + assertSame alg, RsaSignatureAlgorithm.findByKey(strongPub) + assertSame alg, RsaSignatureAlgorithm.findByKey(strongPriv) + } + } + + @Test + void testFindByKeyOid() { + for (def entry : RsaSignatureAlgorithm.PKCSv15_ALGS.entrySet()) { + def oid = entry.getKey() + def alg = entry.getValue() + def oidKey = new TestPrivateKey(algorithm: oid) + assertSame alg, RsaSignatureAlgorithm.findByKey(oidKey) + } + } } diff --git a/impl/src/main/java/io/jsonwebtoken/impl/security/Curve.java b/impl/src/test/groovy/io/jsonwebtoken/impl/security/StandardSecureDigestAlgorithmsTest.groovy similarity index 59% rename from impl/src/main/java/io/jsonwebtoken/impl/security/Curve.java rename to impl/src/test/groovy/io/jsonwebtoken/impl/security/StandardSecureDigestAlgorithmsTest.groovy index 8982bd19c..6c43df6ec 100644 --- a/impl/src/main/java/io/jsonwebtoken/impl/security/Curve.java +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/StandardSecureDigestAlgorithmsTest.groovy @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022 jsonwebtoken.io + * Copyright © 2023 jsonwebtoken.io * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,10 +13,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.jsonwebtoken.impl.security; +package io.jsonwebtoken.impl.security -import io.jsonwebtoken.Identifiable; -import io.jsonwebtoken.security.KeyPairBuilderSupplier; +import org.junit.Test -public interface Curve extends Identifiable, KeyPairBuilderSupplier { +import static org.junit.Assert.assertNull + +class StandardSecureDigestAlgorithmsTest { + + @Test + void testFindByPublicSigningKey() { + //public keys are not supported for signing: + assertNull StandardSecureDigestAlgorithms.findBySigningKey(new TestPublicKey()) + } } diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/TestCertificates.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/TestCertificates.groovy index 5b14008ff..2b2b2e84a 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/TestCertificates.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/TestCertificates.groovy @@ -15,12 +15,14 @@ */ package io.jsonwebtoken.impl.security +import io.jsonwebtoken.Identifiable import io.jsonwebtoken.impl.lang.Bytes import io.jsonwebtoken.impl.lang.CheckedFunction +import io.jsonwebtoken.impl.lang.Conditions import io.jsonwebtoken.lang.Assert import io.jsonwebtoken.lang.Classes import io.jsonwebtoken.lang.Strings -import io.jsonwebtoken.security.SecureDigestAlgorithm +import io.jsonwebtoken.security.SignatureAlgorithm import org.bouncycastle.asn1.pkcs.PrivateKeyInfo import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo import org.bouncycastle.openssl.PEMKeyPair @@ -53,6 +55,9 @@ import java.security.spec.X509EncodedKeySpec */ class TestCertificates { + private static Provider BC = Assert.notNull(Providers.findBouncyCastle(Conditions.TRUE), + "BC must be available to test cases.") + private static InputStream getResourceStream(String filename) { String packageName = TestCertificates.class.getPackage().getName() String resourcePath = Strings.replace(packageName, ".", "/") + "/" + filename @@ -60,55 +65,75 @@ class TestCertificates { } private static PEMParser getParser(String filename) { - InputStream is = Classes.getResourceAsStream('io/jsonwebtoken/impl/security/' + filename) + InputStream is = getResourceStream(filename) return new PEMParser(new BufferedReader(new InputStreamReader(is, StandardCharsets.ISO_8859_1))) } - private static String getKeyFilePrefix(SecureDigestAlgorithm alg) { - if (alg instanceof EdSignatureAlgorithm) { - return alg.preferredCurve.getId() - } - return alg.getId() - } - - static X509Certificate readTestCertificate(SecureDigestAlgorithm alg) { - InputStream is = getResourceStream(getKeyFilePrefix(alg) + '.crt.pem') + private static T bcFallback(final Identifiable alg, Closure closure) { + Provider provider = alg.getProvider() as Provider // null on JVMs with native support for `alg` try { - JcaTemplate template = new JcaTemplate("X.509", alg.getProvider()) - template.withCertificateFactory(new CheckedFunction() { - @Override - X509Certificate apply(CertificateFactory factory) throws Exception { - return (X509Certificate) factory.generateCertificate(is) - } - }) - } finally { - is.close() + return closure.call(alg, provider) + } catch (Throwable t) { + + // All test cert and key files were created with OpenSSL, so the only time this should happen is if the + // JDK natively supports the alg, but has a bug that prevents it from reading the file correctly. So + // we account for those bugs here as indicators that we should retry with BC. + + // https://bugs.openjdk.org/browse/JDK-8242556 + // Oracle only backported this fix to JDK 8u271+, 11.0.9+, and 15+, so we'll need to fall back to + // BC (which can read the files correctly) on JDK 9, 10, 12, 13, and 14. + boolean jdk8242556Bug = alg instanceof SignatureAlgorithm && alg.getId().startsWith("PS") && + t.message.contains('Unsupported algorithm 1.2.840.113549.1.1.10') + + // https://bugs.openjdk.org/browse/JDK-8213363) for X25519 and X448 encoded keys. JDK 11's + // SunCE provider incorrectly expects an ASN.1 OCTET STRING (without the DER tag/length prefix) + // when it should actually be a BER-encoded OCTET STRING (with the tag/length prefix). + boolean jdk8213363Bug = alg instanceof EdwardsCurve && !((EdwardsCurve) alg).isSignatureCurve() && + System.getProperty("java.version").startsWith("11") + + // Now assert that we're experiencing one of the expected bugs, because if not, we need to know about + // it in test results and fix this implementation: + if (!jdk8242556Bug && !jdk8213363Bug) { + String msg = "Unable to read ${alg.getId()} file: ${t.message}" + throw new IllegalStateException(msg, t) + } + + // otherwise, we are indeed experiencing one of the expected bugs, so use BC as a backup: + return closure.call(alg, BC) } } - static PublicKey readTestPublicKey(EdwardsCurve crv) { - PEMParser parser = getParser(crv.getId() + '.pub.pem') - try { + private static def readPublicKey = { Identifiable alg, Provider provider -> + PEMParser parser = getParser(alg.id + '.pub.pem') + parser.withCloseable { SubjectPublicKeyInfo info = parser.readObject() as SubjectPublicKeyInfo - def template = new JcaTemplate(crv.getJcaName(), crv.getProvider()) - return template.withKeyFactory(new CheckedFunction() { + JcaTemplate template = new JcaTemplate(alg.getJcaName(), provider) + template.withKeyFactory(new CheckedFunction() { @Override PublicKey apply(KeyFactory keyFactory) throws Exception { return keyFactory.generatePublic(new X509EncodedKeySpec(info.getEncoded())) } }) - } finally { - parser.close() } } - static PrivateKey readTestPrivateKey(SecureDigestAlgorithm alg) { - return readTestPrivateKey(getKeyFilePrefix(alg), alg.getProvider()) + private static def readCert = { Identifiable alg, Provider provider -> + InputStream is = getResourceStream(alg.id + '.crt.pem') + is.withCloseable { + JcaTemplate template = new JcaTemplate("X.509", provider) + template.withCertificateFactory(new CheckedFunction() { + @Override + X509Certificate apply(CertificateFactory factory) throws Exception { + return (X509Certificate) factory.generateCertificate(it) + } + }) + } } - static PrivateKey readTestPrivateKey(String filenamePrefix, Provider provider) { - PEMParser parser = getParser(filenamePrefix + '.key.pem') - try { + private static def readPrivateKey = { Identifiable alg, Provider provider -> + final String id = alg.id + PEMParser parser = getParser(id + '.key.pem') + parser.withCloseable { PrivateKeyInfo info Object object = parser.readObject() if (object instanceof PEMKeyPair) { @@ -116,12 +141,11 @@ class TestCertificates { } else { info = (PrivateKeyInfo) object } - def converter = new JcaPEMKeyConverter() if (provider != null) { converter.setProvider(provider) - } else if (filenamePrefix.startsWith("X") && System.getProperty("java.version").startsWith("11")) { - EdwardsCurve curve = EdwardsCurve.findById(filenamePrefix) + } else if (id.startsWith("X") && System.getProperty("java.version").startsWith("11")) { + EdwardsCurve curve = EdwardsCurve.findById(id) Assert.notNull(curve, "Curve cannot be null.") int expectedByteLen = ((curve.keyBitLength + 7) / 8) as int // Address the [JDK 11 SunCE provider bug](https://bugs.openjdk.org/browse/JDK-8213363) for X25519 @@ -139,20 +163,22 @@ class TestCertificates { return curve.toPrivateKey(keyOctets, null) } return converter.getPrivateKey(info) - } finally { - parser.close() } } static TestKeys.Bundle readBundle(EdwardsCurve curve) { - PublicKey pub = readTestPublicKey(curve) - PrivateKey priv = readTestPrivateKey(curve.getId(), curve.getProvider()) + //PublicKey pub = readTestPublicKey(curve) + //PrivateKey priv = readTestPrivateKey(curve) + PublicKey pub = bcFallback(curve, readPublicKey) as PublicKey + PrivateKey priv = bcFallback(curve, readPrivateKey) as PrivateKey return new TestKeys.Bundle(pub, priv) } - static TestKeys.Bundle readAsymmetricBundle(SecureDigestAlgorithm alg) { - X509Certificate cert = readTestCertificate(alg) - PrivateKey priv = readTestPrivateKey(alg) + static TestKeys.Bundle readBundle(Identifiable alg) { + //X509Certificate cert = readTestCertificate(alg) + //PrivateKey priv = readTestPrivateKey(alg) + X509Certificate cert = bcFallback(alg, readCert) as X509Certificate + PrivateKey priv = bcFallback(alg, readPrivateKey) as PrivateKey return new TestKeys.Bundle(cert, priv) } } diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/TestKeys.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/TestKeys.groovy index 384d87df0..70ee1ae69 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/TestKeys.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/TestKeys.groovy @@ -18,9 +18,7 @@ package io.jsonwebtoken.impl.security import io.jsonwebtoken.Identifiable import io.jsonwebtoken.Jwts import io.jsonwebtoken.lang.Collections -import io.jsonwebtoken.security.KeyBuilderSupplier -import io.jsonwebtoken.security.SecretKeyBuilder -import io.jsonwebtoken.security.SignatureAlgorithm +import io.jsonwebtoken.security.Jwks import javax.crypto.SecretKey import java.security.KeyPair @@ -65,14 +63,14 @@ class TestKeys { // ======================================================= // Elliptic Curve Keys & Certificates // ======================================================= - static Bundle ES256 = TestCertificates.readAsymmetricBundle(Jwts.SIG.ES256) - static Bundle ES384 = TestCertificates.readAsymmetricBundle(Jwts.SIG.ES384) - static Bundle ES512 = TestCertificates.readAsymmetricBundle(Jwts.SIG.ES512) + static Bundle ES256 = TestCertificates.readBundle(Jwts.SIG.ES256) + static Bundle ES384 = TestCertificates.readBundle(Jwts.SIG.ES384) + static Bundle ES512 = TestCertificates.readBundle(Jwts.SIG.ES512) static Set EC = Collections.setOf(ES256, ES384, ES512) - static Bundle EdDSA = TestCertificates.readAsymmetricBundle(Jwts.SIG.EdDSA) - static Bundle Ed25519 = TestCertificates.readAsymmetricBundle(Jwts.SIG.Ed25519) - static Bundle Ed448 = TestCertificates.readAsymmetricBundle(Jwts.SIG.Ed448) + static Bundle EdDSA = TestCertificates.readBundle(Jwts.SIG.EdDSA) + static Bundle Ed25519 = TestCertificates.readBundle(Jwks.CRV.Ed25519) + static Bundle Ed448 = TestCertificates.readBundle(Jwks.CRV.Ed448) static Bundle X25519 = TestCertificates.readBundle(EdwardsCurve.X25519) static Bundle X448 = TestCertificates.readBundle(EdwardsCurve.X448) static Set EdEC = Collections.setOf(EdDSA, Ed25519, Ed448, X25519, X448) @@ -80,10 +78,15 @@ class TestKeys { // ======================================================= // RSA Keys & Certificates // ======================================================= - static Bundle RS256 = TestCertificates.readAsymmetricBundle(Jwts.SIG.RS256) - static Bundle RS384 = TestCertificates.readAsymmetricBundle(Jwts.SIG.RS384) - static Bundle RS512 = TestCertificates.readAsymmetricBundle(Jwts.SIG.RS512) - static Set RSA = Collections.setOf(RS256, RS384, RS512) + static Bundle RS256 = TestCertificates.readBundle(Jwts.SIG.RS256) + static Bundle RS384 = TestCertificates.readBundle(Jwts.SIG.RS384) + static Bundle RS512 = TestCertificates.readBundle(Jwts.SIG.RS512) + static Bundle PS256 = TestCertificates.readBundle(Jwts.SIG.PS256) + static Bundle PS384 = TestCertificates.readBundle(Jwts.SIG.PS384) + static Bundle PS512 = TestCertificates.readBundle(Jwts.SIG.PS512) +// static Set PKCSv15 = Collections.setOf(RS256, RS384, RS512) +// static Set RSASSA_PSS = Collections.setOf(PS256, PS384, PS512) + static Set RSA = Collections.setOf(RS256, RS384, RS512, PS256, PS384, PS512) static Set ASYM = new LinkedHashSet<>() static { @@ -92,22 +95,8 @@ class TestKeys { ASYM.addAll(RSA) } - static & Identifiable> SecretKey forAlgorithm(T alg) { + static Bundle forAlgorithm(Identifiable alg) { String id = alg.getId() - if (id.contains('-')) { - id = id.replace('-', '_') - } - return TestKeys.metaClass.getAttribute(TestKeys, id) as SecretKey - } - - static Bundle forAlgorithm(SignatureAlgorithm alg) { - String id = alg.getId() - if (id.startsWith('PS')) { - id = 'R' + id.substring(1) //keys for PS* algs are the same as RS algs - } - if (alg instanceof EdSignatureAlgorithm) { - id = alg.preferredCurve.getId() - } return TestKeys.metaClass.getAttribute(TestKeys, id) as Bundle } @@ -126,10 +115,14 @@ class TestKeys { this.pair = new KeyPair(cert.getPublicKey(), privateKey) } - Bundle(PublicKey pub, PrivateKey priv) { + Bundle(KeyPair pair) { this.cert = null this.chain = Collections.emptyList() - this.pair = new KeyPair(pub, priv) + this.pair = pair + } + + Bundle(PublicKey pub, PrivateKey priv) { + this(new KeyPair(pub, priv)) } } } diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/TestRSAKey.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/TestRSAKey.groovy index c0c4b8d96..30caeaa41 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/TestRSAKey.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/TestRSAKey.groovy @@ -20,28 +20,18 @@ import java.security.interfaces.RSAKey class TestRSAKey extends TestKey implements RSAKey { final def src + BigInteger modulus TestRSAKey(def key) { this.src = key - } - - @Override - String getAlgorithm() { - return src.algorithm - } - - @Override - String getFormat() { - return src.format - } - - @Override - byte[] getEncoded() { - return src.encoded + this.algorithm = key?.getAlgorithm() + this.format = key?.getFormat() + this.encoded = key?.getEncoded() + this.modulus = key?.getModulus() } @Override BigInteger getModulus() { - return src.getModulus() + return this.modulus } } diff --git a/impl/src/test/groovy/io/jsonwebtoken/security/JwtsSigTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/security/JwtsSigTest.groovy deleted file mode 100644 index f7b61a71e..000000000 --- a/impl/src/test/groovy/io/jsonwebtoken/security/JwtsSigTest.groovy +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (C) 2022 jsonwebtoken.io - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.jsonwebtoken.security - -import io.jsonwebtoken.Jwts -import org.junit.Test - -import static org.junit.Assert.assertNotNull -import static org.junit.Assert.assertNull - -/** - * The {@link StandardAlgorithmsTest} class contains the majority of test cases relevant for the - * {@link Jwts.SIG} implementation. This test class exists for additional checks/assertions - * for the convenience Ed2448 and Ed25519 aliases. - */ -class JwtsSigTest { - - private static final def registry = Jwts.SIG.get() - - @Test(expected = ClassCastException) - void testGetWithoutString() { - assertNull registry.get(1) - } - - @Test - void testFindEd448() { - assertNotNull registry.get('Ed448') - } - - @Test - void testFindEd448CaseInsensitive() { - assertNotNull registry.get('ED448') - assertNotNull registry.get('ed448') - } - - @Test - void testFindEd25519() { - assertNotNull registry.get('Ed25519') - } - - @Test - void testFindEd25519CaseInsensitive() { - assertNotNull registry.get('ED25519') - assertNotNull registry.get('ed25519') - } -} diff --git a/impl/src/test/groovy/io/jsonwebtoken/security/KeysImplTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/security/KeysImplTest.groovy index 628eaa800..516a74a9e 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/security/KeysImplTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/security/KeysImplTest.groovy @@ -76,12 +76,13 @@ class KeysImplTest { PublicKey pub = pair.getPublic() assert pub instanceof RSAPublicKey - assertEquals alg.familyName, pub.algorithm + def keyAlgName = alg.jcaName.equals("RSASSA-PSS") ? "RSASSA-PSS" : alg.familyName + assertEquals keyAlgName, pub.algorithm assertEquals alg.digestLength * 8, pub.modulus.bitLength() PrivateKey priv = pair.getPrivate() assert priv instanceof RSAPrivateKey - assertEquals alg.familyName, priv.algorithm + assertEquals keyAlgName, priv.algorithm assertEquals alg.digestLength * 8, priv.modulus.bitLength() } else if (alg.isEllipticCurve()) { diff --git a/impl/src/test/groovy/io/jsonwebtoken/security/KeysTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/security/KeysTest.groovy index 5d1b0778d..917783af9 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/security/KeysTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/security/KeysTest.groovy @@ -19,7 +19,9 @@ package io.jsonwebtoken.security import io.jsonwebtoken.Jwts import io.jsonwebtoken.impl.DefaultJwtBuilder import io.jsonwebtoken.impl.lang.Bytes -import io.jsonwebtoken.impl.security.* +import io.jsonwebtoken.impl.security.EdwardsCurve +import io.jsonwebtoken.impl.security.KeysBridge +import io.jsonwebtoken.impl.security.PasswordSpec import org.junit.Test import javax.crypto.SecretKey @@ -154,12 +156,13 @@ class KeysTest { PublicKey pub = pair.getPublic() assert pub instanceof RSAPublicKey - assertEquals alg.familyName, pub.algorithm + def keyAlgName = alg.jcaName.equals("RSASSA-PSS") ? "RSASSA-PSS" : alg.familyName + assertEquals keyAlgName, pub.algorithm assertEquals alg.digestLength * 8, pub.modulus.bitLength() PrivateKey priv = pair.getPrivate() assert priv instanceof RSAPrivateKey - assertEquals alg.familyName, priv.algorithm + assertEquals keyAlgName, priv.algorithm assertEquals alg.digestLength * 8, priv.modulus.bitLength() } else if (alg.isEllipticCurve()) { @@ -205,11 +208,16 @@ class KeysTest { } @Test - void testKeyPairFor() { + void testKeyPairBuilder() { - for (SecureDigestAlgorithm alg : Jwts.SIG.get().values()) { + Collection algs = Jwts.SIG.get().values() + .findAll({it instanceof KeyPairBuilderSupplier}) as Collection + + for (SignatureAlgorithm alg : algs) { + + String id = alg.getId() - if (alg instanceof RsaSignatureAlgorithm) { + if (id.startsWith("RS") || id.startsWith("PS")) { def pair = alg.keyPair().build() assertNotNull pair @@ -222,7 +230,7 @@ class KeysTest { assert priv instanceof RSAPrivateKey assertEquals alg.preferredKeyBitLength, priv.modulus.bitLength() - } else if (alg instanceof EdSignatureAlgorithm) { + } else if (id == "EdDSA") { def pair = alg.keyPair().build() assertNotNull pair @@ -235,7 +243,7 @@ class KeysTest { assert priv instanceof PrivateKey assertTrue EdwardsCurve.isEdwards(priv) - } else if (alg instanceof EcSignatureAlgorithm) { + } else if (id.startsWith("ES")) { def pair = alg.keyPair().build() assertNotNull pair @@ -267,8 +275,8 @@ class KeysTest { assertEquals alg.orderBitLength, priv.params.order.bitLength() } else { - assertFalse alg instanceof SignatureAlgorithm - //assert we've accounted for all asymmetric ones above + // unexpected algorithm that is not accounted for in this test: + fail() } } } diff --git a/impl/src/test/groovy/io/jsonwebtoken/security/StandardAlgorithmsTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/security/StandardAlgorithmsTest.groovy index 538987bac..b659a3860 100644 --- a/impl/src/test/groovy/io/jsonwebtoken/security/StandardAlgorithmsTest.groovy +++ b/impl/src/test/groovy/io/jsonwebtoken/security/StandardAlgorithmsTest.groovy @@ -87,4 +87,16 @@ class StandardAlgorithmsTest { } } + @SuppressWarnings('GroovyUnusedCatchParameter') + @Test + void testGetWithoutStringKey() { + registries.each { reg -> + try { + assertNull reg.get(2) // not a string, should fail + fail() + } catch (ClassCastException expected) { // allowed per Map#get contract + } + } + } + } diff --git a/impl/src/test/resources/io/jsonwebtoken/impl/security/PS256.crt.pem b/impl/src/test/resources/io/jsonwebtoken/impl/security/PS256.crt.pem index 45195339b..c0fb3b81a 100644 --- a/impl/src/test/resources/io/jsonwebtoken/impl/security/PS256.crt.pem +++ b/impl/src/test/resources/io/jsonwebtoken/impl/security/PS256.crt.pem @@ -15,22 +15,27 @@ # -----BEGIN CERTIFICATE----- -MIIDRDCCAiwCCQCgd9OzR40NCDANBgkqhkiG9w0BAQsFADBjMQswCQYDVQQGEwJV -UzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzEY -MBYGA1UECgwPanNvbndlYnRva2VuLmlvMQ0wCwYDVQQLDARqand0MCAXDTIwMDIw -MzIzMDQzM1oYDzMwMjAwMjExMjMwNDMzWjBjMQswCQYDVQQGEwJVUzETMBEGA1UE -CAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzEYMBYGA1UECgwP -anNvbndlYnRva2VuLmlvMQ0wCwYDVQQLDARqand0MIIBIjANBgkqhkiG9w0BAQEF -AAOCAQ8AMIIBCgKCAQEAzkH0MwxQ2cUFWsvOPVFqI/dk2EFTjQolCy97mI5/wYCb -aOoZ9Rm7c675mAeemRtNzgNVEz7m298ENqNGqPk2Nv3pBJ/XCaybBlp61CLez7dQ -2h5jUFEJ6FJcjeKHS+MwXr56t2ISdfLNMYtVIxjvXQcYx5VmS4mIqTxj5gVGtQVi -0GXdH6SvpdKV0fjE9KOhjsdBfKQzZfcQlusHg8pThwvjpMwCZnkxCS0RKa9y4+5+ -7MkC33+8+neZUzS7b6NdFxh6T/pMXpkf8d81fzVo4ZBMloweW0/l8MOdVxeX7M/7 -XSC1ank5i3IEZcotLmJYMwEo7rMpZVLevEQ118Eo8QIDAQABMA0GCSqGSIb3DQEB -CwUAA4IBAQBGbfmJumXEHMLko1ioY/eY5EYgrBRJAuuAMGqBZmK+1Iy2CqB90aEh -ve+jXjIBsrvXRuLxMdlzoP58Ia9C5M+78Vq0bEjuGJu3zxGev11Gt4E3V6bWfT7G -fhg66dbmjnqkhgSzpDzfYR7HHOQiDAGe5IH5FbvWehRzENoAODHHP1z3NdoGhsl9 -4DIjOTGYdhW0yUTSjGTWygo6OPU2L4M2k0gTA06FkvdLIS450GWRpgoVO/vfcPnO -h8KwZcWVwJVmG0Hv0fNhQk/tRuhYhCWGxc7gxkbLb7/xPpPKMD6EvgG0BSm27NxO -H5l3KYwtbdj5nYHU73cLqC1D6ki6F8+h +MIIERTCCAvmgAwIBAgIUHAjkgfU2dEiUaT+VDBS3bXQgDcswQQYJKoZIhvcNAQEK +MDSgDzANBglghkgBZQMEAgEFAKEcMBoGCSqGSIb3DQEBCDANBglghkgBZQMEAgEF +AKIDAgEgMGMxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYD +VQQHDA1TYW4gRnJhbmNpc2NvMRgwFgYDVQQKDA9qc29ud2VidG9rZW4uaW8xDTAL +BgNVBAsMBGpqd3QwIBcNMjMwODE0MTk0NjU4WhgPMzAyMzA4MjIxOTQ2NThaMGMx +CzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1TYW4g +RnJhbmNpc2NvMRgwFgYDVQQKDA9qc29ud2VidG9rZW4uaW8xDTALBgNVBAsMBGpq +d3QwggFWMEEGCSqGSIb3DQEBCjA0oA8wDQYJYIZIAWUDBAIBBQChHDAaBgkqhkiG +9w0BAQgwDQYJYIZIAWUDBAIBBQCiAwIBIAOCAQ8AMIIBCgKCAQEA0b7eGccEnfOG +0bd5zptCwGEhd+YmtvgaYKsmdxTK9y1vXq13ZsSyd4IpPZIVpam2BYgmxXix4ikH +beKzydJG3bvr2J+f7Z9bgPZZNB9NJjX3j4IlEkGVI4/ZrROKrC004ItGcHqUJdlq +48W3JFyKWswBrFYxaCR2HyTj6uI+dsxwuPWse/rqyu+1NKN7uxmh1RXAKa+kYVkK +Smyta2UN+TJZ3bj0a0Sk9cyAqYVGI+kPKF+BYItgh6W+1cmYEscBjNkgcLbV/hen +BMjX90OZsTel/iQeXb0w7NgHfVQ2ZR3UmzkAwt8Eh/5+AtIsXRMuV9xgG17MKiN4 +JJUCjr8b/QIDAQABo1MwUTAdBgNVHQ4EFgQUl6+ASzYpbLLWGyKw/Qjj0JZK+24w +HwYDVR0jBBgwFoAUl6+ASzYpbLLWGyKw/Qjj0JZK+24wDwYDVR0TAQH/BAUwAwEB +/zBBBgkqhkiG9w0BAQowNKAPMA0GCWCGSAFlAwQCAQUAoRwwGgYJKoZIhvcNAQEI +MA0GCWCGSAFlAwQCAQUAogMCASADggEBAHQQiwmyaT9Ga7Bug5ux6LquaJAQCHu7 +THny14VdgcEdDp92+1+7CoRhDznpN6RKZPWyou6Jk0RL80ReKuijK054SjXiHsPx +UPSeHr5F7WCGTc6af8GXF7IJoEG+HjAXUz+lTQucK6d5TRk9mVknKnH4UiorRfZu +rdWmCVvb4CjKYCKVKfl/ZqAd8ZDE947AOosbCPcPivpWPIcuaAPeGiuJEcVkH537 +onM3j3v1yMnaAbomUfWp5aEdv/7GCfYM0j4SpAOwoStfJBc1iPWymRCEhVSLNqKp +J3W63YTrBKyXzoXF2M/+Q2xdpwASAF+DwsFyEgcy7h/APKaEOkvmyMg= -----END CERTIFICATE----- diff --git a/impl/src/test/resources/io/jsonwebtoken/impl/security/PS256.key.pem b/impl/src/test/resources/io/jsonwebtoken/impl/security/PS256.key.pem index 61088c2ff..4e6bfccc1 100644 --- a/impl/src/test/resources/io/jsonwebtoken/impl/security/PS256.key.pem +++ b/impl/src/test/resources/io/jsonwebtoken/impl/security/PS256.key.pem @@ -15,30 +15,31 @@ # -----BEGIN PRIVATE KEY----- -MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDOQfQzDFDZxQVa -y849UWoj92TYQVONCiULL3uYjn/BgJto6hn1GbtzrvmYB56ZG03OA1UTPubb3wQ2 -o0ao+TY2/ekEn9cJrJsGWnrUIt7Pt1DaHmNQUQnoUlyN4odL4zBevnq3YhJ18s0x -i1UjGO9dBxjHlWZLiYipPGPmBUa1BWLQZd0fpK+l0pXR+MT0o6GOx0F8pDNl9xCW -6weDylOHC+OkzAJmeTEJLREpr3Lj7n7syQLff7z6d5lTNLtvo10XGHpP+kxemR/x -3zV/NWjhkEyWjB5bT+Xww51XF5fsz/tdILVqeTmLcgRlyi0uYlgzASjusyllUt68 -RDXXwSjxAgMBAAECggEAZ90ahaJMDH2ERsaeoo4e7uGjrKqo0jsrkEhm6tnHR7/l -gp1wWNaOaKDSG1aq7NqtAXL4Imroggv56TGrYWetf1+5OZTsCnkaz8Y8WBr/LIZZ -dp0a0dUdMhpXdTN/gh1zvCIbVcFTHoYYAjzxsGzcDHKIbeizzJIDeYVpoOlDQ9/9 -Bv6ft4mhaG5SHVnec9QdmbJnKDq5rI4aPXCCXOCzDjdTVfgntdH5TvoCH91ESSKw -kddciAbVsXoOWnBx3jKMj+hIA4F1p6nzZUbiVzmxhqfShQhDnCEvq8tF7KqRbUsS -Gx8MVtwSkEGaiJCDVjwSRGkghXlguNwZcfnWMtGMYQKBgQDmFWAApeXv4xXF2a/1 -HKumO5Z+w+XkKiM76YyTHTKO/KtDYRJiIlJMgx+hoRTBwlpYDrlbS9+Jnm7bZ9Ib -pxRyMAFRoV7eIhnoAn9KrxhS8xCYF2Km7U1lg/+m3pFKghjV4+K1GHbggmvoiIY1 -2t250zkZSslwTxu/2+jRKYOptQKBgQDlfYrzvuGqClJ9QClxlOV2UrWiGxq6eTgL -4V3l0HwPU9OW/hX0Hued8S70Dpb3o+AAyptbcAqFjSdyIPMbCfKLQQkKpfBUtOvb -Nm12z/VNKNZbu7kvaOJHunQNHzyMEHcjsB9daAVI0gJZKN+m6Qh4VF4jao7G9GNR -d7ge0KcXzQKBgQCqf8p9kHJ9OsVmsTMgK1fTvrJ+S8LvOn6TpjVCy08tAHYVXzjV -OePMyRpGluyfzNtQB9E5o1cKTzqNIjljvoN7PrGrgS6g45pZAIi9mlUnGvIAEsxL -MOy6vn9Tc/kswo2O6umUE4X8RwmZ7pmuDPtj+e+FG5N8w1Kn8VlsrhvgRQKBgAgz -clG/koTnFYeQUWrTrVeLIR6H5W6gglY6WYaq6qQJlNgigFpW+GP2iH0EQHTdEFY2 -51JfMKERKEW107o1ostDKbWNtIbyaDNPQJ4sVFHLkc15aea90shJa3hEk39V30wR -MS2/V+EAUEErasKmNT1Hlo2hczS86wewRY4kWrRJAoGAeYUG04cu55GwCgp50P3J -0NCNyiOkhnaj0wGPztMbDqNkaUAoaycoEsas5lhRAWT4YIVglz5pwR4uiI57w1cL -Mvjk5yDiQs7h3bV/qtm95YPBBC+y3mmZYlEA1lH0qktRNBlMVtfYkPztBh50UBOH -8qhIwqrpm3+JJ1p2p0XPl1c= +MIIE8QIBADBBBgkqhkiG9w0BAQowNKAPMA0GCWCGSAFlAwQCAQUAoRwwGgYJKoZI +hvcNAQEIMA0GCWCGSAFlAwQCAQUAogMCASAEggSnMIIEowIBAAKCAQEA0b7eGccE +nfOG0bd5zptCwGEhd+YmtvgaYKsmdxTK9y1vXq13ZsSyd4IpPZIVpam2BYgmxXix +4ikHbeKzydJG3bvr2J+f7Z9bgPZZNB9NJjX3j4IlEkGVI4/ZrROKrC004ItGcHqU +Jdlq48W3JFyKWswBrFYxaCR2HyTj6uI+dsxwuPWse/rqyu+1NKN7uxmh1RXAKa+k +YVkKSmyta2UN+TJZ3bj0a0Sk9cyAqYVGI+kPKF+BYItgh6W+1cmYEscBjNkgcLbV +/henBMjX90OZsTel/iQeXb0w7NgHfVQ2ZR3UmzkAwt8Eh/5+AtIsXRMuV9xgG17M +KiN4JJUCjr8b/QIDAQABAoIBACj0qS/FYcxp6hB3UCycupsQHFXqNfMSXSw1H0yv +XbaIQ6/sFV2W2PZnDyB7rwhrLCTGYjO7DpkHw/CcDNlC2x2e/T2OZc8jh92VvPNl +jU4BybZXBmAbOED6bNnT8AcQyLtz1qxN8zG0059oUwuhmk6CeW0qY3lfbUVFkc+i +n+nYRUBuezEZ4QUg8oX98IFaCDikFByUvnpDoc2t43xX5A4f5mzC/Sa+MLUhgNBX +9VL2D0iVD598tLiHb2TmGHtWzijF0JSqWlvVxRzfLi7w9Ke3pmAWTB2rKAaCa/Sx +1G2HeeiobuLobgi9Gxcw5amd2bgdRBr6G4XtZfAY32DIuOECgYEA7aUKPByEx3ke +5uCoafvzd73/FMlHGm5MC36U2UlGFDLxSQKq/iAzPyiFFhdMOsRXN4bARthgEmjC +oZWFkR+UKKAx9p2clFtJpic5+xwds3bApE4fXmlG+vTjhAIPjPllSsPml7q44WSB +2M4DnMWFmnEI5r2YvM5WScC2LYLDvpkCgYEA4fItV4kR3z5U7IQuyp/KfdD8csAI +nX5r1g98LxHo4AIRrwoeBxAB3XGIgz1ykIaw8dg6V0SG16sOkOQ24F9MV+cSe0EM +tnWmy5SD2+nUJfMpfI/HDSI6H3Mx8E4Ae74ungsMFTmxuyu++/sNt/igIqfkQO2f +hV2VXu58mYUMWwUCgYB1oKZjQJ58ebhRAUx7QUmusG2tJT+7lnKvkdUthDZa0yhZ +QifPJ7MWBQFzAM8rm3msM1fC+WD8W7xS7MazIZVdUoXIkxUo3dKjmnD5mV4eMZ6C +9WRTf/qxRzvCYJ6/4cZAbp0Z50OR1QTsgnSJSb+qxV5pj9klQ2C0mt3RwxMOqQKB +gCQiZ+/04t/SByDgLt+G2Ipwjr8HSRlu624Lge/BLH4OtqdIte6pN7MjghKDFDxa +3hd/Xi0wr2P0Xlr7tG8DrqDsOn9tssvHWwp50PCtn5kGH19lWw8Vpzf6Y0UsJFWl +36y01ZTbajolz+BakSIX5/xC33Umy3k3szjAaTrgFU7FAoGBAMl9TGtpKAXuqvU7 +MIorzE1kd70bajWQiYrlxPu8kD6pi9POSZv4tEYF6sE8zK4OskvTn3F+mu/kmHN1 +qak4Sqgwek16n6AdvSoGlDG/eFVIioMaLXAGGXuWZ8J/doCTPH5JPRsEVdeWwI8E +v69m7uG79SuNZ1vHaycsQU7FEqe3 -----END PRIVATE KEY----- diff --git a/impl/src/test/resources/io/jsonwebtoken/impl/security/PS256.pkcs1.key.pem b/impl/src/test/resources/io/jsonwebtoken/impl/security/PS256.pkcs1.key.pem deleted file mode 120000 index 6aba8b0c4..000000000 --- a/impl/src/test/resources/io/jsonwebtoken/impl/security/PS256.pkcs1.key.pem +++ /dev/null @@ -1 +0,0 @@ -rsa2048.pkcs1.key.pem \ No newline at end of file diff --git a/impl/src/test/resources/io/jsonwebtoken/impl/security/PS256.pkcs1.key.pem b/impl/src/test/resources/io/jsonwebtoken/impl/security/PS256.pkcs1.key.pem new file mode 100644 index 000000000..5bb49a85b --- /dev/null +++ b/impl/src/test/resources/io/jsonwebtoken/impl/security/PS256.pkcs1.key.pem @@ -0,0 +1,43 @@ +# +# Copyright © 2020 jsonwebtoken.io +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +-----BEGIN RSA-PSS PRIVATE KEY----- +MIIEowIBAAKCAQEA0b7eGccEnfOG0bd5zptCwGEhd+YmtvgaYKsmdxTK9y1vXq13 +ZsSyd4IpPZIVpam2BYgmxXix4ikHbeKzydJG3bvr2J+f7Z9bgPZZNB9NJjX3j4Il +EkGVI4/ZrROKrC004ItGcHqUJdlq48W3JFyKWswBrFYxaCR2HyTj6uI+dsxwuPWs +e/rqyu+1NKN7uxmh1RXAKa+kYVkKSmyta2UN+TJZ3bj0a0Sk9cyAqYVGI+kPKF+B +YItgh6W+1cmYEscBjNkgcLbV/henBMjX90OZsTel/iQeXb0w7NgHfVQ2ZR3UmzkA +wt8Eh/5+AtIsXRMuV9xgG17MKiN4JJUCjr8b/QIDAQABAoIBACj0qS/FYcxp6hB3 +UCycupsQHFXqNfMSXSw1H0yvXbaIQ6/sFV2W2PZnDyB7rwhrLCTGYjO7DpkHw/Cc +DNlC2x2e/T2OZc8jh92VvPNljU4BybZXBmAbOED6bNnT8AcQyLtz1qxN8zG0059o +Uwuhmk6CeW0qY3lfbUVFkc+in+nYRUBuezEZ4QUg8oX98IFaCDikFByUvnpDoc2t +43xX5A4f5mzC/Sa+MLUhgNBX9VL2D0iVD598tLiHb2TmGHtWzijF0JSqWlvVxRzf +Li7w9Ke3pmAWTB2rKAaCa/Sx1G2HeeiobuLobgi9Gxcw5amd2bgdRBr6G4XtZfAY +32DIuOECgYEA7aUKPByEx3ke5uCoafvzd73/FMlHGm5MC36U2UlGFDLxSQKq/iAz +PyiFFhdMOsRXN4bARthgEmjCoZWFkR+UKKAx9p2clFtJpic5+xwds3bApE4fXmlG ++vTjhAIPjPllSsPml7q44WSB2M4DnMWFmnEI5r2YvM5WScC2LYLDvpkCgYEA4fIt +V4kR3z5U7IQuyp/KfdD8csAInX5r1g98LxHo4AIRrwoeBxAB3XGIgz1ykIaw8dg6 +V0SG16sOkOQ24F9MV+cSe0EMtnWmy5SD2+nUJfMpfI/HDSI6H3Mx8E4Ae74ungsM +FTmxuyu++/sNt/igIqfkQO2fhV2VXu58mYUMWwUCgYB1oKZjQJ58ebhRAUx7QUmu +sG2tJT+7lnKvkdUthDZa0yhZQifPJ7MWBQFzAM8rm3msM1fC+WD8W7xS7MazIZVd +UoXIkxUo3dKjmnD5mV4eMZ6C9WRTf/qxRzvCYJ6/4cZAbp0Z50OR1QTsgnSJSb+q +xV5pj9klQ2C0mt3RwxMOqQKBgCQiZ+/04t/SByDgLt+G2Ipwjr8HSRlu624Lge/B +LH4OtqdIte6pN7MjghKDFDxa3hd/Xi0wr2P0Xlr7tG8DrqDsOn9tssvHWwp50PCt +n5kGH19lWw8Vpzf6Y0UsJFWl36y01ZTbajolz+BakSIX5/xC33Umy3k3szjAaTrg +FU7FAoGBAMl9TGtpKAXuqvU7MIorzE1kd70bajWQiYrlxPu8kD6pi9POSZv4tEYF +6sE8zK4OskvTn3F+mu/kmHN1qak4Sqgwek16n6AdvSoGlDG/eFVIioMaLXAGGXuW +Z8J/doCTPH5JPRsEVdeWwI8Ev69m7uG79SuNZ1vHaycsQU7FEqe3 +-----END RSA-PSS PRIVATE KEY----- diff --git a/impl/src/test/resources/io/jsonwebtoken/impl/security/PS256.pub.pem b/impl/src/test/resources/io/jsonwebtoken/impl/security/PS256.pub.pem deleted file mode 120000 index 518164ebb..000000000 --- a/impl/src/test/resources/io/jsonwebtoken/impl/security/PS256.pub.pem +++ /dev/null @@ -1 +0,0 @@ -rsa2048.pub.pem \ No newline at end of file diff --git a/impl/src/test/resources/io/jsonwebtoken/impl/security/PS256.pub.pem b/impl/src/test/resources/io/jsonwebtoken/impl/security/PS256.pub.pem new file mode 100644 index 000000000..9c5740df6 --- /dev/null +++ b/impl/src/test/resources/io/jsonwebtoken/impl/security/PS256.pub.pem @@ -0,0 +1,26 @@ +# +# Copyright © 2020 jsonwebtoken.io +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +-----BEGIN PUBLIC KEY----- +MIIBVjBBBgkqhkiG9w0BAQowNKAPMA0GCWCGSAFlAwQCAQUAoRwwGgYJKoZIhvcN +AQEIMA0GCWCGSAFlAwQCAQUAogMCASADggEPADCCAQoCggEBANG+3hnHBJ3zhtG3 +ec6bQsBhIXfmJrb4GmCrJncUyvctb16td2bEsneCKT2SFaWptgWIJsV4seIpB23i +s8nSRt2769ifn+2fW4D2WTQfTSY194+CJRJBlSOP2a0TiqwtNOCLRnB6lCXZauPF +tyRcilrMAaxWMWgkdh8k4+riPnbMcLj1rHv66srvtTSje7sZodUVwCmvpGFZCkps +rWtlDfkyWd249GtEpPXMgKmFRiPpDyhfgWCLYIelvtXJmBLHAYzZIHC21f4XpwTI +1/dDmbE3pf4kHl29MOzYB31UNmUd1Js5AMLfBIf+fgLSLF0TLlfcYBtezCojeCSV +Ao6/G/0CAwEAAQ== +-----END PUBLIC KEY----- diff --git a/impl/src/test/resources/io/jsonwebtoken/impl/security/PS384.crt.pem b/impl/src/test/resources/io/jsonwebtoken/impl/security/PS384.crt.pem index 9f6e42e37..d2e8cff89 100644 --- a/impl/src/test/resources/io/jsonwebtoken/impl/security/PS384.crt.pem +++ b/impl/src/test/resources/io/jsonwebtoken/impl/security/PS384.crt.pem @@ -15,27 +15,33 @@ # -----BEGIN CERTIFICATE----- -MIIERDCCAqwCCQDqxucO41yAmTANBgkqhkiG9w0BAQsFADBjMQswCQYDVQQGEwJV -UzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzEY -MBYGA1UECgwPanNvbndlYnRva2VuLmlvMQ0wCwYDVQQLDARqand0MCAXDTIwMDIw -MzIzMDQ1OFoYDzMwMjAwMjExMjMwNDU4WjBjMQswCQYDVQQGEwJVUzETMBEGA1UE -CAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzEYMBYGA1UECgwP -anNvbndlYnRva2VuLmlvMQ0wCwYDVQQLDARqand0MIIBojANBgkqhkiG9w0BAQEF -AAOCAY8AMIIBigKCAYEA0DmQS4Xtgu5xtnQdxkuzB1j+W4OvNEOVOsg3Zcn9W1d5 -NowtngUh9K9vwBpl59M2j5PHj9dseEIuRqr++ZnZhBMlh/lLiIQ0oQ3cEa7wrwJO -i9ycZZbeNDHVNzAdQZEQR1DIMUhSTEMR96pVD4a9DzBKLQJaKxZRUOrMhf3QhAZ5 -9m0d/Kqu1Dm6YeWMLQQEewAaSQ9g22gty1EcLAvp/vnhR/DJSYIHCayd5mZwvk9q -WkXySfUmJGP70GFGG4GOnVLLkmCQgfT+OrzTtiIzNT26mtAsoUMnoD42TTBkR0aL -hULcj1MYUcB9uVCmJTvYuiCTODoNlL8T40r9L99HoHlTWVi9vf6I1vyNdHp3dXKB -MVL13+i5BeNIjADr0KKs0jtEEicWyuVhJz3rPLzBbPhz/DGQ/hTj/DRSdo9L9YA4 -WkqgD8uFUvIEKAJ/hXYx3QPEiIMU7hT4jk2Z2SIBiKKiNW4E/20EZOFmaeNWQaqq -mwX0cHtMygJtTYnEJ1IDAgMBAAEwDQYJKoZIhvcNAQELBQADggGBAGKkmv6d372z -Ujt1qjsjH7LHfIsPXdvnp7OhvujDEtY7dzwDCtR40zgB2qp+iXUO61FXErx8yDp9 -l7sDzk0AjY7RupANuo/3FyDuo0WoTUV3CJNnXf3Mrvu/DMjbaS6D4Jryz/HLE+2r -GYtdm165FZK/hQXuFfurkc4yqjrX90Wr+YHeen2y5Wk3jeUknmdp97F6+zkq6N5D -dKjy/ZOvy+1huNd5bzvJoiZLKqdSh/RQUoU6AP1p+83lo+7cPvS/zm/HvwxwMamA -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 +bXVUUwwl8tRC -----END CERTIFICATE----- diff --git a/impl/src/test/resources/io/jsonwebtoken/impl/security/PS384.key.pem b/impl/src/test/resources/io/jsonwebtoken/impl/security/PS384.key.pem index 4fd9098bf..a9aa65e81 100644 --- a/impl/src/test/resources/io/jsonwebtoken/impl/security/PS384.key.pem +++ b/impl/src/test/resources/io/jsonwebtoken/impl/security/PS384.key.pem @@ -15,42 +15,43 @@ # -----BEGIN PRIVATE KEY----- -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 -5I2wbxUhb3FO7gj9pxJbwX4= +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 +lVynub2OR3qrrfMw0voYdeaYeLELzQ== -----END PRIVATE KEY----- diff --git a/impl/src/test/resources/io/jsonwebtoken/impl/security/PS384.pkcs1.key.pem b/impl/src/test/resources/io/jsonwebtoken/impl/security/PS384.pkcs1.key.pem deleted file mode 120000 index 75de2b26e..000000000 --- a/impl/src/test/resources/io/jsonwebtoken/impl/security/PS384.pkcs1.key.pem +++ /dev/null @@ -1 +0,0 @@ -rsa3072.pkcs1.key.pem \ No newline at end of file diff --git a/impl/src/test/resources/io/jsonwebtoken/impl/security/PS384.pkcs1.key.pem b/impl/src/test/resources/io/jsonwebtoken/impl/security/PS384.pkcs1.key.pem new file mode 100644 index 000000000..bd3f037e7 --- /dev/null +++ b/impl/src/test/resources/io/jsonwebtoken/impl/security/PS384.pkcs1.key.pem @@ -0,0 +1,55 @@ +# +# Copyright © 2020 jsonwebtoken.io +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +-----BEGIN RSA-PSS PRIVATE KEY----- +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 +-----END RSA-PSS PRIVATE KEY----- diff --git a/impl/src/test/resources/io/jsonwebtoken/impl/security/PS384.pub.pem b/impl/src/test/resources/io/jsonwebtoken/impl/security/PS384.pub.pem deleted file mode 120000 index 6d0de80e7..000000000 --- a/impl/src/test/resources/io/jsonwebtoken/impl/security/PS384.pub.pem +++ /dev/null @@ -1 +0,0 @@ -rsa3072.pub.pem \ No newline at end of file diff --git a/impl/src/test/resources/io/jsonwebtoken/impl/security/PS384.pub.pem b/impl/src/test/resources/io/jsonwebtoken/impl/security/PS384.pub.pem new file mode 100644 index 000000000..bddb8977c --- /dev/null +++ b/impl/src/test/resources/io/jsonwebtoken/impl/security/PS384.pub.pem @@ -0,0 +1,28 @@ +# +# Copyright © 2020 jsonwebtoken.io +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +-----BEGIN PUBLIC KEY----- +MIIB1jBBBgkqhkiG9w0BAQowNKAPMA0GCWCGSAFlAwQCAgUAoRwwGgYJKoZIhvcN +AQEIMA0GCWCGSAFlAwQCAgUAogMCATADggGPADCCAYoCggGBAK08UFGaokghRc3G +5lYLgqgwmRrNvBbdP5ZsB2uWFiGtni9XlO2M3Sal20f+sJ+ZxqfhmFHVJ6hTso4X +3hrSAma5jQeEETSmY8aO4OmRJ/kxJ9bxy/MXmK5Z4zDz7eqK3cEK2Ac40epK33v9 +eZdrJyScz6MdWoyTXyRHtNF60Hi59Z8EqwjFtkVi33l0yYZQs2FiilE1jSzNS4BY +ks0ZvU/7V4afY3UdNZdsLrasywCn4tX98EtWCoDK+00GZIN2H4oHPz6M/7ago5M6 +YjVcMGghqnumVzeTpbmbuHQmswFfgpRqFsUKgcxdIoWVLH5CbXozFlTc3suyZpCE +3hiFquZNIoK16qd3zQ71LVpne9MLsFsh+yEYhHrWBd93k43VxbkDb20zPRquPvDl +x2nuSEvbe/bQCgMT4bPxFQ+yj4BrJSzCwhJuYM42e4JWtDsUxbaKtFc2s+wuCQvg +iD80jp+IZV4v0ibYS/GA2DjYJNTskBZ3hSxf50NRJLek6LUmFQIDAQAB +-----END PUBLIC KEY----- diff --git a/impl/src/test/resources/io/jsonwebtoken/impl/security/PS512.crt.pem b/impl/src/test/resources/io/jsonwebtoken/impl/security/PS512.crt.pem index 55a08c370..1dd4dbb90 100644 --- a/impl/src/test/resources/io/jsonwebtoken/impl/security/PS512.crt.pem +++ b/impl/src/test/resources/io/jsonwebtoken/impl/security/PS512.crt.pem @@ -15,33 +15,38 @@ # -----BEGIN CERTIFICATE----- -MIIFRDCCAywCCQC4g2isVGolKjANBgkqhkiG9w0BAQsFADBjMQswCQYDVQQGEwJV -UzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzEY -MBYGA1UECgwPanNvbndlYnRva2VuLmlvMQ0wCwYDVQQLDARqand0MCAXDTIwMDIw -MzIzMDY1MloYDzMwMjAwMjExMjMwNjUyWjBjMQswCQYDVQQGEwJVUzETMBEGA1UE -CAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzEYMBYGA1UECgwP -anNvbndlYnRva2VuLmlvMQ0wCwYDVQQLDARqand0MIICIjANBgkqhkiG9w0BAQEF -AAOCAg8AMIICCgKCAgEAw7jTXeRwCRrDdYnrIwcLvSNfhpmJZ0ap1jzKVgUyCOYL -TaB9+naJRjHqx7B5wgx/ArRF2nluQ5tawZPMFw2I/iqXYrQEPTbq1XVugYC/C491 -bcXOTKx+DgEvnhNysm/KmzFsEcw78prB5sIAZSR+S5zZPuny4zww2UzE9TZ433RB -kyA+wVkd64bgXdkMrVc+gsRsOtvwPFbQ89zg8d/pNV0mDtjDsfiYw0pSAah11fJG -a+aRc46CqFu/6rHuN4uq6542LdtshPbHz29VKHxk8agtcx06+8F05Bg4LFm1rRhY -0g3KsT7s8XHMVdo9h2bIQuWOaFg3mehpH6ZYBV4ENo98V/jDaUPpBHsaUXw4fG/w -rnI+YwRjGlmp2QEr5VRfh0x8Addf6N64lmbQUpCPhJweJd54D3JvIpJr8HiG3GYW -eFsrmDzmhrozZHxE4P7UesW6lWwQzGfwYGXs7j6TEa2hZ8EB/t1jsYNjZ5UYY/Jb -KgFGSkMGje4Bi5Bv6kh4+pp3DT5QsG/AfLVlr5ineLDWkJ15uZjOxl12EOPXOCWV -iVqS6rayJfb95YJQ52rT4H83BsApHbzFj7q/CIaeJkUdv9GJ2SOADcXdgG7Xk7tH -qb1VIH4zRBo5mc0qN1cAwjopxHv2h3tGaTHKbptvfiLulH+AvvuWmLMEQo6ZDlsC -AwEAATANBgkqhkiG9w0BAQsFAAOCAgEApnHjMQwt5hm6UlEDvdWCYbh7ctkLbgwR -iBP1lvunm2oF0jGpipt8oDR/TT43usb6ieuU+ABksjxOROeoVZbK8bEpnzeo3nNE -41ERI3Byjp7tsja8QGG0uBk9QZ0+7MhJqhEDVAIbS0Lf4exkWiLZrW7ogAEFYKTN -DE6CxOcfR/kXj6ejuCnvN4xYqnw8G/OF/3tnHMfKnnnqtMmWdAKd3Y5S1EJZ5vtp -lZ3I9HA5Hx0sTH1ruCOIRzaC5En1c6zW1HjxmeAqLeG814gezlEhHzb4SCkabgQh -Bq15O8eQaW92f8xZoUQN25w7SNYszk9AdhroJz3+BOzG3+Y1EInLk5hDHT8oUNFz -e8EosJEwJDK3wq9YOhn8PUT/DacyNKONJVNly3fTBXoSR3oReW61p6T19z4AYsY9 -qMwSjIL2UcgAF8Kpsx2NdQrDfdveNMhul7AjIgz+e2DtRqCkZ6ypdhht2pmlpiXO -TiUG/1OBq2yTeJF9LjAUzsSNnsZ/F8pJbwSpr7VqDmTNGTfrh6x1ojHNFjJeTqK8 -MCTmQtJJTAbV4nuB+thFFWDx0IWvbG7ViYds9sdJNO4L3baXeAioJhHs5buBy3eb -ZWjLAwHpSCqNY3d6+ouGLwE1YVFsk8sV9UM+gl15VynKkunbYoKhiD82HGASNYtE -33eif1l5Nk0= +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 +E3vd9XobDXMOJLBBPLceTt8pvv/6GyF6bQ== -----END CERTIFICATE----- diff --git a/impl/src/test/resources/io/jsonwebtoken/impl/security/PS512.key.pem b/impl/src/test/resources/io/jsonwebtoken/impl/security/PS512.key.pem index cb8296b23..b0cbf793d 100644 --- a/impl/src/test/resources/io/jsonwebtoken/impl/security/PS512.key.pem +++ b/impl/src/test/resources/io/jsonwebtoken/impl/security/PS512.key.pem @@ -15,54 +15,55 @@ # -----BEGIN PRIVATE KEY----- -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 -lczRTJNTE/KNUE0pkC5P4c/e0A1OFu0= +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 +fSc/Kr3l8kzu0dexW4usUiKuLju4X471jKg= -----END PRIVATE KEY----- diff --git a/impl/src/test/resources/io/jsonwebtoken/impl/security/PS512.pkcs1.key.pem b/impl/src/test/resources/io/jsonwebtoken/impl/security/PS512.pkcs1.key.pem deleted file mode 120000 index 15d6f5c04..000000000 --- a/impl/src/test/resources/io/jsonwebtoken/impl/security/PS512.pkcs1.key.pem +++ /dev/null @@ -1 +0,0 @@ -rsa4096.pkcs1.key.pem \ No newline at end of file diff --git a/impl/src/test/resources/io/jsonwebtoken/impl/security/PS512.pkcs1.key.pem b/impl/src/test/resources/io/jsonwebtoken/impl/security/PS512.pkcs1.key.pem new file mode 100644 index 000000000..0b2b26fe8 --- /dev/null +++ b/impl/src/test/resources/io/jsonwebtoken/impl/security/PS512.pkcs1.key.pem @@ -0,0 +1,67 @@ +# +# Copyright © 2020 jsonwebtoken.io +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +-----BEGIN RSA-PSS PRIVATE KEY----- +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 +-----END RSA-PSS PRIVATE KEY----- diff --git a/impl/src/test/resources/io/jsonwebtoken/impl/security/PS512.pub.pem b/impl/src/test/resources/io/jsonwebtoken/impl/security/PS512.pub.pem deleted file mode 120000 index 74c57d7fb..000000000 --- a/impl/src/test/resources/io/jsonwebtoken/impl/security/PS512.pub.pem +++ /dev/null @@ -1 +0,0 @@ -rsa4096.pub.pem \ No newline at end of file diff --git a/impl/src/test/resources/io/jsonwebtoken/impl/security/PS512.pub.pem b/impl/src/test/resources/io/jsonwebtoken/impl/security/PS512.pub.pem new file mode 100644 index 000000000..b3e324d13 --- /dev/null +++ b/impl/src/test/resources/io/jsonwebtoken/impl/security/PS512.pub.pem @@ -0,0 +1,31 @@ +# +# Copyright © 2020 jsonwebtoken.io +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +-----BEGIN PUBLIC KEY----- +MIICVjBBBgkqhkiG9w0BAQowNKAPMA0GCWCGSAFlAwQCAwUAoRwwGgYJKoZIhvcN +AQEIMA0GCWCGSAFlAwQCAwUAogMCAUADggIPADCCAgoCggIBALwyFsfuAMqDU0sX +qO97Z+b4BXLFBOJ4NOAhhAMoptoe6jiN7iLhLPeD+GBZM+3nrMLVa/1mDdpVJz6C +QH6tRBgOxc+DSLNdGIEbHtyOcvwCrxipqpdLSHkJGq/6+kTNBIyv/Uv7Aou+/fHz +7H++ktmeHRtMqSB9VeCwMGkrSOvsE+vfvWS8TLScQBdNrEBmmQoRhPpRa6MnOF83 +Hmc6XvlQlw4Ld4YBFwBio/Iq+nwHWOI4f2zM9vv5o4FHgoaHBWRvvZVqy0uYGPp6 +SBmhI9gzP0DqBE5howInmJY6a+HggliAJugupcC7EXY9IZje+6byuJc6F5JZiNi3 +kAyVR8eoq/+1Fr7KVaZN6DhLYT5KSN298pvxAAoPzB+IsF8nohsO9oYRWJ0xg0Yp +6rv6144CHsVDC7aTE2mrnCYEy6Dj3aBVtJruB7inNYTbILzFmmh9/5dPaCg66rOE +At0kFUOIL5mb1rlSOVv79V9oZk2sDRNd+nPhTtxE+G+0U06FHKvSGWVe+rrJe19Z +dpIqYqH0/UFewA8P4apjqYi2wLdqt8EYx10G9IuiJZLl6TiOrSHIu08NyHra9k55 +01SQBnsx+9HFXgHRaAhOgV++3LJxp63bZn0TDWhnrY/MFvcjceb67EIZUc+AFcfJ +7MeEDt9mGPbMDBsDKqZD4qnhgqfbAgMBAAE= +-----END PUBLIC KEY----- diff --git a/impl/src/test/resources/io/jsonwebtoken/impl/security/README.md b/impl/src/test/resources/io/jsonwebtoken/impl/security/README.md index 6677b7e57..4772a5210 100644 --- a/impl/src/test/resources/io/jsonwebtoken/impl/security/README.md +++ b/impl/src/test/resources/io/jsonwebtoken/impl/security/README.md @@ -1,18 +1,28 @@ -The RSA `*.key.pem`, `*.crt.pem`, `*.pub.pem`, and `*.pkcs1.key.pem` files in this directory were created for testing as follows: +The RSA `*.key.pem`, `*.crt.pem`, `*.pub.pem`, and `*.pkcs1.key.pem` files in this directory were created for testing +using the `openssl` version `3.1.2` as follows: - openssl req -x509 -newkey rsa:2048 -keyout rsa2048.key.pem -out rsa2048.crt.pem -days 365250 -nodes -subj '/C=US/ST=California/L=San Francisco/O=jsonwebtoken.io/OU=jjwt' - openssl req -x509 -newkey rsa:3072 -keyout rsa3072.key.pem -out rsa3072.crt.pem -days 365250 -nodes -subj '/C=US/ST=California/L=San Francisco/O=jsonwebtoken.io/OU=jjwt' - openssl req -x509 -newkey rsa:4096 -keyout rsa4096.key.pem -out rsa4096.crt.pem -days 365250 -nodes -subj '/C=US/ST=California/L=San Francisco/O=jsonwebtoken.io/OU=jjwt' + openssl req -new -x509 -newkey rsa:2048 -keyout RS256.key.pem -out RS256.crt.pem -days 365250 -nodes -subj '/C=US/ST=California/L=San Francisco/O=jsonwebtoken.io/OU=jjwt' + openssl req -new -x509 -newkey rsa:3072 -keyout RS384.key.pem -out RS384.crt.pem -days 365250 -nodes -subj '/C=US/ST=California/L=San Francisco/O=jsonwebtoken.io/OU=jjwt' + openssl req -new -x509 -newkey rsa:4096 -keyout RS512.key.pem -out RS512.crt.pem -days 365250 -nodes -subj '/C=US/ST=California/L=San Francisco/O=jsonwebtoken.io/OU=jjwt' + openssl req -new -x509 -newkey rsa-pss -keyout PS256.key.pem -out PS256.crt.pem -days 365250 -nodes -subj '/C=US/ST=California/L=San Francisco/O=jsonwebtoken.io/OU=jjwt' -pkeyopt rsa_keygen_bits:2048 -pkeyopt rsa_pss_keygen_md:sha256 -pkeyopt rsa_pss_keygen_mgf1_md:sha256 -pkeyopt rsa_pss_keygen_saltlen:32 -sigopt rsa_padding_mode:pss -sigopt rsa_pss_saltlen:32 -sigopt rsa_mgf1_md:sha256 -sha256 + openssl req -new -x509 -newkey rsa-pss -keyout PS384.key.pem -out PS384.crt.pem -days 365250 -nodes -subj '/C=US/ST=California/L=San Francisco/O=jsonwebtoken.io/OU=jjwt' -pkeyopt rsa_keygen_bits:3072 -pkeyopt rsa_pss_keygen_md:sha384 -pkeyopt rsa_pss_keygen_mgf1_md:sha384 -pkeyopt rsa_pss_keygen_saltlen:48 -sigopt rsa_padding_mode:pss -sigopt rsa_pss_saltlen:48 -sigopt rsa_mgf1_md:sha384 -sha384 + openssl req -new -x509 -newkey rsa-pss -keyout PS512.key.pem -out PS512.crt.pem -days 365250 -nodes -subj '/C=US/ST=California/L=San Francisco/O=jsonwebtoken.io/OU=jjwt' -pkeyopt rsa_keygen_bits:4096 -pkeyopt rsa_pss_keygen_md:sha512 -pkeyopt rsa_pss_keygen_mgf1_md:sha512 -pkeyopt rsa_pss_keygen_saltlen:64 -sigopt rsa_padding_mode:pss -sigopt rsa_pss_saltlen:64 -sigopt rsa_mgf1_md:sha512 -sha512 # extract the public key from the X.509 certificates to their own files: - openssl x509 -pubkey -noout -in rsa2048.crt.pem > rsa2048.pub.pem - openssl x509 -pubkey -noout -in rsa3072.crt.pem > rsa3072.pub.pem - openssl x509 -pubkey -noout -in rsa4096.crt.pem > rsa4096.pub.pem + openssl x509 -pubkey -noout -in RS256.crt.pem > RS256.pub.pem + openssl x509 -pubkey -noout -in RS384.crt.pem > RS384.pub.pem + openssl x509 -pubkey -noout -in RS512.crt.pem > RS512.pub.pem + openssl x509 -pubkey -noout -in PS256.crt.pem > PS256.pub.pem + openssl x509 -pubkey -noout -in PS384.crt.pem > PS384.pub.pem + openssl x509 -pubkey -noout -in PS512.crt.pem > PS512.pub.pem # convert the PKCS8 private key format to PKCS1 format for additional testing: - openssl rsa -in rsa2048.key.pem -out rsa2048.pkcs1.key.pem - openssl rsa -in rsa3072.key.pem -out rsa3072.pkcs1.key.pem - openssl rsa -in rsa4096.key.pem -out rsa4096.pkcs1.key.pem + openssl rsa -in RS256.key.pem -traditional -out RS256.pkcs1.key.pem + openssl rsa -in RS384.key.pem -traditional -out RS384.pkcs1.key.pem + openssl rsa -in RS512.key.pem -traditional -out RS512.pkcs1.key.pem + openssl rsa -in PS256.key.pem -traditional -out PS256.pkcs1.key.pem + openssl rsa -in PS384.key.pem -traditional -out PS384.pkcs1.key.pem + openssl rsa -in PS512.key.pem -traditional -out PS512.pkcs1.key.pem The only difference is the key size and file names using sizes of `2048`, `3072`, and `4096`. @@ -63,6 +73,5 @@ All `ES*`, `RS*`, `PS*`, `X*` and `Ed*` file prefixes are equal to JWA standard Curve IDs. This allows easy file lookup based on the `SignatureAlgorithm` `getId()` or `EdwardsCurve#getId()` value when authoring tests. -Finally, the `RS*`, `PS*`, and `EdDSA*` files in this directory are just are symlinks back to source files based on -the JWT alg names and their respective key sizes. This is so the `RS*` and `PS*` algorithms can use the same files -since there is no difference in keys between the two sets of algorithms. +Finally, the `EdDSA*` files in this directory are just are symlinks back to source files based on +the `EdSignatureAlgorithm`'s preferred `Ed448` key sizes. diff --git a/impl/src/test/resources/io/jsonwebtoken/impl/security/RS256.pkcs1.key.pem b/impl/src/test/resources/io/jsonwebtoken/impl/security/RS256.pkcs1.key.pem deleted file mode 120000 index 6aba8b0c4..000000000 --- a/impl/src/test/resources/io/jsonwebtoken/impl/security/RS256.pkcs1.key.pem +++ /dev/null @@ -1 +0,0 @@ -rsa2048.pkcs1.key.pem \ No newline at end of file diff --git a/impl/src/test/resources/io/jsonwebtoken/impl/security/RS256.pkcs1.key.pem b/impl/src/test/resources/io/jsonwebtoken/impl/security/RS256.pkcs1.key.pem new file mode 100644 index 000000000..9e995d1b0 --- /dev/null +++ b/impl/src/test/resources/io/jsonwebtoken/impl/security/RS256.pkcs1.key.pem @@ -0,0 +1,43 @@ +# +# Copyright © 2022 jsonwebtoken.io +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEAzkH0MwxQ2cUFWsvOPVFqI/dk2EFTjQolCy97mI5/wYCbaOoZ +9Rm7c675mAeemRtNzgNVEz7m298ENqNGqPk2Nv3pBJ/XCaybBlp61CLez7dQ2h5j +UFEJ6FJcjeKHS+MwXr56t2ISdfLNMYtVIxjvXQcYx5VmS4mIqTxj5gVGtQVi0GXd +H6SvpdKV0fjE9KOhjsdBfKQzZfcQlusHg8pThwvjpMwCZnkxCS0RKa9y4+5+7MkC +33+8+neZUzS7b6NdFxh6T/pMXpkf8d81fzVo4ZBMloweW0/l8MOdVxeX7M/7XSC1 +ank5i3IEZcotLmJYMwEo7rMpZVLevEQ118Eo8QIDAQABAoIBAGfdGoWiTAx9hEbG +nqKOHu7ho6yqqNI7K5BIZurZx0e/5YKdcFjWjmig0htWquzarQFy+CJq6IIL+ekx +q2FnrX9fuTmU7Ap5Gs/GPFga/yyGWXadGtHVHTIaV3Uzf4Idc7wiG1XBUx6GGAI8 +8bBs3AxyiG3os8ySA3mFaaDpQ0Pf/Qb+n7eJoWhuUh1Z3nPUHZmyZyg6uayOGj1w +glzgsw43U1X4J7XR+U76Ah/dREkisJHXXIgG1bF6Dlpwcd4yjI/oSAOBdaep82VG +4lc5sYan0oUIQ5whL6vLReyqkW1LEhsfDFbcEpBBmoiQg1Y8EkRpIIV5YLjcGXH5 +1jLRjGECgYEA5hVgAKXl7+MVxdmv9RyrpjuWfsPl5CojO+mMkx0yjvyrQ2ESYiJS +TIMfoaEUwcJaWA65W0vfiZ5u22fSG6cUcjABUaFe3iIZ6AJ/Sq8YUvMQmBdipu1N +ZYP/pt6RSoIY1ePitRh24IJr6IiGNdrdudM5GUrJcE8bv9vo0SmDqbUCgYEA5X2K +877hqgpSfUApcZTldlK1ohsaunk4C+Fd5dB8D1PTlv4V9B7nnfEu9A6W96PgAMqb +W3AKhY0nciDzGwnyi0EJCqXwVLTr2zZtds/1TSjWW7u5L2jiR7p0DR88jBB3I7Af +XWgFSNICWSjfpukIeFReI2qOxvRjUXe4HtCnF80CgYEAqn/KfZByfTrFZrEzICtX +076yfkvC7zp+k6Y1QstPLQB2FV841TnjzMkaRpbsn8zbUAfROaNXCk86jSI5Y76D +ez6xq4EuoOOaWQCIvZpVJxryABLMSzDsur5/U3P5LMKNjurplBOF/EcJme6Zrgz7 +Y/nvhRuTfMNSp/FZbK4b4EUCgYAIM3JRv5KE5xWHkFFq061XiyEeh+VuoIJWOlmG +quqkCZTYIoBaVvhj9oh9BEB03RBWNudSXzChEShFtdO6NaLLQym1jbSG8mgzT0Ce +LFRRy5HNeWnmvdLISWt4RJN/Vd9METEtv1fhAFBBK2rCpjU9R5aNoXM0vOsHsEWO +JFq0SQKBgHmFBtOHLueRsAoKedD9ydDQjcojpIZ2o9MBj87TGw6jZGlAKGsnKBLG +rOZYUQFk+GCFYJc+acEeLoiOe8NXCzL45Ocg4kLO4d21f6rZveWDwQQvst5pmWJR +ANZR9KpLUTQZTFbX2JD87QYedFATh/KoSMKq6Zt/iSdadqdFz5dX +-----END RSA PRIVATE KEY----- diff --git a/impl/src/test/resources/io/jsonwebtoken/impl/security/RS256.pub.pem b/impl/src/test/resources/io/jsonwebtoken/impl/security/RS256.pub.pem deleted file mode 120000 index 518164ebb..000000000 --- a/impl/src/test/resources/io/jsonwebtoken/impl/security/RS256.pub.pem +++ /dev/null @@ -1 +0,0 @@ -rsa2048.pub.pem \ No newline at end of file diff --git a/impl/src/test/resources/io/jsonwebtoken/impl/security/RS256.pub.pem b/impl/src/test/resources/io/jsonwebtoken/impl/security/RS256.pub.pem new file mode 100644 index 000000000..88c76f3e4 --- /dev/null +++ b/impl/src/test/resources/io/jsonwebtoken/impl/security/RS256.pub.pem @@ -0,0 +1,25 @@ +# +# Copyright © 2022 jsonwebtoken.io +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +-----BEGIN PUBLIC KEY----- +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzkH0MwxQ2cUFWsvOPVFq +I/dk2EFTjQolCy97mI5/wYCbaOoZ9Rm7c675mAeemRtNzgNVEz7m298ENqNGqPk2 +Nv3pBJ/XCaybBlp61CLez7dQ2h5jUFEJ6FJcjeKHS+MwXr56t2ISdfLNMYtVIxjv +XQcYx5VmS4mIqTxj5gVGtQVi0GXdH6SvpdKV0fjE9KOhjsdBfKQzZfcQlusHg8pT +hwvjpMwCZnkxCS0RKa9y4+5+7MkC33+8+neZUzS7b6NdFxh6T/pMXpkf8d81fzVo +4ZBMloweW0/l8MOdVxeX7M/7XSC1ank5i3IEZcotLmJYMwEo7rMpZVLevEQ118Eo +8QIDAQAB +-----END PUBLIC KEY----- diff --git a/impl/src/test/resources/io/jsonwebtoken/impl/security/RS384.pkcs1.key.pem b/impl/src/test/resources/io/jsonwebtoken/impl/security/RS384.pkcs1.key.pem deleted file mode 120000 index 75de2b26e..000000000 --- a/impl/src/test/resources/io/jsonwebtoken/impl/security/RS384.pkcs1.key.pem +++ /dev/null @@ -1 +0,0 @@ -rsa3072.pkcs1.key.pem \ No newline at end of file diff --git a/impl/src/test/resources/io/jsonwebtoken/impl/security/RS384.pkcs1.key.pem b/impl/src/test/resources/io/jsonwebtoken/impl/security/RS384.pkcs1.key.pem new file mode 100644 index 000000000..4be97fc37 --- /dev/null +++ b/impl/src/test/resources/io/jsonwebtoken/impl/security/RS384.pkcs1.key.pem @@ -0,0 +1,55 @@ +# +# Copyright © 2022 jsonwebtoken.io +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +-----BEGIN RSA PRIVATE KEY----- +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 +-----END RSA PRIVATE KEY----- diff --git a/impl/src/test/resources/io/jsonwebtoken/impl/security/RS384.pub.pem b/impl/src/test/resources/io/jsonwebtoken/impl/security/RS384.pub.pem deleted file mode 120000 index 6d0de80e7..000000000 --- a/impl/src/test/resources/io/jsonwebtoken/impl/security/RS384.pub.pem +++ /dev/null @@ -1 +0,0 @@ -rsa3072.pub.pem \ No newline at end of file diff --git a/impl/src/test/resources/io/jsonwebtoken/impl/security/RS384.pub.pem b/impl/src/test/resources/io/jsonwebtoken/impl/security/RS384.pub.pem new file mode 100644 index 000000000..3ab8814a3 --- /dev/null +++ b/impl/src/test/resources/io/jsonwebtoken/impl/security/RS384.pub.pem @@ -0,0 +1,27 @@ +# +# Copyright © 2022 jsonwebtoken.io +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +-----BEGIN PUBLIC KEY----- +MIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEA0DmQS4Xtgu5xtnQdxkuz +B1j+W4OvNEOVOsg3Zcn9W1d5NowtngUh9K9vwBpl59M2j5PHj9dseEIuRqr++ZnZ +hBMlh/lLiIQ0oQ3cEa7wrwJOi9ycZZbeNDHVNzAdQZEQR1DIMUhSTEMR96pVD4a9 +DzBKLQJaKxZRUOrMhf3QhAZ59m0d/Kqu1Dm6YeWMLQQEewAaSQ9g22gty1EcLAvp +/vnhR/DJSYIHCayd5mZwvk9qWkXySfUmJGP70GFGG4GOnVLLkmCQgfT+OrzTtiIz +NT26mtAsoUMnoD42TTBkR0aLhULcj1MYUcB9uVCmJTvYuiCTODoNlL8T40r9L99H +oHlTWVi9vf6I1vyNdHp3dXKBMVL13+i5BeNIjADr0KKs0jtEEicWyuVhJz3rPLzB +bPhz/DGQ/hTj/DRSdo9L9YA4WkqgD8uFUvIEKAJ/hXYx3QPEiIMU7hT4jk2Z2SIB +iKKiNW4E/20EZOFmaeNWQaqqmwX0cHtMygJtTYnEJ1IDAgMBAAE= +-----END PUBLIC KEY----- diff --git a/impl/src/test/resources/io/jsonwebtoken/impl/security/RS512.pkcs1.key.pem b/impl/src/test/resources/io/jsonwebtoken/impl/security/RS512.pkcs1.key.pem deleted file mode 120000 index 15d6f5c04..000000000 --- a/impl/src/test/resources/io/jsonwebtoken/impl/security/RS512.pkcs1.key.pem +++ /dev/null @@ -1 +0,0 @@ -rsa4096.pkcs1.key.pem \ No newline at end of file diff --git a/impl/src/test/resources/io/jsonwebtoken/impl/security/RS512.pkcs1.key.pem b/impl/src/test/resources/io/jsonwebtoken/impl/security/RS512.pkcs1.key.pem new file mode 100644 index 000000000..275d9a574 --- /dev/null +++ b/impl/src/test/resources/io/jsonwebtoken/impl/security/RS512.pkcs1.key.pem @@ -0,0 +1,67 @@ +# +# Copyright © 2022 jsonwebtoken.io +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +-----BEGIN RSA PRIVATE KEY----- +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 +-----END RSA PRIVATE KEY----- diff --git a/impl/src/test/resources/io/jsonwebtoken/impl/security/RS512.pub.pem b/impl/src/test/resources/io/jsonwebtoken/impl/security/RS512.pub.pem deleted file mode 120000 index 74c57d7fb..000000000 --- a/impl/src/test/resources/io/jsonwebtoken/impl/security/RS512.pub.pem +++ /dev/null @@ -1 +0,0 @@ -rsa4096.pub.pem \ No newline at end of file diff --git a/impl/src/test/resources/io/jsonwebtoken/impl/security/RS512.pub.pem b/impl/src/test/resources/io/jsonwebtoken/impl/security/RS512.pub.pem new file mode 100644 index 000000000..b86424f6c --- /dev/null +++ b/impl/src/test/resources/io/jsonwebtoken/impl/security/RS512.pub.pem @@ -0,0 +1,30 @@ +# +# Copyright © 2022 jsonwebtoken.io +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +-----BEGIN PUBLIC KEY----- +MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAw7jTXeRwCRrDdYnrIwcL +vSNfhpmJZ0ap1jzKVgUyCOYLTaB9+naJRjHqx7B5wgx/ArRF2nluQ5tawZPMFw2I +/iqXYrQEPTbq1XVugYC/C491bcXOTKx+DgEvnhNysm/KmzFsEcw78prB5sIAZSR+ +S5zZPuny4zww2UzE9TZ433RBkyA+wVkd64bgXdkMrVc+gsRsOtvwPFbQ89zg8d/p +NV0mDtjDsfiYw0pSAah11fJGa+aRc46CqFu/6rHuN4uq6542LdtshPbHz29VKHxk +8agtcx06+8F05Bg4LFm1rRhY0g3KsT7s8XHMVdo9h2bIQuWOaFg3mehpH6ZYBV4E +No98V/jDaUPpBHsaUXw4fG/wrnI+YwRjGlmp2QEr5VRfh0x8Addf6N64lmbQUpCP +hJweJd54D3JvIpJr8HiG3GYWeFsrmDzmhrozZHxE4P7UesW6lWwQzGfwYGXs7j6T +Ea2hZ8EB/t1jsYNjZ5UYY/JbKgFGSkMGje4Bi5Bv6kh4+pp3DT5QsG/AfLVlr5in +eLDWkJ15uZjOxl12EOPXOCWViVqS6rayJfb95YJQ52rT4H83BsApHbzFj7q/CIae +JkUdv9GJ2SOADcXdgG7Xk7tHqb1VIH4zRBo5mc0qN1cAwjopxHv2h3tGaTHKbptv +fiLulH+AvvuWmLMEQo6ZDlsCAwEAAQ== +-----END PUBLIC KEY----- diff --git a/impl/src/test/resources/io/jsonwebtoken/impl/security/rsa2048.crt.pem b/impl/src/test/resources/io/jsonwebtoken/impl/security/rsa2048.crt.pem deleted file mode 100644 index 45195339b..000000000 --- a/impl/src/test/resources/io/jsonwebtoken/impl/security/rsa2048.crt.pem +++ /dev/null @@ -1,36 +0,0 @@ -# -# Copyright © 2020 jsonwebtoken.io -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - ------BEGIN CERTIFICATE----- -MIIDRDCCAiwCCQCgd9OzR40NCDANBgkqhkiG9w0BAQsFADBjMQswCQYDVQQGEwJV -UzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzEY -MBYGA1UECgwPanNvbndlYnRva2VuLmlvMQ0wCwYDVQQLDARqand0MCAXDTIwMDIw -MzIzMDQzM1oYDzMwMjAwMjExMjMwNDMzWjBjMQswCQYDVQQGEwJVUzETMBEGA1UE -CAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzEYMBYGA1UECgwP -anNvbndlYnRva2VuLmlvMQ0wCwYDVQQLDARqand0MIIBIjANBgkqhkiG9w0BAQEF -AAOCAQ8AMIIBCgKCAQEAzkH0MwxQ2cUFWsvOPVFqI/dk2EFTjQolCy97mI5/wYCb -aOoZ9Rm7c675mAeemRtNzgNVEz7m298ENqNGqPk2Nv3pBJ/XCaybBlp61CLez7dQ -2h5jUFEJ6FJcjeKHS+MwXr56t2ISdfLNMYtVIxjvXQcYx5VmS4mIqTxj5gVGtQVi -0GXdH6SvpdKV0fjE9KOhjsdBfKQzZfcQlusHg8pThwvjpMwCZnkxCS0RKa9y4+5+ -7MkC33+8+neZUzS7b6NdFxh6T/pMXpkf8d81fzVo4ZBMloweW0/l8MOdVxeX7M/7 -XSC1ank5i3IEZcotLmJYMwEo7rMpZVLevEQ118Eo8QIDAQABMA0GCSqGSIb3DQEB -CwUAA4IBAQBGbfmJumXEHMLko1ioY/eY5EYgrBRJAuuAMGqBZmK+1Iy2CqB90aEh -ve+jXjIBsrvXRuLxMdlzoP58Ia9C5M+78Vq0bEjuGJu3zxGev11Gt4E3V6bWfT7G -fhg66dbmjnqkhgSzpDzfYR7HHOQiDAGe5IH5FbvWehRzENoAODHHP1z3NdoGhsl9 -4DIjOTGYdhW0yUTSjGTWygo6OPU2L4M2k0gTA06FkvdLIS450GWRpgoVO/vfcPnO -h8KwZcWVwJVmG0Hv0fNhQk/tRuhYhCWGxc7gxkbLb7/xPpPKMD6EvgG0BSm27NxO -H5l3KYwtbdj5nYHU73cLqC1D6ki6F8+h ------END CERTIFICATE----- diff --git a/impl/src/test/resources/io/jsonwebtoken/impl/security/rsa2048.key.pem b/impl/src/test/resources/io/jsonwebtoken/impl/security/rsa2048.key.pem deleted file mode 100644 index 61088c2ff..000000000 --- a/impl/src/test/resources/io/jsonwebtoken/impl/security/rsa2048.key.pem +++ /dev/null @@ -1,44 +0,0 @@ -# -# Copyright © 2020 jsonwebtoken.io -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - ------BEGIN PRIVATE KEY----- -MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDOQfQzDFDZxQVa -y849UWoj92TYQVONCiULL3uYjn/BgJto6hn1GbtzrvmYB56ZG03OA1UTPubb3wQ2 -o0ao+TY2/ekEn9cJrJsGWnrUIt7Pt1DaHmNQUQnoUlyN4odL4zBevnq3YhJ18s0x -i1UjGO9dBxjHlWZLiYipPGPmBUa1BWLQZd0fpK+l0pXR+MT0o6GOx0F8pDNl9xCW -6weDylOHC+OkzAJmeTEJLREpr3Lj7n7syQLff7z6d5lTNLtvo10XGHpP+kxemR/x -3zV/NWjhkEyWjB5bT+Xww51XF5fsz/tdILVqeTmLcgRlyi0uYlgzASjusyllUt68 -RDXXwSjxAgMBAAECggEAZ90ahaJMDH2ERsaeoo4e7uGjrKqo0jsrkEhm6tnHR7/l -gp1wWNaOaKDSG1aq7NqtAXL4Imroggv56TGrYWetf1+5OZTsCnkaz8Y8WBr/LIZZ -dp0a0dUdMhpXdTN/gh1zvCIbVcFTHoYYAjzxsGzcDHKIbeizzJIDeYVpoOlDQ9/9 -Bv6ft4mhaG5SHVnec9QdmbJnKDq5rI4aPXCCXOCzDjdTVfgntdH5TvoCH91ESSKw -kddciAbVsXoOWnBx3jKMj+hIA4F1p6nzZUbiVzmxhqfShQhDnCEvq8tF7KqRbUsS -Gx8MVtwSkEGaiJCDVjwSRGkghXlguNwZcfnWMtGMYQKBgQDmFWAApeXv4xXF2a/1 -HKumO5Z+w+XkKiM76YyTHTKO/KtDYRJiIlJMgx+hoRTBwlpYDrlbS9+Jnm7bZ9Ib -pxRyMAFRoV7eIhnoAn9KrxhS8xCYF2Km7U1lg/+m3pFKghjV4+K1GHbggmvoiIY1 -2t250zkZSslwTxu/2+jRKYOptQKBgQDlfYrzvuGqClJ9QClxlOV2UrWiGxq6eTgL -4V3l0HwPU9OW/hX0Hued8S70Dpb3o+AAyptbcAqFjSdyIPMbCfKLQQkKpfBUtOvb -Nm12z/VNKNZbu7kvaOJHunQNHzyMEHcjsB9daAVI0gJZKN+m6Qh4VF4jao7G9GNR -d7ge0KcXzQKBgQCqf8p9kHJ9OsVmsTMgK1fTvrJ+S8LvOn6TpjVCy08tAHYVXzjV -OePMyRpGluyfzNtQB9E5o1cKTzqNIjljvoN7PrGrgS6g45pZAIi9mlUnGvIAEsxL -MOy6vn9Tc/kswo2O6umUE4X8RwmZ7pmuDPtj+e+FG5N8w1Kn8VlsrhvgRQKBgAgz -clG/koTnFYeQUWrTrVeLIR6H5W6gglY6WYaq6qQJlNgigFpW+GP2iH0EQHTdEFY2 -51JfMKERKEW107o1ostDKbWNtIbyaDNPQJ4sVFHLkc15aea90shJa3hEk39V30wR -MS2/V+EAUEErasKmNT1Hlo2hczS86wewRY4kWrRJAoGAeYUG04cu55GwCgp50P3J -0NCNyiOkhnaj0wGPztMbDqNkaUAoaycoEsas5lhRAWT4YIVglz5pwR4uiI57w1cL -Mvjk5yDiQs7h3bV/qtm95YPBBC+y3mmZYlEA1lH0qktRNBlMVtfYkPztBh50UBOH -8qhIwqrpm3+JJ1p2p0XPl1c= ------END PRIVATE KEY----- diff --git a/impl/src/test/resources/io/jsonwebtoken/impl/security/rsa2048.pkcs1.key.pem b/impl/src/test/resources/io/jsonwebtoken/impl/security/rsa2048.pkcs1.key.pem deleted file mode 100644 index 9e995d1b0..000000000 --- a/impl/src/test/resources/io/jsonwebtoken/impl/security/rsa2048.pkcs1.key.pem +++ /dev/null @@ -1,43 +0,0 @@ -# -# Copyright © 2022 jsonwebtoken.io -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - ------BEGIN RSA PRIVATE KEY----- -MIIEowIBAAKCAQEAzkH0MwxQ2cUFWsvOPVFqI/dk2EFTjQolCy97mI5/wYCbaOoZ -9Rm7c675mAeemRtNzgNVEz7m298ENqNGqPk2Nv3pBJ/XCaybBlp61CLez7dQ2h5j -UFEJ6FJcjeKHS+MwXr56t2ISdfLNMYtVIxjvXQcYx5VmS4mIqTxj5gVGtQVi0GXd -H6SvpdKV0fjE9KOhjsdBfKQzZfcQlusHg8pThwvjpMwCZnkxCS0RKa9y4+5+7MkC -33+8+neZUzS7b6NdFxh6T/pMXpkf8d81fzVo4ZBMloweW0/l8MOdVxeX7M/7XSC1 -ank5i3IEZcotLmJYMwEo7rMpZVLevEQ118Eo8QIDAQABAoIBAGfdGoWiTAx9hEbG -nqKOHu7ho6yqqNI7K5BIZurZx0e/5YKdcFjWjmig0htWquzarQFy+CJq6IIL+ekx -q2FnrX9fuTmU7Ap5Gs/GPFga/yyGWXadGtHVHTIaV3Uzf4Idc7wiG1XBUx6GGAI8 -8bBs3AxyiG3os8ySA3mFaaDpQ0Pf/Qb+n7eJoWhuUh1Z3nPUHZmyZyg6uayOGj1w -glzgsw43U1X4J7XR+U76Ah/dREkisJHXXIgG1bF6Dlpwcd4yjI/oSAOBdaep82VG -4lc5sYan0oUIQ5whL6vLReyqkW1LEhsfDFbcEpBBmoiQg1Y8EkRpIIV5YLjcGXH5 -1jLRjGECgYEA5hVgAKXl7+MVxdmv9RyrpjuWfsPl5CojO+mMkx0yjvyrQ2ESYiJS -TIMfoaEUwcJaWA65W0vfiZ5u22fSG6cUcjABUaFe3iIZ6AJ/Sq8YUvMQmBdipu1N -ZYP/pt6RSoIY1ePitRh24IJr6IiGNdrdudM5GUrJcE8bv9vo0SmDqbUCgYEA5X2K -877hqgpSfUApcZTldlK1ohsaunk4C+Fd5dB8D1PTlv4V9B7nnfEu9A6W96PgAMqb -W3AKhY0nciDzGwnyi0EJCqXwVLTr2zZtds/1TSjWW7u5L2jiR7p0DR88jBB3I7Af -XWgFSNICWSjfpukIeFReI2qOxvRjUXe4HtCnF80CgYEAqn/KfZByfTrFZrEzICtX -076yfkvC7zp+k6Y1QstPLQB2FV841TnjzMkaRpbsn8zbUAfROaNXCk86jSI5Y76D -ez6xq4EuoOOaWQCIvZpVJxryABLMSzDsur5/U3P5LMKNjurplBOF/EcJme6Zrgz7 -Y/nvhRuTfMNSp/FZbK4b4EUCgYAIM3JRv5KE5xWHkFFq061XiyEeh+VuoIJWOlmG -quqkCZTYIoBaVvhj9oh9BEB03RBWNudSXzChEShFtdO6NaLLQym1jbSG8mgzT0Ce -LFRRy5HNeWnmvdLISWt4RJN/Vd9METEtv1fhAFBBK2rCpjU9R5aNoXM0vOsHsEWO -JFq0SQKBgHmFBtOHLueRsAoKedD9ydDQjcojpIZ2o9MBj87TGw6jZGlAKGsnKBLG -rOZYUQFk+GCFYJc+acEeLoiOe8NXCzL45Ocg4kLO4d21f6rZveWDwQQvst5pmWJR -ANZR9KpLUTQZTFbX2JD87QYedFATh/KoSMKq6Zt/iSdadqdFz5dX ------END RSA PRIVATE KEY----- diff --git a/impl/src/test/resources/io/jsonwebtoken/impl/security/rsa2048.pub.pem b/impl/src/test/resources/io/jsonwebtoken/impl/security/rsa2048.pub.pem deleted file mode 100644 index 88c76f3e4..000000000 --- a/impl/src/test/resources/io/jsonwebtoken/impl/security/rsa2048.pub.pem +++ /dev/null @@ -1,25 +0,0 @@ -# -# Copyright © 2022 jsonwebtoken.io -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - ------BEGIN PUBLIC KEY----- -MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzkH0MwxQ2cUFWsvOPVFq -I/dk2EFTjQolCy97mI5/wYCbaOoZ9Rm7c675mAeemRtNzgNVEz7m298ENqNGqPk2 -Nv3pBJ/XCaybBlp61CLez7dQ2h5jUFEJ6FJcjeKHS+MwXr56t2ISdfLNMYtVIxjv -XQcYx5VmS4mIqTxj5gVGtQVi0GXdH6SvpdKV0fjE9KOhjsdBfKQzZfcQlusHg8pT -hwvjpMwCZnkxCS0RKa9y4+5+7MkC33+8+neZUzS7b6NdFxh6T/pMXpkf8d81fzVo -4ZBMloweW0/l8MOdVxeX7M/7XSC1ank5i3IEZcotLmJYMwEo7rMpZVLevEQ118Eo -8QIDAQAB ------END PUBLIC KEY----- diff --git a/impl/src/test/resources/io/jsonwebtoken/impl/security/rsa3072.crt.pem b/impl/src/test/resources/io/jsonwebtoken/impl/security/rsa3072.crt.pem deleted file mode 100644 index 9f6e42e37..000000000 --- a/impl/src/test/resources/io/jsonwebtoken/impl/security/rsa3072.crt.pem +++ /dev/null @@ -1,41 +0,0 @@ -# -# Copyright © 2020 jsonwebtoken.io -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - ------BEGIN CERTIFICATE----- -MIIERDCCAqwCCQDqxucO41yAmTANBgkqhkiG9w0BAQsFADBjMQswCQYDVQQGEwJV -UzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzEY -MBYGA1UECgwPanNvbndlYnRva2VuLmlvMQ0wCwYDVQQLDARqand0MCAXDTIwMDIw -MzIzMDQ1OFoYDzMwMjAwMjExMjMwNDU4WjBjMQswCQYDVQQGEwJVUzETMBEGA1UE -CAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzEYMBYGA1UECgwP -anNvbndlYnRva2VuLmlvMQ0wCwYDVQQLDARqand0MIIBojANBgkqhkiG9w0BAQEF -AAOCAY8AMIIBigKCAYEA0DmQS4Xtgu5xtnQdxkuzB1j+W4OvNEOVOsg3Zcn9W1d5 -NowtngUh9K9vwBpl59M2j5PHj9dseEIuRqr++ZnZhBMlh/lLiIQ0oQ3cEa7wrwJO -i9ycZZbeNDHVNzAdQZEQR1DIMUhSTEMR96pVD4a9DzBKLQJaKxZRUOrMhf3QhAZ5 -9m0d/Kqu1Dm6YeWMLQQEewAaSQ9g22gty1EcLAvp/vnhR/DJSYIHCayd5mZwvk9q -WkXySfUmJGP70GFGG4GOnVLLkmCQgfT+OrzTtiIzNT26mtAsoUMnoD42TTBkR0aL -hULcj1MYUcB9uVCmJTvYuiCTODoNlL8T40r9L99HoHlTWVi9vf6I1vyNdHp3dXKB -MVL13+i5BeNIjADr0KKs0jtEEicWyuVhJz3rPLzBbPhz/DGQ/hTj/DRSdo9L9YA4 -WkqgD8uFUvIEKAJ/hXYx3QPEiIMU7hT4jk2Z2SIBiKKiNW4E/20EZOFmaeNWQaqq -mwX0cHtMygJtTYnEJ1IDAgMBAAEwDQYJKoZIhvcNAQELBQADggGBAGKkmv6d372z -Ujt1qjsjH7LHfIsPXdvnp7OhvujDEtY7dzwDCtR40zgB2qp+iXUO61FXErx8yDp9 -l7sDzk0AjY7RupANuo/3FyDuo0WoTUV3CJNnXf3Mrvu/DMjbaS6D4Jryz/HLE+2r -GYtdm165FZK/hQXuFfurkc4yqjrX90Wr+YHeen2y5Wk3jeUknmdp97F6+zkq6N5D -dKjy/ZOvy+1huNd5bzvJoiZLKqdSh/RQUoU6AP1p+83lo+7cPvS/zm/HvwxwMamA -1Cip1FypNxUxt5HR4bC5LwEvMTZ/+UTEelbyfjMdYU97aa58nPoMxf7DRBbr0tfj -GItI+mMoAw60eIaDbTncXvO1LVrFF5BfzVOTQ8ioPRwI7A5LMSC5JvxW8KsW2VX0 -vGwRbw8I6HXGRbBZ3zwmAK73q7go31+Dl/5VPFo+fVTL0P7/k/g0ZAtCu4/Wly9e -DLnYMoZbIF5lgp9cAzPOaWXiInsA6HSdgFUfXsBemRpholuw+Sacxg== ------END CERTIFICATE----- diff --git a/impl/src/test/resources/io/jsonwebtoken/impl/security/rsa3072.key.pem b/impl/src/test/resources/io/jsonwebtoken/impl/security/rsa3072.key.pem deleted file mode 100644 index 4fd9098bf..000000000 --- a/impl/src/test/resources/io/jsonwebtoken/impl/security/rsa3072.key.pem +++ /dev/null @@ -1,56 +0,0 @@ -# -# Copyright © 2020 jsonwebtoken.io -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - ------BEGIN PRIVATE KEY----- -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 -5I2wbxUhb3FO7gj9pxJbwX4= ------END PRIVATE KEY----- diff --git a/impl/src/test/resources/io/jsonwebtoken/impl/security/rsa3072.pkcs1.key.pem b/impl/src/test/resources/io/jsonwebtoken/impl/security/rsa3072.pkcs1.key.pem deleted file mode 100644 index 4be97fc37..000000000 --- a/impl/src/test/resources/io/jsonwebtoken/impl/security/rsa3072.pkcs1.key.pem +++ /dev/null @@ -1,55 +0,0 @@ -# -# Copyright © 2022 jsonwebtoken.io -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - ------BEGIN RSA PRIVATE KEY----- -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 ------END RSA PRIVATE KEY----- diff --git a/impl/src/test/resources/io/jsonwebtoken/impl/security/rsa3072.pub.pem b/impl/src/test/resources/io/jsonwebtoken/impl/security/rsa3072.pub.pem deleted file mode 100644 index 3ab8814a3..000000000 --- a/impl/src/test/resources/io/jsonwebtoken/impl/security/rsa3072.pub.pem +++ /dev/null @@ -1,27 +0,0 @@ -# -# Copyright © 2022 jsonwebtoken.io -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - ------BEGIN PUBLIC KEY----- -MIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEA0DmQS4Xtgu5xtnQdxkuz -B1j+W4OvNEOVOsg3Zcn9W1d5NowtngUh9K9vwBpl59M2j5PHj9dseEIuRqr++ZnZ -hBMlh/lLiIQ0oQ3cEa7wrwJOi9ycZZbeNDHVNzAdQZEQR1DIMUhSTEMR96pVD4a9 -DzBKLQJaKxZRUOrMhf3QhAZ59m0d/Kqu1Dm6YeWMLQQEewAaSQ9g22gty1EcLAvp -/vnhR/DJSYIHCayd5mZwvk9qWkXySfUmJGP70GFGG4GOnVLLkmCQgfT+OrzTtiIz -NT26mtAsoUMnoD42TTBkR0aLhULcj1MYUcB9uVCmJTvYuiCTODoNlL8T40r9L99H -oHlTWVi9vf6I1vyNdHp3dXKBMVL13+i5BeNIjADr0KKs0jtEEicWyuVhJz3rPLzB -bPhz/DGQ/hTj/DRSdo9L9YA4WkqgD8uFUvIEKAJ/hXYx3QPEiIMU7hT4jk2Z2SIB -iKKiNW4E/20EZOFmaeNWQaqqmwX0cHtMygJtTYnEJ1IDAgMBAAE= ------END PUBLIC KEY----- diff --git a/impl/src/test/resources/io/jsonwebtoken/impl/security/rsa4096.crt.pem b/impl/src/test/resources/io/jsonwebtoken/impl/security/rsa4096.crt.pem deleted file mode 100644 index 55a08c370..000000000 --- a/impl/src/test/resources/io/jsonwebtoken/impl/security/rsa4096.crt.pem +++ /dev/null @@ -1,47 +0,0 @@ -# -# Copyright © 2020 jsonwebtoken.io -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - ------BEGIN CERTIFICATE----- -MIIFRDCCAywCCQC4g2isVGolKjANBgkqhkiG9w0BAQsFADBjMQswCQYDVQQGEwJV -UzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzEY -MBYGA1UECgwPanNvbndlYnRva2VuLmlvMQ0wCwYDVQQLDARqand0MCAXDTIwMDIw -MzIzMDY1MloYDzMwMjAwMjExMjMwNjUyWjBjMQswCQYDVQQGEwJVUzETMBEGA1UE -CAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzEYMBYGA1UECgwP -anNvbndlYnRva2VuLmlvMQ0wCwYDVQQLDARqand0MIICIjANBgkqhkiG9w0BAQEF -AAOCAg8AMIICCgKCAgEAw7jTXeRwCRrDdYnrIwcLvSNfhpmJZ0ap1jzKVgUyCOYL -TaB9+naJRjHqx7B5wgx/ArRF2nluQ5tawZPMFw2I/iqXYrQEPTbq1XVugYC/C491 -bcXOTKx+DgEvnhNysm/KmzFsEcw78prB5sIAZSR+S5zZPuny4zww2UzE9TZ433RB -kyA+wVkd64bgXdkMrVc+gsRsOtvwPFbQ89zg8d/pNV0mDtjDsfiYw0pSAah11fJG -a+aRc46CqFu/6rHuN4uq6542LdtshPbHz29VKHxk8agtcx06+8F05Bg4LFm1rRhY -0g3KsT7s8XHMVdo9h2bIQuWOaFg3mehpH6ZYBV4ENo98V/jDaUPpBHsaUXw4fG/w -rnI+YwRjGlmp2QEr5VRfh0x8Addf6N64lmbQUpCPhJweJd54D3JvIpJr8HiG3GYW -eFsrmDzmhrozZHxE4P7UesW6lWwQzGfwYGXs7j6TEa2hZ8EB/t1jsYNjZ5UYY/Jb -KgFGSkMGje4Bi5Bv6kh4+pp3DT5QsG/AfLVlr5ineLDWkJ15uZjOxl12EOPXOCWV -iVqS6rayJfb95YJQ52rT4H83BsApHbzFj7q/CIaeJkUdv9GJ2SOADcXdgG7Xk7tH -qb1VIH4zRBo5mc0qN1cAwjopxHv2h3tGaTHKbptvfiLulH+AvvuWmLMEQo6ZDlsC -AwEAATANBgkqhkiG9w0BAQsFAAOCAgEApnHjMQwt5hm6UlEDvdWCYbh7ctkLbgwR -iBP1lvunm2oF0jGpipt8oDR/TT43usb6ieuU+ABksjxOROeoVZbK8bEpnzeo3nNE -41ERI3Byjp7tsja8QGG0uBk9QZ0+7MhJqhEDVAIbS0Lf4exkWiLZrW7ogAEFYKTN -DE6CxOcfR/kXj6ejuCnvN4xYqnw8G/OF/3tnHMfKnnnqtMmWdAKd3Y5S1EJZ5vtp -lZ3I9HA5Hx0sTH1ruCOIRzaC5En1c6zW1HjxmeAqLeG814gezlEhHzb4SCkabgQh -Bq15O8eQaW92f8xZoUQN25w7SNYszk9AdhroJz3+BOzG3+Y1EInLk5hDHT8oUNFz -e8EosJEwJDK3wq9YOhn8PUT/DacyNKONJVNly3fTBXoSR3oReW61p6T19z4AYsY9 -qMwSjIL2UcgAF8Kpsx2NdQrDfdveNMhul7AjIgz+e2DtRqCkZ6ypdhht2pmlpiXO -TiUG/1OBq2yTeJF9LjAUzsSNnsZ/F8pJbwSpr7VqDmTNGTfrh6x1ojHNFjJeTqK8 -MCTmQtJJTAbV4nuB+thFFWDx0IWvbG7ViYds9sdJNO4L3baXeAioJhHs5buBy3eb -ZWjLAwHpSCqNY3d6+ouGLwE1YVFsk8sV9UM+gl15VynKkunbYoKhiD82HGASNYtE -33eif1l5Nk0= ------END CERTIFICATE----- diff --git a/impl/src/test/resources/io/jsonwebtoken/impl/security/rsa4096.key.pem b/impl/src/test/resources/io/jsonwebtoken/impl/security/rsa4096.key.pem deleted file mode 100644 index cb8296b23..000000000 --- a/impl/src/test/resources/io/jsonwebtoken/impl/security/rsa4096.key.pem +++ /dev/null @@ -1,68 +0,0 @@ -# -# Copyright © 2020 jsonwebtoken.io -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - ------BEGIN PRIVATE KEY----- -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 -lczRTJNTE/KNUE0pkC5P4c/e0A1OFu0= ------END PRIVATE KEY----- diff --git a/impl/src/test/resources/io/jsonwebtoken/impl/security/rsa4096.pkcs1.key.pem b/impl/src/test/resources/io/jsonwebtoken/impl/security/rsa4096.pkcs1.key.pem deleted file mode 100644 index 275d9a574..000000000 --- a/impl/src/test/resources/io/jsonwebtoken/impl/security/rsa4096.pkcs1.key.pem +++ /dev/null @@ -1,67 +0,0 @@ -# -# Copyright © 2022 jsonwebtoken.io -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - ------BEGIN RSA PRIVATE KEY----- -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 ------END RSA PRIVATE KEY----- diff --git a/impl/src/test/resources/io/jsonwebtoken/impl/security/rsa4096.pub.pem b/impl/src/test/resources/io/jsonwebtoken/impl/security/rsa4096.pub.pem deleted file mode 100644 index b86424f6c..000000000 --- a/impl/src/test/resources/io/jsonwebtoken/impl/security/rsa4096.pub.pem +++ /dev/null @@ -1,30 +0,0 @@ -# -# Copyright © 2022 jsonwebtoken.io -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - ------BEGIN PUBLIC KEY----- -MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAw7jTXeRwCRrDdYnrIwcL -vSNfhpmJZ0ap1jzKVgUyCOYLTaB9+naJRjHqx7B5wgx/ArRF2nluQ5tawZPMFw2I -/iqXYrQEPTbq1XVugYC/C491bcXOTKx+DgEvnhNysm/KmzFsEcw78prB5sIAZSR+ -S5zZPuny4zww2UzE9TZ433RBkyA+wVkd64bgXdkMrVc+gsRsOtvwPFbQ89zg8d/p -NV0mDtjDsfiYw0pSAah11fJGa+aRc46CqFu/6rHuN4uq6542LdtshPbHz29VKHxk -8agtcx06+8F05Bg4LFm1rRhY0g3KsT7s8XHMVdo9h2bIQuWOaFg3mehpH6ZYBV4E -No98V/jDaUPpBHsaUXw4fG/wrnI+YwRjGlmp2QEr5VRfh0x8Addf6N64lmbQUpCP -hJweJd54D3JvIpJr8HiG3GYWeFsrmDzmhrozZHxE4P7UesW6lWwQzGfwYGXs7j6T -Ea2hZ8EB/t1jsYNjZ5UYY/JbKgFGSkMGje4Bi5Bv6kh4+pp3DT5QsG/AfLVlr5in -eLDWkJ15uZjOxl12EOPXOCWViVqS6rayJfb95YJQ52rT4H83BsApHbzFj7q/CIae -JkUdv9GJ2SOADcXdgG7Xk7tHqb1VIH4zRBo5mc0qN1cAwjopxHv2h3tGaTHKbptv -fiLulH+AvvuWmLMEQo6ZDlsCAwEAAQ== ------END PUBLIC KEY----- diff --git a/tdjar/src/test/java/io/jsonwebtoken/all/JavaReadmeTest.java b/tdjar/src/test/java/io/jsonwebtoken/all/JavaReadmeTest.java index b846d1252..5a98db96a 100644 --- a/tdjar/src/test/java/io/jsonwebtoken/all/JavaReadmeTest.java +++ b/tdjar/src/test/java/io/jsonwebtoken/all/JavaReadmeTest.java @@ -352,7 +352,7 @@ public void testExampleEcPrivateJwk() { @SuppressWarnings({"unchecked", "rawtypes"}) @Test public void testExampleEdEcPublicJwk() { - PublicKey key = Jwts.SIG.Ed25519.keyPair().build().getPublic(); + PublicKey key = Jwks.CRV.Ed25519.keyPair().build().getPublic(); OctetPublicJwk jwk = builder().octetKey(key).idFromThumbprint().build(); assert jwk.getId().equals(jwk.thumbprint().toString()); @@ -369,7 +369,7 @@ public void testExampleEdEcPublicJwk() { @SuppressWarnings({"unchecked", "rawtypes"}) @Test public void testExampleEdEcPrivateJwk() { - KeyPair pair = Jwts.SIG.Ed448.keyPair().build(); + KeyPair pair = Jwks.CRV.Ed448.keyPair().build(); PublicKey pubKey = pair.getPublic(); PrivateKey privKey = pair.getPrivate();