Zum Inhalt springen
ecdsa.com
Java · Kotlin

jose4j

jose4j von Brian Campbell, die JOSE-Bibliothek hinter mehreren Java-Identitätsservern: ein JwtConsumer, der standardmäßig none blockiert und unpassende Schlüsseltypen ablehnt, für einen Schlüssel aber jeden anderen Algorithmus zulässt, sofern du die Algorithmen nicht einschränkst.
Lizenz
Apache-2.0
Geprüfte Version
0.9.7 ·
Quellcode
bitbucket.org/b_c/jose4j
Dokumentation
bitbucket.org/b_c/jose4j/wiki/Home

Kompatibilität auf einen Blick

JOSE und JWT

JWS-Algorithmen
HS256HS384HS512RS256RS384RS512PS256PS384PS512ES256ES384ES512EdDSA

jose4j implementiert JWS, JWE, JWK und JWT auf Basis der JDK-eigenen Provider, mit JsonWebSignature zum Signieren und einem mit JwtConsumerBuilder gebauten JwtConsumer für die Prüfung von Signaturen und Claims. Version 0.9.7 bestand den Roundtrip mit HS, RS, PS und ES bei 256/384/512 sowie mit EdDSA; ES256K, Ed25519 und Ed448 sind keine bekannten Algorithmusnamen.

Die Standardeinstellungen blockieren die beiden klassischen Angriffe, lassen den Algorithmus aber offen. none wird abgelehnt ('none' is a blocked algorithm.), sofern Signaturen nicht ausdrücklich abgeschaltet sind, und der Schlüsseltyp muss passen: Ein RS256-Token, geprüft mit einem EC-Schlüssel, und ein HS256-Token mit dem PEM-Text des EC-Schlüssels als Schlüssel scheiterten beide (cannot be used for HMAC verification). Jeden anderen Algorithmus, den der Schlüssel ausführen kann, akzeptiert die Bibliothek jedoch – lege den Algorithmus also mit setJwsAlgorithmConstraints(ConstraintType.PERMIT, ...) fest, wie es das Beispiel tut. Mit einem aus den PEM-Bytes gebauten HmacKey bestand das gefälschte HS256-Token die Prüfung – Schlüssel müssen aus der Konfiguration kommen, nie aus dem, was das Token behauptet.

Schlüssellängen werden durchgesetzt: ES256 lehnt einen P-384-Schlüssel ab (expects a key using P-256 but was P-384), und HS256 lehnte einen 16-Byte-Schlüssel ab, weil RFC 7518 Schlüssel verlangt, die mindestens so lang sind wie die Ausgabe der Hashfunktion. ES256-Signaturen sind das 64 Byte lange rohe r‖s; eine DER-Signatur scheitert mit Invalid JWS Signature – der JWT-Debugger zeigt die Länge.

Bei den Claims fallen die Standardeinstellungen gegensätzlich aus: Die fehlende Toleranz für Uhrenabweichungen (Clock Skew) ist strenger, als die meisten Teams erwarten, das nicht verpflichtende exp dagegen großzügiger. setRequireExpirationTime(), setExpectedIssuer(), setExpectedAudience() und setAllowedClockSkewInSeconds() gehören in jeden Consumer, der Tokens eines anderen Dienstes liest.

Bei verschlüsselten Tokens zeigt der JWE-Inspektor, was ein von jose4j erzeugtes JWE enthält.

Fakten und die Prüfungen dahinter

Nichts im Folgenden ist aus einer Dokumentation abgeschrieben. Das Prüfskript content/libraries/verify/jose4j/run.sh hat jose4j 0.9.7 am 20. Oktober 2026 im Container-Image maven:3.9.16-eclipse-temurin-25 ausgeführt; die Seite muss mit seiner Ausgabe übereinstimmen, und jeder Fakt führt die zugehörigen Zeilen auf.

  • JWS-Algorithmen

    HS256HS384HS512RS256RS384RS512PS256PS384PS512ES256ES384ES512EdDSA

    Signieren und Prüfen funktionierten mit HS, RS, PS und ES bei 256/384/512 sowie mit EdDSA; ES256K, Ed25519 und Ed448 lösten InvalidAlgorithmException aus.

    Von der Prüfung aufgezeichnet
    fact jws-algorithms = HS256, HS384, HS512, RS256, RS384, RS512, PS256, PS384, PS512, ES256, ES384, ES512, EdDSA
    evidence jws-algorithms: ES256K: InvalidAlgorithmException: ES256K is an unknown, unsupported or unavailable alg algorithm (not one of [none, HS256, HS384, HS512, EdDSA, ES256, ES384, ES512, RS256, RS384, RS512, PS256, PS384, PS512]).
    evidence jws-algorithms: Ed25519: InvalidAlgorithmException: Ed25519 is an unknown, unsupported or unavailable alg algorithm (not one of [none, HS256, HS384, HS512, EdDSA, ES256, ES384, ES512, RS256, RS384, RS512, PS256, PS384, PS512]).
    evidence jws-algorithms: Ed448: InvalidAlgorithmException: Ed448 is an unknown, unsupported or unavailable alg algorithm (not one of [none, HS256, HS384, HS512, EdDSA, ES256, ES384, ES512, RS256, RS384, RS512, PS256, PS384, PS512]).
  • Kodierung von ES256-Signaturen

    raw

    ES256-Signaturen bestehen aus 64 Byte rohem r‖s.

    Von der Prüfung aufgezeichnet
    fact jws-ecdsa-encoding = raw
  • DER-Signatur in einer JWS

    rejected

    Eine DER-kodierte ES256-Signatur scheitert mit InvalidJwtSignatureException: JWT rejected due to invalid signature.

    Von der Prüfung aufgezeichnet
    fact jws-der-signature = rejected
    evidence jws-der-signature: InvalidJwtSignatureException: JWT rejected due to invalid signature. Additional details: [[9] Invalid JWS Signature:
  • Allowlist der Algorithmen

    from-key

    Ohne Einschränkung der Algorithmen entscheidet der Schlüsseltyp: Ein RS256-Token scheiterte an einem EC-Schlüssel mit The given key (algorithm=EC) is not valid for SHA256withRSA.

    Von der Prüfung aufgezeichnet
    fact jwt-algorithm-allowlist = from-key
    evidence jwt-algorithm-allowlist: JwtConsumer without algorithm constraints, RS256 token against an EC key: InvalidJwtException: JWT processing failed. Additional details: [[17] Unable to process JOSE object (cause: org.jose4j.lang.InvalidKeyException: The given key (algorithm=EC) is not valid for SHA256withRSA):
  • Unsignierte Tokens (alg none)

    opt-in

    Der Standard-Consumer lehnt unsignierte Tokens mit 'none' is a blocked algorithm. ab; setDisableRequireSignature() ohne Einschränkung der Algorithmen akzeptiert sie.

    Von der Prüfung aufgezeichnet
    fact jwt-alg-none = opt-in
    evidence jwt-alg-none: default JwtConsumer: InvalidJwtException: JWT processing failed. Additional details: [[17] Unable to process JOSE object (cause: org.jose4j.lang.InvalidAlgorithmException: 'none' is a blocked algorithm.):
    evidence jwt-alg-none: setDisableRequireSignature with no algorithm constraints: verified
  • Öffentlicher Schlüssel als HMAC-Secret

    rejected

    Ein HS256-Token mit dem PEM-Text als Schlüssel scheiterte am öffentlichen Schlüssel vom Typ EC, mit einem aus den PEM-Bytes gebauten HmacKey bestand es dagegen die Prüfung.

    Von der Prüfung aufgezeichnet
    fact jwt-hmac-public-key = rejected
    evidence jwt-hmac-public-key: JwtConsumer with the EC public key: InvalidJwtException: JWT processing failed. Additional details: [[17] Unable to process JOSE object (cause: org.jose4j.lang.InvalidKeyException: class sun.security.ec.ECPublicKeyImpl cannot be used for HMAC verification.):
    evidence jwt-hmac-public-key: JwtConsumer with an HmacKey built from the PEM bytes: verified
  • Abgleich der Kurve mit alg

    enforced

    Das Signieren mit ES256 und einem P-384-Schlüssel scheitert mit ES256/SHA256withECDSA expects a key using P-256 but was P-384.

    Von der Prüfung aufgezeichnet
    fact jwt-ecdsa-curve-check = enforced
    evidence jwt-ecdsa-curve-check: InvalidKeyException: ES256/SHA256withECDSA expects a key using P-256 but was P-384
  • Standardtoleranz für Uhrabweichungen

    0s

    Standardmäßig keine Toleranz für Uhrenabweichungen (Clock Skew): Ein Token, das drei Sekunden zuvor abgelaufen war, wurde abgelehnt.

    Von der Prüfung aufgezeichnet
    fact jwt-clock-skew = 0s
  • Ablauf-Claim erforderlich

    no

    Ein Token ohne exp wurde akzeptiert; setRequireExpirationTime() macht den Claim zur Pflicht.

    Von der Prüfung aufgezeichnet
    fact jwt-exp-required = no
  • Kurzes HMAC-Secret

    rejected

    HS256 lehnte einen 16-Byte-Schlüssel ab: A key of the same size as the hash output ... or larger MUST be used.

    Von der Prüfung aufgezeichnet
    fact jwt-hmac-short-secret = rejected
    evidence jwt-hmac-short-secret: HS256 with a 16-byte key: InvalidKeyException: A key of the same size as the hash output (i.e. 256 bits for HS256) or larger MUST be used with the HMAC SHA algorithms but this key is only 128 bits

Verwendung

Signiere ein ES256-Token mit einem generierten JWK und verarbeite es mit festgelegtem Algorithmus, verpflichtendem Aussteller und exp sowie 30 Sekunden Toleranz.
import org.jose4j.jwa.AlgorithmConstraints.ConstraintType;
import org.jose4j.jwk.EcJwkGenerator;
import org.jose4j.jwk.EllipticCurveJsonWebKey;
import org.jose4j.jws.AlgorithmIdentifiers;
import org.jose4j.jws.JsonWebSignature;
import org.jose4j.jwt.JwtClaims;
import org.jose4j.jwt.consumer.JwtConsumer;
import org.jose4j.jwt.consumer.JwtConsumerBuilder;
import org.jose4j.keys.EllipticCurves;

public class Usage {
    public static void main(String[] args) throws Exception {
        EllipticCurveJsonWebKey key = EcJwkGenerator.generateJwk(EllipticCurves.P256);
        JwtClaims claims = new JwtClaims();
        claims.setSubject("user-42");
        claims.setIssuer("https://auth.example.com");
        claims.setExpirationTimeMinutesInTheFuture(10);

        JsonWebSignature jws = new JsonWebSignature();
        jws.setPayload(claims.toJson());
        jws.setAlgorithmHeaderValue(AlgorithmIdentifiers.ECDSA_USING_P256_CURVE_AND_SHA256);
        jws.setKey(key.getPrivateKey());

        // Pin the algorithm and require exp; the defaults would allow any non-'none' alg for the key.
        JwtConsumer consumer = new JwtConsumerBuilder()
            .setJwsAlgorithmConstraints(ConstraintType.PERMIT, AlgorithmIdentifiers.ECDSA_USING_P256_CURVE_AND_SHA256)
            .setVerificationKey(key.getPublicKey())
            .setExpectedIssuer("https://auth.example.com")
            .setRequireExpirationTime()
            .setAllowedClockSkewInSeconds(30)
            .build();
        System.out.println("sub: " + consumer.processToClaims(jws.getCompactSerialization()).getSubject());
    }
}

Die Snippet-Testumgebung führt jedes Beispiel unverändert im Container-Image maven:3.9.16-eclipse-temurin-25 aus, und der Lauf schlägt fehl, wenn die Ausgabe nicht übereinstimmt.

Einrichtung
mvn -q -B dependency:copy-dependencies -DoutputDirectory=lib >/dev/null
Befehl
java -cp 'lib/*' Usage.java
Ausgabe muss passen (regulärer Ausdruck)
sub: user-42

Bibliotheken