RFC 7515 -> Appendix F (Detached Content)

@Dino-at-Google

Need assistance with detached jws signature for open banking using PS256 alg.

https://openbankinguk.github.io/read-write-api-site3/v3.1.6/profiles/read-write-data-api-profile.htm...

x-jws-signature -> Able to detach content but having challenges in verification.

Ref:

https://medium.com/syntaxa-tech-blog/open-banking-message-signing-b4ab4f7f92d1

https://medium.com/syntaxa-tech-blog/more-open-banking-message-signing-fe461f0a627d

It is extended from the original code to implement the feature..

https://github.com/apigee/iloveapis2015-jwt-jwe-jws/tree/master/jwt_signed

Not sure what is making it unhappy to validate the signature(key is valid,sign -not sure (both are base64 encoded while creation/validation ,crit headers seems to be deferred while validation but why? not sure)

Observation is bitStringKey(BitArray) & SigningInputString values differ..Do they need to match? Unable to figure out at the moment and looking for guidance.

Is it possible to open a case #? or if you have access to my org vinnumca-trial -> GeneratJWT_rev26_2020_09_04 (rev2)

Looking forward for thoughts.

0 8 541
8 REPLIES 8

sorry I won't be able to help you debug your Java code.

I'm aware of the need for detached content in JWS, and we have a pending change that will add this to the builtin policies. (ref: b/158204922)

At the moment, the iloveapis2015 repo does not include a policy that can generate a JWS with detached content. I can work on an update to provide that , but it won't be today. Maybe tomorrow.

Would that be acceptable?

EDIT:

Vinay, I updated the classes at https://github.com/apigee/iloveapis2015-jwt-jwe-jws/tree/master/jwt_signed/callout ; they now can generate and verify signed JWS, with or without detached content. It also works with the PS256 algorithm. I've also added support for specifying the public key source via the JWKS URI. (Check the README), You need v1.0.20 for that change.

Check it out. See if it works for you. Please note that with the version change, I also changed some of the class names and the package names. That means you need to modify your Policy configuration appropriately. Check the README for the updated examples.

Sure. Thankyou. Will continue troubleshoot but want to learn what is the gap in my understanding and apply a fix.Attached the code for reference.

We use jwks url + kid to extract the certificate and reattach it before validating.

Attache Java code for reference.

jwtsigned.zip

See my updated response above.

Hey Vinay, did you get a chance to look?

Dino,

Thankyou for your quick help. Working on validation.

Will keep posted.

Thanks,

Vinay

We are doing different & need help. May be a call (if possible/email exchange) or some sort of way where we can discuss to resolve the issue. It is 1 step to close it but not able to identify what is the root cause. Tried different valid keys combination but it still fails to validate.

For Creation, we pass below properties & produce a detached JWS (which has critical params).

==

String jsonClaim = "{\"id\":1234,\"verified\":true,\"allocations\":[4,\"seven\",false]}";
Map properties = new HashMap();
properties.put("issuer", "XX1XX");
properties.put("audience", "XXXX2X");
properties.put("subject", "XXXX2");
properties.put("algorithm", "PS256");
properties.put("debug", "true");
properties.put("private-key", privateKeyMap.get("rsa-private-3"));
properties.put("private-key-password", "XXXX");
properties.put("expiresIn", "300"); // seconds
properties.put("jti", jti);
properties.put("kid", "XXXXXX");
properties.put("claim_json_account", jsonClaim);

For Validating by passing detached JWS & same jsonClaim/payload to validate the signature.

String jsonClaim = "{\"id\":1234,\"verified\":true,\"allocations\":[4,\"seven\",false]}";
Map properties = new HashMap();
properties.put("algorithm", "PS256");
properties.put("jwt", jwtMap.get("ms3"));
properties.put("payload", jsonClaim);
properties.put("jwksUri", "https://test.aaaa.com/v1/test/jwks.jwks");


0> Recieve the detached JWS + payload & reattach with all 3 parts to produce JWS.
1> Get Header,Kid,validate alg
2> Get & validate public Key (Providing JWKS,KID & extracting the x5c from jwks url & constructing the certificate)
3> Pass pub key with headers & critical params to verify
4> We see issues during the verification at step 3.

JWSVerifier jwsVerifier = new RSASSAVerifier(pubKey,jwsObject.getHeader().getCriticalParams());

if (jwsObject.verify(jwsVerifier)) {
verified = true;
msgCtxt.setVariable(varName("verified"), "true");
} else {
msgCtxt.setVariable(varName("verified"), "false");

You have the zip file which has the code for reference.

==

Update:

Looks like two possibilities with the test.It is appending = which it is generating...

1. payload padding issue (=)

Below payload part is causing issues

 private String reattachJws(String detachedJws, String unencodedPayload) {
        String[] jwsParts = StringUtils.split(detachedJws, ".");
        byte[] encodedPayload = Base64.getEncoder().encode(unencodedPayload.getBytes());

        return jwsParts[0] + "." + new String(encodedPayload)+ "." + jwsParts[1];
    }

==

Base64url Encoding Base64 encoding using the URL- and filename-safe character set defined in Section 5 of RFC 4648 [RFC4648], with all trailing '=' characters omitted (as permitted by Section 3.2) and without the inclusion of any line breaks, whitespace, or other additional characters. Note that the base64url encoding of the empty octet sequence is the empty string. (See Appendix C for notes on implementing base64url encoding without padding.)

==

2.critical params

Need to investigate why adding crit params cause an issue..

-Vinay

It seems like you should use Base64.getUrlEncoder() rather than Base64.getEncoder().

BTW, What you're doing - re-splicing the payload into the encoded JWT string - should work, but also there's a way to do what you want without doing string manipulation, using the nimbus library. You just pass the detached content to the verifier constructor. (If i recall correctly).

Crit params are tricky to handle.

Even so, it sounds like you have this nearly figured out.

I understand you've been asking me for help, but it's outside my area of focus. You're asking me to review Java code that you wrote, code. that is not behaving the way you want it to behave, even outside of the Apigee execution context. That's not my thing!

I've updated MY callout , and I've added features to it, like the support for detached content. It seems like you don't want to use what I wrote, for whatever reason. That's fine, no problem! That's your prerogative. but I'm not in the practice of reviewing the code of everyone else's Java callouts.

Good luck!

Thankyou for your guidance. Was able to move forward.

Found padding issue which got resolved. Was able to verify it.

byte[] encodedPayload = Base64.getUrlEncoder().withoutPadding().encode(unencodedPayload.getBytes());