I'm trying to write some code to sign and validate payloads using my private/public keys in java following JOSE standards. I need to use the PS256 encryption algorithm for this.
I'm using connect2id's library Nimbus JOSE + JWT. I'm able to get to the point where I can sign a payload with a private key I load from the file system, and I can also validate it. However as part of my requirements, my header needs to have a "crit" value (explained as part of RFC-7515).
My problem is the following: As soon as I have a "crit" value in the header, my token validation fails (even if the values in the "crit" array are present in my jws header, as required by the standard). If I take out the "crit", then the signature is validated correctly.
// create RSA key used for signing.
RSAKey rsaJWK = new RSAKey.Builder(pub)
.privateKey(priv)
.keyUse(KeyUse.SIGNATURE)
.algorithm(JWSAlgorithm.PS256)
.keyID("KeyID")
.build();
// Create RSA-signer with the private key
JWSSigner signer = new RSASSASigner(rsaJWK);
// setting critical values to be used in jws header
Set crit = new HashSet();
crit.add("myHeader");
// setting additional parameters for the jws header
Map myParams = new HashMap();
myParams.put("myHeader", false);
// build the jws header with all the values needed
JWSHeader jwsHeader = new JWSHeader.Builder(JWSAlgorithm.PS256)
.type(JOSEObjectType.JOSE)
.contentType("application/json")
.keyID("KeyID")
.criticalParams(crit)
.customParams(myParams)
.build();
// build the jws object with the header we created above and a static payload for now
JWSObject jwsObject = new JWSObject(jwsHeader, new Payload("{\"message\":\"In RSA we trust!!!\"}"));
// sign the payload
jwsObject.sign(signer);
// print out the token
String s = jwsObject.serialize();
System.out.println("Your token:" + s);
// To parse the JWS and verify it, e.g. on client-side
JWSObject jwsValObj = JWSObject.parse(s);
JWSVerifier verifier = new RSASSAVerifier(pub);
// verify the signature of the parsed token
boolean sigval = jwsValObj.verify(verifier);
System.out.println("Signature Validation passed: " + String.valueOf(sigval));
I'm expecting the signature to be verified properly since the values in "crit" are present in the token given.
As soon as I remove the line with .criticalParams(crit)
, then verification goes through without a problem.
Can someone help me out with this? Am I misunderstanding something or missing some glaring detail?
Following RFC 7515, critical headers must be understood by application, so you need to indicate library that they are deferred to the application for processing
Looking at RSASSAVerifier source code, Try to change
JWSVerifier verifier = new RSASSAVerifier(pub);
with
JWSVerifier verifier = new RSASSAVerifier(pub, crit);