Skip to content

Commit

Permalink
JWE support. Resolves #113
Browse files Browse the repository at this point in the history
- impl checkpoint: adjusted @SInCE version, added KeyManagementMode concept w/ supporting interfaces
- KeyManagementMode interfaces and implementations are dummy implementations to enable compiling.  Design still needs to be vetted.
- Added JWE EncryptionAlgorithm and supporting interfaces/implementations, and refactored SignatureAlgorithm to be an interface instead of an enum to enable custom algorithms
- NoneSignatureAlgorithm cleanup. Added UnsupportedKeyExceptionTest.
- testing additions, cleanup cont'd
  • Loading branch information
lhazlewood committed Aug 18, 2020
1 parent 5c5f1b8 commit a571505
Show file tree
Hide file tree
Showing 238 changed files with 9,225 additions and 618 deletions.
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
*.class
.DS_Store

# Mobile Tools for Java (J2ME)
Expand Down
6 changes: 3 additions & 3 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,18 @@ before_install:
- export MVN_CMD="./mvnw --no-transfer-progress" # hide verbose download messages (log spam)
- |
if [[ "${TRAVIS_JDK_VERSION}" == "openjdk7" ]]; then
export MAVEN_OPTS="-Dhttps.protocols=TLSv1.2 -Xmx512m -XX:MaxPermSize=128m"
export JAVA_HOME="/usr/lib/jvm/java-7-oracle" # Set JAVA_HOME to where we want to install Oracle JDK 7
export PATH="${JAVA_HOME}/bin:${PATH}"
if [[ ! -d "${JAVA_HOME}" ]]; then
# Download and install Oracle JDK 7:
wget https://238dj3282as03k369.s3-us-west-1.amazonaws.com/jdk-7u80-linux-x64.tar.gz -O /tmp/jdk-7u80-linux-x64.tar.gz
tar xvfz /tmp/jdk-7u80-linux-x64.tar.gz -C /tmp
sudo mv /tmp/jdk1.7.0_80 "${JAVA_HOME}"
fi
# Download and install JCE Unlimited Strength Crypto policies for Oracle JDK 7:
curl -q -L -C - https://238dj3282as03k369.s3-us-west-1.amazonaws.com/UnlimitedJCEPolicyJDK7.zip -o /tmp/UnlimitedJCEPolicyJDK7.zip
sudo unzip -oj -d "$JAVA_HOME/jre/lib/security" /tmp/UnlimitedJCEPolicyJDK7.zip \*/\*.jar
Expand Down
12 changes: 8 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ enforcement.
* [Custom Clock](#jws-read-clock-custom)
* [Decompression](#jws-read-decompression)
<!-- * [Error Handling](#jws-read-errors) -->
* [Encrypted JWTs](#jwe)
* [Compression](#compression)
* [Custom Compression Codec](#compression-custom)
* [JSON Processor](#json)
Expand Down Expand Up @@ -372,13 +373,13 @@ Most complexity is hidden behind a convenient and readable builder-based [fluent

```java
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.SignatureAlgorithms;
import io.jsonwebtoken.security.Keys;
import java.security.Key;

// We need a signing key, so we'll create one just for this example. Usually
// the key would be read from your application configuration instead.
Key key = Keys.secretKeyFor(SignatureAlgorithm.HS256);
Key key = SignatureAlgorithms.HS256.generateKey();

String jws = Jwts.builder().setSubject("Joe").signWith(key).compact();
```
Expand Down Expand Up @@ -528,7 +529,7 @@ key algorithms - identified by the following names:
* `PS384`: RSASSA-PSS using SHA-384 and MGF1 with SHA-384
* `PS512`: RSASSA-PSS using SHA-512 and MGF1 with SHA-512

These are all represented in the `io.jsonwebtoken.SignatureAlgorithm` enum.
These are all represented in the `io.jsonwebtoken.security.SignatureAlgorithms` enum class.

What's really important about these algorithms - other than their security properties - is that the JWT specification
[RFC 7518, Sections 3.2 through 3.5](https://tools.ietf.org/html/rfc7518#section-3)
Expand Down Expand Up @@ -1183,7 +1184,10 @@ how to resolve your `CompressionCodec` to decompress the JWT.

Please see the [Compression](#compression) section below to see how to decompress JWTs during parsing.

<!-- TODO: ## Encrypted JWTs -->
<a name="jwe"></a>
## Encrypted JWTs

TODO: NOTE: A128GCM, A192GCM, A256GCM algorithms require JDK 8 or BouncyCastle.

<a name="compression"></a>
## Compression
Expand Down
2 changes: 1 addition & 1 deletion api/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
<parent>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-root</artifactId>
<version>0.11.3-SNAPSHOT</version>
<version>0.12.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

Expand Down
6 changes: 4 additions & 2 deletions api/src/main/java/io/jsonwebtoken/CompressionCodec.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,11 @@
public interface CompressionCodec {

/**
* The compression algorithm name to use as the JWT's {@code zip} header value.
* The algorithm name to use as the JWT's
* <a href="https://tools.ietf.org/html/rfc7516#section-4.1.3"><code>zip</code></a> header value.
*
* @return the compression algorithm name to use as the JWT's {@code zip} header value.
* @return the algorithm name to use as the JWT's
* <a href="https://tools.ietf.org/html/rfc7516#section-4.1.3"><code>zip</code></a> header value.
*/
String getAlgorithmName();

Expand Down
82 changes: 76 additions & 6 deletions api/src/main/java/io/jsonwebtoken/Header.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
* <h3>Creation</h3>
*
* <p>It is easiest to create a {@code Header} instance by calling one of the
* {@link Jwts#header() JWTs.header()} factory methods.</p>
* {@link Jwts#header() Jwts.header()} factory methods.</p>
*
* @since 0.1
*/
Expand All @@ -48,6 +48,14 @@ public interface Header<T extends Header<T>> extends Map<String,Object> {
/** JWT {@code Content Type} header parameter name: <code>"cty"</code> */
public static final String CONTENT_TYPE = "cty";

/**
* JWT {@code Algorithm} header parameter name: <code>"alg"</code>.
*
* @see <a href="https://tools.ietf.org/html/rfc7515#section-4.1.1">JWS Algorithm Header</a>
* @see <a href="https://tools.ietf.org/html/rfc7516#section-4.1.1">JWE Algorithm Header</a>
*/
public static final String ALGORITHM = "alg";

/** JWT {@code Compression Algorithm} header parameter name: <code>"zip"</code> */
public static final String COMPRESSION_ALGORITHM = "zip";

Expand Down Expand Up @@ -109,22 +117,84 @@ public interface Header<T extends Header<T>> extends Map<String,Object> {
T setContentType(String cty);

/**
* Returns the JWT <code>zip</code> (Compression Algorithm) header value or {@code null} if not present.
* Returns the JWT {@code alg} (Algorithm) header value or {@code null} if not present.
*
* <ul>
* <li>If the JWT is a Signed JWT (a JWS), the <a href="https://tools.ietf.org/html/rfc7515#section-4.1.1">
* <code>alg</code></a> (Algorithm) header parameter identifies the cryptographic algorithm used to secure the
* JWS. Consider using
* {@link io.jsonwebtoken.security.SignatureAlgorithms#forName(String) SignatureAlgorithms.forName} to
* convert this string value to a type-safe enum instance.</li>
* <li>If the JWT is an Encrypted JWT (a JWE), the
* <a href="https://tools.ietf.org/html/rfc7516#section-4.1.1"><code>alg</code></a> (Algorithm) header parameter
* identifies the cryptographic key management algorithm used to encrypt or determine the value of the Content
* Encryption Key (CEK). The encrypted content is not usable if the <code>alg</code> value does not represent a
* supported algorithm, or if the recipient does not have a key that can be used with that algorithm</li>
* </ul>
*
* @return the {@code alg} header value or {@code null} if not present. This will always be
* {@code non-null} on validly constructed JWT instances, but could be {@code null} during construction.
* @since JJWT_RELEASE_VERSION
*/
String getAlgorithm();

/**
* Sets the JWT <code>alg</code></a> (Algorithm) header value. A {@code null} value will remove the property
* from the JSON map.
* <ul>
* <li>If the JWT is a Signed JWT (a JWS), the <a href="https://tools.ietf.org/html/rfc7515#section-4.1.1">
* <code>alg</code></a> (Algorithm) header parameter identifies the cryptographic algorithm used to secure the
* JWS. Consider using
* {@link io.jsonwebtoken.security.SignatureAlgorithms#forName(String) SignatureAlgorithms.forName} to
* convert this string value to a type-safe enum instance.</li>
* <li>If the JWT is an Encrypted JWT (a JWE), the
* <a href="https://tools.ietf.org/html/rfc7516#section-4.1.1"><code>alg</code></a> (Algorithm) header parameter
* identifies the cryptographic key management algorithm used to encrypt or determine the value of the Content
* Encryption Key (CEK). The encrypted content is not usable if the <code>alg</code> value does not represent a
* supported algorithm, or if the recipient does not have a key that can be used with that algorithm</li>
* </ul>
*
* @param alg the {@code alg} header value
* @return this header for method chaining
* @since JJWT_RELEASE_VERSION
*/
T setAlgorithm(String alg);

/**
* Returns the JWT <a href="https://tools.ietf.org/html/rfc7516#section-4.1.3"><code>zip</code></a>
* (Compression Algorithm) header parameter value or {@code null} if not present.
*
* <h3>Compatiblity Note</h3>
*
* <p>While the JWT family of specifications only defines the <code>zip</code> header in the JWE
* (JSON Web Encryption) specification, JJWT will also support compression for JWS as well if you choose to use it.
* However, be aware that <b>if you use compression when creating a JWS token, other libraries may not be able to
* parse the JWS</b>. However, compression when creating JWE tokens should be universally accepted for any library
* that supports JWE.</p>
*
* @return the {@code zip} header parameter value or {@code null} if not present.
* @since 0.6.0
*/
String getCompressionAlgorithm();

/**
* Sets the JWT <code>zip</code> (Compression Algorithm) header parameter value. A {@code null} value will remove
* Sets the JWT <a href="https://tools.ietf.org/html/rfc7516#section-4.1.3"><code>zip</code></a>
* (Compression Algorithm) header parameter value. A {@code null} value will remove
* the property from the JSON map.
* <p>
* <p>The compression algorithm is NOT part of the <a href="https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25">JWT specification</a>
* and must be used carefully since, is not expected that other libraries (including previous versions of this one)
* be able to deserialize a compressed JTW body correctly. </p>
* be able to deserialize a compressed JWT body correctly. </p>
*
* <h3>Compatibility Note</h3>
*
* <p>While the JWT family of specifications only defines the <code>zip</code> header in the JWE
* (JSON Web Encryption) specification, JJWT will also support compression for JWS as well if you choose to use it.
* However, be aware that <b>if you use compression when creating a JWS token, other libraries may not be able to
* parse the JWS</b>. However, Compression when creating JWE tokens should be universally accepted for any library
* that supports JWE.</p>
*
* @param zip the JWT compression algorithm {@code zip} value or {@code null} to remove the property from the JSON map.
* @param zip the JWT compression algorithm {@code zip} value or {@code null} to remove the property from the
* JSON map.
* @since 0.6.0
*/
T setCompressionAlgorithm(String zip);
Expand Down
12 changes: 12 additions & 0 deletions api/src/main/java/io/jsonwebtoken/Jwe.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package io.jsonwebtoken;

/**
* @param <B> payload type
* @since JJWT_RELEASE_VERSION
*/
public interface Jwe<B> extends Jwt<JweHeader,B> {

byte[] getInitializationVector();

byte[] getAadTag();
}
88 changes: 88 additions & 0 deletions api/src/main/java/io/jsonwebtoken/JweHeader.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package io.jsonwebtoken;

/**
* A <a href="https://tools.ietf.org/html/rfc7516">JWE</a> header.
*
* @since JJWT_RELEASE_VERSION
*/
public interface JweHeader extends Header<JweHeader> {

/**
* JWE <a href="https://tools.ietf.org/html/rfc7516#section-4.1.1">Algorithm Header</a> name: the string literal <b><code>alg</code></b>
*/
public static final String ALGORITHM = "alg";

/**
* JWE <a href="https://tools.ietf.org/html/rfc7516#section-4.1.2">Encryption Algorithm Header</a> name: the string literal <b><code>enc</code></b>
*/
public static final String ENCRYPTION_ALGORITHM = "enc";

/**
* JWE <a href="https://tools.ietf.org/html/rfc7516#section-4.1.3">Compression Algorithm Header</a> name: the string literal <b><code>zip</code></b>
*/
public static final String COMPRESSION_ALGORITHM = "zip";

/**
* JWE <a href="https://tools.ietf.org/html/rfc7516#section-4.1.4">JWK Set URL Header</a> name: the string literal <b><code>jku</code></b>
*/
public static final String JWK_SET_URL = "jku";

/**
* JWE <a href="https://tools.ietf.org/html/rfc7516#section-4.1.5">JSON Web Key Header</a> name: the string literal <b><code>jwk</code></b>
*/
public static final String JSON_WEB_KEY = "jwk";

/**
* JWE <a href="https://tools.ietf.org/html/rfc7516#section-4.1.6">Key ID Header</a> name: the string literal <b><code>kid</code></b>
*/
public static final String KEY_ID = "kid";

/**
* JWE <a href="https://tools.ietf.org/html/rfc7516#section-4.1.7">X.509 URL Header</a> name: the string literal <b><code>x5u</code></b>
*/
public static final String X509_URL = "x5u";

/**
* JWE <a href="https://tools.ietf.org/html/rfc7516#section-4.1.8">X.509 Certificate Chain Header</a> name: the string literal <b><code>x5c</code></b>
*/
public static final String X509_CERT_CHAIN = "x5c";

/**
* JWE <a href="https://tools.ietf.org/html/rfc7516#section-4.1.9">X.509 Certificate SHA-1 Thumbprint Header</a> name: the string literal <b><code>x5t</code></b>
*/
public static final String X509_CERT_SHA1_THUMBPRINT = "x5t";

/**
* JWE <a href="https://tools.ietf.org/html/rfc7516#section-4.1.10">X.509 Certificate SHA-256 Thumbprint Header</a> name: the string literal <b><code>x5t#S256</code></b>
*/
public static final String X509_CERT_SHA256_THUMBPRINT = "x5t#S256";

/**
* JWE <a href="https://tools.ietf.org/html/rfc7516#section-4.1.13">Critical Header</a> name: the string literal <b><code>crit</code></b>
*/
public static final String CRITICAL = "crit";

/**
* Returns the JWE <a href="https://tools.ietf.org/html/rfc7516#section-4.1.2"><code>enc</code></a> (Encryption
* Algorithm) header value or {@code null} if not present.
* <p>The JWE {@code enc} (encryption algorithm) Header Parameter identifies the content encryption algorithm
* used to perform authenticated encryption on the plaintext to produce the ciphertext and the JWE
* {@code Authentication Tag}.</p>
*
* @return the JWE {@code enc} (Encryption Algorithm) header value or {@code null} if not present. This will
* always be {@code non-null} on validly constructed JWE instances, but could be {@code null} during construction.
*/
String getEncryptionAlgorithm();

/**
* Sets the JWE <a href="https://tools.ietf.org/html/rfc7516#section-4.1.2"><code>enc</code></a> (Encryption
* Algorithm) header value. A {@code null} value will remove the property from the JSON map.
* <p>The JWE {@code enc} (encryption algorithm) Header Parameter identifies the content encryption algorithm
* used to perform authenticated encryption on the plaintext to produce the ciphertext and the JWE
* {@code Authentication Tag}.</p>
*
* @param enc the encryption algorithm identifier
* @return this header for method chaining
*/
JweHeader setEncryptionAlgorithm(String enc);
}
Loading

0 comments on commit a571505

Please sign in to comment.