mirror of https://github.com/jwtk/jjwt.git
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+)
This commit is contained in:
parent
c142fb5c7a
commit
620cc5d97f
|
@ -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
|
* `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.
|
ago have been removed. All parser configuration requires using the `JwtParserBuilder`.
|
||||||
`Jwts.parser()`).
|
|
||||||
|
|
||||||
|
|
||||||
* Similarly, `io.jsonwebtoken.Jwts`'s `parser()` method deprecated 4 years ago has been changed to now return a
|
* 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.
|
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
|
* `io.jsonwebtoken.CompressionCodec` implementations are no longer discoverable via `java.util.ServiceLoader` due to
|
||||||
runtime performance problems with the JDK's `ServiceLoader` implementation per
|
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
|
https://github.com/jwtk/jjwt/issues/648. Custom implementations should be made available to the `JwtParser` via
|
||||||
|
|
|
@ -3477,7 +3477,7 @@ Example creating and parsing an Edwards Elliptic Curve (Ed25519, Ed448, X25519,
|
||||||
`OctetPublicJwk` interface names):
|
`OctetPublicJwk` interface names):
|
||||||
|
|
||||||
```java
|
```java
|
||||||
PublicKey key = Jwts.SIG.Ed25519.keyPair().build().getPublic();
|
PublicKey key = Jwks.CRV.Ed25519.keyPair().build().getPublic();
|
||||||
OctetPublicJwk<PublicKey> jwk = builder().octetKey(key).idFromThumbprint().build();
|
OctetPublicJwk<PublicKey> jwk = builder().octetKey(key).idFromThumbprint().build();
|
||||||
|
|
||||||
assert jwk.getId().equals(jwk.thumbprint().toString());
|
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):
|
`OctetPrivateJwk` and `OctetPublicJwk` interface names):
|
||||||
|
|
||||||
```java
|
```java
|
||||||
KeyPair pair = Jwts.SIG.Ed448.keyPair().build();
|
KeyPair pair = Jwks.CRV.Ed448.keyPair().build();
|
||||||
PublicKey pubKey = pair.getPublic();
|
PublicKey pubKey = pair.getPublic();
|
||||||
PrivateKey privKey = pair.getPrivate();
|
PrivateKey privKey = pair.getPrivate();
|
||||||
|
|
||||||
|
|
|
@ -40,6 +40,11 @@ package io.jsonwebtoken;
|
||||||
* parameter value.</td>
|
* parameter value.</td>
|
||||||
* </tr>
|
* </tr>
|
||||||
* <tr>
|
* <tr>
|
||||||
|
* <td>{@link io.jsonwebtoken.security.Curve Curve}</td>
|
||||||
|
* <td>JWK's <a href="https://www.rfc-editor.org/rfc/rfc7518.html#section-6.2.1.1">{@code crv} (Curve)</a>
|
||||||
|
* parameter value.</td>
|
||||||
|
* </tr>
|
||||||
|
* <tr>
|
||||||
* <td>{@link io.jsonwebtoken.io.CompressionAlgorithm CompressionAlgorithm}</td>
|
* <td>{@link io.jsonwebtoken.io.CompressionAlgorithm CompressionAlgorithm}</td>
|
||||||
* <td>JWE protected header's
|
* <td>JWE protected header's
|
||||||
* <a href="https://www.rfc-editor.org/rfc/rfc7516.html#section-4.1.3">{@code zip} (Compression Algorithm)</a>
|
* <a href="https://www.rfc-editor.org/rfc/rfc7516.html#section-4.1.3">{@code zip} (Compression Algorithm)</a>
|
||||||
|
|
|
@ -527,14 +527,8 @@ public interface JwtBuilder extends ClaimsMutator<JwtBuilder> {
|
||||||
* <tr>
|
* <tr>
|
||||||
* <td><a href="https://docs.oracle.com/en/java/javase/15/docs/api/java.base/java/security/interfaces/EdECKey.html">EdECKey</a><sup>7</sup></td>
|
* <td><a href="https://docs.oracle.com/en/java/javase/15/docs/api/java.base/java/security/interfaces/EdECKey.html">EdECKey</a><sup>7</sup></td>
|
||||||
* <td><code>instanceof {@link PrivateKey}</code></td>
|
* <td><code>instanceof {@link PrivateKey}</code></td>
|
||||||
* <td>256</td>
|
* <td>256 || 456</td>
|
||||||
* <td>{@link Jwts.SIG#Ed25519 Ed25519}</td>
|
* <td>{@link Jwts.SIG#EdDSA EdDSA}</td>
|
||||||
* </tr>
|
|
||||||
* <tr>
|
|
||||||
* <td><a href="https://docs.oracle.com/en/java/javase/15/docs/api/java.base/java/security/interfaces/EdECKey.html">EdECKey</a><sup>7</sup></td>
|
|
||||||
* <td><code>instanceof {@link PrivateKey}</code></td>
|
|
||||||
* <td>456</td>
|
|
||||||
* <td>{@link Jwts.SIG#Ed448 Ed448}</td>
|
|
||||||
* </tr>
|
* </tr>
|
||||||
* </tbody>
|
* </tbody>
|
||||||
* </table>
|
* </table>
|
||||||
|
|
|
@ -328,7 +328,7 @@ public interface JwtParserBuilder extends Builder<JwtParser> {
|
||||||
* {@link #verifyWith(SecretKey)} for type safety, to reflect accurate naming of the concept, and for name
|
* {@link #verifyWith(SecretKey)} for type safety, to reflect accurate naming of the concept, and for name
|
||||||
* congruence with the {@link #decryptWith(SecretKey)} method.</p>
|
* congruence with the {@link #decryptWith(SecretKey)} method.</p>
|
||||||
*
|
*
|
||||||
* <p>This method merely delegates directly to {@link #verifyWith(SecretKey)}.</p>
|
* <p>This method merely delegates directly to {@link #verifyWith(SecretKey) or {@link #verifyWith(PublicKey)}}.</p>
|
||||||
*
|
*
|
||||||
* @param key the algorithm-specific signature verification key to use to verify all encountered JWS digital
|
* @param key the algorithm-specific signature verification key to use to verify all encountered JWS digital
|
||||||
* signatures.
|
* signatures.
|
||||||
|
|
|
@ -21,6 +21,7 @@ import io.jsonwebtoken.lang.Classes;
|
||||||
import io.jsonwebtoken.lang.Registry;
|
import io.jsonwebtoken.lang.Registry;
|
||||||
import io.jsonwebtoken.security.AeadAlgorithm;
|
import io.jsonwebtoken.security.AeadAlgorithm;
|
||||||
import io.jsonwebtoken.security.KeyAlgorithm;
|
import io.jsonwebtoken.security.KeyAlgorithm;
|
||||||
|
import io.jsonwebtoken.security.KeyPairBuilderSupplier;
|
||||||
import io.jsonwebtoken.security.MacAlgorithm;
|
import io.jsonwebtoken.security.MacAlgorithm;
|
||||||
import io.jsonwebtoken.security.Password;
|
import io.jsonwebtoken.security.Password;
|
||||||
import io.jsonwebtoken.security.SecretKeyAlgorithm;
|
import io.jsonwebtoken.security.SecretKeyAlgorithm;
|
||||||
|
@ -293,33 +294,25 @@ public final class Jwts {
|
||||||
public static final SignatureAlgorithm ES512 = Jwts.get(REGISTRY, "ES512");
|
public static final SignatureAlgorithm ES512 = Jwts.get(REGISTRY, "ES512");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@code EdDSA} signature algorithm as defined by
|
* {@code EdDSA} signature algorithm defined by
|
||||||
* <a href="https://www.rfc-editor.org/rfc/rfc8037#section-3.1">RFC 8037, Section 3.1</a>. This algorithm
|
* <a href="https://www.rfc-editor.org/rfc/rfc8037#section-3.1">RFC 8037, Section 3.1</a> that requires
|
||||||
* requires either {@code Ed25519} or {@code Ed448} Edwards Curve keys.
|
* either {@code Ed25519} or {@code Ed448} Edwards Elliptic Curve<sup><b>1</b></sup> keys.
|
||||||
* <p><b>This algorithm requires at least JDK 15 or a compatible JCA Provider (like BouncyCastle) in the runtime
|
*
|
||||||
|
* <p><b>KeyPair Generation</b></p>
|
||||||
|
*
|
||||||
|
* <p>This instance's {@link KeyPairBuilderSupplier#keyPair() keyPair()} builder creates {@code Ed448} keys,
|
||||||
|
* and is essentially an alias for
|
||||||
|
* <code>{@link io.jsonwebtoken.security.Jwks.CRV Jwks.CRV}.{@link io.jsonwebtoken.security.Jwks.CRV#Ed448 Ed448}.{@link KeyPairBuilderSupplier#keyPair() keyPair()}</code>.</p>
|
||||||
|
*
|
||||||
|
* <p>If you would like to generate an {@code Ed25519} {@code KeyPair} for use with the {@code EdDSA} algorithm,
|
||||||
|
* you may use the
|
||||||
|
* <code>{@link io.jsonwebtoken.security.Jwks.CRV Jwks.CRV}.{@link io.jsonwebtoken.security.Jwks.CRV#Ed25519 Ed25519}.{@link KeyPairBuilderSupplier#keyPair() keyPair()}</code>
|
||||||
|
* builder instead.</p>
|
||||||
|
*
|
||||||
|
* <p><b><sup>1</sup>This algorithm requires at least JDK 15 or a compatible JCA Provider (like BouncyCastle) in the runtime
|
||||||
* classpath.</b></p>
|
* classpath.</b></p>
|
||||||
*/
|
*/
|
||||||
public static final SignatureAlgorithm EdDSA = Jwts.get(REGISTRY, "EdDSA");
|
public static final SignatureAlgorithm EdDSA = Jwts.get(REGISTRY, "EdDSA");
|
||||||
|
|
||||||
/**
|
|
||||||
* {@code EdDSA} signature algorithm using Curve {@code Ed25519} as defined by
|
|
||||||
* <a href="https://www.rfc-editor.org/rfc/rfc8037#section-3.1">RFC 8037, Section 3.1</a>. This algorithm
|
|
||||||
* requires {@code Ed25519} Edwards Curve keys to create signatures. <b>This is a convenience alias for
|
|
||||||
* {@link #EdDSA}</b> that defaults key generation to {@code Ed25519} keys.
|
|
||||||
* <p><b>This algorithm requires at least JDK 15 or a compatible JCA Provider (like BouncyCastle) in the runtime
|
|
||||||
* classpath.</b></p>
|
|
||||||
*/
|
|
||||||
public static final SignatureAlgorithm Ed25519 = Jwts.get(REGISTRY, "Ed25519");
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@code EdDSA} signature algorithm using Curve {@code Ed448} as defined by
|
|
||||||
* <a href="https://www.rfc-editor.org/rfc/rfc8037#section-3.1">RFC 8037, Section 3.1</a>. This algorithm
|
|
||||||
* requires {@code Ed448} Edwards Curve keys to create signatures. <b>This is a convenience alias for
|
|
||||||
* {@link #EdDSA}</b> that defaults key generation to {@code Ed448} keys.
|
|
||||||
* <p><b>This algorithm requires at least JDK 15 or a compatible JCA Provider (like BouncyCastle) in the runtime
|
|
||||||
* classpath.</b></p>
|
|
||||||
*/
|
|
||||||
public static final SignatureAlgorithm Ed448 = Jwts.get(REGISTRY, "Ed448");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -351,7 +351,7 @@ public final class Assert {
|
||||||
* Assert that the provided object is an instance of the provided class.
|
* Assert that the provided object is an instance of the provided class.
|
||||||
* <pre class="code">Assert.instanceOf(Foo.class, foo);</pre>
|
* <pre class="code">Assert.instanceOf(Foo.class, foo);</pre>
|
||||||
*
|
*
|
||||||
* @param <T> the type of instance expected
|
* @param <T> the type of instance expected
|
||||||
* @param clazz the required class
|
* @param clazz the required class
|
||||||
* @param obj the object to check
|
* @param obj the object to check
|
||||||
* @return the expected instance of type {@code T}
|
* @return the expected instance of type {@code T}
|
||||||
|
@ -423,35 +423,56 @@ public final class Assert {
|
||||||
* an {@link IllegalArgumentException} with the given message if not.
|
* an {@link IllegalArgumentException} with the given message if not.
|
||||||
*
|
*
|
||||||
* @param <T> the type of argument
|
* @param <T> the type of argument
|
||||||
* @param requirement the integer that {@code value} must be greater than
|
|
||||||
* @param value the value to check
|
* @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.
|
* @param msg the message to use for the {@code IllegalArgumentException} if thrown.
|
||||||
* @return {@code value} if greater than the specified {@code requirement}.
|
* @return {@code value} if greater than the specified {@code requirement}.
|
||||||
* @since JJWT_RELEASE_VERSION
|
* @since JJWT_RELEASE_VERSION
|
||||||
*/
|
*/
|
||||||
public static <T extends Number> T eq(T requirement, T value, String msg) {
|
public static <T extends Comparable<T>> T eq(T value, T requirement, String msg) {
|
||||||
notNull(requirement, "requirement cannot be null.");
|
if (compareTo(value, requirement) != 0) {
|
||||||
notNull(value, "value cannot be null.");
|
|
||||||
if (!requirement.equals(value)) {
|
|
||||||
throw new IllegalArgumentException(msg);
|
throw new IllegalArgumentException(msg);
|
||||||
}
|
}
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static <T extends Comparable<T>> 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
|
* Asserts that a specified {@code value} is greater than the given {@code requirement}, throwing
|
||||||
* an {@link IllegalArgumentException} with the given message if not.
|
* an {@link IllegalArgumentException} with the given message if not.
|
||||||
*
|
*
|
||||||
|
* @param <T> the type of value to check and return if the requirement is met
|
||||||
* @param value the value to check
|
* @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.
|
* @param msg the message to use for the {@code IllegalArgumentException} if thrown.
|
||||||
* @return {@code value} if greater than the specified {@code requirement}.
|
* @return {@code value} if greater than the specified {@code requirement}.
|
||||||
* @since JJWT_RELEASE_VERSION
|
* @since JJWT_RELEASE_VERSION
|
||||||
*/
|
*/
|
||||||
public static Integer gt(Integer value, Integer requirement, String msg) {
|
public static <T extends Comparable<T>> T gt(T value, T requirement, String msg) {
|
||||||
notNull(value, "value cannot be null.");
|
if (!(compareTo(value, requirement) > 0)) {
|
||||||
notNull(requirement, "requirement cannot be null.");
|
throw new IllegalArgumentException(msg);
|
||||||
if (!(value > requirement)) {
|
}
|
||||||
|
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 <T> 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 extends Comparable<T>> T lte(T value, T requirement, String msg) {
|
||||||
|
if (compareTo(value, requirement) > 0) {
|
||||||
throw new IllegalArgumentException(msg);
|
throw new IllegalArgumentException(msg);
|
||||||
}
|
}
|
||||||
return value;
|
return value;
|
||||||
|
@ -495,7 +516,7 @@ public final class Assert {
|
||||||
*
|
*
|
||||||
* @param value value to assert is not null
|
* @param value value to assert is not null
|
||||||
* @param msg exception message to use if {@code value} is null
|
* @param msg exception message to use if {@code value} is null
|
||||||
* @param <T> value type
|
* @param <T> value type
|
||||||
* @return the non-null value
|
* @return the non-null value
|
||||||
* @throws IllegalStateException with the specified {@code msg} if {@code value} is null.
|
* @throws IllegalStateException with the specified {@code msg} if {@code value} is null.
|
||||||
* @since JJWT_RELEASE_VERSION
|
* @since JJWT_RELEASE_VERSION
|
||||||
|
|
|
@ -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.
|
||||||
|
*
|
||||||
|
* <p><b>Curve Identifier</b></p>
|
||||||
|
*
|
||||||
|
* <p>This interface extends {@link Identifiable}; the value returned from {@link #getId()} will
|
||||||
|
* be used as the JWK
|
||||||
|
* <a href="https://datatracker.ietf.org/doc/html/rfc7518#section-6.2.1.1"><code>crv</code></a> value.</p>
|
||||||
|
*
|
||||||
|
* <p><b>KeyPair Generation</b></p>
|
||||||
|
*
|
||||||
|
* <p>A secure-random KeyPair of sufficient strength on the curve may be obtained with its {@link #keyPair()} builder.</p>
|
||||||
|
*
|
||||||
|
* <p><b>Standard Implementations</b></p>
|
||||||
|
*
|
||||||
|
* <p>Constants for all JWA standard Curves are available via the {@link Jwks.CRV} registry.</p>
|
||||||
|
*
|
||||||
|
* @see Jwks.CRV
|
||||||
|
* @since JJWT_RELEASE_VERSION
|
||||||
|
*/
|
||||||
|
public interface Curve extends Identifiable, KeyPairBuilderSupplier {
|
||||||
|
}
|
|
@ -44,6 +44,121 @@ public final class Jwks {
|
||||||
|
|
||||||
private static final String PARSERBUILDER_CLASSNAME = "io.jsonwebtoken.impl.security.DefaultJwkParserBuilder";
|
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 <a href="https://datatracker.ietf.org/doc/html/rfc7518#section-7.6">RFC 7518, Section 7.6</a>
|
||||||
|
* (for Weierstrass Elliptic Curves) and
|
||||||
|
* <a href="https://www.rfc-editor.org/rfc/rfc8037#section-5">RFC 8037, Section 5</a> (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:
|
||||||
|
* <blockquote><pre>
|
||||||
|
* Jwks.CRV.P256.keyPair().build();</pre></blockquote>
|
||||||
|
* <p>They are also available together as a {@link Registry} instance via the {@link #get()} method.</p>
|
||||||
|
*
|
||||||
|
* @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<String, Curve> REGISTRY = Classes.newInstance(IMPL_CLASSNAME);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a registry of all standard Elliptic Curves in the {@code JSON Web Key Elliptic Curve Registry}
|
||||||
|
* defined by <a href="https://datatracker.ietf.org/doc/html/rfc7518#section-7.6">RFC 7518, Section 7.6</a>
|
||||||
|
* (for Weierstrass Elliptic Curves) and
|
||||||
|
* <a href="https://www.rfc-editor.org/rfc/rfc8037#section-5">RFC 8037, Section 5</a> (for Edwards Elliptic Curves).
|
||||||
|
*
|
||||||
|
* @return a registry of all standard Elliptic Curves in the {@code JSON Web Key Elliptic Curve Registry}.
|
||||||
|
*/
|
||||||
|
public static Registry<String, Curve> get() {
|
||||||
|
return REGISTRY;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@code P-256} Elliptic Curve defined by
|
||||||
|
* <a href="https://datatracker.ietf.org/doc/html/rfc7518#section-6.2.1.1">RFC 7518, Section 6.2.1.1</a>
|
||||||
|
* using the native Java JCA {@code secp256r1} algorithm.
|
||||||
|
*
|
||||||
|
* @see <a href="https://docs.oracle.com/en/java/javase/17/docs/specs/security/standard-names.html">Java Security Standard Algorithm Names</a>
|
||||||
|
*/
|
||||||
|
public static final Curve P256 = get().forKey("P-256");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@code P-384} Elliptic Curve defined by
|
||||||
|
* <a href="https://datatracker.ietf.org/doc/html/rfc7518#section-6.2.1.1">RFC 7518, Section 6.2.1.1</a>
|
||||||
|
* using the native Java JCA {@code secp384r1} algorithm.
|
||||||
|
*
|
||||||
|
* @see <a href="https://docs.oracle.com/en/java/javase/17/docs/specs/security/standard-names.html">Java Security Standard Algorithm Names</a>
|
||||||
|
*/
|
||||||
|
public static final Curve P384 = get().forKey("P-384");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@code P-521} Elliptic Curve defined by
|
||||||
|
* <a href="https://datatracker.ietf.org/doc/html/rfc7518#section-6.2.1.1">RFC 7518, Section 6.2.1.1</a>
|
||||||
|
* using the native Java JCA {@code secp521r1} algorithm.
|
||||||
|
*
|
||||||
|
* @see <a href="https://docs.oracle.com/en/java/javase/17/docs/specs/security/standard-names.html">Java Security Standard Algorithm Names</a>
|
||||||
|
*/
|
||||||
|
public static final Curve P521 = get().forKey("P-521");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@code Ed25519} Elliptic Curve defined by
|
||||||
|
* <a href="https://www.rfc-editor.org/rfc/rfc8037#section-3.1">RFC 8037, Section 3.1</a>
|
||||||
|
* using the native Java JCA {@code Ed25519}<b><sup>1</sup></b> algorithm.
|
||||||
|
*
|
||||||
|
* <p><b><sup>1</sup></b> 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.</p>
|
||||||
|
*
|
||||||
|
* @see <a href="https://docs.oracle.com/en/java/javase/17/docs/specs/security/standard-names.html">Java Security Standard Algorithm Names</a>
|
||||||
|
*/
|
||||||
|
public static final Curve Ed25519 = get().forKey("Ed25519");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@code Ed448} Elliptic Curve defined by
|
||||||
|
* <a href="https://www.rfc-editor.org/rfc/rfc8037#section-3.1">RFC 8037, Section 3.1</a>
|
||||||
|
* using the native Java JCA {@code Ed448}<b><sup>1</sup></b> algorithm.
|
||||||
|
*
|
||||||
|
* <p><b><sup>1</sup></b> 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.</p>
|
||||||
|
*
|
||||||
|
* @see <a href="https://docs.oracle.com/en/java/javase/17/docs/specs/security/standard-names.html">Java Security Standard Algorithm Names</a>
|
||||||
|
*/
|
||||||
|
public static final Curve Ed448 = get().forKey("Ed448");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@code X25519} Elliptic Curve defined by
|
||||||
|
* <a href="https://www.rfc-editor.org/rfc/rfc8037#section-3.2">RFC 8037, Section 3.2</a>
|
||||||
|
* using the native Java JCA {@code X25519}<b><sup>1</sup></b> algorithm.
|
||||||
|
*
|
||||||
|
* <p><b><sup>1</sup></b> 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.</p>
|
||||||
|
*
|
||||||
|
* @see <a href="https://docs.oracle.com/en/java/javase/17/docs/specs/security/standard-names.html">Java Security Standard Algorithm Names</a>
|
||||||
|
*/
|
||||||
|
public static final Curve X25519 = get().forKey("X25519");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@code X448} Elliptic Curve defined by
|
||||||
|
* <a href="https://www.rfc-editor.org/rfc/rfc8037#section-3.2">RFC 8037, Section 3.2</a>
|
||||||
|
* using the native Java JCA {@code X448}<b><sup>1</sup></b> algorithm.
|
||||||
|
*
|
||||||
|
* <p><b><sup>1</sup></b> 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.</p>
|
||||||
|
*
|
||||||
|
* @see <a href="https://docs.oracle.com/en/java/javase/17/docs/specs/security/standard-names.html">Java Security Standard Algorithm Names</a>
|
||||||
|
*/
|
||||||
|
public static final Curve X448 = get().forKey("X448");
|
||||||
|
|
||||||
|
//prevent instantiation
|
||||||
|
private CRV() {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Various (<em>but not all</em>)
|
* Various (<em>but not all</em>)
|
||||||
* <a href="https://www.iana.org/assignments/named-information/named-information.xhtml#hash-alg">IANA Hash
|
* <a href="https://www.iana.org/assignments/named-information/named-information.xhtml#hash-alg">IANA Hash
|
||||||
|
|
|
@ -84,7 +84,7 @@ public class OrgJsonSerializer<T> implements Serializer<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (object instanceof Supplier) {
|
if (object instanceof Supplier) {
|
||||||
object = ((Supplier<?>)object).get();
|
object = ((Supplier<?>) object).get();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (object instanceof JSONObject || object instanceof JSONArray
|
if (object instanceof JSONObject || object instanceof JSONArray
|
||||||
|
@ -163,6 +163,12 @@ public class OrgJsonSerializer<T> implements Serializer<T> {
|
||||||
return array;
|
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
|
@SuppressWarnings("WeakerAccess") //for testing
|
||||||
protected byte[] toBytes(Object o) {
|
protected byte[] toBytes(Object o) {
|
||||||
String s;
|
String s;
|
||||||
|
|
|
@ -31,6 +31,8 @@
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<jjwt.root>${basedir}/..</jjwt.root>
|
<jjwt.root>${basedir}/..</jjwt.root>
|
||||||
|
<!-- This module is not intended for direct use or extension, no need to worry about perfect JavaDoc: -->
|
||||||
|
<maven.javadoc.additionalOptions>-Xdoclint:none</maven.javadoc.additionalOptions>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
|
|
@ -27,6 +27,7 @@ import io.jsonwebtoken.impl.security.DefaultAeadRequest;
|
||||||
import io.jsonwebtoken.impl.security.DefaultKeyRequest;
|
import io.jsonwebtoken.impl.security.DefaultKeyRequest;
|
||||||
import io.jsonwebtoken.impl.security.DefaultSecureRequest;
|
import io.jsonwebtoken.impl.security.DefaultSecureRequest;
|
||||||
import io.jsonwebtoken.impl.security.Pbes2HsAkwAlgorithm;
|
import io.jsonwebtoken.impl.security.Pbes2HsAkwAlgorithm;
|
||||||
|
import io.jsonwebtoken.impl.security.StandardSecureDigestAlgorithms;
|
||||||
import io.jsonwebtoken.io.CompressionAlgorithm;
|
import io.jsonwebtoken.io.CompressionAlgorithm;
|
||||||
import io.jsonwebtoken.io.Decoders;
|
import io.jsonwebtoken.io.Decoders;
|
||||||
import io.jsonwebtoken.io.Encoder;
|
import io.jsonwebtoken.io.Encoder;
|
||||||
|
@ -49,6 +50,7 @@ import io.jsonwebtoken.security.SecureDigestAlgorithm;
|
||||||
import io.jsonwebtoken.security.SecureRequest;
|
import io.jsonwebtoken.security.SecureRequest;
|
||||||
import io.jsonwebtoken.security.SecurityException;
|
import io.jsonwebtoken.security.SecurityException;
|
||||||
import io.jsonwebtoken.security.SignatureException;
|
import io.jsonwebtoken.security.SignatureException;
|
||||||
|
import io.jsonwebtoken.security.UnsupportedKeyException;
|
||||||
|
|
||||||
import javax.crypto.SecretKey;
|
import javax.crypto.SecretKey;
|
||||||
import javax.crypto.spec.SecretKeySpec;
|
import javax.crypto.spec.SecretKeySpec;
|
||||||
|
@ -179,10 +181,21 @@ public class DefaultJwtBuilder implements JwtBuilder {
|
||||||
return this.headerBuilder.add(name, value).and();
|
return this.headerBuilder.add(name, value).and();
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked") // TODO: remove for 1.0
|
@SuppressWarnings({"unchecked", "deprecation"}) // TODO: remove for 1.0
|
||||||
protected static <K extends Key> SecureDigestAlgorithm<K, ?> forSigningKey(K key) {
|
protected static <K extends Key> SecureDigestAlgorithm<K, ?> forSigningKey(K key) {
|
||||||
@SuppressWarnings("deprecation") io.jsonwebtoken.SignatureAlgorithm alg = io.jsonwebtoken.SignatureAlgorithm.forSigningKey(key);
|
Assert.notNull(key, "Key cannot be null.");
|
||||||
return (SecureDigestAlgorithm<K, ?>) Jwts.SIG.get().forKey(alg.getValue());
|
SecureDigestAlgorithm<K, ?> 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<K, ?>) Jwts.SIG.get().forKey(dalg.getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -195,7 +208,7 @@ public class DefaultJwtBuilder implements JwtBuilder {
|
||||||
@Override
|
@Override
|
||||||
public <K extends Key> JwtBuilder signWith(K key, final SecureDigestAlgorithm<? super K, ?> alg) throws InvalidKeyException {
|
public <K extends Key> JwtBuilder signWith(K key, final SecureDigestAlgorithm<? super K, ?> alg) throws InvalidKeyException {
|
||||||
Assert.notNull(key, "Key argument cannot be null.");
|
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);
|
throw new IllegalArgumentException(PUB_KEY_SIGN_MSG);
|
||||||
}
|
}
|
||||||
// Implementation note: Ordinarily Passwords should not be used to create secure digests because they usually
|
// Implementation note: Ordinarily Passwords should not be used to create secure digests because they usually
|
||||||
|
|
|
@ -35,6 +35,7 @@ import io.jsonwebtoken.security.AeadAlgorithm;
|
||||||
import io.jsonwebtoken.security.KeyAlgorithm;
|
import io.jsonwebtoken.security.KeyAlgorithm;
|
||||||
import io.jsonwebtoken.security.Keys;
|
import io.jsonwebtoken.security.Keys;
|
||||||
import io.jsonwebtoken.security.SecureDigestAlgorithm;
|
import io.jsonwebtoken.security.SecureDigestAlgorithm;
|
||||||
|
import io.jsonwebtoken.security.UnsupportedKeyException;
|
||||||
|
|
||||||
import javax.crypto.SecretKey;
|
import javax.crypto.SecretKey;
|
||||||
import java.security.Key;
|
import java.security.Key;
|
||||||
|
@ -229,7 +230,14 @@ public class DefaultJwtParserBuilder implements JwtParserBuilder {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public JwtParserBuilder setSigningKey(final Key key) {
|
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
|
@Override
|
||||||
|
|
|
@ -82,7 +82,7 @@ public final class Conditions {
|
||||||
Object value = null;
|
Object value = null;
|
||||||
try {
|
try {
|
||||||
value = supplier.get();
|
value = supplier.get();
|
||||||
} catch (Exception ignored) {
|
} catch (Throwable ignored) {
|
||||||
}
|
}
|
||||||
return value != null;
|
return value != null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ import io.jsonwebtoken.impl.lang.CheckedFunction;
|
||||||
import io.jsonwebtoken.impl.lang.Converters;
|
import io.jsonwebtoken.impl.lang.Converters;
|
||||||
import io.jsonwebtoken.impl.lang.Field;
|
import io.jsonwebtoken.impl.lang.Field;
|
||||||
import io.jsonwebtoken.io.Encoders;
|
import io.jsonwebtoken.io.Encoders;
|
||||||
|
import io.jsonwebtoken.security.Curve;
|
||||||
import io.jsonwebtoken.security.Jwk;
|
import io.jsonwebtoken.security.Jwk;
|
||||||
import io.jsonwebtoken.security.UnsupportedKeyException;
|
import io.jsonwebtoken.security.UnsupportedKeyException;
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,7 @@ package io.jsonwebtoken.impl.security;
|
||||||
import io.jsonwebtoken.impl.lang.CheckedFunction;
|
import io.jsonwebtoken.impl.lang.CheckedFunction;
|
||||||
import io.jsonwebtoken.impl.lang.Field;
|
import io.jsonwebtoken.impl.lang.Field;
|
||||||
import io.jsonwebtoken.lang.Assert;
|
import io.jsonwebtoken.lang.Assert;
|
||||||
|
import io.jsonwebtoken.lang.Strings;
|
||||||
import io.jsonwebtoken.security.InvalidKeyException;
|
import io.jsonwebtoken.security.InvalidKeyException;
|
||||||
import io.jsonwebtoken.security.Jwk;
|
import io.jsonwebtoken.security.Jwk;
|
||||||
import io.jsonwebtoken.security.KeyException;
|
import io.jsonwebtoken.security.KeyException;
|
||||||
|
@ -73,8 +74,14 @@ abstract class AbstractFamilyJwkFactory<K extends Key, J extends Jwk<K>> impleme
|
||||||
return generateKey(ctx, this.keyType, fn);
|
return generateKey(ctx, this.keyType, fn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected String getKeyFactoryJcaName(final JwkContext<?> ctx) {
|
||||||
|
String jcaName = KeysBridge.findAlgorithm(ctx.getKey());
|
||||||
|
return Strings.hasText(jcaName) ? jcaName : getId();
|
||||||
|
}
|
||||||
|
|
||||||
protected <T extends Key> T generateKey(final JwkContext<?> ctx, final Class<T> type, final CheckedFunction<KeyFactory, T> fn) {
|
protected <T extends Key> T generateKey(final JwkContext<?> ctx, final Class<T> type, final CheckedFunction<KeyFactory, T> 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<KeyFactory, T>() {
|
return template.withKeyFactory(new CheckedFunction<KeyFactory, T>() {
|
||||||
@Override
|
@Override
|
||||||
public T apply(KeyFactory instance) {
|
public T apply(KeyFactory instance) {
|
||||||
|
|
|
@ -41,7 +41,7 @@ abstract class AbstractSecureDigestAlgorithm<S extends Key, V extends Key> exten
|
||||||
@Override
|
@Override
|
||||||
public final byte[] digest(SecureRequest<byte[], S> request) throws SecurityException {
|
public final byte[] digest(SecureRequest<byte[], S> request) throws SecurityException {
|
||||||
Assert.notNull(request, "Request cannot be null.");
|
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.");
|
Assert.notEmpty(request.getPayload(), "Request content cannot be null or empty.");
|
||||||
try {
|
try {
|
||||||
validateKey(key, true);
|
validateKey(key, true);
|
||||||
|
@ -60,7 +60,7 @@ abstract class AbstractSecureDigestAlgorithm<S extends Key, V extends Key> exten
|
||||||
@Override
|
@Override
|
||||||
public final boolean verify(VerifySecureDigestRequest<V> request) throws SecurityException {
|
public final boolean verify(VerifySecureDigestRequest<V> request) throws SecurityException {
|
||||||
Assert.notNull(request, "Request cannot be null.");
|
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.getPayload(), "Request content cannot be null or empty.");
|
||||||
Assert.notEmpty(request.getDigest(), "Request signature byte array cannot be null or empty.");
|
Assert.notEmpty(request.getDigest(), "Request signature byte array cannot be null or empty.");
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -33,7 +33,7 @@ abstract class AbstractSignatureAlgorithm extends AbstractSecureDigestAlgorithm<
|
||||||
private static final String KEY_TYPE_MSG_PATTERN =
|
private static final String KEY_TYPE_MSG_PATTERN =
|
||||||
"{0} {1} keys must be {2}s (implement {3}). Provided key type: {4}.";
|
"{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);
|
super(id, jcaName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@ import io.jsonwebtoken.impl.lang.IdRegistry;
|
||||||
import io.jsonwebtoken.lang.Assert;
|
import io.jsonwebtoken.lang.Assert;
|
||||||
import io.jsonwebtoken.lang.Collections;
|
import io.jsonwebtoken.lang.Collections;
|
||||||
import io.jsonwebtoken.lang.Registry;
|
import io.jsonwebtoken.lang.Registry;
|
||||||
|
import io.jsonwebtoken.security.Curve;
|
||||||
|
|
||||||
import java.security.spec.EllipticCurve;
|
import java.security.spec.EllipticCurve;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
@ -33,7 +34,7 @@ public final class Curves {
|
||||||
|
|
||||||
private static final Collection<ECCurve> EC_CURVES = Collections.setOf((ECCurve) P_256, (ECCurve) P_384, (ECCurve) P_521);
|
private static final Collection<ECCurve> EC_CURVES = Collections.setOf((ECCurve) P_256, (ECCurve) P_384, (ECCurve) P_521);
|
||||||
|
|
||||||
private static final Collection<Curve> VALUES = new LinkedHashSet<>();
|
static final Collection<Curve> VALUES = new LinkedHashSet<>();
|
||||||
|
|
||||||
static {
|
static {
|
||||||
VALUES.addAll(EC_CURVES);
|
VALUES.addAll(EC_CURVES);
|
||||||
|
|
|
@ -17,6 +17,7 @@ package io.jsonwebtoken.impl.security;
|
||||||
|
|
||||||
import io.jsonwebtoken.lang.Assert;
|
import io.jsonwebtoken.lang.Assert;
|
||||||
import io.jsonwebtoken.lang.Strings;
|
import io.jsonwebtoken.lang.Strings;
|
||||||
|
import io.jsonwebtoken.security.Curve;
|
||||||
import io.jsonwebtoken.security.KeyPairBuilder;
|
import io.jsonwebtoken.security.KeyPairBuilder;
|
||||||
|
|
||||||
import java.security.Provider;
|
import java.security.Provider;
|
||||||
|
|
|
@ -209,6 +209,20 @@ public class DefaultJwkContext<K extends Key> extends AbstractX509Context<JwkCon
|
||||||
return this;
|
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<String> ops = getOperations();
|
||||||
|
if (Collections.isEmpty(ops)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return ops.contains("sign") || ops.contains("verify");
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public K getKey() {
|
public K getKey() {
|
||||||
return this.key;
|
return this.key;
|
||||||
|
|
|
@ -29,39 +29,51 @@ import io.jsonwebtoken.security.WeakKeyException;
|
||||||
import javax.crypto.Mac;
|
import javax.crypto.Mac;
|
||||||
import javax.crypto.SecretKey;
|
import javax.crypto.SecretKey;
|
||||||
import java.security.Key;
|
import java.security.Key;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @since JJWT_RELEASE_VERSION
|
* @since JJWT_RELEASE_VERSION
|
||||||
*/
|
*/
|
||||||
public class DefaultMacAlgorithm extends AbstractSecureDigestAlgorithm<SecretKey, SecretKey> implements MacAlgorithm {
|
final class DefaultMacAlgorithm extends AbstractSecureDigestAlgorithm<SecretKey, SecretKey> 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<String> JWA_STANDARD_IDS = new LinkedHashSet<>(Collections.of("HS256", "HS384", "HS512"));
|
private static final Set<String> 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
|
static final DefaultMacAlgorithm HS256 = new DefaultMacAlgorithm(256);
|
||||||
private static final Set<String> HS256_JCA_NAMES = new LinkedHashSet<>(Collections.of("HMACSHA256", "1.2.840.113549.2.9"));
|
static final DefaultMacAlgorithm HS384 = new DefaultMacAlgorithm(384);
|
||||||
private static final Set<String> HS384_JCA_NAMES = new LinkedHashSet<>(Collections.of("HMACSHA384", "1.2.840.113549.2.10"));
|
static final DefaultMacAlgorithm HS512 = new DefaultMacAlgorithm(512);
|
||||||
private static final Set<String> HS512_JCA_NAMES = new LinkedHashSet<>(Collections.of("HMACSHA512", "1.2.840.113549.2.11"));
|
|
||||||
|
|
||||||
private static final Set<String> VALID_HS256_JCA_NAMES;
|
private static final Map<String, MacAlgorithm> JCA_NAME_MAP;
|
||||||
private static final Set<String> VALID_HS384_JCA_NAMES;
|
|
||||||
|
|
||||||
static {
|
static {
|
||||||
VALID_HS384_JCA_NAMES = new LinkedHashSet<>(HS384_JCA_NAMES);
|
JCA_NAME_MAP = new LinkedHashMap<>(6);
|
||||||
VALID_HS384_JCA_NAMES.addAll(HS512_JCA_NAMES);
|
|
||||||
VALID_HS256_JCA_NAMES = new LinkedHashSet<>(HS256_JCA_NAMES);
|
// In addition to JCA names, PKCS12 OIDs are added to these per
|
||||||
VALID_HS256_JCA_NAMES.addAll(VALID_HS384_JCA_NAMES);
|
// 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);
|
this("HS" + digestBitLength, "HmacSHA" + digestBitLength, digestBitLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
public DefaultMacAlgorithm(String id, String jcaName, int minKeyBitLength) {
|
DefaultMacAlgorithm(String id, String jcaName, int minKeyBitLength) {
|
||||||
super(id, jcaName);
|
super(id, jcaName);
|
||||||
Assert.isTrue(minKeyBitLength > 0, "minKeyLength must be greater than zero.");
|
Assert.isTrue(minKeyBitLength > 0, "minKeyLength must be greater than zero.");
|
||||||
this.minKeyBitLength = minKeyBitLength;
|
this.minKeyBitLength = minKeyBitLength;
|
||||||
|
@ -76,10 +88,36 @@ public class DefaultMacAlgorithm extends AbstractSecureDigestAlgorithm<SecretKey
|
||||||
return JWA_STANDARD_IDS.contains(getId());
|
return JWA_STANDARD_IDS.contains(getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isJwaStandardJcaName(String jcaName) {
|
private static boolean isJwaStandardJcaName(String jcaName) {
|
||||||
return VALID_HS256_JCA_NAMES.contains(jcaName.toUpperCase(Locale.ENGLISH));
|
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
|
@Override
|
||||||
public SecretKeyBuilder key() {
|
public SecretKeyBuilder key() {
|
||||||
return new DefaultSecretKeyBuilder(getJcaName(), getKeyBitLength());
|
return new DefaultSecretKeyBuilder(getJcaName(), getKeyBitLength());
|
||||||
|
@ -91,11 +129,11 @@ public class DefaultMacAlgorithm extends AbstractSecureDigestAlgorithm<SecretKey
|
||||||
final String keyType = keyType(signing);
|
final String keyType = keyType(signing);
|
||||||
|
|
||||||
if (k == null) {
|
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)) {
|
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();
|
k.getClass().getName();
|
||||||
throw new InvalidKeyException(msg);
|
throw new InvalidKeyException(msg);
|
||||||
}
|
}
|
||||||
|
@ -116,24 +154,13 @@ public class DefaultMacAlgorithm extends AbstractSecureDigestAlgorithm<SecretKey
|
||||||
"HmacSHA* algorithm name or PKCS12 OID and cannot be used with " + id + ".");
|
"HmacSHA* algorithm name or PKCS12 OID and cannot be used with " + id + ".");
|
||||||
}
|
}
|
||||||
|
|
||||||
byte[] encoded = null;
|
int size = KeysBridge.findBitLength(key);
|
||||||
|
|
||||||
// https://github.com/jwtk/jjwt/issues/478
|
// We can only perform length validation if key bit length is available
|
||||||
//
|
|
||||||
// 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) {
|
|
||||||
}
|
|
||||||
|
|
||||||
// We can only perform length validation if key.getEncoded() is not null or does not throw an exception
|
|
||||||
// per https://github.com/jwtk/jjwt/issues/478 and https://github.com/jwtk/jjwt/issues/619
|
// per https://github.com/jwtk/jjwt/issues/478 and https://github.com/jwtk/jjwt/issues/619
|
||||||
// so return early if we can't:
|
// 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) {
|
if (size < this.minKeyBitLength) {
|
||||||
String msg = "The " + keyType + " key's size is " + size + " bits which " +
|
String msg = "The " + keyType + " key's size is " + size + " bits which " +
|
||||||
"is not secure enough for the " + id + " algorithm.";
|
"is not secure enough for the " + id + " algorithm.";
|
||||||
|
|
|
@ -22,6 +22,7 @@ import io.jsonwebtoken.security.KeyAlgorithm;
|
||||||
import io.jsonwebtoken.security.KeyRequest;
|
import io.jsonwebtoken.security.KeyRequest;
|
||||||
import io.jsonwebtoken.security.KeyResult;
|
import io.jsonwebtoken.security.KeyResult;
|
||||||
import io.jsonwebtoken.security.SecurityException;
|
import io.jsonwebtoken.security.SecurityException;
|
||||||
|
import io.jsonwebtoken.security.UnsupportedKeyException;
|
||||||
import io.jsonwebtoken.security.WeakKeyException;
|
import io.jsonwebtoken.security.WeakKeyException;
|
||||||
|
|
||||||
import javax.crypto.Cipher;
|
import javax.crypto.Cipher;
|
||||||
|
@ -56,6 +57,13 @@ public class DefaultRsaKeyAlgorithm extends CryptoAlgorithm implements KeyAlgori
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void validate(Key key, boolean encryption) { // true = encryption, false = decryption
|
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
|
// 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 so, we can provide additional safety checks:
|
||||||
if (key instanceof RSAKey) {
|
if (key instanceof RSAKey) {
|
||||||
|
|
|
@ -19,9 +19,11 @@ import io.jsonwebtoken.JwtException;
|
||||||
import io.jsonwebtoken.impl.lang.Bytes;
|
import io.jsonwebtoken.impl.lang.Bytes;
|
||||||
import io.jsonwebtoken.impl.lang.CheckedFunction;
|
import io.jsonwebtoken.impl.lang.CheckedFunction;
|
||||||
import io.jsonwebtoken.lang.Assert;
|
import io.jsonwebtoken.lang.Assert;
|
||||||
|
import io.jsonwebtoken.lang.Strings;
|
||||||
import io.jsonwebtoken.security.InvalidKeyException;
|
import io.jsonwebtoken.security.InvalidKeyException;
|
||||||
import io.jsonwebtoken.security.KeyPairBuilder;
|
import io.jsonwebtoken.security.KeyPairBuilder;
|
||||||
import io.jsonwebtoken.security.SecureRequest;
|
import io.jsonwebtoken.security.SecureRequest;
|
||||||
|
import io.jsonwebtoken.security.SignatureAlgorithm;
|
||||||
import io.jsonwebtoken.security.SignatureException;
|
import io.jsonwebtoken.security.SignatureException;
|
||||||
import io.jsonwebtoken.security.VerifySecureDigestRequest;
|
import io.jsonwebtoken.security.VerifySecureDigestRequest;
|
||||||
|
|
||||||
|
@ -33,19 +35,28 @@ import java.security.Signature;
|
||||||
import java.security.interfaces.ECKey;
|
import java.security.interfaces.ECKey;
|
||||||
import java.security.spec.ECGenParameterSpec;
|
import java.security.spec.ECGenParameterSpec;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
// @since JJWT_RELEASE_VERSION
|
// @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 REQD_ORDER_BIT_LENGTH_MSG = "orderBitLength must equal 256, 384, or 521.";
|
||||||
|
|
||||||
private static final String DER_ENCODING_SYS_PROPERTY_NAME =
|
private static final String DER_ENCODING_SYS_PROPERTY_NAME =
|
||||||
"io.jsonwebtoken.impl.crypto.EllipticCurveSignatureValidator.derEncodingSupported";
|
"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 ECGenParameterSpec KEY_PAIR_GEN_PARAMS;
|
||||||
|
|
||||||
private final int orderBitLength;
|
private final int orderBitLength;
|
||||||
|
|
||||||
|
private final String OID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* JWA EC (concat formatted) length in bytes for this instance's {@link #orderBitLength}.
|
* JWA EC (concat formatted) length in bytes for this instance's {@link #orderBitLength}.
|
||||||
*/
|
*/
|
||||||
|
@ -89,9 +100,51 @@ public class EcSignatureAlgorithm extends AbstractSignatureAlgorithm {
|
||||||
return orderBitLength == 256 || orderBitLength == 384 || orderBitLength == 521;
|
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<String, SignatureAlgorithm> 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");
|
super("ES" + shaSize(orderBitLength), "SHA" + shaSize(orderBitLength) + "withECDSA");
|
||||||
Assert.isTrue(isSupportedOrderBitLength(orderBitLength), REQD_ORDER_BIT_LENGTH_MSG);
|
Assert.isTrue(isSupportedOrderBitLength(orderBitLength), REQD_ORDER_BIT_LENGTH_MSG);
|
||||||
|
this.OID = Assert.hasText(oid, "Invalid OID.");
|
||||||
String curveName = "secp" + orderBitLength + "r1";
|
String curveName = "secp" + orderBitLength + "r1";
|
||||||
this.KEY_PAIR_GEN_PARAMS = new ECGenParameterSpec(curveName);
|
this.KEY_PAIR_GEN_PARAMS = new ECGenParameterSpec(curveName);
|
||||||
this.orderBitLength = orderBitLength;
|
this.orderBitLength = orderBitLength;
|
||||||
|
@ -142,7 +195,7 @@ public class EcSignatureAlgorithm extends AbstractSignatureAlgorithm {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
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;
|
ECKey ecKey = (ECKey) key;
|
||||||
BigInteger order = ecKey.getParams().getOrder();
|
BigInteger order = ecKey.getParams().getOrder();
|
||||||
|
|
|
@ -23,25 +23,27 @@ import io.jsonwebtoken.security.UnsupportedKeyException;
|
||||||
import io.jsonwebtoken.security.VerifyDigestRequest;
|
import io.jsonwebtoken.security.VerifyDigestRequest;
|
||||||
|
|
||||||
import java.security.Key;
|
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 static final String ID = "EdDSA";
|
||||||
|
|
||||||
private final EdwardsCurve preferredCurve;
|
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);
|
super(ID, ID);
|
||||||
this.preferredCurve = EdwardsCurve.Ed448;
|
this.preferredCurve = EdwardsCurve.Ed448;
|
||||||
// EdDSA is not available natively until JDK 15, so try to load BC as a backup provider if possible:
|
// EdDSA is not available natively until JDK 15, so try to load BC as a backup provider if possible:
|
||||||
setProvider(this.preferredCurve.getProvider());
|
setProvider(this.preferredCurve.getProvider());
|
||||||
}
|
Assert.isTrue(this.preferredCurve.isSignatureCurve(), "Must be signature curve, not key agreement curve.");
|
||||||
|
|
||||||
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());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -74,7 +76,7 @@ public class EdSignatureAlgorithm extends AbstractSignatureAlgorithm {
|
||||||
EdwardsCurve curve = EdwardsCurve.findByKey(key);
|
EdwardsCurve curve = EdwardsCurve.findByKey(key);
|
||||||
if (curve != null && !curve.isSignatureCurve()) {
|
if (curve != null && !curve.isSignatureCurve()) {
|
||||||
String msg = curve.getId() + " keys may not be used with " + getId() + " digital signatures per " +
|
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);
|
throw new UnsupportedKeyException(msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -281,14 +281,14 @@ public class EdwardsCurve extends DefaultCurve implements KeyLengthSupplier {
|
||||||
int keyLen = 0;
|
int keyLen = 0;
|
||||||
if (encoded[i] == 0x05) { // NULL terminator, next should be zero byte indicator
|
if (encoded[i] == 0x05) { // NULL terminator, next should be zero byte indicator
|
||||||
int unusedBytes = encoded[++i];
|
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++;
|
i++;
|
||||||
}
|
}
|
||||||
if (encoded[i] == 0x03) { // DER bit stream, Public Key
|
if (encoded[i] == 0x03) { // DER bit stream, Public Key
|
||||||
i++;
|
i++;
|
||||||
keyLen = encoded[i++];
|
keyLen = encoded[i++];
|
||||||
int unusedBytes = 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--;
|
keyLen--;
|
||||||
} else if (encoded[i] == 0x04) { // DER octet sequence, Private Key. Key length follows as next byte.
|
} else if (encoded[i] == 0x04) { // DER octet sequence, Private Key. Key length follows as next byte.
|
||||||
i++;
|
i++;
|
||||||
|
@ -298,10 +298,10 @@ public class EdwardsCurve extends DefaultCurve implements KeyLengthSupplier {
|
||||||
keyLen = encoded[i++]; // next byte is length
|
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);
|
byte[] result = Arrays.copyOfRange(encoded, i, i + keyLen);
|
||||||
keyLen = Bytes.length(result);
|
keyLen = Bytes.length(result);
|
||||||
Assert.eq(this.encodedKeyByteLength, keyLen, "Invalid key length.");
|
Assert.eq(keyLen, this.encodedKeyByteLength, "Invalid key length.");
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -53,6 +53,20 @@ public interface JwkContext<K extends Key> extends Identifiable, Map<String, Obj
|
||||||
|
|
||||||
JwkContext<K> setPublicKeyUse(String use);
|
JwkContext<K> 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:
|
||||||
|
* <ul>
|
||||||
|
* <li>"sig".equals({@link #getPublicKeyUse()}), OR</li>
|
||||||
|
* <li>{@link #getOperations()} is not empty and contains either "sign" or "verify"</li>
|
||||||
|
* </ul>
|
||||||
|
* <p>otherwise {@code false}.</p>
|
||||||
|
*
|
||||||
|
* @return {@code true} if relevant context values indicate JWK use with MAC or digital signature algorithms,
|
||||||
|
* {@code false} otherwise.
|
||||||
|
*/
|
||||||
|
boolean isSigUse();
|
||||||
|
|
||||||
K getKey();
|
K getKey();
|
||||||
|
|
||||||
JwkContext<K> setKey(K key);
|
JwkContext<K> setKey(K key);
|
||||||
|
|
|
@ -15,16 +15,20 @@
|
||||||
*/
|
*/
|
||||||
package io.jsonwebtoken.impl.security;
|
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.impl.lang.Converter;
|
||||||
import io.jsonwebtoken.io.Decoders;
|
import io.jsonwebtoken.io.Decoders;
|
||||||
import io.jsonwebtoken.io.Encoders;
|
import io.jsonwebtoken.io.Encoders;
|
||||||
import io.jsonwebtoken.lang.Arrays;
|
|
||||||
import io.jsonwebtoken.lang.Assert;
|
import io.jsonwebtoken.lang.Assert;
|
||||||
|
import io.jsonwebtoken.lang.Strings;
|
||||||
|
import io.jsonwebtoken.security.SecurityException;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.security.Provider;
|
||||||
import java.security.cert.CertificateEncodingException;
|
import java.security.cert.CertificateEncodingException;
|
||||||
import java.security.cert.CertificateException;
|
|
||||||
import java.security.cert.CertificateFactory;
|
import java.security.cert.CertificateFactory;
|
||||||
import java.security.cert.X509Certificate;
|
import java.security.cert.X509Certificate;
|
||||||
|
|
||||||
|
@ -44,32 +48,60 @@ public class JwtX509StringConverter implements Converter<X509Certificate, String
|
||||||
der = cert.getEncoded();
|
der = cert.getEncoded();
|
||||||
} catch (CertificateEncodingException e) {
|
} catch (CertificateEncodingException e) {
|
||||||
String msg = "Unable to access X509Certificate encoded bytes necessary to perform DER " +
|
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);
|
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 + "}.";
|
String msg = "X509Certificate encoded bytes cannot be null or empty. Certificate: {" + cert + "}.";
|
||||||
throw new IllegalArgumentException(msg);
|
throw new IllegalArgumentException(msg);
|
||||||
}
|
}
|
||||||
return Encoders.BASE64.encode(der);
|
return Encoders.BASE64.encode(der);
|
||||||
}
|
}
|
||||||
|
|
||||||
//visible for testing
|
// visible for testing
|
||||||
protected CertificateFactory newCertificateFactory() throws CertificateException {
|
protected X509Certificate toCert(final byte[] der, Provider provider) throws SecurityException {
|
||||||
return CertificateFactory.getInstance("X.509");
|
JcaTemplate template = new JcaTemplate("X.509", provider);
|
||||||
|
final InputStream is = new ByteArrayInputStream(der);
|
||||||
|
return template.withCertificateFactory(new CheckedFunction<CertificateFactory, X509Certificate>() {
|
||||||
|
@Override
|
||||||
|
public X509Certificate apply(CertificateFactory cf) throws Exception {
|
||||||
|
return (X509Certificate) cf.generateCertificate(is);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public X509Certificate applyFrom(String s) {
|
public X509Certificate applyFrom(String s) {
|
||||||
Assert.hasText(s, "X.509 Certificate encoded string cannot be null or empty.");
|
Assert.hasText(s, "X.509 Certificate encoded string cannot be null or empty.");
|
||||||
|
byte[] der = null;
|
||||||
try {
|
try {
|
||||||
byte[] der = Decoders.BASE64.decode(s); //RFC requires Base64, not Base64Url
|
der = Decoders.BASE64.decode(s); //RFC requires Base64, not Base64Url
|
||||||
CertificateFactory cf = newCertificateFactory();
|
return toCert(der, null);
|
||||||
InputStream stream = new ByteArrayInputStream(der);
|
} catch (final Throwable t) {
|
||||||
return (X509Certificate) cf.generateCertificate(stream);
|
|
||||||
} catch (Exception e) {
|
// Some JDK implementations don't support RSASSA-PSS certificates:
|
||||||
String msg = "Unable to convert Base64 String '" + s + "' to X509Certificate instance. Cause: " + e.getMessage();
|
//
|
||||||
throw new IllegalArgumentException(msg, e);
|
// 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,11 +17,15 @@ package io.jsonwebtoken.impl.security;
|
||||||
|
|
||||||
import io.jsonwebtoken.impl.lang.Bytes;
|
import io.jsonwebtoken.impl.lang.Bytes;
|
||||||
import io.jsonwebtoken.lang.Assert;
|
import io.jsonwebtoken.lang.Assert;
|
||||||
|
import io.jsonwebtoken.lang.Strings;
|
||||||
import io.jsonwebtoken.security.Password;
|
import io.jsonwebtoken.security.Password;
|
||||||
import io.jsonwebtoken.security.UnsupportedKeyException;
|
import io.jsonwebtoken.security.UnsupportedKeyException;
|
||||||
|
|
||||||
|
import javax.crypto.SecretKey;
|
||||||
import java.security.Key;
|
import java.security.Key;
|
||||||
import java.security.PublicKey;
|
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
|
@SuppressWarnings({"unused"}) // reflection bridge class for the io.jsonwebtoken.security.Keys implementation
|
||||||
public final class KeysBridge {
|
public final class KeysBridge {
|
||||||
|
@ -34,6 +38,20 @@ public final class KeysBridge {
|
||||||
return new PasswordSpec(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.
|
||||||
|
*
|
||||||
|
* <p>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.</p>
|
||||||
|
*
|
||||||
|
* @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) {
|
public static byte[] findEncoded(Key key) {
|
||||||
Assert.notNull(key, "Key cannot be null.");
|
Assert.notNull(key, "Key cannot be null.");
|
||||||
byte[] encoded = null;
|
byte[] encoded = null;
|
||||||
|
@ -44,6 +62,40 @@ public final class KeysBridge {
|
||||||
return encoded;
|
return encoded;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the specified key's key length (in bits) if possible, or {@code -1} if unable to determine the length.
|
||||||
|
*
|
||||||
|
* <p>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.</p>
|
||||||
|
*
|
||||||
|
* @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) {
|
public static byte[] getEncoded(Key key) {
|
||||||
Assert.notNull(key, "Key cannot be null.");
|
Assert.notNull(key, "Key cannot be null.");
|
||||||
byte[] encoded = findEncoded(key);
|
byte[] encoded = findEncoded(key);
|
||||||
|
|
|
@ -23,10 +23,15 @@ import io.jsonwebtoken.security.VerifySecureDigestRequest;
|
||||||
|
|
||||||
import java.security.Key;
|
import java.security.Key;
|
||||||
|
|
||||||
public class NoneSignatureAlgorithm implements SecureDigestAlgorithm<Key, Key> {
|
final class NoneSignatureAlgorithm implements SecureDigestAlgorithm<Key, Key> {
|
||||||
|
|
||||||
private static final String ID = "none";
|
private static final String ID = "none";
|
||||||
|
|
||||||
|
static final SecureDigestAlgorithm<Key, Key> INSTANCE = new NoneSignatureAlgorithm();
|
||||||
|
|
||||||
|
private NoneSignatureAlgorithm() {
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getId() {
|
public String getId() {
|
||||||
return ID;
|
return ID;
|
||||||
|
|
|
@ -196,7 +196,7 @@ class RsaPrivateJwkFactory extends AbstractFamilyJwkFactory<RSAPrivateKey, RsaPr
|
||||||
if (ctx.containsKey(DefaultRsaPrivateJwk.OTHER_PRIMES_INFO.getId())) {
|
if (ctx.containsKey(DefaultRsaPrivateJwk.OTHER_PRIMES_INFO.getId())) {
|
||||||
List<RSAOtherPrimeInfo> otherPrimes = reader.get(DefaultRsaPrivateJwk.OTHER_PRIMES_INFO);
|
List<RSAOtherPrimeInfo> otherPrimes = reader.get(DefaultRsaPrivateJwk.OTHER_PRIMES_INFO);
|
||||||
RSAOtherPrimeInfo[] arr = new RSAOtherPrimeInfo[Collections.size(otherPrimes)];
|
RSAOtherPrimeInfo[] arr = new RSAOtherPrimeInfo[Collections.size(otherPrimes)];
|
||||||
otherPrimes.toArray(arr);
|
arr = otherPrimes.toArray(arr);
|
||||||
spec = new RSAMultiPrimePrivateCrtKeySpec(modulus, publicExponent, privateExponent, firstPrime,
|
spec = new RSAMultiPrimePrivateCrtKeySpec(modulus, publicExponent, privateExponent, firstPrime,
|
||||||
secondPrime, firstCrtExponent, secondCrtExponent, firstCrtCoefficient, arr);
|
secondPrime, firstCrtExponent, secondCrtExponent, firstCrtCoefficient, arr);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -18,9 +18,12 @@ package io.jsonwebtoken.impl.security;
|
||||||
import io.jsonwebtoken.impl.lang.CheckedFunction;
|
import io.jsonwebtoken.impl.lang.CheckedFunction;
|
||||||
import io.jsonwebtoken.impl.lang.CheckedSupplier;
|
import io.jsonwebtoken.impl.lang.CheckedSupplier;
|
||||||
import io.jsonwebtoken.impl.lang.Conditions;
|
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.KeyPairBuilder;
|
||||||
import io.jsonwebtoken.security.SecureRequest;
|
import io.jsonwebtoken.security.SecureRequest;
|
||||||
|
import io.jsonwebtoken.security.SignatureAlgorithm;
|
||||||
import io.jsonwebtoken.security.VerifySecureDigestRequest;
|
import io.jsonwebtoken.security.VerifySecureDigestRequest;
|
||||||
import io.jsonwebtoken.security.WeakKeyException;
|
import io.jsonwebtoken.security.WeakKeyException;
|
||||||
|
|
||||||
|
@ -32,43 +35,78 @@ import java.security.interfaces.RSAKey;
|
||||||
import java.security.spec.AlgorithmParameterSpec;
|
import java.security.spec.AlgorithmParameterSpec;
|
||||||
import java.security.spec.MGF1ParameterSpec;
|
import java.security.spec.MGF1ParameterSpec;
|
||||||
import java.security.spec.PSSParameterSpec;
|
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
|
* @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<String> 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 final int MIN_KEY_BIT_LENGTH = 2048;
|
||||||
|
|
||||||
private static AlgorithmParameterSpec pssParamFromSaltBitLength(int saltBitLength) {
|
private static AlgorithmParameterSpec pssParamSpec(int digestBitLength) {
|
||||||
MGF1ParameterSpec ps = new MGF1ParameterSpec("SHA-" + saltBitLength);
|
MGF1ParameterSpec ps = new MGF1ParameterSpec("SHA-" + digestBitLength);
|
||||||
int saltByteLength = saltBitLength / Byte.SIZE;
|
int saltByteLength = digestBitLength / Byte.SIZE;
|
||||||
return new PSSParameterSpec(ps.getDigestAlgorithm(), "MGF1", ps, saltByteLength, 1);
|
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<String, SignatureAlgorithm> 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 int preferredKeyBitLength;
|
||||||
|
|
||||||
private final AlgorithmParameterSpec algorithmParameterSpec;
|
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);
|
super(name, jcaName);
|
||||||
if (preferredKeyBitLength < MIN_KEY_BIT_LENGTH) {
|
this.preferredKeyBitLength = digestBitLength * Byte.SIZE; // RSA invariant
|
||||||
String msg = "preferredKeyBitLength must be greater than the JWA mandatory minimum key length of " +
|
// invariant since this is a protected constructor:
|
||||||
MIN_KEY_BIT_LENGTH;
|
Assert.state(this.preferredKeyBitLength >= MIN_KEY_BIT_LENGTH);
|
||||||
throw new IllegalArgumentException(msg);
|
this.algorithmParameterSpec = paramSpec;
|
||||||
}
|
|
||||||
this.preferredKeyBitLength = preferredKeyBitLength;
|
|
||||||
this.algorithmParameterSpec = algParam;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public RsaSignatureAlgorithm(int digestBitLength, int preferredKeyBitLength) {
|
private RsaSignatureAlgorithm(int digestBitLength) {
|
||||||
this("RS" + digestBitLength, "SHA" + digestBitLength + "withRSA", preferredKeyBitLength, null);
|
this("RS" + digestBitLength, "SHA" + digestBitLength + "withRSA", digestBitLength, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public RsaSignatureAlgorithm(int digestBitLength, int preferredKeyBitLength, int pssSaltBitLength) {
|
// RSASSA-PSS constructor
|
||||||
this("PS" + digestBitLength, PSS_JCA_NAME, preferredKeyBitLength, pssParamFromSaltBitLength(pssSaltBitLength));
|
private RsaSignatureAlgorithm(int digestBitLength, AlgorithmParameterSpec paramSpec) {
|
||||||
// PSS is not available natively until JDK 11, so try to load BC as a backup provider if possible on <= JDK 10:
|
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<Signature>() {
|
setProvider(Providers.findBouncyCastle(Conditions.notExists(new CheckedSupplier<Signature>() {
|
||||||
@Override
|
@Override
|
||||||
public Signature get() throws Exception {
|
public Signature get() throws Exception {
|
||||||
|
@ -77,23 +115,73 @@ public class RsaSignatureAlgorithm extends AbstractSignatureAlgorithm {
|
||||||
})));
|
})));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
@Override
|
||||||
public KeyPairBuilder keyPair() {
|
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())
|
.provider(getProvider())
|
||||||
.random(Randoms.secureRandom());
|
.random(Randoms.secureRandom());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void validateKey(Key key, boolean signing) {
|
protected void validateKey(Key key, boolean signing) {
|
||||||
|
super.validateKey(key, signing);
|
||||||
// https://github.com/jwtk/jjwt/issues/68
|
// 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Some PKCS11 providers and HSMs won't expose the RSAKey interface, so we have to check to see if we can cast
|
// 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 so, we can provide additional safety checks:
|
||||||
if (key instanceof RSAKey) {
|
if (key instanceof RSAKey) {
|
||||||
|
@ -105,8 +193,8 @@ public class RsaSignatureAlgorithm extends AbstractSignatureAlgorithm {
|
||||||
String msg = "The " + keyType(signing) + " key's size is " + size + " bits which is not secure " +
|
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 " +
|
"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. " +
|
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 " +
|
"Consider using the Jwts.SIG." + id + ".keyPair() builder to create a " +
|
||||||
"key pair guaranteed to be secure enough for " + id + ". See " +
|
"KeyPair guaranteed to be secure enough for " + id + ". See " +
|
||||||
"https://tools.ietf.org/html/rfc7518#section-" + section + " for more information.";
|
"https://tools.ietf.org/html/rfc7518#section-" + section + " for more information.";
|
||||||
throw new WeakKeyException(msg);
|
throw new WeakKeyException(msg);
|
||||||
}
|
}
|
||||||
|
@ -130,10 +218,6 @@ public class RsaSignatureAlgorithm extends AbstractSignatureAlgorithm {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean doVerify(final VerifySecureDigestRequest<PublicKey> request) {
|
protected boolean doVerify(final VerifySecureDigestRequest<PublicKey> 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<Signature, Boolean>() {
|
return jca(request).withSignature(new CheckedFunction<Signature, Boolean>() {
|
||||||
@Override
|
@Override
|
||||||
public Boolean apply(Signature sig) throws Exception {
|
public Boolean apply(Signature sig) throws Exception {
|
||||||
|
|
|
@ -22,7 +22,6 @@ import io.jsonwebtoken.impl.lang.RequiredFieldReader;
|
||||||
import io.jsonwebtoken.io.Encoders;
|
import io.jsonwebtoken.io.Encoders;
|
||||||
import io.jsonwebtoken.lang.Arrays;
|
import io.jsonwebtoken.lang.Arrays;
|
||||||
import io.jsonwebtoken.lang.Assert;
|
import io.jsonwebtoken.lang.Assert;
|
||||||
import io.jsonwebtoken.lang.Collections;
|
|
||||||
import io.jsonwebtoken.lang.Strings;
|
import io.jsonwebtoken.lang.Strings;
|
||||||
import io.jsonwebtoken.security.MacAlgorithm;
|
import io.jsonwebtoken.security.MacAlgorithm;
|
||||||
import io.jsonwebtoken.security.MalformedKeyException;
|
import io.jsonwebtoken.security.MalformedKeyException;
|
||||||
|
@ -87,7 +86,12 @@ class SecretJwkFactory extends AbstractFamilyJwkFactory<SecretKey, SecretJwk> {
|
||||||
if (bitLen != requiredBitLen) {
|
if (bitLen != requiredBitLen) {
|
||||||
// Implementors note: Don't print out any information about the `bytes` value itself - size,
|
// Implementors note: Don't print out any information about the `bytes` value itself - size,
|
||||||
// content, etc., as it is considered secret material:
|
// 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);
|
throw new MalformedKeyException(msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -107,21 +111,15 @@ class SecretJwkFactory extends AbstractFamilyJwkFactory<SecretKey, SecretJwk> {
|
||||||
assertKeyBitLength(bytes, (MacAlgorithm) alg);
|
assertKeyBitLength(bytes, (MacAlgorithm) alg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!Strings.hasText(jcaName) &&
|
if (!Strings.hasText(jcaName)) {
|
||||||
("sig".equalsIgnoreCase(ctx.getPublicKeyUse()) || // [1]
|
if (ctx.isSigUse()) {
|
||||||
(!Collections.isEmpty(ctx.getOperations()) && ctx.getOperations().contains("sign")))) { // [2]
|
// The only JWA SecretKey signature algorithms are HS256, HS384, HS512, so choose based on bit length:
|
||||||
// [1] Even though 'use' is for PUBLIC KEY use (as defined in RFC 7515), RFC 7520 shows secret keys with
|
jcaName = "HmacSHA" + Bytes.bitLength(bytes);
|
||||||
// 'use' values, so we'll account for that as well
|
} else { // not an HS* algorithm, and all standard AeadAlgorithms use AES keys:
|
||||||
//
|
jcaName = AesAlgorithm.KEY_ALG_NAME;
|
||||||
// [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:
|
Assert.stateNotNull(jcaName, "jcaName cannot be null (invariant)");
|
||||||
jcaName = AesAlgorithm.KEY_ALG_NAME;
|
|
||||||
}
|
|
||||||
|
|
||||||
SecretKey key = new SecretKeySpec(bytes, jcaName);
|
SecretKey key = new SecretKeySpec(bytes, jcaName);
|
||||||
ctx.setKey(key);
|
ctx.setKey(key);
|
||||||
return new DefaultSecretJwk(ctx);
|
return new DefaultSecretJwk(ctx);
|
||||||
|
|
|
@ -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<String, Curve> {
|
||||||
|
public StandardCurves() {
|
||||||
|
super(new IdRegistry<>("Elliptic Curve", Curves.VALUES, false));
|
||||||
|
}
|
||||||
|
}
|
|
@ -18,51 +18,57 @@ package io.jsonwebtoken.impl.security;
|
||||||
import io.jsonwebtoken.impl.lang.DelegatingRegistry;
|
import io.jsonwebtoken.impl.lang.DelegatingRegistry;
|
||||||
import io.jsonwebtoken.impl.lang.IdRegistry;
|
import io.jsonwebtoken.impl.lang.IdRegistry;
|
||||||
import io.jsonwebtoken.lang.Collections;
|
import io.jsonwebtoken.lang.Collections;
|
||||||
|
import io.jsonwebtoken.security.Password;
|
||||||
import io.jsonwebtoken.security.SecureDigestAlgorithm;
|
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
|
@SuppressWarnings("unused") // used via reflection in io.jsonwebtoken.Jwts.SIG
|
||||||
public final class StandardSecureDigestAlgorithms extends DelegatingRegistry<String, SecureDigestAlgorithm<?, ?>> {
|
public final class StandardSecureDigestAlgorithms extends DelegatingRegistry<String, SecureDigestAlgorithm<?, ?>> {
|
||||||
|
|
||||||
private static final EdSignatureAlgorithm Ed25519 = new EdSignatureAlgorithm(EdwardsCurve.Ed25519);
|
|
||||||
private static final EdSignatureAlgorithm Ed448 = new EdSignatureAlgorithm(EdwardsCurve.Ed448);
|
|
||||||
|
|
||||||
public StandardSecureDigestAlgorithms() {
|
public StandardSecureDigestAlgorithms() {
|
||||||
super(new IdRegistry<>("JWS Digital Signature or MAC", Collections.of(
|
super(new IdRegistry<>("JWS Digital Signature or MAC", Collections.of(
|
||||||
new NoneSignatureAlgorithm(),
|
NoneSignatureAlgorithm.INSTANCE,
|
||||||
new DefaultMacAlgorithm(256),
|
DefaultMacAlgorithm.HS256,
|
||||||
new DefaultMacAlgorithm(384),
|
DefaultMacAlgorithm.HS384,
|
||||||
new DefaultMacAlgorithm(512),
|
DefaultMacAlgorithm.HS512,
|
||||||
new RsaSignatureAlgorithm(256, 2048),
|
RsaSignatureAlgorithm.RS256,
|
||||||
new RsaSignatureAlgorithm(384, 3072),
|
RsaSignatureAlgorithm.RS384,
|
||||||
new RsaSignatureAlgorithm(512, 4096),
|
RsaSignatureAlgorithm.RS512,
|
||||||
new RsaSignatureAlgorithm(256, 2048, 256),
|
RsaSignatureAlgorithm.PS256,
|
||||||
new RsaSignatureAlgorithm(384, 3072, 384),
|
RsaSignatureAlgorithm.PS384,
|
||||||
new RsaSignatureAlgorithm(512, 4096, 512),
|
RsaSignatureAlgorithm.PS512,
|
||||||
new EcSignatureAlgorithm(256),
|
EcSignatureAlgorithm.ES256,
|
||||||
new EcSignatureAlgorithm(384),
|
EcSignatureAlgorithm.ES384,
|
||||||
new EcSignatureAlgorithm(521),
|
EcSignatureAlgorithm.ES512,
|
||||||
new EdSignatureAlgorithm()
|
EdSignatureAlgorithm.INSTANCE
|
||||||
), false));
|
), false));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@SuppressWarnings("unchecked")
|
||||||
public SecureDigestAlgorithm<?, ?> get(Object id) {
|
public static <K extends Key> SecureDigestAlgorithm<K, ?> findBySigningKey(K key) {
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
SecureDigestAlgorithm<?, ?> alg = null; // null value means no suitable match
|
||||||
public SecureDigestAlgorithm<?, ?> forKey(String id) throws IllegalArgumentException {
|
|
||||||
if (EdwardsCurve.Ed448.getId().equalsIgnoreCase(id)) {
|
if (key instanceof SecretKey && !(key instanceof Password)) {
|
||||||
return Ed448;
|
|
||||||
} else if (EdwardsCurve.Ed25519.getId().equalsIgnoreCase(id)) {
|
alg = DefaultMacAlgorithm.findByKey(key);
|
||||||
return Ed25519;
|
|
||||||
|
} 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<K, ?>) alg;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
|
@ -36,6 +36,8 @@ import java.security.Key
|
||||||
import java.security.KeyPair
|
import java.security.KeyPair
|
||||||
import java.security.PrivateKey
|
import java.security.PrivateKey
|
||||||
import java.security.PublicKey
|
import java.security.PublicKey
|
||||||
|
import java.security.interfaces.ECPublicKey
|
||||||
|
import java.security.interfaces.RSAPublicKey
|
||||||
|
|
||||||
import static org.junit.Assert.*
|
import static org.junit.Assert.*
|
||||||
|
|
||||||
|
@ -614,21 +616,6 @@ class JwtsTest {
|
||||||
testRsa(Jwts.SIG.PS512)
|
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
|
@Test
|
||||||
void testES256() {
|
void testES256() {
|
||||||
testEC(Jwts.SIG.ES256)
|
testEC(Jwts.SIG.ES256)
|
||||||
|
@ -651,12 +638,12 @@ class JwtsTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testEd25519() {
|
void testEd25519() {
|
||||||
testEC(Jwts.SIG.Ed25519)
|
testEC(Jwts.SIG.EdDSA, TestKeys.forAlgorithm(Jwks.CRV.Ed25519).pair)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testEd448() {
|
void testEd448() {
|
||||||
testEC(Jwts.SIG.Ed448)
|
testEC(Jwts.SIG.EdDSA, TestKeys.forAlgorithm(Jwks.CRV.Ed448).pair)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -1211,16 +1198,20 @@ class JwtsTest {
|
||||||
// Now for the forgery: simulate an attacker using the RSA public key to sign a token, but
|
// 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:
|
// using it as an HMAC signing key instead of RSA:
|
||||||
Mac mac = Mac.getInstance('HmacSHA256')
|
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')))
|
byte[] signatureBytes = mac.doFinal(compact.getBytes(Charset.forName('US-ASCII')))
|
||||||
String encodedSignature = Encoders.BASE64URL.encode(signatureBytes)
|
String encodedSignature = Encoders.BASE64URL.encode(signatureBytes)
|
||||||
|
|
||||||
//Finally, the forged token is the header + body + forged signature:
|
//Finally, the forged token is the header + body + forged signature:
|
||||||
String forged = compact + encodedSignature
|
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 {
|
try {
|
||||||
Jwts.parser().setSigningKey(privateKey).build().parse(forged)
|
Jwts.parser().verifyWith(privateKey).build().parse(forged)
|
||||||
fail("Forged token must not be successfully parsed.")
|
fail("Forged token must not be successfully parsed.")
|
||||||
} catch (UnsupportedJwtException expected) {
|
} catch (UnsupportedJwtException expected) {
|
||||||
assertTrue expected.getMessage().startsWith('The parsed JWT indicates it was signed with the')
|
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
|
// 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:
|
// using it as an HMAC signing key instead of RSA:
|
||||||
Mac mac = Mac.getInstance('HmacSHA256')
|
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')))
|
byte[] signatureBytes = mac.doFinal(compact.getBytes(Charset.forName('US-ASCII')))
|
||||||
String encodedSignature = Encoders.BASE64URL.encode(signatureBytes)
|
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
|
// 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:
|
// using it as an HMAC signing key instead of Elliptic Curve:
|
||||||
Mac mac = Mac.getInstance('HmacSHA256')
|
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')))
|
byte[] signatureBytes = mac.doFinal(compact.getBytes(Charset.forName('US-ASCII')))
|
||||||
String encodedSignature = Encoders.BASE64URL.encode(signatureBytes)
|
String encodedSignature = Encoders.BASE64URL.encode(signatureBytes)
|
||||||
|
|
||||||
|
@ -1566,7 +1565,7 @@ class JwtsTest {
|
||||||
return Jwts.parser().decryptWith(key).build().parseClaimsJwe(jwe)
|
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
|
KeyPair kp = TestKeys.forAlgorithm(alg).pair
|
||||||
PublicKey publicKey = kp.getPublic()
|
PublicKey publicKey = kp.getPublic()
|
||||||
|
@ -1576,12 +1575,7 @@ class JwtsTest {
|
||||||
|
|
||||||
String jwt = Jwts.builder().claims().add(claims).and().signWith(privateKey, alg).compact()
|
String jwt = Jwts.builder().claims().add(claims).and().signWith(privateKey, alg).compact()
|
||||||
|
|
||||||
def key = publicKey
|
def token = Jwts.parser().verifyWith(publicKey).build().parse(jwt)
|
||||||
if (verifyWithPrivateKey) {
|
|
||||||
key = privateKey
|
|
||||||
}
|
|
||||||
|
|
||||||
def token = Jwts.parser().verifyWith(key).build().parse(jwt)
|
|
||||||
|
|
||||||
assertEquals([alg: alg.getId()], token.header)
|
assertEquals([alg: alg.getId()], token.header)
|
||||||
assertEquals(claims, token.payload)
|
assertEquals(claims, token.payload)
|
||||||
|
@ -1603,8 +1597,11 @@ class JwtsTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void testEC(io.jsonwebtoken.security.SignatureAlgorithm alg, boolean verifyWithPrivateKey = false) {
|
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()
|
PublicKey publicKey = pair.getPublic()
|
||||||
PrivateKey privateKey = pair.getPrivate()
|
PrivateKey privateKey = pair.getPrivate()
|
||||||
|
|
||||||
|
@ -1621,6 +1618,7 @@ class JwtsTest {
|
||||||
|
|
||||||
assertEquals([alg: alg.getId()], token.header)
|
assertEquals([alg: alg.getId()], token.header)
|
||||||
assertEquals(claims, token.payload)
|
assertEquals(claims, token.payload)
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,14 +21,15 @@ import io.jsonwebtoken.Jwts
|
||||||
import io.jsonwebtoken.SignatureAlgorithm
|
import io.jsonwebtoken.SignatureAlgorithm
|
||||||
import io.jsonwebtoken.impl.lang.Services
|
import io.jsonwebtoken.impl.lang.Services
|
||||||
import io.jsonwebtoken.impl.security.Randoms
|
import io.jsonwebtoken.impl.security.Randoms
|
||||||
|
import io.jsonwebtoken.impl.security.TestKey
|
||||||
import io.jsonwebtoken.impl.security.TestKeys
|
import io.jsonwebtoken.impl.security.TestKeys
|
||||||
import io.jsonwebtoken.io.*
|
import io.jsonwebtoken.io.*
|
||||||
import io.jsonwebtoken.security.*
|
import io.jsonwebtoken.security.*
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
|
||||||
import javax.crypto.KeyGenerator
|
|
||||||
import java.nio.charset.StandardCharsets
|
import java.nio.charset.StandardCharsets
|
||||||
|
import java.security.MessageDigest
|
||||||
import java.security.Provider
|
import java.security.Provider
|
||||||
import java.security.SecureRandom
|
import java.security.SecureRandom
|
||||||
|
|
||||||
|
@ -314,20 +315,56 @@ class DefaultJwtBuilderTest {
|
||||||
@Test
|
@Test
|
||||||
void testSignWithKeyOnly() {
|
void testSignWithKeyOnly() {
|
||||||
|
|
||||||
def b = new DefaultJwtBuilder()
|
builder.subject("Joe") // make Claims JWS
|
||||||
b.header().keyId('a')
|
|
||||||
b.setPayload('foo')
|
|
||||||
|
|
||||||
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)
|
def parser = Jwts.parser().verifyWith(vkey).build()
|
||||||
String s1 = b.compact()
|
|
||||||
|
|
||||||
//ensure matches same result with specified algorithm:
|
String s1 = builder.signWith(key).compact()
|
||||||
b.signWith(key, SignatureAlgorithm.HS256)
|
def jws = parser.parseClaimsJws(s1)
|
||||||
String s2 = b.compact()
|
|
||||||
|
|
||||||
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
|
@Test
|
||||||
|
@ -337,7 +374,8 @@ class DefaultJwtBuilderTest {
|
||||||
new DefaultJwtBuilder().signWith(SignatureAlgorithm.ES256, bytes);
|
new DefaultJwtBuilder().signWith(SignatureAlgorithm.ES256, bytes);
|
||||||
fail()
|
fail()
|
||||||
} catch (IllegalArgumentException iae) {
|
} 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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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 {
|
static class TestCompressionCodec implements CompressionCodec {
|
||||||
|
|
||||||
String id
|
String id
|
||||||
|
|
|
@ -26,6 +26,7 @@ import org.junit.Test
|
||||||
|
|
||||||
import java.nio.charset.StandardCharsets
|
import java.nio.charset.StandardCharsets
|
||||||
import java.security.Key
|
import java.security.Key
|
||||||
|
import java.security.Provider
|
||||||
|
|
||||||
import static org.junit.Assert.*
|
import static org.junit.Assert.*
|
||||||
|
|
||||||
|
@ -35,12 +36,8 @@ class DefaultJwkParserTest {
|
||||||
void testKeys() {
|
void testKeys() {
|
||||||
|
|
||||||
Set<Key> keys = new LinkedHashSet<>()
|
Set<Key> keys = new LinkedHashSet<>()
|
||||||
TestKeys.HS.each { keys.add(it) }
|
TestKeys.SECRET.each { keys.add(it) }
|
||||||
TestKeys.RSA.each {
|
TestKeys.ASYM.each {
|
||||||
keys.add(it.pair.public)
|
|
||||||
keys.add(it.pair.private)
|
|
||||||
}
|
|
||||||
TestKeys.EC.each {
|
|
||||||
keys.add(it.pair.public)
|
keys.add(it.pair.public)
|
||||||
keys.add(it.pair.private)
|
keys.add(it.pair.private)
|
||||||
}
|
}
|
||||||
|
@ -48,7 +45,13 @@ class DefaultJwkParserTest {
|
||||||
def serializer = Services.loadFirst(Serializer)
|
def serializer = Services.loadFirst(Serializer)
|
||||||
for (Key key : keys) {
|
for (Key key : keys) {
|
||||||
//noinspection GroovyAssignabilityCheck
|
//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)
|
def data = serializer.serialize(jwk)
|
||||||
String json = new String(data, StandardCharsets.UTF_8)
|
String json = new String(data, StandardCharsets.UTF_8)
|
||||||
def parsed = Jwks.parser().build().parse(json)
|
def parsed = Jwks.parser().build().parse(json)
|
||||||
|
@ -61,29 +64,37 @@ class DefaultJwkParserTest {
|
||||||
|
|
||||||
Set<Key> keys = new LinkedHashSet<>()
|
Set<Key> keys = new LinkedHashSet<>()
|
||||||
TestKeys.HS.each { keys.add(it) }
|
TestKeys.HS.each { keys.add(it) }
|
||||||
TestKeys.RSA.each {
|
TestKeys.ASYM.each {
|
||||||
keys.add(it.pair.public)
|
|
||||||
keys.add(it.pair.private)
|
|
||||||
}
|
|
||||||
TestKeys.EC.each {
|
|
||||||
keys.add(it.pair.public)
|
keys.add(it.pair.public)
|
||||||
keys.add(it.pair.private)
|
keys.add(it.pair.private)
|
||||||
}
|
}
|
||||||
|
|
||||||
def serializer = Services.loadFirst(Serializer)
|
def serializer = Services.loadFirst(Serializer)
|
||||||
def provider = Providers.findBouncyCastle(Conditions.TRUE)
|
def provider = Providers.findBouncyCastle(Conditions.TRUE) //always used
|
||||||
|
|
||||||
for (Key key : keys) {
|
for (Key key : keys) {
|
||||||
//noinspection GroovyAssignabilityCheck
|
//noinspection GroovyAssignabilityCheck
|
||||||
def jwk = Jwks.builder().key(key).build()
|
def jwk = Jwks.builder().provider(provider).key(key).build()
|
||||||
def data = serializer.serialize(jwk)
|
def data = serializer.serialize(jwk)
|
||||||
String json = new String(data, StandardCharsets.UTF_8)
|
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
|
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
|
@Test
|
||||||
void testDeserializationFailure() {
|
void testDeserializationFailure() {
|
||||||
def parser = new DefaultJwkParser(null, Services.loadFirst(Deserializer)) {
|
def parser = new DefaultJwkParser(null, Services.loadFirst(Deserializer)) {
|
||||||
|
|
|
@ -22,7 +22,7 @@ import javax.crypto.spec.SecretKeySpec
|
||||||
import java.nio.charset.StandardCharsets
|
import java.nio.charset.StandardCharsets
|
||||||
import java.security.Key
|
import java.security.Key
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals
|
import static org.junit.Assert.*
|
||||||
|
|
||||||
class DefaultMacAlgorithmTest {
|
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()
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
package io.jsonwebtoken.impl.security
|
package io.jsonwebtoken.impl.security
|
||||||
|
|
||||||
import io.jsonwebtoken.Jwts
|
import io.jsonwebtoken.Jwts
|
||||||
|
import io.jsonwebtoken.security.UnsupportedKeyException
|
||||||
import io.jsonwebtoken.security.WeakKeyException
|
import io.jsonwebtoken.security.WeakKeyException
|
||||||
import org.junit.Test
|
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
|
@Test
|
||||||
void testWeakEncryptionKey() {
|
void testWeakEncryptionKey() {
|
||||||
for (DefaultRsaKeyAlgorithm alg : algs) {
|
for (DefaultRsaKeyAlgorithm alg : algs) {
|
||||||
RSAPublicKey key = createMock(RSAPublicKey)
|
RSAPublicKey key = createMock(RSAPublicKey)
|
||||||
|
expect(key.getAlgorithm()).andReturn("RSA")
|
||||||
expect(key.getModulus()).andReturn(BigInteger.ONE)
|
expect(key.getModulus()).andReturn(BigInteger.ONE)
|
||||||
replay(key)
|
replay(key)
|
||||||
try {
|
try {
|
||||||
|
@ -65,6 +99,7 @@ class DefaultRsaKeyAlgorithmTest {
|
||||||
void testWeakDecryptionKey() {
|
void testWeakDecryptionKey() {
|
||||||
for (DefaultRsaKeyAlgorithm alg : algs) {
|
for (DefaultRsaKeyAlgorithm alg : algs) {
|
||||||
RSAPrivateKey key = createMock(RSAPrivateKey)
|
RSAPrivateKey key = createMock(RSAPrivateKey)
|
||||||
|
expect(key.getAlgorithm()).andReturn("RSA")
|
||||||
expect(key.getModulus()).andReturn(BigInteger.ONE)
|
expect(key.getModulus()).andReturn(BigInteger.ONE)
|
||||||
replay(key)
|
replay(key)
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -48,16 +48,44 @@ class EcSignatureAlgorithmTest {
|
||||||
@Test
|
@Test
|
||||||
void testConstructorWithWeakKeyLength() {
|
void testConstructorWithWeakKeyLength() {
|
||||||
try {
|
try {
|
||||||
new EcSignatureAlgorithm(128)
|
new EcSignatureAlgorithm(128, 'foo')
|
||||||
} catch (IllegalArgumentException iae) {
|
} catch (IllegalArgumentException iae) {
|
||||||
String msg = 'orderBitLength must equal 256, 384, or 521.'
|
String msg = 'orderBitLength must equal 256, 384, or 521.'
|
||||||
assertEquals msg, iae.getMessage()
|
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
|
@Test
|
||||||
void testValidateKeyWithoutEcKey() {
|
void testValidateKeyWithoutEcKey() {
|
||||||
def key = createMock(PublicKey)
|
PublicKey key = createMock(PublicKey)
|
||||||
replay key
|
replay key
|
||||||
algs().each {
|
algs().each {
|
||||||
it.validateKey(key, false)
|
it.validateKey(key, false)
|
||||||
|
@ -68,7 +96,7 @@ class EcSignatureAlgorithmTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testIsValidRAndSWithoutEcKey() {
|
void testIsValidRAndSWithoutEcKey() {
|
||||||
def key = createMock(PublicKey)
|
PublicKey key = createMock(PublicKey)
|
||||||
replay key
|
replay key
|
||||||
algs().each {
|
algs().each {
|
||||||
it.isValidRAndS(key, Bytes.EMPTY)
|
it.isValidRAndS(key, Bytes.EMPTY)
|
||||||
|
|
|
@ -17,7 +17,6 @@ package io.jsonwebtoken.impl.security
|
||||||
|
|
||||||
import io.jsonwebtoken.Jwts
|
import io.jsonwebtoken.Jwts
|
||||||
import io.jsonwebtoken.UnsupportedJwtException
|
import io.jsonwebtoken.UnsupportedJwtException
|
||||||
import io.jsonwebtoken.security.SignatureAlgorithm
|
|
||||||
import io.jsonwebtoken.security.SignatureException
|
import io.jsonwebtoken.security.SignatureException
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
|
||||||
|
@ -28,41 +27,30 @@ import static org.junit.Assert.*
|
||||||
|
|
||||||
class EdSignatureAlgorithmTest {
|
class EdSignatureAlgorithmTest {
|
||||||
|
|
||||||
static List<EdSignatureAlgorithm> algs = [Jwts.SIG.EdDSA, Jwts.SIG.Ed25519, Jwts.SIG.Ed448] as List<EdSignatureAlgorithm>
|
static EdSignatureAlgorithm alg = Jwts.SIG.EdDSA as EdSignatureAlgorithm
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testJcaName() {
|
void testJcaName() {
|
||||||
assertEquals Jwts.SIG.EdDSA.getId(), Jwts.SIG.EdDSA.getJcaName()
|
// the JWT RFC id and the JDK standard name appen to be the same:
|
||||||
assertEquals EdwardsCurve.Ed25519.getId(), Jwts.SIG.Ed25519.getJcaName()
|
assertEquals alg.getId(), alg.getJcaName()
|
||||||
assertEquals EdwardsCurve.Ed448.getId(), Jwts.SIG.Ed448.getJcaName()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testId() {
|
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:
|
||||||
// https://www.rfc-editor.org/rfc/rfc8037#section-3.1 and
|
assertEquals 'EdDSA', alg.getId()
|
||||||
// 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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testKeyPairBuilder() {
|
void testKeyPairBuilder() {
|
||||||
algs.each {
|
def pair = alg.keyPair().build()
|
||||||
def pair = it.keyPair().build()
|
assertNotNull pair.public
|
||||||
assertNotNull pair.public
|
assertTrue pair.public instanceof PublicKey
|
||||||
assertTrue pair.public instanceof PublicKey
|
String algName = pair.public.getAlgorithm()
|
||||||
String alg = pair.public.getAlgorithm()
|
assertTrue alg.getId().equals(algName) || algName.equals(alg.preferredCurve.getId())
|
||||||
assertTrue Jwts.SIG.EdDSA.getId().equals(alg) || alg.equals(it.preferredCurve.getId())
|
|
||||||
|
|
||||||
alg = pair.private.getAlgorithm()
|
algName = pair.private.getAlgorithm()
|
||||||
assertTrue Jwts.SIG.EdDSA.getId().equals(alg) || alg.equals(it.preferredCurve.getId())
|
assertTrue alg.getId().equals(algName) || algName.equals(alg.preferredCurve.getId())
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -71,46 +59,44 @@ class EdSignatureAlgorithmTest {
|
||||||
@Test
|
@Test
|
||||||
void testGetAlgorithmJcaNameWhenCantFindCurve() {
|
void testGetAlgorithmJcaNameWhenCantFindCurve() {
|
||||||
def key = new TestKey(algorithm: 'foo')
|
def key = new TestKey(algorithm: 'foo')
|
||||||
algs.each {
|
def payload = [0x00] as byte[]
|
||||||
def payload = [0x00] as byte[]
|
def req = new DefaultSecureRequest(payload, null, null, key)
|
||||||
def req = new DefaultSecureRequest(payload, null , null, key)
|
assertEquals alg.getJcaName(), alg.getJcaName(req)
|
||||||
assertEquals it.getJcaName(), it.getJcaName(req)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testEd25519SigVerifyWithEd448() {
|
void testEd25519SigVerifyWithEd448() {
|
||||||
testIncorrectVerificationKey(Jwts.SIG.Ed25519, TestKeys.Ed25519.pair.private, TestKeys.Ed448.pair.public)
|
testIncorrectVerificationKey(TestKeys.Ed25519.pair.private, TestKeys.Ed448.pair.public)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testEd25519SigVerifyWithX25519() {
|
void testEd25519SigVerifyWithX25519() {
|
||||||
testInvalidVerificationKey(Jwts.SIG.Ed25519, TestKeys.Ed25519.pair.private, TestKeys.X25519.pair.public)
|
testInvalidVerificationKey(TestKeys.Ed25519.pair.private, TestKeys.X25519.pair.public)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testEd25519SigVerifyWithX448() {
|
void testEd25519SigVerifyWithX448() {
|
||||||
testInvalidVerificationKey(Jwts.SIG.Ed25519, TestKeys.Ed25519.pair.private, TestKeys.X448.pair.public)
|
testInvalidVerificationKey(TestKeys.Ed25519.pair.private, TestKeys.X448.pair.public)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testEd448SigVerifyWithEd25519() {
|
void testEd448SigVerifyWithEd25519() {
|
||||||
testIncorrectVerificationKey(Jwts.SIG.Ed448, TestKeys.Ed448.pair.private, TestKeys.Ed25519.pair.public)
|
testIncorrectVerificationKey(TestKeys.Ed448.pair.private, TestKeys.Ed25519.pair.public)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testEd448SigVerifyWithX25519() {
|
void testEd448SigVerifyWithX25519() {
|
||||||
testInvalidVerificationKey(Jwts.SIG.Ed448, TestKeys.Ed448.pair.private, TestKeys.X25519.pair.public)
|
testInvalidVerificationKey(TestKeys.Ed448.pair.private, TestKeys.X25519.pair.public)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testEd448SigVerifyWithX448() {
|
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 {
|
try {
|
||||||
testSig(alg, priv, pub)
|
testSig(priv, pub)
|
||||||
fail()
|
fail()
|
||||||
} catch (SignatureException expected) {
|
} catch (SignatureException expected) {
|
||||||
// SignatureException message can differ depending on JDK version and if BC is enabled or not:
|
// 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 {
|
try {
|
||||||
testSig(alg, priv, pub)
|
testSig(priv, pub)
|
||||||
fail()
|
fail()
|
||||||
} catch (UnsupportedJwtException expected) {
|
} catch (UnsupportedJwtException expected) {
|
||||||
def cause = expected.getCause()
|
def cause = expected.getCause()
|
||||||
def keyCurve = EdwardsCurve.forKey(pub)
|
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()
|
assertEquals expectedMsg, cause.getMessage()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void testSig(SignatureAlgorithm alg, PrivateKey signing, PublicKey verification) {
|
static void testSig(PrivateKey signing, PublicKey verification) {
|
||||||
String jwt = Jwts.builder().setIssuer('me').setAudience('you').signWith(signing, alg).compact()
|
String jwt = Jwts.builder().issuer('me').audience('you').signWith(signing, alg).compact()
|
||||||
def token = Jwts.parser().verifyWith(verification).build().parseClaimsJws(jwt)
|
def token = Jwts.parser().verifyWith(verification).build().parseClaimsJws(jwt)
|
||||||
assertEquals([alg: alg.getId()], token.header)
|
assertEquals([alg: alg.getId()], token.header)
|
||||||
assertEquals 'me', token.getPayload().getIssuer()
|
assertEquals 'me', token.getPayload().getIssuer()
|
||||||
|
|
|
@ -57,11 +57,6 @@ class EdwardsCurveTest {
|
||||||
assertFalse EdwardsCurve.isEdwards(null)
|
assertFalse EdwardsCurve.isEdwards(null)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
void testFindByNullKey() {
|
|
||||||
assertNull EdwardsCurve.findByKey(null)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testForKeyNonEdwards() {
|
void testForKeyNonEdwards() {
|
||||||
def alg = 'foo'
|
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
|
@Test
|
||||||
void testFindByKeyUsingEncoding() {
|
void testFindByKeyUsingEncoding() {
|
||||||
curves.each {
|
curves.each {
|
||||||
|
|
|
@ -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 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<SignatureAlgorithm, String> JWS_0_10_7_VALUES = [
|
private static Map<SignatureAlgorithm, String> JWS_0_10_7_VALUES = [
|
||||||
(Jwts.SIG.PS256): PS256_0_10_7,
|
(Jwts.SIG.RS256): PS256_0_10_7,
|
||||||
(Jwts.SIG.PS384): PS384_0_10_7,
|
(Jwts.SIG.RS384): PS384_0_10_7,
|
||||||
(Jwts.SIG.PS512): PS512_0_10_7
|
(Jwts.SIG.RS512): PS512_0_10_7
|
||||||
]
|
]
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -50,10 +50,7 @@ class Issue542Test {
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
void testRsaSsaPssBackwardsCompatibility() {
|
void testRsaSsaPssBackwardsCompatibility() {
|
||||||
|
for (alg in JWS_0_10_7_VALUES.keySet()) {
|
||||||
def algs = [Jwts.SIG.PS256, Jwts.SIG.PS384, Jwts.SIG.PS512]
|
|
||||||
|
|
||||||
for (alg in algs) {
|
|
||||||
PublicKey key = TestKeys.forAlgorithm(alg).pair.public
|
PublicKey key = TestKeys.forAlgorithm(alg).pair.public
|
||||||
String jws = JWS_0_10_7_VALUES[alg]
|
String jws = JWS_0_10_7_VALUES[alg]
|
||||||
def token = Jwts.parser().verifyWith(key).build().parseClaimsJws(jws)
|
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.
|
* class. This method implementation was retained only to demonstrate how they were created for future reference.
|
||||||
*/
|
*/
|
||||||
static void main(String[] args) {
|
static void main(String[] args) {
|
||||||
def algs = [Jwts.SIG.PS256, Jwts.SIG.PS384, Jwts.SIG.PS512]
|
for (alg in JWS_0_10_7_VALUES.keySet()) {
|
||||||
for (alg in algs) {
|
|
||||||
PrivateKey privateKey = TestKeys.forAlgorithm(alg).pair.private
|
PrivateKey privateKey = TestKeys.forAlgorithm(alg).pair.private
|
||||||
String jws = Jwts.builder().setIssuer('joe').signWith(privateKey, alg).compact()
|
String jws = Jwts.builder().setIssuer('joe').signWith(privateKey, alg).compact()
|
||||||
println "private static String ${alg.getId()}_0_10_7 = '$jws'"
|
println "private static String ${alg.getId()}_0_10_7 = '$jws'"
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
package io.jsonwebtoken.impl.security
|
package io.jsonwebtoken.impl.security
|
||||||
|
|
||||||
import io.jsonwebtoken.Jwts
|
import io.jsonwebtoken.Jwts
|
||||||
|
import io.jsonwebtoken.impl.lang.Conditions
|
||||||
import io.jsonwebtoken.impl.lang.Converters
|
import io.jsonwebtoken.impl.lang.Converters
|
||||||
import io.jsonwebtoken.io.Decoders
|
import io.jsonwebtoken.io.Decoders
|
||||||
import io.jsonwebtoken.io.Encoders
|
import io.jsonwebtoken.io.Encoders
|
||||||
|
@ -23,10 +24,7 @@ import io.jsonwebtoken.security.*
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
|
||||||
import javax.crypto.SecretKey
|
import javax.crypto.SecretKey
|
||||||
import java.security.MessageDigest
|
import java.security.*
|
||||||
import java.security.PrivateKey
|
|
||||||
import java.security.PublicKey
|
|
||||||
import java.security.SecureRandom
|
|
||||||
import java.security.cert.X509Certificate
|
import java.security.cert.X509Certificate
|
||||||
import java.security.interfaces.ECKey
|
import java.security.interfaces.ECKey
|
||||||
import java.security.interfaces.ECPublicKey
|
import java.security.interfaces.ECPublicKey
|
||||||
|
@ -186,7 +184,7 @@ class JwksTest {
|
||||||
|
|
||||||
for (def alg : algs) {
|
for (def alg : algs) {
|
||||||
//get test cert:
|
//get test cert:
|
||||||
X509Certificate cert = TestCertificates.readTestCertificate(alg)
|
X509Certificate cert = TestKeys.forAlgorithm(alg).cert
|
||||||
def builder = Jwks.builder().chain(Arrays.asList(cert))
|
def builder = Jwks.builder().chain(Arrays.asList(cert))
|
||||||
|
|
||||||
if (number == 1) {
|
if (number == 1) {
|
||||||
|
@ -255,19 +253,26 @@ class JwksTest {
|
||||||
@Test
|
@Test
|
||||||
void testAsymmetricJwks() {
|
void testAsymmetricJwks() {
|
||||||
|
|
||||||
Collection<KeyPairBuilderSupplier> algs = Jwts.SIG.get().values().findAll({ it instanceof SignatureAlgorithm }) as Collection<SignatureAlgorithm>
|
Collection<SignatureAlgorithm> algs = Jwts.SIG.get().values()
|
||||||
|
.findAll({ it instanceof SignatureAlgorithm }) as Collection<SignatureAlgorithm>
|
||||||
|
|
||||||
for (def alg : algs) {
|
for (SignatureAlgorithm alg : algs) {
|
||||||
|
|
||||||
def pair = alg.keyPair().build()
|
def pair = alg.keyPair().build()
|
||||||
PublicKey pub = pair.getPublic()
|
PublicKey pub = pair.getPublic()
|
||||||
PrivateKey priv = pair.getPrivate()
|
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
|
// 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()
|
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) {
|
if (alg instanceof EdSignatureAlgorithm) {
|
||||||
// We haven't implemented EdDSA public-key derivation yet, so public key is required
|
// We haven't implemented EdDSA public-key derivation yet, so public key is required
|
||||||
builder.publicKey(pub)
|
builder.publicKey(pub)
|
||||||
|
@ -282,12 +287,13 @@ class JwksTest {
|
||||||
assertEquals priv, jwkPair.getPrivate()
|
assertEquals priv, jwkPair.getPrivate()
|
||||||
|
|
||||||
// test pair
|
// test pair
|
||||||
|
builder = Jwks.builder().provider(provider)
|
||||||
if (pub instanceof ECKey) {
|
if (pub instanceof ECKey) {
|
||||||
builder = Jwks.builder().ecKeyPair(pair)
|
builder = builder.ecKeyPair(pair)
|
||||||
} else if (pub instanceof RSAKey) {
|
} else if (pub instanceof RSAKey) {
|
||||||
builder = Jwks.builder().rsaKeyPair(pair)
|
builder = builder.rsaKeyPair(pair)
|
||||||
} else {
|
} else {
|
||||||
builder = Jwks.builder().octetKeyPair(pair)
|
builder = builder.octetKeyPair(pair)
|
||||||
}
|
}
|
||||||
privJwk = builder.publicKeyUse("sig").build() as PrivateJwk
|
privJwk = builder.publicKeyUse("sig").build() as PrivateJwk
|
||||||
assertEquals priv, privJwk.toKey()
|
assertEquals priv, privJwk.toKey()
|
||||||
|
|
|
@ -16,11 +16,14 @@
|
||||||
package io.jsonwebtoken.impl.security
|
package io.jsonwebtoken.impl.security
|
||||||
|
|
||||||
import io.jsonwebtoken.impl.lang.Bytes
|
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 org.junit.Test
|
||||||
|
|
||||||
|
import java.security.Provider
|
||||||
import java.security.cert.CertificateEncodingException
|
import java.security.cert.CertificateEncodingException
|
||||||
import java.security.cert.CertificateException
|
import java.security.cert.CertificateException
|
||||||
import java.security.cert.CertificateFactory
|
|
||||||
import java.security.cert.X509Certificate
|
import java.security.cert.X509Certificate
|
||||||
|
|
||||||
import static org.easymock.EasyMock.*
|
import static org.easymock.EasyMock.*
|
||||||
|
@ -28,6 +31,13 @@ import static org.junit.Assert.*
|
||||||
|
|
||||||
class JwtX509StringConverterTest {
|
class JwtX509StringConverterTest {
|
||||||
|
|
||||||
|
private JwtX509StringConverter converter
|
||||||
|
|
||||||
|
@Before
|
||||||
|
void setUp() {
|
||||||
|
converter = JwtX509StringConverter.INSTANCE
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testApplyToThrowsEncodingException() {
|
void testApplyToThrowsEncodingException() {
|
||||||
|
|
||||||
|
@ -38,12 +48,11 @@ class JwtX509StringConverterTest {
|
||||||
replay cert
|
replay cert
|
||||||
|
|
||||||
try {
|
try {
|
||||||
JwtX509StringConverter.INSTANCE.applyTo(cert)
|
converter.applyTo(cert)
|
||||||
fail()
|
fail()
|
||||||
} catch (IllegalArgumentException expected) {
|
} catch (IllegalArgumentException expected) {
|
||||||
String expectedMsg = 'Unable to access X509Certificate encoded bytes necessary to perform DER ' +
|
String expectedMsg = "Unable to access X509Certificate encoded bytes necessary to perform DER " +
|
||||||
'Base64-encoding. Certificate: {EasyMock for class java.security.cert.X509Certificate}. ' +
|
"Base64-encoding. Certificate: {${cert}}. Cause: " + ex.getMessage()
|
||||||
'Cause: ' + ex.getMessage()
|
|
||||||
assertSame ex, expected.getCause()
|
assertSame ex, expected.getCause()
|
||||||
assertEquals expectedMsg, expected.getMessage()
|
assertEquals expectedMsg, expected.getMessage()
|
||||||
}
|
}
|
||||||
|
@ -59,7 +68,7 @@ class JwtX509StringConverterTest {
|
||||||
replay cert
|
replay cert
|
||||||
|
|
||||||
try {
|
try {
|
||||||
JwtX509StringConverter.INSTANCE.applyTo(cert)
|
converter.applyTo(cert)
|
||||||
fail()
|
fail()
|
||||||
} catch (IllegalArgumentException expected) {
|
} catch (IllegalArgumentException expected) {
|
||||||
String expectedMsg = 'X509Certificate encoded bytes cannot be null or empty. Certificate: ' +
|
String expectedMsg = 'X509Certificate encoded bytes cannot be null or empty. Certificate: ' +
|
||||||
|
@ -71,12 +80,13 @@ class JwtX509StringConverterTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testApplyFromThrowsCertificateException() {
|
void testApplyFromBadBase64() {
|
||||||
|
final CertificateException ex = new CertificateException('nope')
|
||||||
def converter = new JwtX509StringConverter() {
|
converter = new JwtX509StringConverter() {
|
||||||
@Override
|
@Override
|
||||||
protected CertificateFactory newCertificateFactory() throws CertificateException {
|
protected X509Certificate toCert(byte[] der, Provider provider) throws SecurityException {
|
||||||
throw new CertificateException("nope")
|
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) {
|
} catch (IllegalArgumentException expected) {
|
||||||
String expectedMsg = "Unable to convert Base64 String '$s' to X509Certificate instance. Cause: nope"
|
String expectedMsg = "Unable to convert Base64 String '$s' to X509Certificate instance. Cause: nope"
|
||||||
assertEquals expectedMsg, expected.getMessage()
|
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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,6 +34,7 @@ class PrivateConstructorsTest {
|
||||||
new Jwts.ENC()
|
new Jwts.ENC()
|
||||||
new Jwts.KEY()
|
new Jwts.KEY()
|
||||||
new Jwts.ZIP()
|
new Jwts.ZIP()
|
||||||
|
new Jwks.CRV()
|
||||||
new Jwks.HASH()
|
new Jwks.HASH()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,10 +16,12 @@
|
||||||
package io.jsonwebtoken.impl.security
|
package io.jsonwebtoken.impl.security
|
||||||
|
|
||||||
import io.jsonwebtoken.Jwts
|
import io.jsonwebtoken.Jwts
|
||||||
|
import io.jsonwebtoken.impl.lang.CheckedFunction
|
||||||
import io.jsonwebtoken.security.InvalidKeyException
|
import io.jsonwebtoken.security.InvalidKeyException
|
||||||
import io.jsonwebtoken.security.WeakKeyException
|
import io.jsonwebtoken.security.WeakKeyException
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
|
||||||
|
import java.security.KeyPair
|
||||||
import java.security.KeyPairGenerator
|
import java.security.KeyPairGenerator
|
||||||
import java.security.PublicKey
|
import java.security.PublicKey
|
||||||
import java.security.interfaces.RSAPrivateKey
|
import java.security.interfaces.RSAPrivateKey
|
||||||
|
@ -30,15 +32,13 @@ import static org.junit.Assert.*
|
||||||
|
|
||||||
class RsaSignatureAlgorithmTest {
|
class RsaSignatureAlgorithmTest {
|
||||||
|
|
||||||
static Collection<RsaSignatureAlgorithm> algs() {
|
static final Collection<RsaSignatureAlgorithm> algs = Jwts.SIG.get().values().findAll({
|
||||||
return Jwts.SIG.get().values().findAll({
|
it instanceof RsaSignatureAlgorithm
|
||||||
it.id.startsWith("RS") || it.id.startsWith("PS")
|
}) as Collection<RsaSignatureAlgorithm>
|
||||||
}) as Collection<RsaSignatureAlgorithm>
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testKeyPairBuilder() {
|
void testKeyPairBuilder() {
|
||||||
algs().each {
|
algs.each {
|
||||||
def pair = it.keyPair().build()
|
def pair = it.keyPair().build()
|
||||||
assertNotNull pair.public
|
assertNotNull pair.public
|
||||||
assertTrue pair.public instanceof RSAPublicKey
|
assertTrue pair.public instanceof RSAPublicKey
|
||||||
|
@ -48,16 +48,11 @@ class RsaSignatureAlgorithmTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = IllegalArgumentException)
|
|
||||||
void testWeakPreferredKeyLength() {
|
|
||||||
new RsaSignatureAlgorithm(256, 1024) //must be >= 2048
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testValidateKeyWithoutRsaKey() {
|
void testValidateKeyWithoutRsaKey() {
|
||||||
PublicKey key = createMock(PublicKey)
|
PublicKey key = createMock(PublicKey)
|
||||||
replay key
|
replay key
|
||||||
algs().each {
|
algs.each {
|
||||||
it.validateKey(key, false)
|
it.validateKey(key, false)
|
||||||
//no exception - can't check for RSAKey fields (e.g. PKCS11 or HSM key)
|
//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)
|
Jwts.SIG.RS256.digest(request)
|
||||||
fail()
|
fail()
|
||||||
} catch (InvalidKeyException e) {
|
} 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() {
|
void testValidateSigningKeyWeakKey() {
|
||||||
def gen = KeyPairGenerator.getInstance("RSA")
|
def gen = KeyPairGenerator.getInstance("RSA")
|
||||||
gen.initialize(1024) //too week for any JWA RSA algorithm
|
gen.initialize(1024) //too week for any JWA RSA algorithm
|
||||||
def pair = gen.generateKeyPair()
|
def rsaPair = gen.generateKeyPair()
|
||||||
|
|
||||||
def request = new DefaultSecureRequest(new byte[1], null, null, pair.getPrivate())
|
def provider = RsaSignatureAlgorithm.PS256.getProvider() // in case BC was loaded
|
||||||
Jwts.SIG.get().values().findAll({ it.id.startsWith('RS') || it.id.startsWith('PS') }).each {
|
def pssPair = new JcaTemplate(RsaSignatureAlgorithm.PSS_JCA_NAME, provider)
|
||||||
|
.withKeyPairGenerator(new CheckedFunction<KeyPairGenerator, KeyPair>() {
|
||||||
|
@Override
|
||||||
|
KeyPair apply(KeyPairGenerator generator) throws Exception {
|
||||||
|
generator.initialize(1024)
|
||||||
|
return generator.generateKeyPair()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
algs.each {
|
||||||
|
def pair = it.getId().startsWith("PS") ? pssPair : rsaPair
|
||||||
|
def request = new DefaultSecureRequest(new byte[1], null, null, pair.getPrivate())
|
||||||
try {
|
try {
|
||||||
it.digest(request)
|
it.digest(request)
|
||||||
fail()
|
fail()
|
||||||
} catch (WeakKeyException expected) {
|
} 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022 jsonwebtoken.io
|
* Copyright © 2023 jsonwebtoken.io
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package io.jsonwebtoken.impl.security;
|
package io.jsonwebtoken.impl.security
|
||||||
|
|
||||||
import io.jsonwebtoken.Identifiable;
|
import org.junit.Test
|
||||||
import io.jsonwebtoken.security.KeyPairBuilderSupplier;
|
|
||||||
|
|
||||||
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())
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -15,12 +15,14 @@
|
||||||
*/
|
*/
|
||||||
package io.jsonwebtoken.impl.security
|
package io.jsonwebtoken.impl.security
|
||||||
|
|
||||||
|
import io.jsonwebtoken.Identifiable
|
||||||
import io.jsonwebtoken.impl.lang.Bytes
|
import io.jsonwebtoken.impl.lang.Bytes
|
||||||
import io.jsonwebtoken.impl.lang.CheckedFunction
|
import io.jsonwebtoken.impl.lang.CheckedFunction
|
||||||
|
import io.jsonwebtoken.impl.lang.Conditions
|
||||||
import io.jsonwebtoken.lang.Assert
|
import io.jsonwebtoken.lang.Assert
|
||||||
import io.jsonwebtoken.lang.Classes
|
import io.jsonwebtoken.lang.Classes
|
||||||
import io.jsonwebtoken.lang.Strings
|
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.pkcs.PrivateKeyInfo
|
||||||
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo
|
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo
|
||||||
import org.bouncycastle.openssl.PEMKeyPair
|
import org.bouncycastle.openssl.PEMKeyPair
|
||||||
|
@ -53,6 +55,9 @@ import java.security.spec.X509EncodedKeySpec
|
||||||
*/
|
*/
|
||||||
class TestCertificates {
|
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) {
|
private static InputStream getResourceStream(String filename) {
|
||||||
String packageName = TestCertificates.class.getPackage().getName()
|
String packageName = TestCertificates.class.getPackage().getName()
|
||||||
String resourcePath = Strings.replace(packageName, ".", "/") + "/" + filename
|
String resourcePath = Strings.replace(packageName, ".", "/") + "/" + filename
|
||||||
|
@ -60,55 +65,75 @@ class TestCertificates {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static PEMParser getParser(String filename) {
|
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)))
|
return new PEMParser(new BufferedReader(new InputStreamReader(is, StandardCharsets.ISO_8859_1)))
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String getKeyFilePrefix(SecureDigestAlgorithm alg) {
|
private static <T> T bcFallback(final Identifiable alg, Closure<T> closure) {
|
||||||
if (alg instanceof EdSignatureAlgorithm) {
|
Provider provider = alg.getProvider() as Provider // null on JVMs with native support for `alg`
|
||||||
return alg.preferredCurve.getId()
|
|
||||||
}
|
|
||||||
return alg.getId()
|
|
||||||
}
|
|
||||||
|
|
||||||
static X509Certificate readTestCertificate(SecureDigestAlgorithm alg) {
|
|
||||||
InputStream is = getResourceStream(getKeyFilePrefix(alg) + '.crt.pem')
|
|
||||||
try {
|
try {
|
||||||
JcaTemplate template = new JcaTemplate("X.509", alg.getProvider())
|
return closure.call(alg, provider)
|
||||||
template.withCertificateFactory(new CheckedFunction<CertificateFactory, X509Certificate>() {
|
} catch (Throwable t) {
|
||||||
@Override
|
|
||||||
X509Certificate apply(CertificateFactory factory) throws Exception {
|
// All test cert and key files were created with OpenSSL, so the only time this should happen is if the
|
||||||
return (X509Certificate) factory.generateCertificate(is)
|
// 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.
|
||||||
})
|
|
||||||
} finally {
|
// https://bugs.openjdk.org/browse/JDK-8242556
|
||||||
is.close()
|
// 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) {
|
private static def readPublicKey = { Identifiable alg, Provider provider ->
|
||||||
PEMParser parser = getParser(crv.getId() + '.pub.pem')
|
PEMParser parser = getParser(alg.id + '.pub.pem')
|
||||||
try {
|
parser.withCloseable {
|
||||||
SubjectPublicKeyInfo info = parser.readObject() as SubjectPublicKeyInfo
|
SubjectPublicKeyInfo info = parser.readObject() as SubjectPublicKeyInfo
|
||||||
def template = new JcaTemplate(crv.getJcaName(), crv.getProvider())
|
JcaTemplate template = new JcaTemplate(alg.getJcaName(), provider)
|
||||||
return template.withKeyFactory(new CheckedFunction<KeyFactory, PublicKey>() {
|
template.withKeyFactory(new CheckedFunction<KeyFactory, PublicKey>() {
|
||||||
@Override
|
@Override
|
||||||
PublicKey apply(KeyFactory keyFactory) throws Exception {
|
PublicKey apply(KeyFactory keyFactory) throws Exception {
|
||||||
return keyFactory.generatePublic(new X509EncodedKeySpec(info.getEncoded()))
|
return keyFactory.generatePublic(new X509EncodedKeySpec(info.getEncoded()))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
} finally {
|
|
||||||
parser.close()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static PrivateKey readTestPrivateKey(SecureDigestAlgorithm alg) {
|
private static def readCert = { Identifiable alg, Provider provider ->
|
||||||
return readTestPrivateKey(getKeyFilePrefix(alg), alg.getProvider())
|
InputStream is = getResourceStream(alg.id + '.crt.pem')
|
||||||
|
is.withCloseable {
|
||||||
|
JcaTemplate template = new JcaTemplate("X.509", provider)
|
||||||
|
template.withCertificateFactory(new CheckedFunction<CertificateFactory, X509Certificate>() {
|
||||||
|
@Override
|
||||||
|
X509Certificate apply(CertificateFactory factory) throws Exception {
|
||||||
|
return (X509Certificate) factory.generateCertificate(it)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static PrivateKey readTestPrivateKey(String filenamePrefix, Provider provider) {
|
private static def readPrivateKey = { Identifiable alg, Provider provider ->
|
||||||
PEMParser parser = getParser(filenamePrefix + '.key.pem')
|
final String id = alg.id
|
||||||
try {
|
PEMParser parser = getParser(id + '.key.pem')
|
||||||
|
parser.withCloseable {
|
||||||
PrivateKeyInfo info
|
PrivateKeyInfo info
|
||||||
Object object = parser.readObject()
|
Object object = parser.readObject()
|
||||||
if (object instanceof PEMKeyPair) {
|
if (object instanceof PEMKeyPair) {
|
||||||
|
@ -116,12 +141,11 @@ class TestCertificates {
|
||||||
} else {
|
} else {
|
||||||
info = (PrivateKeyInfo) object
|
info = (PrivateKeyInfo) object
|
||||||
}
|
}
|
||||||
|
|
||||||
def converter = new JcaPEMKeyConverter()
|
def converter = new JcaPEMKeyConverter()
|
||||||
if (provider != null) {
|
if (provider != null) {
|
||||||
converter.setProvider(provider)
|
converter.setProvider(provider)
|
||||||
} else if (filenamePrefix.startsWith("X") && System.getProperty("java.version").startsWith("11")) {
|
} else if (id.startsWith("X") && System.getProperty("java.version").startsWith("11")) {
|
||||||
EdwardsCurve curve = EdwardsCurve.findById(filenamePrefix)
|
EdwardsCurve curve = EdwardsCurve.findById(id)
|
||||||
Assert.notNull(curve, "Curve cannot be null.")
|
Assert.notNull(curve, "Curve cannot be null.")
|
||||||
int expectedByteLen = ((curve.keyBitLength + 7) / 8) as int
|
int expectedByteLen = ((curve.keyBitLength + 7) / 8) as int
|
||||||
// Address the [JDK 11 SunCE provider bug](https://bugs.openjdk.org/browse/JDK-8213363) for X25519
|
// 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 curve.toPrivateKey(keyOctets, null)
|
||||||
}
|
}
|
||||||
return converter.getPrivateKey(info)
|
return converter.getPrivateKey(info)
|
||||||
} finally {
|
|
||||||
parser.close()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static TestKeys.Bundle readBundle(EdwardsCurve curve) {
|
static TestKeys.Bundle readBundle(EdwardsCurve curve) {
|
||||||
PublicKey pub = readTestPublicKey(curve)
|
//PublicKey pub = readTestPublicKey(curve)
|
||||||
PrivateKey priv = readTestPrivateKey(curve.getId(), curve.getProvider())
|
//PrivateKey priv = readTestPrivateKey(curve)
|
||||||
|
PublicKey pub = bcFallback(curve, readPublicKey) as PublicKey
|
||||||
|
PrivateKey priv = bcFallback(curve, readPrivateKey) as PrivateKey
|
||||||
return new TestKeys.Bundle(pub, priv)
|
return new TestKeys.Bundle(pub, priv)
|
||||||
}
|
}
|
||||||
|
|
||||||
static TestKeys.Bundle readAsymmetricBundle(SecureDigestAlgorithm alg) {
|
static TestKeys.Bundle readBundle(Identifiable alg) {
|
||||||
X509Certificate cert = readTestCertificate(alg)
|
//X509Certificate cert = readTestCertificate(alg)
|
||||||
PrivateKey priv = readTestPrivateKey(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)
|
return new TestKeys.Bundle(cert, priv)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,9 +18,7 @@ package io.jsonwebtoken.impl.security
|
||||||
import io.jsonwebtoken.Identifiable
|
import io.jsonwebtoken.Identifiable
|
||||||
import io.jsonwebtoken.Jwts
|
import io.jsonwebtoken.Jwts
|
||||||
import io.jsonwebtoken.lang.Collections
|
import io.jsonwebtoken.lang.Collections
|
||||||
import io.jsonwebtoken.security.KeyBuilderSupplier
|
import io.jsonwebtoken.security.Jwks
|
||||||
import io.jsonwebtoken.security.SecretKeyBuilder
|
|
||||||
import io.jsonwebtoken.security.SignatureAlgorithm
|
|
||||||
|
|
||||||
import javax.crypto.SecretKey
|
import javax.crypto.SecretKey
|
||||||
import java.security.KeyPair
|
import java.security.KeyPair
|
||||||
|
@ -65,14 +63,14 @@ class TestKeys {
|
||||||
// =======================================================
|
// =======================================================
|
||||||
// Elliptic Curve Keys & Certificates
|
// Elliptic Curve Keys & Certificates
|
||||||
// =======================================================
|
// =======================================================
|
||||||
static Bundle ES256 = TestCertificates.readAsymmetricBundle(Jwts.SIG.ES256)
|
static Bundle ES256 = TestCertificates.readBundle(Jwts.SIG.ES256)
|
||||||
static Bundle ES384 = TestCertificates.readAsymmetricBundle(Jwts.SIG.ES384)
|
static Bundle ES384 = TestCertificates.readBundle(Jwts.SIG.ES384)
|
||||||
static Bundle ES512 = TestCertificates.readAsymmetricBundle(Jwts.SIG.ES512)
|
static Bundle ES512 = TestCertificates.readBundle(Jwts.SIG.ES512)
|
||||||
static Set<Bundle> EC = Collections.setOf(ES256, ES384, ES512)
|
static Set<Bundle> EC = Collections.setOf(ES256, ES384, ES512)
|
||||||
|
|
||||||
static Bundle EdDSA = TestCertificates.readAsymmetricBundle(Jwts.SIG.EdDSA)
|
static Bundle EdDSA = TestCertificates.readBundle(Jwts.SIG.EdDSA)
|
||||||
static Bundle Ed25519 = TestCertificates.readAsymmetricBundle(Jwts.SIG.Ed25519)
|
static Bundle Ed25519 = TestCertificates.readBundle(Jwks.CRV.Ed25519)
|
||||||
static Bundle Ed448 = TestCertificates.readAsymmetricBundle(Jwts.SIG.Ed448)
|
static Bundle Ed448 = TestCertificates.readBundle(Jwks.CRV.Ed448)
|
||||||
static Bundle X25519 = TestCertificates.readBundle(EdwardsCurve.X25519)
|
static Bundle X25519 = TestCertificates.readBundle(EdwardsCurve.X25519)
|
||||||
static Bundle X448 = TestCertificates.readBundle(EdwardsCurve.X448)
|
static Bundle X448 = TestCertificates.readBundle(EdwardsCurve.X448)
|
||||||
static Set<Bundle> EdEC = Collections.setOf(EdDSA, Ed25519, Ed448, X25519, X448)
|
static Set<Bundle> EdEC = Collections.setOf(EdDSA, Ed25519, Ed448, X25519, X448)
|
||||||
|
@ -80,10 +78,15 @@ class TestKeys {
|
||||||
// =======================================================
|
// =======================================================
|
||||||
// RSA Keys & Certificates
|
// RSA Keys & Certificates
|
||||||
// =======================================================
|
// =======================================================
|
||||||
static Bundle RS256 = TestCertificates.readAsymmetricBundle(Jwts.SIG.RS256)
|
static Bundle RS256 = TestCertificates.readBundle(Jwts.SIG.RS256)
|
||||||
static Bundle RS384 = TestCertificates.readAsymmetricBundle(Jwts.SIG.RS384)
|
static Bundle RS384 = TestCertificates.readBundle(Jwts.SIG.RS384)
|
||||||
static Bundle RS512 = TestCertificates.readAsymmetricBundle(Jwts.SIG.RS512)
|
static Bundle RS512 = TestCertificates.readBundle(Jwts.SIG.RS512)
|
||||||
static Set<Bundle> RSA = Collections.setOf(RS256, RS384, 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<Bundle> PKCSv15 = Collections.setOf(RS256, RS384, RS512)
|
||||||
|
// static Set<Bundle> RSASSA_PSS = Collections.setOf(PS256, PS384, PS512)
|
||||||
|
static Set<Bundle> RSA = Collections.setOf(RS256, RS384, RS512, PS256, PS384, PS512)
|
||||||
|
|
||||||
static Set<Bundle> ASYM = new LinkedHashSet<>()
|
static Set<Bundle> ASYM = new LinkedHashSet<>()
|
||||||
static {
|
static {
|
||||||
|
@ -92,22 +95,8 @@ class TestKeys {
|
||||||
ASYM.addAll(RSA)
|
ASYM.addAll(RSA)
|
||||||
}
|
}
|
||||||
|
|
||||||
static <T extends KeyBuilderSupplier<SecretKey, SecretKeyBuilder> & Identifiable> SecretKey forAlgorithm(T alg) {
|
static Bundle forAlgorithm(Identifiable alg) {
|
||||||
String id = alg.getId()
|
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
|
return TestKeys.metaClass.getAttribute(TestKeys, id) as Bundle
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -126,10 +115,14 @@ class TestKeys {
|
||||||
this.pair = new KeyPair(cert.getPublicKey(), privateKey)
|
this.pair = new KeyPair(cert.getPublicKey(), privateKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
Bundle(PublicKey pub, PrivateKey priv) {
|
Bundle(KeyPair pair) {
|
||||||
this.cert = null
|
this.cert = null
|
||||||
this.chain = Collections.emptyList()
|
this.chain = Collections.emptyList()
|
||||||
this.pair = new KeyPair(pub, priv)
|
this.pair = pair
|
||||||
|
}
|
||||||
|
|
||||||
|
Bundle(PublicKey pub, PrivateKey priv) {
|
||||||
|
this(new KeyPair(pub, priv))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,28 +20,18 @@ import java.security.interfaces.RSAKey
|
||||||
class TestRSAKey extends TestKey implements RSAKey {
|
class TestRSAKey extends TestKey implements RSAKey {
|
||||||
|
|
||||||
final def src
|
final def src
|
||||||
|
BigInteger modulus
|
||||||
|
|
||||||
TestRSAKey(def key) {
|
TestRSAKey(def key) {
|
||||||
this.src = key
|
this.src = key
|
||||||
}
|
this.algorithm = key?.getAlgorithm()
|
||||||
|
this.format = key?.getFormat()
|
||||||
@Override
|
this.encoded = key?.getEncoded()
|
||||||
String getAlgorithm() {
|
this.modulus = key?.getModulus()
|
||||||
return src.algorithm
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
String getFormat() {
|
|
||||||
return src.format
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
byte[] getEncoded() {
|
|
||||||
return src.encoded
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
BigInteger getModulus() {
|
BigInteger getModulus() {
|
||||||
return src.getModulus()
|
return this.modulus
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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')
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -76,12 +76,13 @@ class KeysImplTest {
|
||||||
|
|
||||||
PublicKey pub = pair.getPublic()
|
PublicKey pub = pair.getPublic()
|
||||||
assert pub instanceof RSAPublicKey
|
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()
|
assertEquals alg.digestLength * 8, pub.modulus.bitLength()
|
||||||
|
|
||||||
PrivateKey priv = pair.getPrivate()
|
PrivateKey priv = pair.getPrivate()
|
||||||
assert priv instanceof RSAPrivateKey
|
assert priv instanceof RSAPrivateKey
|
||||||
assertEquals alg.familyName, priv.algorithm
|
assertEquals keyAlgName, priv.algorithm
|
||||||
assertEquals alg.digestLength * 8, priv.modulus.bitLength()
|
assertEquals alg.digestLength * 8, priv.modulus.bitLength()
|
||||||
|
|
||||||
} else if (alg.isEllipticCurve()) {
|
} else if (alg.isEllipticCurve()) {
|
||||||
|
|
|
@ -19,7 +19,9 @@ package io.jsonwebtoken.security
|
||||||
import io.jsonwebtoken.Jwts
|
import io.jsonwebtoken.Jwts
|
||||||
import io.jsonwebtoken.impl.DefaultJwtBuilder
|
import io.jsonwebtoken.impl.DefaultJwtBuilder
|
||||||
import io.jsonwebtoken.impl.lang.Bytes
|
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 org.junit.Test
|
||||||
|
|
||||||
import javax.crypto.SecretKey
|
import javax.crypto.SecretKey
|
||||||
|
@ -154,12 +156,13 @@ class KeysTest {
|
||||||
|
|
||||||
PublicKey pub = pair.getPublic()
|
PublicKey pub = pair.getPublic()
|
||||||
assert pub instanceof RSAPublicKey
|
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()
|
assertEquals alg.digestLength * 8, pub.modulus.bitLength()
|
||||||
|
|
||||||
PrivateKey priv = pair.getPrivate()
|
PrivateKey priv = pair.getPrivate()
|
||||||
assert priv instanceof RSAPrivateKey
|
assert priv instanceof RSAPrivateKey
|
||||||
assertEquals alg.familyName, priv.algorithm
|
assertEquals keyAlgName, priv.algorithm
|
||||||
assertEquals alg.digestLength * 8, priv.modulus.bitLength()
|
assertEquals alg.digestLength * 8, priv.modulus.bitLength()
|
||||||
|
|
||||||
} else if (alg.isEllipticCurve()) {
|
} else if (alg.isEllipticCurve()) {
|
||||||
|
@ -205,11 +208,16 @@ class KeysTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testKeyPairFor() {
|
void testKeyPairBuilder() {
|
||||||
|
|
||||||
for (SecureDigestAlgorithm alg : Jwts.SIG.get().values()) {
|
Collection<SignatureAlgorithm> algs = Jwts.SIG.get().values()
|
||||||
|
.findAll({it instanceof KeyPairBuilderSupplier}) as Collection<SignatureAlgorithm>
|
||||||
|
|
||||||
if (alg instanceof RsaSignatureAlgorithm) {
|
for (SignatureAlgorithm alg : algs) {
|
||||||
|
|
||||||
|
String id = alg.getId()
|
||||||
|
|
||||||
|
if (id.startsWith("RS") || id.startsWith("PS")) {
|
||||||
|
|
||||||
def pair = alg.keyPair().build()
|
def pair = alg.keyPair().build()
|
||||||
assertNotNull pair
|
assertNotNull pair
|
||||||
|
@ -222,7 +230,7 @@ class KeysTest {
|
||||||
assert priv instanceof RSAPrivateKey
|
assert priv instanceof RSAPrivateKey
|
||||||
assertEquals alg.preferredKeyBitLength, priv.modulus.bitLength()
|
assertEquals alg.preferredKeyBitLength, priv.modulus.bitLength()
|
||||||
|
|
||||||
} else if (alg instanceof EdSignatureAlgorithm) {
|
} else if (id == "EdDSA") {
|
||||||
|
|
||||||
def pair = alg.keyPair().build()
|
def pair = alg.keyPair().build()
|
||||||
assertNotNull pair
|
assertNotNull pair
|
||||||
|
@ -235,7 +243,7 @@ class KeysTest {
|
||||||
assert priv instanceof PrivateKey
|
assert priv instanceof PrivateKey
|
||||||
assertTrue EdwardsCurve.isEdwards(priv)
|
assertTrue EdwardsCurve.isEdwards(priv)
|
||||||
|
|
||||||
} else if (alg instanceof EcSignatureAlgorithm) {
|
} else if (id.startsWith("ES")) {
|
||||||
|
|
||||||
def pair = alg.keyPair().build()
|
def pair = alg.keyPair().build()
|
||||||
assertNotNull pair
|
assertNotNull pair
|
||||||
|
@ -267,8 +275,8 @@ class KeysTest {
|
||||||
assertEquals alg.orderBitLength, priv.params.order.bitLength()
|
assertEquals alg.orderBitLength, priv.params.order.bitLength()
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
assertFalse alg instanceof SignatureAlgorithm
|
// unexpected algorithm that is not accounted for in this test:
|
||||||
//assert we've accounted for all asymmetric ones above
|
fail()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,22 +15,27 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
-----BEGIN CERTIFICATE-----
|
-----BEGIN CERTIFICATE-----
|
||||||
MIIDRDCCAiwCCQCgd9OzR40NCDANBgkqhkiG9w0BAQsFADBjMQswCQYDVQQGEwJV
|
MIIERTCCAvmgAwIBAgIUHAjkgfU2dEiUaT+VDBS3bXQgDcswQQYJKoZIhvcNAQEK
|
||||||
UzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzEY
|
MDSgDzANBglghkgBZQMEAgEFAKEcMBoGCSqGSIb3DQEBCDANBglghkgBZQMEAgEF
|
||||||
MBYGA1UECgwPanNvbndlYnRva2VuLmlvMQ0wCwYDVQQLDARqand0MCAXDTIwMDIw
|
AKIDAgEgMGMxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYD
|
||||||
MzIzMDQzM1oYDzMwMjAwMjExMjMwNDMzWjBjMQswCQYDVQQGEwJVUzETMBEGA1UE
|
VQQHDA1TYW4gRnJhbmNpc2NvMRgwFgYDVQQKDA9qc29ud2VidG9rZW4uaW8xDTAL
|
||||||
CAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzEYMBYGA1UECgwP
|
BgNVBAsMBGpqd3QwIBcNMjMwODE0MTk0NjU4WhgPMzAyMzA4MjIxOTQ2NThaMGMx
|
||||||
anNvbndlYnRva2VuLmlvMQ0wCwYDVQQLDARqand0MIIBIjANBgkqhkiG9w0BAQEF
|
CzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1TYW4g
|
||||||
AAOCAQ8AMIIBCgKCAQEAzkH0MwxQ2cUFWsvOPVFqI/dk2EFTjQolCy97mI5/wYCb
|
RnJhbmNpc2NvMRgwFgYDVQQKDA9qc29ud2VidG9rZW4uaW8xDTALBgNVBAsMBGpq
|
||||||
aOoZ9Rm7c675mAeemRtNzgNVEz7m298ENqNGqPk2Nv3pBJ/XCaybBlp61CLez7dQ
|
d3QwggFWMEEGCSqGSIb3DQEBCjA0oA8wDQYJYIZIAWUDBAIBBQChHDAaBgkqhkiG
|
||||||
2h5jUFEJ6FJcjeKHS+MwXr56t2ISdfLNMYtVIxjvXQcYx5VmS4mIqTxj5gVGtQVi
|
9w0BAQgwDQYJYIZIAWUDBAIBBQCiAwIBIAOCAQ8AMIIBCgKCAQEA0b7eGccEnfOG
|
||||||
0GXdH6SvpdKV0fjE9KOhjsdBfKQzZfcQlusHg8pThwvjpMwCZnkxCS0RKa9y4+5+
|
0bd5zptCwGEhd+YmtvgaYKsmdxTK9y1vXq13ZsSyd4IpPZIVpam2BYgmxXix4ikH
|
||||||
7MkC33+8+neZUzS7b6NdFxh6T/pMXpkf8d81fzVo4ZBMloweW0/l8MOdVxeX7M/7
|
beKzydJG3bvr2J+f7Z9bgPZZNB9NJjX3j4IlEkGVI4/ZrROKrC004ItGcHqUJdlq
|
||||||
XSC1ank5i3IEZcotLmJYMwEo7rMpZVLevEQ118Eo8QIDAQABMA0GCSqGSIb3DQEB
|
48W3JFyKWswBrFYxaCR2HyTj6uI+dsxwuPWse/rqyu+1NKN7uxmh1RXAKa+kYVkK
|
||||||
CwUAA4IBAQBGbfmJumXEHMLko1ioY/eY5EYgrBRJAuuAMGqBZmK+1Iy2CqB90aEh
|
Smyta2UN+TJZ3bj0a0Sk9cyAqYVGI+kPKF+BYItgh6W+1cmYEscBjNkgcLbV/hen
|
||||||
ve+jXjIBsrvXRuLxMdlzoP58Ia9C5M+78Vq0bEjuGJu3zxGev11Gt4E3V6bWfT7G
|
BMjX90OZsTel/iQeXb0w7NgHfVQ2ZR3UmzkAwt8Eh/5+AtIsXRMuV9xgG17MKiN4
|
||||||
fhg66dbmjnqkhgSzpDzfYR7HHOQiDAGe5IH5FbvWehRzENoAODHHP1z3NdoGhsl9
|
JJUCjr8b/QIDAQABo1MwUTAdBgNVHQ4EFgQUl6+ASzYpbLLWGyKw/Qjj0JZK+24w
|
||||||
4DIjOTGYdhW0yUTSjGTWygo6OPU2L4M2k0gTA06FkvdLIS450GWRpgoVO/vfcPnO
|
HwYDVR0jBBgwFoAUl6+ASzYpbLLWGyKw/Qjj0JZK+24wDwYDVR0TAQH/BAUwAwEB
|
||||||
h8KwZcWVwJVmG0Hv0fNhQk/tRuhYhCWGxc7gxkbLb7/xPpPKMD6EvgG0BSm27NxO
|
/zBBBgkqhkiG9w0BAQowNKAPMA0GCWCGSAFlAwQCAQUAoRwwGgYJKoZIhvcNAQEI
|
||||||
H5l3KYwtbdj5nYHU73cLqC1D6ki6F8+h
|
MA0GCWCGSAFlAwQCAQUAogMCASADggEBAHQQiwmyaT9Ga7Bug5ux6LquaJAQCHu7
|
||||||
|
THny14VdgcEdDp92+1+7CoRhDznpN6RKZPWyou6Jk0RL80ReKuijK054SjXiHsPx
|
||||||
|
UPSeHr5F7WCGTc6af8GXF7IJoEG+HjAXUz+lTQucK6d5TRk9mVknKnH4UiorRfZu
|
||||||
|
rdWmCVvb4CjKYCKVKfl/ZqAd8ZDE947AOosbCPcPivpWPIcuaAPeGiuJEcVkH537
|
||||||
|
onM3j3v1yMnaAbomUfWp5aEdv/7GCfYM0j4SpAOwoStfJBc1iPWymRCEhVSLNqKp
|
||||||
|
J3W63YTrBKyXzoXF2M/+Q2xdpwASAF+DwsFyEgcy7h/APKaEOkvmyMg=
|
||||||
-----END CERTIFICATE-----
|
-----END CERTIFICATE-----
|
||||||
|
|
|
@ -15,30 +15,31 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
-----BEGIN PRIVATE KEY-----
|
-----BEGIN PRIVATE KEY-----
|
||||||
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
|
||||||
8qhIwqrpm3+JJ1p2p0XPl1c=
|
qak4Sqgwek16n6AdvSoGlDG/eFVIioMaLXAGGXuWZ8J/doCTPH5JPRsEVdeWwI8E
|
||||||
|
v69m7uG79SuNZ1vHaycsQU7FEqe3
|
||||||
-----END PRIVATE KEY-----
|
-----END PRIVATE KEY-----
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
rsa2048.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-----
|
|
@ -1 +0,0 @@
|
||||||
rsa2048.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-----
|
|
@ -15,27 +15,33 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
-----BEGIN CERTIFICATE-----
|
-----BEGIN CERTIFICATE-----
|
||||||
MIIERDCCAqwCCQDqxucO41yAmTANBgkqhkiG9w0BAQsFADBjMQswCQYDVQQGEwJV
|
MIIFRTCCA3mgAwIBAgIUcJUoNEM4A7jE+zrgPRQ3A3PdYdkwQQYJKoZIhvcNAQEK
|
||||||
UzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzEY
|
MDSgDzANBglghkgBZQMEAgIFAKEcMBoGCSqGSIb3DQEBCDANBglghkgBZQMEAgIF
|
||||||
MBYGA1UECgwPanNvbndlYnRva2VuLmlvMQ0wCwYDVQQLDARqand0MCAXDTIwMDIw
|
AKIDAgEwMGMxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYD
|
||||||
MzIzMDQ1OFoYDzMwMjAwMjExMjMwNDU4WjBjMQswCQYDVQQGEwJVUzETMBEGA1UE
|
VQQHDA1TYW4gRnJhbmNpc2NvMRgwFgYDVQQKDA9qc29ud2VidG9rZW4uaW8xDTAL
|
||||||
CAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzEYMBYGA1UECgwP
|
BgNVBAsMBGpqd3QwIBcNMjMwODE0MTk0NzEzWhgPMzAyMzA4MjIxOTQ3MTNaMGMx
|
||||||
anNvbndlYnRva2VuLmlvMQ0wCwYDVQQLDARqand0MIIBojANBgkqhkiG9w0BAQEF
|
CzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1TYW4g
|
||||||
AAOCAY8AMIIBigKCAYEA0DmQS4Xtgu5xtnQdxkuzB1j+W4OvNEOVOsg3Zcn9W1d5
|
RnJhbmNpc2NvMRgwFgYDVQQKDA9qc29ud2VidG9rZW4uaW8xDTALBgNVBAsMBGpq
|
||||||
NowtngUh9K9vwBpl59M2j5PHj9dseEIuRqr++ZnZhBMlh/lLiIQ0oQ3cEa7wrwJO
|
d3QwggHWMEEGCSqGSIb3DQEBCjA0oA8wDQYJYIZIAWUDBAICBQChHDAaBgkqhkiG
|
||||||
i9ycZZbeNDHVNzAdQZEQR1DIMUhSTEMR96pVD4a9DzBKLQJaKxZRUOrMhf3QhAZ5
|
9w0BAQgwDQYJYIZIAWUDBAICBQCiAwIBMAOCAY8AMIIBigKCAYEArTxQUZqiSCFF
|
||||||
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
|
||||||
|
bXVUUwwl8tRC
|
||||||
-----END CERTIFICATE-----
|
-----END CERTIFICATE-----
|
||||||
|
|
|
@ -15,42 +15,43 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
-----BEGIN PRIVATE KEY-----
|
-----BEGIN PRIVATE KEY-----
|
||||||
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
|
||||||
5I2wbxUhb3FO7gj9pxJbwX4=
|
SgCk6OgpjKqABr1NWFFgowjD7UomgT3pVm/KSJD2ebl2mONtr60I02wlskvtwe8L
|
||||||
|
lVynub2OR3qrrfMw0voYdeaYeLELzQ==
|
||||||
-----END PRIVATE KEY-----
|
-----END PRIVATE KEY-----
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
rsa3072.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-----
|
|
@ -1 +0,0 @@
|
||||||
rsa3072.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-----
|
|
@ -15,33 +15,38 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
-----BEGIN CERTIFICATE-----
|
-----BEGIN CERTIFICATE-----
|
||||||
MIIFRDCCAywCCQC4g2isVGolKjANBgkqhkiG9w0BAQsFADBjMQswCQYDVQQGEwJV
|
MIIGRTCCA/mgAwIBAgIUII4HfeMyQ0DFwJgHBeB4DTuDCBUwQQYJKoZIhvcNAQEK
|
||||||
UzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzEY
|
MDSgDzANBglghkgBZQMEAgMFAKEcMBoGCSqGSIb3DQEBCDANBglghkgBZQMEAgMF
|
||||||
MBYGA1UECgwPanNvbndlYnRva2VuLmlvMQ0wCwYDVQQLDARqand0MCAXDTIwMDIw
|
AKIDAgFAMGMxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYD
|
||||||
MzIzMDY1MloYDzMwMjAwMjExMjMwNjUyWjBjMQswCQYDVQQGEwJVUzETMBEGA1UE
|
VQQHDA1TYW4gRnJhbmNpc2NvMRgwFgYDVQQKDA9qc29ud2VidG9rZW4uaW8xDTAL
|
||||||
CAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzEYMBYGA1UECgwP
|
BgNVBAsMBGpqd3QwIBcNMjMwODE0MTk0NzI0WhgPMzAyMzA4MjIxOTQ3MjRaMGMx
|
||||||
anNvbndlYnRva2VuLmlvMQ0wCwYDVQQLDARqand0MIICIjANBgkqhkiG9w0BAQEF
|
CzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1TYW4g
|
||||||
AAOCAg8AMIICCgKCAgEAw7jTXeRwCRrDdYnrIwcLvSNfhpmJZ0ap1jzKVgUyCOYL
|
RnJhbmNpc2NvMRgwFgYDVQQKDA9qc29ud2VidG9rZW4uaW8xDTALBgNVBAsMBGpq
|
||||||
TaB9+naJRjHqx7B5wgx/ArRF2nluQ5tawZPMFw2I/iqXYrQEPTbq1XVugYC/C491
|
d3QwggJWMEEGCSqGSIb3DQEBCjA0oA8wDQYJYIZIAWUDBAIDBQChHDAaBgkqhkiG
|
||||||
bcXOTKx+DgEvnhNysm/KmzFsEcw78prB5sIAZSR+S5zZPuny4zww2UzE9TZ433RB
|
9w0BAQgwDQYJYIZIAWUDBAIDBQCiAwIBQAOCAg8AMIICCgKCAgEAvDIWx+4AyoNT
|
||||||
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
|
||||||
33eif1l5Nk0=
|
xnNcGpAEuk9ldyrj0pRYJcxu6ChtHmIYtLDB/OJ+UD3OJBUBG09dagHFFNrhNBWV
|
||||||
|
aRiBqvnSQ1lRdYssBbzbV995dApQ08t44rl0zUGwLdjcpwI2GtM89PKc5FaoqKHE
|
||||||
|
QrdlJyUCQUzUq1nq/O0KdGLG2tXlN/lV9G+0ayPNGfJYkn8kJCqZ1LXOYYz2ahyW
|
||||||
|
zG5fANL7asksaHBQRAlrNxqTdL31Xfy/a6iYV0ePv6xA3ZTGq8jxTpizK+sajFSh
|
||||||
|
7pV4WYYlS2DqgIxaNmAJIN463mcq6q+1U5VrldCSuMAURlF8e24CMXvRsd2Yc88l
|
||||||
|
E3vd9XobDXMOJLBBPLceTt8pvv/6GyF6bQ==
|
||||||
-----END CERTIFICATE-----
|
-----END CERTIFICATE-----
|
||||||
|
|
|
@ -15,54 +15,55 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
-----BEGIN PRIVATE KEY-----
|
-----BEGIN PRIVATE KEY-----
|
||||||
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
|
||||||
lczRTJNTE/KNUE0pkC5P4c/e0A1OFu0=
|
gyQGFVddNtQu0ulqEd1c7joGeZRUtzTV1tfmOpNcOFQlNkWE5N5AN69AlKClbdxd
|
||||||
|
fSc/Kr3l8kzu0dexW4usUiKuLju4X471jKg=
|
||||||
-----END PRIVATE KEY-----
|
-----END PRIVATE KEY-----
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
rsa4096.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-----
|
|
@ -1 +0,0 @@
|
||||||
rsa4096.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-----
|
|
@ -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 -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 -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 -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 -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: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:
|
# 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 RS256.crt.pem > RS256.pub.pem
|
||||||
openssl x509 -pubkey -noout -in rsa3072.crt.pem > rsa3072.pub.pem
|
openssl x509 -pubkey -noout -in RS384.crt.pem > RS384.pub.pem
|
||||||
openssl x509 -pubkey -noout -in rsa4096.crt.pem > rsa4096.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:
|
# 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 RS256.key.pem -traditional -out RS256.pkcs1.key.pem
|
||||||
openssl rsa -in rsa3072.key.pem -out rsa3072.pkcs1.key.pem
|
openssl rsa -in RS384.key.pem -traditional -out RS384.pkcs1.key.pem
|
||||||
openssl rsa -in rsa4096.key.pem -out rsa4096.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`.
|
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
|
Curve IDs. This allows easy file lookup based on the `SignatureAlgorithm` `getId()` or `EdwardsCurve#getId()` value
|
||||||
when authoring tests.
|
when authoring tests.
|
||||||
|
|
||||||
Finally, the `RS*`, `PS*`, and `EdDSA*` files in this directory are just are symlinks back to source files based on
|
Finally, the `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
|
the `EdSignatureAlgorithm`'s preferred `Ed448` key sizes.
|
||||||
since there is no difference in keys between the two sets of algorithms.
|
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
rsa2048.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-----
|
|
@ -1 +0,0 @@
|
||||||
rsa2048.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-----
|
|
@ -1 +0,0 @@
|
||||||
rsa3072.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-----
|
|
@ -1 +0,0 @@
|
||||||
rsa3072.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-----
|
|
@ -1 +0,0 @@
|
||||||
rsa4096.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-----
|
|
@ -1 +0,0 @@
|
||||||
rsa4096.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-----
|
|
@ -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-----
|
|
|
@ -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-----
|
|
|
@ -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-----
|
|
|
@ -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-----
|
|
|
@ -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-----
|
|
|
@ -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-----
|
|
||||||
MIIG/QIBADANBgkqhkiG9w0BAQEFAASCBucwggbjAgEAAoIBgQDQOZBLhe2C7nG2
|
|
||||||
dB3GS7MHWP5bg680Q5U6yDdlyf1bV3k2jC2eBSH0r2/AGmXn0zaPk8eP12x4Qi5G
|
|
||||||
qv75mdmEEyWH+UuIhDShDdwRrvCvAk6L3Jxllt40MdU3MB1BkRBHUMgxSFJMQxH3
|
|
||||||
qlUPhr0PMEotAlorFlFQ6syF/dCEBnn2bR38qq7UObph5YwtBAR7ABpJD2DbaC3L
|
|
||||||
URwsC+n++eFH8MlJggcJrJ3mZnC+T2paRfJJ9SYkY/vQYUYbgY6dUsuSYJCB9P46
|
|
||||||
vNO2IjM1Pbqa0CyhQyegPjZNMGRHRouFQtyPUxhRwH25UKYlO9i6IJM4Og2UvxPj
|
|
||||||
Sv0v30egeVNZWL29/ojW/I10end1coExUvXf6LkF40iMAOvQoqzSO0QSJxbK5WEn
|
|
||||||
Pes8vMFs+HP8MZD+FOP8NFJ2j0v1gDhaSqAPy4VS8gQoAn+FdjHdA8SIgxTuFPiO
|
|
||||||
TZnZIgGIoqI1bgT/bQRk4WZp41ZBqqqbBfRwe0zKAm1NicQnUgMCAwEAAQKCAYAg
|
|
||||||
ewo+LasKBIXqbxyB5ScNG126CsWWwoARxk+V6jdCO1fmIWGwR56vW3p0HeoNio31
|
|
||||||
QZkcn/8El1Y+ocfaSZx7lL0DA+k7Z1wKT24nuAFFW3fDK2ueETWiMK/QxwmZQ7al
|
|
||||||
WT2RKnXj/YZc+s3/+QWey+qWMMq98+JFXAsBT8FqBtSZkxXdZwaUhljDkpoWH41P
|
|
||||||
Xom7IdH7B7o0//cEC+u5YWM55J6Rf933LV0IJqypkxvE7ypHTR1hCdOrArF78u5z
|
|
||||||
Jg61hZRDi9t+X2RNZZ027ysrVLU/gre6XzSZI1a7NygDOSWBmcycQBAf6ZYJDdeb
|
|
||||||
mLy5M62K0fNavaxiuspA/WD3k4BsXSsK/rGNU6DvpeuymEbWFzPIoD5uKWTwHdSa
|
|
||||||
5ZrJGcR+Q5D12EersJi3jm52tYqYE91sJ8x+q6Ko+u7kWSbUCssqJLITdCqBdoEL
|
|
||||||
tpZspCzfCShJ+7CqlC1jEAIRdYFWFgIk76eLyr1k8aYI+NBqwfQbTzNK9Okj07kC
|
|
||||||
gcEA6BSD2iW2KEHyPi10BsqiWLKWCS6e5UjVBZEgD7+c6pYABxvXrMCKgseyd4LY
|
|
||||||
FBJ15MLNp3KS1vozlQEYp7LFAhpNeYMADql39ZNc7FQPcv+QsyQfDLP26eypabhN
|
|
||||||
BDexMcBY4jhZNkEBXjdxU9l0rGCQw82qLO5mK4WuKfyj+IX0iQv6BOzfBTKYNsgt
|
|
||||||
JAb289KeyrsV7rAoxxxfmsjYqsQadeCaOMQfkATAKyVaMrs6aJfJokuz5ibv+PRz
|
|
||||||
p6JdAoHBAOWvnzNNUF5BAanmk6BeiYK1tf9xAjJ5tAOAdqqflbDVBlZVE8qGYOH2
|
|
||||||
J7x2/LQVz+Dm3chC5AdUL0tu5qZ+rAr8Vc7lJDvGkbcfTaEv4/VbF1gyDwi+dwn1
|
|
||||||
MV3WQMEuFrqLDa1G3zxYER6PsO1DcwMTMRiWWlF6F77FnRm1zmleIkeXEOPW4a3J
|
|
||||||
Id2W043od/tbNr0j4sU/Ha3M+Eb91XjkSVulsABL+98CP/BnqWEFQABgQmfBsXMD
|
|
||||||
Kla06hw/3wKBwHm7iQ28CjhDnxUOMnX9g/qScjCOy7no4hPxc6fPEjfaRll0OUTc
|
|
||||||
GctPhEU71Ktyo3RC2iyi5HLu+m+GC7CrDLt1oH3EQRtvuQSPL4am8ROZCgVtRPwc
|
|
||||||
yb8Z7CMQERXNQJygD/9ZHzJeFqGc40zgG1rvq/+IuWKoCd96V0iexENvwDzCk3pR
|
|
||||||
5QmM6FqT1Vm4bYCnUbN1PqPcswb90wgVodCw3FBIZ5yvAv8//qyjAxTpMFH8jD8d
|
|
||||||
BlgKxIUJdEDR4QKBwGZapfJBsN/fzjL9aqobluHlwg3sOVNvArZQyBDu/tEHjURp
|
|
||||||
s2EcEw5/GGQXDjPeSH3rw8ebb2yIqm7OJADsEBTxL/f8CvKMYaEeVQTQh6BuEHAg
|
|
||||||
Fq0J25hXaMFtWfv8YuqMTvL50z9b630YAXsqBJXJNqbDUcpfQzejbofnie1QoqwO
|
|
||||||
eNtfhcBhEjNiJDJn9xfPJQySclr97mbmIXnZYgj2im5J3q2zLrHJmd6zAzsWENha
|
|
||||||
DR2Zpk8fiP2Mr4sZNwKBwQDX2Y/Ycr/IQtNdP/YsFIDeNHJ+dBLDM4JJCetlbzsY
|
|
||||||
poIKM9+ZvC9EST0KoEumhUT4Fy75b75nbzRGRDmFDNyOxRcHixFVnbgZqWyAeCbw
|
|
||||||
xNCKrIbtrXk5JvFy5y0yjMdBeB2uB1KJZhesuwUS1JnhA8RDapQ7ZwpoleRd+iqg
|
|
||||||
3RJTtcvo5Ky6vdz74isxBL8WH+PMqQEm1el8Jwix5dHx5mKH5QM2XnkUm78V/NX9
|
|
||||||
5I2wbxUhb3FO7gj9pxJbwX4=
|
|
||||||
-----END PRIVATE KEY-----
|
|
|
@ -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-----
|
|
|
@ -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-----
|
|
|
@ -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-----
|
|
|
@ -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-----
|
|
|
@ -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-----
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue