Merge pull request #9036 from luchua-bc/java/hardcoded-jwt-key

Java: CWE-321 Query to detect hardcoded JWT secret keys
This commit is contained in:
Tony Torralba
2022-05-11 16:31:34 +02:00
committed by GitHub
22 changed files with 1433 additions and 0 deletions

View File

@@ -0,0 +1,26 @@
// BAD: Get secret from hardcoded string then sign a JWT token
Algorithm algorithm = Algorithm.HMAC256("hardcoded_secret");
JWT.create()
.withClaim("username", username)
.sign(algorithm);
}
// BAD: Get secret from hardcoded string then verify a JWT token
JWTVerifier verifier = JWT.require(Algorithm.HMAC256("hardcoded_secret"))
.withIssuer(ISSUER)
.build();
verifier.verify(token);
// GOOD: Get secret from system configuration then sign a token
String tokenSecret = System.getenv("SECRET_KEY");
Algorithm algorithm = Algorithm.HMAC256(tokenSecret);
JWT.create()
.withClaim("username", username)
.sign(algorithm);
}
// GOOD: Get secret from environment variable then verify a JWT token
JWTVerifier verifier = JWT.require(Algorithm.HMAC256(System.getenv("SECRET_KEY")))
.withIssuer(ISSUER)
.build();
verifier.verify(token);

View File

@@ -0,0 +1,46 @@
<!DOCTYPE qhelp PUBLIC "-//Semmle//qhelp//EN" "qhelp.dtd">
<qhelp>
<overview>
<p>
JWT (JSON Web Token) is an open standard (RFC 7519) that defines a way to provide information
within a JSON object between two parties. JWT is widely used for sharing security information
between two parties in web applications. Each JWT contains encoded JSON objects, including a
set of claims. JWTs are signed using a cryptographic algorithm to ensure that the claims cannot
be altered after the token is issued.
</p>
<p>
The most basic mistake is using hardcoded secrets for JWT generation/verification. This allows
an attacker to forge the token if the source code (and JWT secret in it) is publicly exposed or
leaked, which leads to authentication bypass or privilege escalation.
</p>
</overview>
<recommendation>
<p>
Generating a cryptographically secure secret key during application initialization and using this
generated key for JWT signing/verification requests can prevent this vulnerability. Or safely store
the secret key in a key vault that cannot be leaked in source code.
</p>
</recommendation>
<example>
<p>
The following examples show the bad case and the good case respectively. The <code>bad</code>
methods show a hardcoded secret key is used to sign and verify JWT tokens. In the <code>good</code>
method, the secret key is loaded from a system environment during application initialization.
</p>
<sample src="HardcodedJwtKey.java" />
</example>
<references>
<li>
Semgrep Blog:
<a href="https://r2c.dev/blog/2020/hardcoded-secrets-unverified-tokens-and-other-common-jwt-mistakes/">Hardcoded secrets, unverified tokens, and other common JWT mistakes</a>
</li>
<li>
CVE-2022-24860:
<a href="https://nvd.nist.gov/vuln/detail/CVE-2022-24860">Databasir 1.01 has Use of Hard-coded Cryptographic Key vulnerability.</a>
</li>
</references>
</qhelp>

View File

@@ -0,0 +1,19 @@
/**
* @name Use of a hardcoded key for signing JWT
* @description Using a hardcoded key for signing JWT can allow an attacker to compromise security.
* @kind path-problem
* @problem.severity error
* @id java/hardcoded-jwt-key
* @tags security
* external/cwe/cwe-321
*/
import java
import HardcodedJwtKey
import semmle.code.java.dataflow.TaintTracking
import DataFlow::PathGraph
from DataFlow::PathNode source, DataFlow::PathNode sink, HardcodedJwtKeyConfiguration cfg
where cfg.hasFlowPath(source, sink)
select sink.getNode(), source, sink, "$@ is used to sign a JWT token.", source.getNode(),
"Hardcoded String"

View File

@@ -0,0 +1,145 @@
/**
* Provides sources and sinks for detecting JWT token signing vulnerabilities.
*/
import java
private import semmle.code.java.dataflow.ExternalFlow
private import semmle.code.java.dataflow.FlowSources
/** The class `com.auth0.jwt.JWT`. */
class Jwt extends RefType {
Jwt() { this.hasQualifiedName("com.auth0.jwt", "JWT") }
}
/** The class `com.auth0.jwt.JWTCreator.Builder`. */
class JwtBuilder extends RefType {
JwtBuilder() { this.hasQualifiedName("com.auth0.jwt", "JWTCreator$Builder") }
}
/** The class `com.auth0.jwt.algorithms.Algorithm`. */
class JwtAlgorithm extends RefType {
JwtAlgorithm() { this.hasQualifiedName("com.auth0.jwt.algorithms", "Algorithm") }
}
/**
* The interface `com.auth0.jwt.interfaces.JWTVerifier` or its implementation
* `com.auth0.jwt.JWTVerifier`.
*/
class JwtVerifier extends RefType {
JwtVerifier() {
this.hasQualifiedName(["com.auth0.jwt", "com.auth0.jwt.interfaces"], "JWTVerifier")
}
}
/** A method that creates an instance of `com.auth0.jwt.algorithms.Algorithm`. */
class GetAlgorithmMethod extends Method {
GetAlgorithmMethod() {
this.getDeclaringType() instanceof JwtAlgorithm and
this.getName().matches(["HMAC%", "ECDSA%", "RSA%"])
}
}
/** The `require` method of `com.auth0.jwt.JWT`. */
class RequireMethod extends Method {
RequireMethod() {
this.getDeclaringType() instanceof Jwt and
this.hasName("require")
}
}
/** The `sign` method of `com.auth0.jwt.JWTCreator.Builder`. */
class SignTokenMethod extends Method {
SignTokenMethod() {
this.getDeclaringType() instanceof JwtBuilder and
this.hasName("sign")
}
}
/** The `verify` method of `com.auth0.jwt.interfaces.JWTVerifier`. */
class VerifyTokenMethod extends Method {
VerifyTokenMethod() {
this.getDeclaringType() instanceof JwtVerifier and
this.hasName("verify")
}
}
/**
* A data flow source for JWT token signing vulnerabilities.
*/
abstract class JwtKeySource extends DataFlow::Node { }
/**
* A data flow sink for JWT token signing vulnerabilities.
*/
abstract class JwtTokenSink extends DataFlow::Node { }
/**
* A hardcoded string literal as a source for JWT token signing vulnerabilities.
*/
class HardcodedKeyStringSource extends JwtKeySource {
HardcodedKeyStringSource() { exists(this.asExpr().(CompileTimeConstantExpr).getStringValue()) }
}
/**
* An expression used to sign JWT tokens as a sink of JWT token signing vulnerabilities.
*/
private class SignTokenSink extends JwtTokenSink {
SignTokenSink() {
exists(MethodAccess ma |
ma.getMethod() instanceof SignTokenMethod and
this.asExpr() = ma.getArgument(0)
)
}
}
/**
* An expression used to verify JWT tokens as a sink of JWT token signing vulnerabilities.
*/
private class VerifyTokenSink extends JwtTokenSink {
VerifyTokenSink() {
exists(MethodAccess ma |
ma.getMethod() instanceof VerifyTokenMethod and
this.asExpr() = ma.getQualifier()
)
}
}
/**
* A configuration depicting taint flow for checking JWT token signing vulnerabilities.
*/
class HardcodedJwtKeyConfiguration extends TaintTracking::Configuration {
HardcodedJwtKeyConfiguration() { this = "Hard-coded JWT Signing Key" }
override predicate isSource(DataFlow::Node source) { source instanceof JwtKeySource }
override predicate isSink(DataFlow::Node sink) { sink instanceof JwtTokenSink }
override predicate isAdditionalTaintStep(DataFlow::Node prev, DataFlow::Node succ) {
exists(MethodAccess ma |
(
ma.getMethod() instanceof GetAlgorithmMethod or
ma.getMethod() instanceof RequireMethod
) and
prev.asExpr() = ma.getArgument(0) and
succ.asExpr() = ma
)
}
}
/** Taint model related to verifying JWT tokens. */
private class VerificationFlowStep extends SummaryModelCsv {
override predicate row(string row) {
row =
[
"com.auth0.jwt.interfaces;Verification;true;build;;;Argument[-1];ReturnValue;taint",
"com.auth0.jwt.interfaces;Verification;true;" +
["acceptLeeway", "acceptExpiresAt", "acceptNotBefore", "acceptIssuedAt", "ignoreIssuedAt"]
+ ";;;Argument[-1];ReturnValue;value",
"com.auth0.jwt.interfaces;Verification;true;with" +
[
"Issuer", "Subject", "Audience", "AnyOfAudience", "ClaimPresence", "Claim",
"ArrayClaim", "JWTId"
] + ";;;Argument[-1];ReturnValue;value"
]
}
}

View File

@@ -0,0 +1,25 @@
edges
| HardcodedJwtKey.java:15:33:15:38 | SECRET : String | HardcodedJwtKey.java:19:49:19:54 | SECRET : String |
| HardcodedJwtKey.java:15:33:15:38 | SECRET : String | HardcodedJwtKey.java:42:62:42:67 | SECRET : String |
| HardcodedJwtKey.java:15:42:15:59 | "hardcoded_secret" : String | HardcodedJwtKey.java:15:33:15:38 | SECRET : String |
| HardcodedJwtKey.java:19:49:19:54 | SECRET : String | HardcodedJwtKey.java:25:23:25:31 | algorithm |
| HardcodedJwtKey.java:42:32:42:69 | require(...) : Verification | HardcodedJwtKey.java:42:32:43:35 | withIssuer(...) : Verification |
| HardcodedJwtKey.java:42:32:43:35 | withIssuer(...) : Verification | HardcodedJwtKey.java:42:32:44:24 | build(...) : JWTVerifier |
| HardcodedJwtKey.java:42:32:44:24 | build(...) : JWTVerifier | HardcodedJwtKey.java:46:13:46:20 | verifier |
| HardcodedJwtKey.java:42:62:42:67 | SECRET : String | HardcodedJwtKey.java:42:32:42:69 | require(...) : Verification |
nodes
| HardcodedJwtKey.java:15:33:15:38 | SECRET : String | semmle.label | SECRET : String |
| HardcodedJwtKey.java:15:42:15:59 | "hardcoded_secret" : String | semmle.label | "hardcoded_secret" : String |
| HardcodedJwtKey.java:19:49:19:54 | SECRET : String | semmle.label | SECRET : String |
| HardcodedJwtKey.java:25:23:25:31 | algorithm | semmle.label | algorithm |
| HardcodedJwtKey.java:42:32:42:69 | require(...) : Verification | semmle.label | require(...) : Verification |
| HardcodedJwtKey.java:42:32:43:35 | withIssuer(...) : Verification | semmle.label | withIssuer(...) : Verification |
| HardcodedJwtKey.java:42:32:44:24 | build(...) : JWTVerifier | semmle.label | build(...) : JWTVerifier |
| HardcodedJwtKey.java:42:62:42:67 | SECRET : String | semmle.label | SECRET : String |
| HardcodedJwtKey.java:46:13:46:20 | verifier | semmle.label | verifier |
subpaths
#select
| HardcodedJwtKey.java:25:23:25:31 | algorithm | HardcodedJwtKey.java:15:42:15:59 | "hardcoded_secret" : String | HardcodedJwtKey.java:25:23:25:31 | algorithm | $@ is used to sign a JWT token. | HardcodedJwtKey.java:15:42:15:59 | "hardcoded_secret" | Hardcoded String |
| HardcodedJwtKey.java:25:23:25:31 | algorithm | HardcodedJwtKey.java:19:49:19:54 | SECRET : String | HardcodedJwtKey.java:25:23:25:31 | algorithm | $@ is used to sign a JWT token. | HardcodedJwtKey.java:19:49:19:54 | SECRET | Hardcoded String |
| HardcodedJwtKey.java:46:13:46:20 | verifier | HardcodedJwtKey.java:15:42:15:59 | "hardcoded_secret" : String | HardcodedJwtKey.java:46:13:46:20 | verifier | $@ is used to sign a JWT token. | HardcodedJwtKey.java:15:42:15:59 | "hardcoded_secret" | Hardcoded String |
| HardcodedJwtKey.java:46:13:46:20 | verifier | HardcodedJwtKey.java:42:62:42:67 | SECRET : String | HardcodedJwtKey.java:46:13:46:20 | verifier | $@ is used to sign a JWT token. | HardcodedJwtKey.java:42:62:42:67 | SECRET | Hardcoded String |

View File

@@ -0,0 +1,65 @@
import java.util.Date;
import java.util.Properties;
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.JWTVerifier;
public class HardcodedJwtKey {
// 15 minutes
private static final long ACCESS_EXPIRE_TIME = 1000 * 60 * 15;
private static final String ISSUER = "example_com";
private static final String SECRET = "hardcoded_secret";
// BAD: Get secret from hardcoded string then sign a JWT token
public String accessTokenBad(String username) {
Algorithm algorithm = Algorithm.HMAC256(SECRET);
return JWT.create()
.withExpiresAt(new Date(new Date().getTime() + ACCESS_EXPIRE_TIME))
.withIssuer(ISSUER)
.withClaim("username", username)
.sign(algorithm);
}
// GOOD: Get secret from system configuration then sign a token
public String accessTokenGood(String username) {
String tokenSecret = System.getenv("SECRET_KEY");
Algorithm algorithm = Algorithm.HMAC256(tokenSecret);
return JWT.create()
.withExpiresAt(new Date(new Date().getTime() + ACCESS_EXPIRE_TIME))
.withIssuer(ISSUER)
.withClaim("username", username)
.sign(algorithm);
}
// BAD: Get secret from hardcoded string then verify a JWT token
public boolean verifyTokenBad(String token) {
JWTVerifier verifier = JWT.require(Algorithm.HMAC256(SECRET))
.withIssuer(ISSUER)
.build();
try {
verifier.verify(token);
return true;
} catch (JWTVerificationException e) {
return false;
}
}
// GOOD: Get secret from environment variable then verify a JWT token
public boolean verifyTokenGood(String token) {
JWTVerifier verifier = JWT.require(Algorithm.HMAC256(System.getenv("SECRET_KEY")))
.withIssuer(ISSUER)
.build();
try {
verifier.verify(token);
return true;
} catch (JWTVerificationException e) {
return false;
}
}
}

View File

@@ -0,0 +1 @@
experimental/Security/CWE/CWE-321/HardcodedJwtKey.ql

View File

@@ -0,0 +1 @@
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/auth0-jwt-2.3

View File

@@ -0,0 +1,57 @@
package com.auth0.jwt;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.auth0.jwt.interfaces.Verification;
public class JWT {
public JWT() {
}
/**
* Decode a given Json Web Token.
* <p>
* Note that this method <b>doesn't verify the token's signature!</b> Use it only if you trust the token or you already verified it.
*
* @param token with jwt format as string.
* @return a decoded JWT.
* @throws JWTDecodeException if any part of the token contained an invalid jwt or JSON format of each of the jwt parts.
*/
public DecodedJWT decodeJwt(String token) throws JWTDecodeException {
return null;
}
/**
* Decode a given Json Web Token.
* <p>
* Note that this method <b>doesn't verify the token's signature!</b> Use it only if you trust the token or you already verified it.
*
* @param token with jwt format as string.
* @return a decoded JWT.
* @throws JWTDecodeException if any part of the token contained an invalid jwt or JSON format of each of the jwt parts.
*/
public static DecodedJWT decode(String token) throws JWTDecodeException {
return null;
}
/**
* Returns a {@link JWTVerifier} builder with the algorithm to be used to validate token signature.
*
* @param algorithm that will be used to verify the token's signature.
* @return {@link JWTVerifier} builder
* @throws IllegalArgumentException if the provided algorithm is null.
*/
public static Verification require(Algorithm algorithm) {
return null;
}
/**
* Returns a Json Web Token builder used to create and sign tokens
*
* @return a token builder.
*/
public static JWTCreator.Builder create() {
return null;
}
}

View File

@@ -0,0 +1,300 @@
package com.auth0.jwt;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTCreationException;
import java.util.*;
/**
* The JWTCreator class holds the sign method to generate a complete JWT (with Signature) from a given Header and Payload content.
* <p>
* This class is thread-safe.
*/
public final class JWTCreator {
/**
* Initialize a JWTCreator instance.
*
* @return a JWTCreator.Builder instance to configure.
*/
static JWTCreator.Builder init() {
return null;
}
/**
* The Builder class holds the Claims that defines the JWT to be created.
*/
public static class Builder {
Builder() {
}
/**
* Add specific Claims to set as the Header.
* If provided map is null then nothing is changed
* If provided map contains a claim with null value then that claim will be removed from the header
*
* @param headerClaims the values to use as Claims in the token's Header.
* @return this same Builder instance.
*/
public Builder withHeader(Map<String, Object> headerClaims) {
return null;
}
/**
* Add a specific Key Id ("kid") claim to the Header.
* If the {@link Algorithm} used to sign this token was instantiated with a KeyProvider, the 'kid' value will be taken from that provider and this one will be ignored.
*
* @param keyId the Key Id value.
* @return this same Builder instance.
*/
public Builder withKeyId(String keyId) {
return null;
}
/**
* Add a specific Issuer ("iss") claim to the Payload.
*
* @param issuer the Issuer value.
* @return this same Builder instance.
*/
public Builder withIssuer(String issuer) {
return null;
}
/**
* Add a specific Subject ("sub") claim to the Payload.
*
* @param subject the Subject value.
* @return this same Builder instance.
*/
public Builder withSubject(String subject) {
return null;
}
/**
* Add a specific Audience ("aud") claim to the Payload.
*
* @param audience the Audience value.
* @return this same Builder instance.
*/
public Builder withAudience(String... audience) {
return null;
}
/**
* Add a specific Expires At ("exp") claim to the Payload.
*
* @param expiresAt the Expires At value.
* @return this same Builder instance.
*/
public Builder withExpiresAt(Date expiresAt) {
return null;
}
/**
* Add a specific Not Before ("nbf") claim to the Payload.
*
* @param notBefore the Not Before value.
* @return this same Builder instance.
*/
public Builder withNotBefore(Date notBefore) {
return null;
}
/**
* Add a specific Issued At ("iat") claim to the Payload.
*
* @param issuedAt the Issued At value.
* @return this same Builder instance.
*/
public Builder withIssuedAt(Date issuedAt) {
return null;
}
/**
* Add a specific JWT Id ("jti") claim to the Payload.
*
* @param jwtId the Token Id value.
* @return this same Builder instance.
*/
public Builder withJWTId(String jwtId) {
return null;
}
/**
* Add a custom Claim value.
*
* @param name the Claim's name.
* @param value the Claim's value.
* @return this same Builder instance.
* @throws IllegalArgumentException if the name is null.
*/
public Builder withClaim(String name, Boolean value) throws IllegalArgumentException {
return null;
}
/**
* Add a custom Claim value.
*
* @param name the Claim's name.
* @param value the Claim's value.
* @return this same Builder instance.
* @throws IllegalArgumentException if the name is null.
*/
public Builder withClaim(String name, Integer value) throws IllegalArgumentException {
return null;
}
/**
* Add a custom Claim value.
*
* @param name the Claim's name.
* @param value the Claim's value.
* @return this same Builder instance.
* @throws IllegalArgumentException if the name is null.
*/
public Builder withClaim(String name, Long value) throws IllegalArgumentException {
return null;
}
/**
* Add a custom Claim value.
*
* @param name the Claim's name.
* @param value the Claim's value.
* @return this same Builder instance.
* @throws IllegalArgumentException if the name is null.
*/
public Builder withClaim(String name, Double value) throws IllegalArgumentException {
return null;
}
/**
* Add a custom Claim value.
*
* @param name the Claim's name.
* @param value the Claim's value.
* @return this same Builder instance.
* @throws IllegalArgumentException if the name is null.
*/
public Builder withClaim(String name, String value) throws IllegalArgumentException {
return null;
}
/**
* Add a custom Claim value.
*
* @param name the Claim's name.
* @param value the Claim's value.
* @return this same Builder instance.
* @throws IllegalArgumentException if the name is null.
*/
public Builder withClaim(String name, Date value) throws IllegalArgumentException {
return null;
}
/**
* Add a custom Array Claim with the given items.
*
* @param name the Claim's name.
* @param items the Claim's value.
* @return this same Builder instance.
* @throws IllegalArgumentException if the name is null.
*/
public Builder withArrayClaim(String name, String[] items) throws IllegalArgumentException {
return null;
}
/**
* Add a custom Array Claim with the given items.
*
* @param name the Claim's name.
* @param items the Claim's value.
* @return this same Builder instance.
* @throws IllegalArgumentException if the name is null.
*/
public Builder withArrayClaim(String name, Integer[] items) throws IllegalArgumentException {
return null;
}
/**
* Add a custom Array Claim with the given items.
*
* @param name the Claim's name.
* @param items the Claim's value.
* @return this same Builder instance.
* @throws IllegalArgumentException if the name is null
*/
public Builder withArrayClaim(String name, Long[] items) throws IllegalArgumentException {
return null;
}
/**
* Add a custom Map Claim with the given items.
* <p>
* Accepted nested types are {@linkplain Map} and {@linkplain List} with basic types
* {@linkplain Boolean}, {@linkplain Integer}, {@linkplain Long}, {@linkplain Double},
* {@linkplain String} and {@linkplain Date}. {@linkplain Map}s cannot contain null keys or values.
* {@linkplain List}s can contain null elements.
*
* @param name the Claim's name.
* @param map the Claim's key-values.
* @return this same Builder instance.
* @throws IllegalArgumentException if the name is null, or if the map contents does not validate.
*/
public Builder withClaim(String name, Map<String, ?> map) throws IllegalArgumentException {
return null;
}
/**
* Add a custom List Claim with the given items.
* <p>
* Accepted nested types are {@linkplain Map} and {@linkplain List} with basic types
* {@linkplain Boolean}, {@linkplain Integer}, {@linkplain Long}, {@linkplain Double},
* {@linkplain String} and {@linkplain Date}. {@linkplain Map}s cannot contain null keys or values.
* {@linkplain List}s can contain null elements.
*
* @param name the Claim's name.
* @param list the Claim's list of values.
* @return this same Builder instance.
* @throws IllegalArgumentException if the name is null, or if the list contents does not validate.
*/
public Builder withClaim(String name, List<?> list) throws IllegalArgumentException {
return null;
}
/**
* Add specific Claims to set as the Payload. If the provided map is null then
* nothing is changed.
* <p>
* Accepted types are {@linkplain Map} and {@linkplain List} with basic types
* {@linkplain Boolean}, {@linkplain Integer}, {@linkplain Long}, {@linkplain Double},
* {@linkplain String} and {@linkplain Date}. {@linkplain Map}s cannot contain null keys or values.
* {@linkplain List}s can contain null elements.
* </p>
*
* <p>
* If any of the claims are invalid, none will be added.
* </p>
*
* @param payloadClaims the values to use as Claims in the token's payload.
* @throws IllegalArgumentException if any of the claim keys or null, or if the values are not of a supported type.
* @return this same Builder instance.
*/
public Builder withPayload(Map<String, ?> payloadClaims) throws IllegalArgumentException {
return null;
}
/**
* Creates a new JWT and signs is with the given algorithm
*
* @param algorithm used to sign the JWT
* @return a new JWT token
* @throws IllegalArgumentException if the provided algorithm is null.
* @throws JWTCreationException if the claims could not be converted to a valid JSON or there was a problem with the signing key.
*/
public String sign(Algorithm algorithm) throws IllegalArgumentException, JWTCreationException {
return null;
}
}
}

View File

@@ -0,0 +1,397 @@
package com.auth0.jwt.algorithms;
import com.auth0.jwt.exceptions.SignatureGenerationException;
import com.auth0.jwt.exceptions.SignatureVerificationException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.auth0.jwt.interfaces.ECDSAKeyProvider;
import com.auth0.jwt.interfaces.RSAKeyProvider;
import java.security.interfaces.*;
/**
* The Algorithm class represents an algorithm to be used in the Signing or Verification process of a Token.
* <p>
* This class and its subclasses are thread-safe.
*/
public abstract class Algorithm {
/**
* Creates a new Algorithm instance using SHA256withRSA. Tokens specify this as "RS256".
*
* @param keyProvider the provider of the Public Key and Private Key for the verify and signing instance.
* @return a valid RSA256 Algorithm.
* @throws IllegalArgumentException if the provided Key is null.
*/
public static Algorithm RSA256(RSAKeyProvider keyProvider) throws IllegalArgumentException {
return null;
}
/**
* Creates a new Algorithm instance using SHA256withRSA. Tokens specify this as "RS256".
*
* @param publicKey the key to use in the verify instance.
* @param privateKey the key to use in the signing instance.
* @return a valid RSA256 Algorithm.
* @throws IllegalArgumentException if both provided Keys are null.
*/
public static Algorithm RSA256(RSAPublicKey publicKey, RSAPrivateKey privateKey) throws IllegalArgumentException {
return null;
}
/**
* Creates a new Algorithm instance using SHA256withRSA. Tokens specify this as "RS256".
*
* @param key the key to use in the verify or signing instance.
* @return a valid RSA256 Algorithm.
* @throws IllegalArgumentException if the Key Provider is null.
* @deprecated use {@link #RSA256(RSAPublicKey, RSAPrivateKey)} or {@link #RSA256(RSAKeyProvider)}
*/
@Deprecated
public static Algorithm RSA256(RSAKey key) throws IllegalArgumentException {
return null;
}
/**
* Creates a new Algorithm instance using SHA384withRSA. Tokens specify this as "RS384".
*
* @param keyProvider the provider of the Public Key and Private Key for the verify and signing instance.
* @return a valid RSA384 Algorithm.
* @throws IllegalArgumentException if the Key Provider is null.
*/
public static Algorithm RSA384(RSAKeyProvider keyProvider) throws IllegalArgumentException {
return null;
}
/**
* Creates a new Algorithm instance using SHA384withRSA. Tokens specify this as "RS384".
*
* @param publicKey the key to use in the verify instance.
* @param privateKey the key to use in the signing instance.
* @return a valid RSA384 Algorithm.
* @throws IllegalArgumentException if both provided Keys are null.
*/
public static Algorithm RSA384(RSAPublicKey publicKey, RSAPrivateKey privateKey) throws IllegalArgumentException {
return null;
}
/**
* Creates a new Algorithm instance using SHA384withRSA. Tokens specify this as "RS384".
*
* @param key the key to use in the verify or signing instance.
* @return a valid RSA384 Algorithm.
* @throws IllegalArgumentException if the provided Key is null.
* @deprecated use {@link #RSA384(RSAPublicKey, RSAPrivateKey)} or {@link #RSA384(RSAKeyProvider)}
*/
@Deprecated
public static Algorithm RSA384(RSAKey key) throws IllegalArgumentException {
return null;
}
/**
* Creates a new Algorithm instance using SHA512withRSA. Tokens specify this as "RS512".
*
* @param keyProvider the provider of the Public Key and Private Key for the verify and signing instance.
* @return a valid RSA512 Algorithm.
* @throws IllegalArgumentException if the Key Provider is null.
*/
public static Algorithm RSA512(RSAKeyProvider keyProvider) throws IllegalArgumentException {
return null;
}
/**
* Creates a new Algorithm instance using SHA512withRSA. Tokens specify this as "RS512".
*
* @param publicKey the key to use in the verify instance.
* @param privateKey the key to use in the signing instance.
* @return a valid RSA512 Algorithm.
* @throws IllegalArgumentException if both provided Keys are null.
*/
public static Algorithm RSA512(RSAPublicKey publicKey, RSAPrivateKey privateKey) throws IllegalArgumentException {
return null;
}
/**
* Creates a new Algorithm instance using SHA512withRSA. Tokens specify this as "RS512".
*
* @param key the key to use in the verify or signing instance.
* @return a valid RSA512 Algorithm.
* @throws IllegalArgumentException if the provided Key is null.
* @deprecated use {@link #RSA512(RSAPublicKey, RSAPrivateKey)} or {@link #RSA512(RSAKeyProvider)}
*/
@Deprecated
public static Algorithm RSA512(RSAKey key) throws IllegalArgumentException {
return null;
}
/**
* Creates a new Algorithm instance using HmacSHA256. Tokens specify this as "HS256".
*
* @param secret the secret to use in the verify or signing instance.
* @return a valid HMAC256 Algorithm.
* @throws IllegalArgumentException if the provided Secret is null.
*/
public static Algorithm HMAC256(String secret) throws IllegalArgumentException {
return null;
}
/**
* Creates a new Algorithm instance using HmacSHA384. Tokens specify this as "HS384".
*
* @param secret the secret to use in the verify or signing instance.
* @return a valid HMAC384 Algorithm.
* @throws IllegalArgumentException if the provided Secret is null.
*/
public static Algorithm HMAC384(String secret) throws IllegalArgumentException {
return null;
}
/**
* Creates a new Algorithm instance using HmacSHA512. Tokens specify this as "HS512".
*
* @param secret the secret to use in the verify or signing instance.
* @return a valid HMAC512 Algorithm.
* @throws IllegalArgumentException if the provided Secret is null.
*/
public static Algorithm HMAC512(String secret) throws IllegalArgumentException {
return null;
}
/**
* Creates a new Algorithm instance using HmacSHA256. Tokens specify this as "HS256".
*
* @param secret the secret bytes to use in the verify or signing instance.
* @return a valid HMAC256 Algorithm.
* @throws IllegalArgumentException if the provided Secret is null.
*/
public static Algorithm HMAC256(byte[] secret) throws IllegalArgumentException {
return null;
}
/**
* Creates a new Algorithm instance using SHA256withECDSA. Tokens specify this as "ES256K".
*
* @param keyProvider the provider of the Public Key and Private Key for the verify and signing instance.
* @return a valid ECDSA256 Algorithm.
* @throws IllegalArgumentException if the Key Provider is null.
* @deprecated The SECP-256K1 Curve algorithm has been disabled beginning in Java 15.
* Use of this method in those unsupported Java versions will throw a {@link java.security.SignatureException}.
* This method will be removed in the next major version. See for additional information
*/
@Deprecated
public static Algorithm ECDSA256K(ECDSAKeyProvider keyProvider) throws IllegalArgumentException {
return null;
}
/**
* Creates a new Algorithm instance using SHA256withECDSA. Tokens specify this as "ES256K".
*
* @param publicKey the key to use in the verify instance.
* @param privateKey the key to use in the signing instance.
* @return a valid ECDSA256 Algorithm.
* @throws IllegalArgumentException if the provided Key is null.
* @deprecated The SECP-256K1 Curve algorithm has been disabled beginning in Java 15.
* Use of this method in those unsupported Java versions will throw a {@link java.security.SignatureException}.
* This method will be removed in the next major version. See for additional information
*/
@Deprecated
public static Algorithm ECDSA256K(ECPublicKey publicKey, ECPrivateKey privateKey) throws IllegalArgumentException {
return null;
}
/**
* Creates a new Algorithm instance using HmacSHA384. Tokens specify this as "HS384".
*
* @param secret the secret bytes to use in the verify or signing instance.
* @return a valid HMAC384 Algorithm.
* @throws IllegalArgumentException if the provided Secret is null.
*/
public static Algorithm HMAC384(byte[] secret) throws IllegalArgumentException {
return null;
}
/**
* Creates a new Algorithm instance using HmacSHA512. Tokens specify this as "HS512".
*
* @param secret the secret bytes to use in the verify or signing instance.
* @return a valid HMAC512 Algorithm.
* @throws IllegalArgumentException if the provided Secret is null.
*/
public static Algorithm HMAC512(byte[] secret) throws IllegalArgumentException {
return null;
}
/**
* Creates a new Algorithm instance using SHA256withECDSA. Tokens specify this as "ES256".
*
* @param keyProvider the provider of the Public Key and Private Key for the verify and signing instance.
* @return a valid ECDSA256 Algorithm.
* @throws IllegalArgumentException if the Key Provider is null.
*/
public static Algorithm ECDSA256(ECDSAKeyProvider keyProvider) throws IllegalArgumentException {
return null;
}
/**
* Creates a new Algorithm instance using SHA256withECDSA. Tokens specify this as "ES256".
*
* @param publicKey the key to use in the verify instance.
* @param privateKey the key to use in the signing instance.
* @return a valid ECDSA256 Algorithm.
* @throws IllegalArgumentException if the provided Key is null.
*/
public static Algorithm ECDSA256(ECPublicKey publicKey, ECPrivateKey privateKey) throws IllegalArgumentException {
return null;
}
/**
* Creates a new Algorithm instance using SHA256withECDSA. Tokens specify this as "ES256".
*
* @param key the key to use in the verify or signing instance.
* @return a valid ECDSA256 Algorithm.
* @throws IllegalArgumentException if the provided Key is null.
* @deprecated use {@link #ECDSA256(ECPublicKey, ECPrivateKey)} or {@link #ECDSA256(ECDSAKeyProvider)}
*/
@Deprecated
public static Algorithm ECDSA256(ECKey key) throws IllegalArgumentException {
return null;
}
/**
* Creates a new Algorithm instance using SHA384withECDSA. Tokens specify this as "ES384".
*
* @param keyProvider the provider of the Public Key and Private Key for the verify and signing instance.
* @return a valid ECDSA384 Algorithm.
* @throws IllegalArgumentException if the Key Provider is null.
*/
public static Algorithm ECDSA384(ECDSAKeyProvider keyProvider) throws IllegalArgumentException {
return null;
}
/**
* Creates a new Algorithm instance using SHA384withECDSA. Tokens specify this as "ES384".
*
* @param publicKey the key to use in the verify instance.
* @param privateKey the key to use in the signing instance.
* @return a valid ECDSA384 Algorithm.
* @throws IllegalArgumentException if the provided Key is null.
*/
public static Algorithm ECDSA384(ECPublicKey publicKey, ECPrivateKey privateKey) throws IllegalArgumentException {
return null;
}
/**
* Creates a new Algorithm instance using SHA384withECDSA. Tokens specify this as "ES384".
*
* @param key the key to use in the verify or signing instance.
* @return a valid ECDSA384 Algorithm.
* @throws IllegalArgumentException if the provided Key is null.
* @deprecated use {@link #ECDSA384(ECPublicKey, ECPrivateKey)} or {@link #ECDSA384(ECDSAKeyProvider)}
*/
@Deprecated
public static Algorithm ECDSA384(ECKey key) throws IllegalArgumentException {
return null;
}
/**
* Creates a new Algorithm instance using SHA512withECDSA. Tokens specify this as "ES512".
*
* @param keyProvider the provider of the Public Key and Private Key for the verify and signing instance.
* @return a valid ECDSA512 Algorithm.
* @throws IllegalArgumentException if the Key Provider is null.
*/
public static Algorithm ECDSA512(ECDSAKeyProvider keyProvider) throws IllegalArgumentException {
return null;
}
/**
* Creates a new Algorithm instance using SHA512withECDSA. Tokens specify this as "ES512".
*
* @param publicKey the key to use in the verify instance.
* @param privateKey the key to use in the signing instance.
* @return a valid ECDSA512 Algorithm.
* @throws IllegalArgumentException if the provided Key is null.
*/
public static Algorithm ECDSA512(ECPublicKey publicKey, ECPrivateKey privateKey) throws IllegalArgumentException {
return null;
}
/**
* Creates a new Algorithm instance using SHA512withECDSA. Tokens specify this as "ES512".
*
* @param key the key to use in the verify or signing instance.
* @return a valid ECDSA512 Algorithm.
* @throws IllegalArgumentException if the provided Key is null.
* @deprecated use {@link #ECDSA512(ECPublicKey, ECPrivateKey)} or {@link #ECDSA512(ECDSAKeyProvider)}
*/
@Deprecated
public static Algorithm ECDSA512(ECKey key) throws IllegalArgumentException {
return null;
}
public static Algorithm none() {
return null;
}
/**
* Getter for the Id of the Private Key used to sign the tokens. This is usually specified as the `kid` claim in the Header.
*
* @return the Key Id that identifies the Signing Key or null if it's not specified.
*/
public String getSigningKeyId() {
return null;
}
/**
* Getter for the name of this Algorithm, as defined in the JWT Standard. i.e. "HS256"
*
* @return the algorithm name.
*/
public String getName() {
return null;
}
/**
* Getter for the description of this Algorithm, required when instantiating a Mac or Signature object. i.e. "HmacSHA256"
*
* @return the algorithm description.
*/
String getDescription() {
return null;
}
/**
* Verify the given token using this Algorithm instance.
*
* @param jwt the already decoded JWT that it's going to be verified.
* @throws SignatureVerificationException if the Token's Signature is invalid, meaning that it doesn't match the signatureBytes, or if the Key is invalid.
*/
public abstract void verify(DecodedJWT jwt) throws SignatureVerificationException;
/**
* Sign the given content using this Algorithm instance.
*
* @param headerBytes an array of bytes representing the base64 encoded header content to be verified against the signature.
* @param payloadBytes an array of bytes representing the base64 encoded payload content to be verified against the signature.
* @return the signature in a base64 encoded array of bytes
* @throws SignatureGenerationException if the Key is invalid.
*/
public byte[] sign(byte[] headerBytes, byte[] payloadBytes) throws SignatureGenerationException {
return null;
}
/**
* Sign the given content using this Algorithm instance.
*
* @param contentBytes an array of bytes representing the base64 encoded content to be verified against the signature.
* @return the signature in a base64 encoded array of bytes
* @throws SignatureGenerationException if the Key is invalid.
* @deprecated Please use the {@linkplain #sign(byte[], byte[])} method instead.
*/
@Deprecated
public abstract byte[] sign(byte[] contentBytes) throws SignatureGenerationException;
}

View File

@@ -0,0 +1,6 @@
package com.auth0.jwt.exceptions;
public class JWTCreationException extends RuntimeException {
public JWTCreationException(String message, Throwable cause) {
}
}

View File

@@ -0,0 +1,9 @@
package com.auth0.jwt.exceptions;
public class JWTDecodeException extends RuntimeException {
public JWTDecodeException(String message) {
}
public JWTDecodeException(String message, Throwable cause) {
}
}

View File

@@ -0,0 +1,9 @@
package com.auth0.jwt.exceptions;
public class JWTVerificationException extends RuntimeException {
public JWTVerificationException(String message) {
}
public JWTVerificationException(String message, Throwable cause) {
}
}

View File

@@ -0,0 +1,8 @@
package com.auth0.jwt.exceptions;
import com.auth0.jwt.algorithms.Algorithm;
public class SignatureGenerationException extends RuntimeException {
public SignatureGenerationException(Algorithm algorithm, Throwable cause) {
}
}

View File

@@ -0,0 +1,13 @@
package com.auth0.jwt.exceptions;
import com.auth0.jwt.algorithms.Algorithm;
public class SignatureVerificationException extends RuntimeException {
public SignatureVerificationException(Algorithm algorithm) {
}
public SignatureVerificationException(Algorithm algorithm, Throwable cause) {
}
}

View File

@@ -0,0 +1,37 @@
package com.auth0.jwt.interfaces;
/**
* Class that represents a Json Web Token that was decoded from it's string representation.
*/
public interface DecodedJWT {
/**
* Getter for the String Token used to create this JWT instance.
*
* @return the String Token.
*/
String getToken();
/**
* Getter for the Header contained in the JWT as a Base64 encoded String.
* This represents the first part of the token.
*
* @return the Header of the JWT.
*/
String getHeader();
/**
* Getter for the Payload contained in the JWT as a Base64 encoded String.
* This represents the second part of the token.
*
* @return the Payload of the JWT.
*/
String getPayload();
/**
* Getter for the Signature contained in the JWT as a Base64 encoded String.
* This represents the third part of the token.
*
* @return the Signature of the JWT.
*/
String getSignature();
}

View File

@@ -0,0 +1,10 @@
package com.auth0.jwt.interfaces;
import java.security.interfaces.ECPrivateKey;
import java.security.interfaces.ECPublicKey;
/**
* Elliptic Curve (EC) Public/Private Key provider.
*/
public interface ECDSAKeyProvider extends KeyProvider<ECPublicKey, ECPrivateKey> {
}

View File

@@ -0,0 +1,25 @@
package com.auth0.jwt.interfaces;
import com.auth0.jwt.exceptions.JWTVerificationException;
public interface JWTVerifier {
/**
* Performs the verification against the given Token
*
* @param token to verify.
* @return a verified and decoded JWT.
* @throws JWTVerificationException if any of the verification steps fail
*/
DecodedJWT verify(String token) throws JWTVerificationException;
/**
* Performs the verification against the given decoded JWT
*
* @param jwt to verify.
* @return a verified and decoded JWT.
* @throws JWTVerificationException if any of the verification steps fail
*/
DecodedJWT verify(DecodedJWT jwt) throws JWTVerificationException;
}

View File

@@ -0,0 +1,35 @@
package com.auth0.jwt.interfaces;
import java.security.PrivateKey;
import java.security.PublicKey;
/**
* Generic Public/Private Key provider.
*
* @param <U> the class that represents the Public Key
* @param <R> the class that represents the Private Key
*/
interface KeyProvider<U extends PublicKey, R extends PrivateKey> {
/**
* Getter for the Public Key instance with the given Id. Used to verify the signature on the JWT verification stage.
*
* @param keyId the Key Id specified in the Token's Header or null if none is available. Provides a hint on which Public Key to use to verify the token's signature.
* @return the Public Key instance
*/
U getPublicKeyById(String keyId);
/**
* Getter for the Private Key instance. Used to sign the content on the JWT signing stage.
*
* @return the Private Key instance
*/
R getPrivateKey();
/**
* Getter for the Id of the Private Key used to sign the tokens. This represents the `kid` claim and will be placed in the Header.
*
* @return the Key Id that identifies the Private Key or null if it's not specified.
*/
String getPrivateKeyId();
}

View File

@@ -0,0 +1,10 @@
package com.auth0.jwt.interfaces;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
/**
* RSA Public/Private Key provider.
*/
public interface RSAKeyProvider extends KeyProvider<RSAPublicKey, RSAPrivateKey> {
}

View File

@@ -0,0 +1,189 @@
package com.auth0.jwt.interfaces;
import java.util.Date;
/**
* Holds the Claims and claim-based configurations required for a JWT to be considered valid.
*/
public interface Verification {
/**
* Require a specific Issuer ("iss") claim.
*
* @param issuer the required Issuer value. If multiple values are given, the claim must at least match one of them
* @return this same Verification instance.
*/
Verification withIssuer(String... issuer);
/**
* Require a specific Subject ("sub") claim.
*
* @param subject the required Subject value
* @return this same Verification instance.
*/
Verification withSubject(String subject);
/**
* Require a specific Audience ("aud") claim. If multiple audiences are specified, they must all be present
* in the "aud" claim.
*
* If this is used in conjunction with {@link #withAnyOfAudience(String...)}, whichever one is configured last will
* determine the audience validation behavior.
*
* @param audience the required Audience value
* @return this same Verification instance.
*/
Verification withAudience(String... audience);
/**
* Set a specific leeway window in seconds in which the Expires At ("exp") Claim will still be valid.
* Expiration Date is always verified when the value is present. This method overrides the value set with acceptLeeway
*
* @param leeway the window in seconds in which the Expires At Claim will still be valid.
* @return this same Verification instance.
* @throws IllegalArgumentException if leeway is negative.
*/
Verification acceptExpiresAt(long leeway) throws IllegalArgumentException;
/**
* Set a specific leeway window in seconds in which the Not Before ("nbf") Claim will still be valid.
* Not Before Date is always verified when the value is present. This method overrides the value set with acceptLeeway
*
* @param leeway the window in seconds in which the Not Before Claim will still be valid.
* @return this same Verification instance.
* @throws IllegalArgumentException if leeway is negative.
*/
Verification acceptNotBefore(long leeway) throws IllegalArgumentException;
/**
* Set a specific leeway window in seconds in which the Issued At ("iat") Claim will still be valid.
* This method overrides the value set with {@link #acceptLeeway(long)}.
* By default, the Issued At claim is always verified when the value is present, unless disabled with {@link #ignoreIssuedAt()}.
* If Issued At verification has been disabled, no verification of the Issued At claim will be performed, and this method has no effect.
*
* @param leeway the window in seconds in which the Issued At Claim will still be valid.
* @return this same Verification instance.
* @throws IllegalArgumentException if leeway is negative.
*/
Verification acceptIssuedAt(long leeway) throws IllegalArgumentException;
/**
* Require a specific JWT Id ("jti") claim.
*
* @param jwtId the required Id value
* @return this same Verification instance.
*/
Verification withJWTId(String jwtId);
/**
* Require a claim to be present, with any value.
* @param name the Claim's name.
* @return this same Verification instance
* @throws IllegalArgumentException if the name is null.
*/
Verification withClaimPresence(String name) throws IllegalArgumentException;
/**
* Require a specific Claim value.
*
* @param name the Claim's name.
* @param value the Claim's value.
* @return this same Verification instance.
* @throws IllegalArgumentException if the name is null.
*/
Verification withClaim(String name, Boolean value) throws IllegalArgumentException;
/**
* Require a specific Claim value.
*
* @param name the Claim's name.
* @param value the Claim's value.
* @return this same Verification instance.
* @throws IllegalArgumentException if the name is null.
*/
Verification withClaim(String name, Integer value) throws IllegalArgumentException;
/**
* Require a specific Claim value.
*
* @param name the Claim's name.
* @param value the Claim's value.
* @return this same Verification instance.
* @throws IllegalArgumentException if the name is null.
*/
Verification withClaim(String name, Long value) throws IllegalArgumentException;
/**
* Require a specific Claim value.
*
* @param name the Claim's name.
* @param value the Claim's value.
* @return this same Verification instance.
* @throws IllegalArgumentException if the name is null.
*/
Verification withClaim(String name, Double value) throws IllegalArgumentException;
/**
* Require a specific Claim value.
*
* @param name the Claim's name.
* @param value the Claim's value.
* @return this same Verification instance.
* @throws IllegalArgumentException if the name is null.
*/
Verification withClaim(String name, String value) throws IllegalArgumentException;
/**
* Require a specific Claim value.
*
* @param name the Claim's name.
* @param value the Claim's value.
* @return this same Verification instance.
* @throws IllegalArgumentException if the name is null.
*/
Verification withClaim(String name, Date value) throws IllegalArgumentException;
/**
* Require a specific Array Claim to contain at least the given items.
*
* @param name the Claim's name.
* @param items the items the Claim must contain.
* @return this same Verification instance.
* @throws IllegalArgumentException if the name is null.
*/
Verification withArrayClaim(String name, String... items) throws IllegalArgumentException;
/**
* Require a specific Array Claim to contain at least the given items.
*
* @param name the Claim's name.
* @param items the items the Claim must contain.
* @return this same Verification instance.
* @throws IllegalArgumentException if the name is null.
*/
Verification withArrayClaim(String name, Integer... items) throws IllegalArgumentException;
/**
* Require a specific Array Claim to contain at least the given items.
*
* @param name the Claim's name.
* @param items the items the Claim must contain.
* @return this same Verification instance.
* @throws IllegalArgumentException if the name is null.
*/
Verification withArrayClaim(String name, Long ... items) throws IllegalArgumentException;
/**
* Skip the Issued At ("iat") date verification. By default, the verification is performed.
*
* @return this same Verification instance.
*/
Verification ignoreIssuedAt();
/**
* Creates a new and reusable instance of the JWTVerifier with the configuration already provided.
*
* @return a new JWTVerifier instance.
*/
JWTVerifier build();
}