Verifying JWS with detached payload using jose4j fails
As per this SO Question, I’m having an issue with verifying a JWS with a detached payload. This is the code I’m using:
public class TestPayconiqManager extends TestCase{
public static void testVerifySignature() {
String payload = "{\"paymentId\":\"d927a7c8cca3392907808ef2\",\"transferAmount\":1310,\"tippingAmount\":0,"
+ "\"amount\":1310,\"totalAmount\":1310,\"description\":\"Invoice Payment\",\"reference\":\"0006-485\","
+ "\"createdAt\":\"2021-12-16T13:41:08.726Z\",\"expireAt\":\"2031-12-16T23:53:08.726Z\",\"succeededAt\":\"2021-12-16T13:41:20.189Z\","
+ "\"status\":\"SUCCEEDED\",\"debtor\":{\"name\":\"Koen\",\"iban\":\"*************24680\"},\"currency\":\"EUR\"}";
String signature = "eyJ0eXAiOiJKT1NFK0pTT04iLCJraWQiOiJlcy5zaWduYXR1cmUuZXh0LjIwMjIiLCJhbGciOiJFUzI1NiIsImh0d"
+ "HBzOi8vcGF5Y29uaXEuY29tL2lhdCI6IjIwMjEtMTItMTZUMTM6NDE6MjAuMjA5NTU0WiIsImh0dHBzOi8vcGF5Y29uaXEuY29tL2p0aSI"
+ "6IjIzZjVhNzVkMTNmYWMzOWEiLCJodHRwczovL3BheWNvbmlxLmNvbS9wYXRoIjoiaHR0cHM6Ly90ZXN0Mi5zb25ldGFzLmV1L2Z1Z2Evc"
+ "mVzdC9wYXljb25pcS9pbnZvaWNlUGF5bWVudCIsImh0dHBzOi8vcGF5Y29uaXEuY29tL2lzcyI6IlBheWNvbmlxIiwiaHR0cHM6Ly9wYXl"
+ "jb25pcS5jb20vc3ViIjoiNjFiMDcxNThkZjUwODkwMDA3ZGM3Y2NhIiwiY3JpdCI6WyJodHRwczovL3BheWNvbmlxLmNvbS9pYXQiLCJod"
+ "HRwczovL3BheWNvbmlxLmNvbS9qdGkiLCJodHRwczovL3BheWNvbmlxLmNvbS9wYXRoIiwiaHR0cHM6Ly9wYXljb25pcS5jb20vaXNzIiw"
+ "iaHR0cHM6Ly9wYXljb25pcS5jb20vc3ViIl19..AZCpJ_3M8fKyK_sQ0XS9ifdCnZUiQHReQ7owWhVdrfs90mFj66z9XEh-Fcl_IteSUgR"
+ "JU7-TrLDdEfrISvG0lw";
String[] critHeaders = {
"https://payconiq.com/sub",
"https://payconiq.com/iss",
"https://payconiq.com/iat",
"https://payconiq.com/jti",
"https://payconiq.com/path"
};
String key = "{"
+ "\"kty\": \"EC\","
+ "\"use\": \"sig\","
+ "\"x5t#S256\": \"IZOqCxLESbQkCaObdW1kxMPgV5VFGb9nFkjiwL0G_eg\","
+ "\"crv\": \"P-256\","
+ "\"kid\": \"es.signature.ext.2022\","
+ "\"alg\": \"ES256\","
+ "\"x5c\": ["
+ "\"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\""
+ "],"
+ "\"x\": \"SKS3tNpbLjLOhtZUEEcN2aOBpQcMYtYexAw-hgvTMWE\","
+ "\"y\": \"GSTE5AysnVQoPeeLh1dwJmMfK_YYa9aE0gI5oKyj0SU\""
+ "}";
try{
JsonWebSignature jws = new JsonWebSignature();
PublicJsonWebKey jwk = PublicJsonWebKey.Factory.newPublicJwk(key);
jws.setAlgorithmConstraints(new AlgorithmConstraints(AlgorithmConstraints.ConstraintType.PERMIT,
AlgorithmIdentifiers.ECDSA_USING_P256_CURVE_AND_SHA256));
jws.setKnownCriticalHeaders(critHeaders);
jws.setCompactSerialization(signature);
jws.setPayload(payload);
jws.setKey(jwk.getPublicKey());
boolean result = jws.verifySignature();
Assert.assertTrue(result);
} catch (JoseException e){
e.printStackTrace();
}
}
}
This is the code that does work in Nimbus, signature and payload are the same, jwk is retrieved from jwks here but is the same.
JWSObject jws = JWSObject.parse(signature, new Payload(payload));
//retrieves same key as above from keyStore
JWK jwk = payconiqJWK.getKeyByKeyId(jws.getHeader().getKeyID());
JWSVerifier verifier = null;
if(jwk.getKeyType() == KeyType.EC){
verifier = new ECDSAVerifier(jwk.toECKey().toECPublicKey(), jws.getHeader().getCriticalParams());
} else if (jwk.getKeyType() == KeyType.RSA){
verifier = new RSASSAVerifier(jwk.toRSAKey().toRSAPublicKey(), jws.getHeader().getCriticalParams());
}
result = jws.verify(verifier);
the keystore used is found at following URL: https://ext.payconiq.com/certificates
Comments (5)
-
-
In this case it seems that the detached payload is being conveyed in unencoded form but the signature is over the encoded payload (and the expectation that the receiver do the encoding itself before or as part of the signature check). Which is not exactly a typical usage. But not necessarily unreasonable. The only reason it didn’t work with jose4j was due to a defect with inconsistent internal representation of the payload and encoded payload in
JsonWebSignature
that only seems to manifest when used like this.
-
repo owner - changed status to resolved
JsonWebSignature's payload and encoded payload could get in an inconsistent state when trying to verify a JWS with detached payload that needed to be encoded. Fixes Issue
#194→ <<cset f8738d73a5c8>>
-
reporter In this case it seems that the detached payload is being conveyed in unencoded form but the signature is over the encoded payload
I suspected this was the issue, thanks for looking into it!
-
repo owner - changed status to closed
released with jose4j-0.7.10
- Log in to comment
Thanks for the detail. Very helpful. More info to come but in the meantime adding a
jws.setEncodedPayload(null);
right afterjws.setCompactSerialization(signature);
will make it work.