Aller au contenu
ecdsa.com
Java · Kotlin

jose4j

jose4j de Brian Campbell, la bibliothèque JOSE sur laquelle reposent plusieurs serveurs d’identité Java : un JwtConsumer qui, par défaut, bloque none et refuse les types de clés incompatibles, mais autorise tout autre algorithme pour une clé, sauf si vous restreignez les algorithmes.
Licence
Apache-2.0
Version vérifiée
0.9.7 ·
Code source
bitbucket.org/b_c/jose4j
Documentation
bitbucket.org/b_c/jose4j/wiki/Home

Compatibilité en un coup d’œil

JOSE et JWT

Algorithmes JWS
HS256HS384HS512RS256RS384RS512PS256PS384PS512ES256ES384ES512EdDSA

jose4j implémente JWS, JWE, JWK et JWT sur les fournisseurs propres du JDK, avec JsonWebSignature pour la signature et un JwtConsumer construit par JwtConsumerBuilder pour la vérification et le contrôle des claims. La 0.9.7 a fonctionné en aller-retour avec HS, RS, PS et ES en 256/384/512 ainsi qu’avec EdDSA ; ES256K, Ed25519 et Ed448 ne sont pas des noms d’algorithmes reconnus.

Les valeurs par défaut bloquent les deux attaques classiques, mais laissent l’algorithme ouvert. none est refusé ('none' is a blocked algorithm.), sauf si les signatures sont explicitement désactivées, et le type de clé doit correspondre : un jeton RS256 présenté à une clé EC et un jeton HS256 dont la clé est le texte PEM de la clé EC ont tous deux échoué (cannot be used for HMAC verification). Tout autre algorithme que la clé peut exécuter est en revanche accepté : fixez-le donc avec setJwsAlgorithmConstraints(ConstraintType.PERMIT, ...), comme le fait l’exemple. Une HmacKey construite à partir des octets PEM a vérifié le jeton HS256 forgé : les clés doivent provenir de la configuration, jamais de ce qu’affirme le jeton.

Les tailles de clé sont contrôlées : ES256 refuse une clé P-384 (expects a key using P-256 but was P-384) et HS256 a refusé une clé de 16 octets, car la RFC 7518 exige des clés au moins aussi longues que le condensat. Les signatures ES256 sont le r‖s brut de 64 octets ; une signature DER échoue avec Invalid JWS Signature, et le débogueur JWT en montre la longueur.

Les valeurs par défaut des claims tirent en sens contraires : l’absence de tolérance au décalage d’horloge est plus stricte que ce qu’attendent la plupart des équipes, et un exp non obligatoire est plus laxiste. setRequireExpirationTime(), setExpectedIssuer(), setExpectedAudience() et setAllowedClockSkewInSeconds() ont leur place dans tout consommateur qui lit des jetons provenant d’un autre service.

Pour les jetons chiffrés, l’inspecteur JWE montre ce que contient un JWE produit par jose4j.

Les faits et les vérifications qui les fondent

Rien de ce qui suit n’est copié d’une documentation. La vérification content/libraries/verify/jose4j/run.sh a exécuté jose4j 0.9.7 dans l’image de conteneur maven:3.9.16-eclipse-temurin-25 le 20 octobre 2026 ; la page doit correspondre à ce que la vérification a affiché, et chaque fait cite les lignes en question.

  • Algorithmes JWS

    HS256HS384HS512RS256RS384RS512PS256PS384PS512ES256ES384ES512EdDSA

    Signature et vérification réussies avec HS, RS, PS et ES en 256/384/512 ainsi qu’avec EdDSA ; ES256K, Ed25519 et Ed448 ont levé InvalidAlgorithmException.

    Relevé par la vérification
    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]).
  • Encodage des signatures ES256

    raw

    Les signatures ES256 font 64 octets, en r‖s brut.

    Relevé par la vérification
    fact jws-ecdsa-encoding = raw
  • Signature DER dans un JWS

    rejected

    Une signature ES256 encodée en DER échoue avec InvalidJwtSignatureException: JWT rejected due to invalid signature.

    Relevé par la vérification
    fact jws-der-signature = rejected
    evidence jws-der-signature: InvalidJwtSignatureException: JWT rejected due to invalid signature. Additional details: [[9] Invalid JWS Signature:
  • Liste d’algorithmes autorisés

    from-key

    Sans contraintes d’algorithme, c’est le type de clé qui décide : un jeton RS256 présenté à une clé EC a échoué avec The given key (algorithm=EC) is not valid for SHA256withRSA.

    Relevé par la vérification
    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):
  • Jetons non signés (alg none)

    opt-in

    Le consommateur par défaut refuse les jetons non signés avec 'none' is a blocked algorithm. ; setDisableRequireSignature() sans contraintes d’algorithme les accepte.

    Relevé par la vérification
    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
  • Clé publique utilisée comme secret HMAC

    rejected

    Un jeton HS256 dont la clé est le texte PEM a échoué face à la clé publique EC, mais une HmacKey construite à partir des octets PEM l’a vérifié.

    Relevé par la vérification
    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
  • Courbe vérifiée par rapport à alg

    enforced

    Signer en ES256 avec une clé P-384 échoue avec ES256/SHA256withECDSA expects a key using P-256 but was P-384.

    Relevé par la vérification
    fact jwt-ecdsa-curve-check = enforced
    evidence jwt-ecdsa-curve-check: InvalidKeyException: ES256/SHA256withECDSA expects a key using P-256 but was P-384
  • Décalage d’horloge toléré par défaut

    0s

    Aucune tolérance au décalage d’horloge par défaut : un jeton expiré depuis trois secondes a été rejeté.

    Relevé par la vérification
    fact jwt-clock-skew = 0s
  • Claim d’expiration obligatoire

    no

    Un jeton sans exp a été accepté ; setRequireExpirationTime() rend ce claim obligatoire.

    Relevé par la vérification
    fact jwt-exp-required = no
  • Secret HMAC court

    rejected

    HS256 a refusé une clé de 16 octets : A key of the same size as the hash output ... or larger MUST be used.

    Relevé par la vérification
    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

Utilisation

Signer un jeton ES256 avec une JWK générée et le consommer avec l’algorithme fixé, l’émetteur et exp obligatoires et 30 secondes de tolérance.
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());
    }
}

Le banc de test des extraits de code exécute chaque exemple tel quel dans l’image de conteneur maven:3.9.16-eclipse-temurin-25, et l’exécution échoue si la sortie ne correspond pas.

Mise en place
mvn -q -B dependency:copy-dependencies -DoutputDirectory=lib >/dev/null
Commande
java -cp 'lib/*' Usage.java
La sortie doit correspondre à cette expression régulière
sub: user-42

Bibliothèques