JOSE for the win

Blog Post created by birjo05 Employee on May 25, 2017


During our 2017 kick off meeting for CA API in APJ the Presales team were directed to prepare a presentation on a topic of interest and present to the wider team. One of the opportunities I had been working on related to the Australian New Payments Platform (NPP) project (See About New Payments Platform | RBA).

Specifically, it was an implementation which leveraged the NPP to allow for inter-bank communication.


Following my presentation @FrancoisLascelles suggested I put my notes together in a blog post so feel free to blame him if you find yourself having to read through this... 


A tale of two banks

The banks elected to use JOSE to implement secure communication of payment information. JOSE stands for Javascript Object Signing and Encryption.


As the protocol requires the use of cryptographic keying material the banks also wished to use a Hardware Security Module (See Hardware security module - Wikipedia) in order to securely store and handle the private keys.


JOSE itself is a set of standards (reference: Jose Status Pages). Before we can look at the implementation we need to understand some of the underlying acronyms.  The important acronyms are as follows:

From Javascript Object Signing and Encryption (JOSE) — jose 0.1 documentation :

  • JWT - JSON Web token is a named tuple result produced by either encrypting and signing a JWE or a JWS.
  • JWKJSON Web Key (JWK) is a JSON data structure that represents a cryptographic key.
  • JWEJSON Web Encryption
  • JWSJSON Web Signature


So basically, we start by taking some clear-text data we wish to send to another party, a signing public/private key pair and an encrypting public/private key pair as well as the public signing and encrypting certificate from the same other party.


Following the standard, the cryptographic material would be presented and consumed in JWK format although from a technical point of view the format the keying material is stored is not important.


The two banks in question are major Australian entities whose identity I can't share so for the purposes of this post I will refer to them as B1 and B2 (See Bananas in Pyjamas - ABC KIDS).


From B1's point of view:

  1. Sign the data to send using B1's private signing key.
  2. Encrypt the data to send using the B2's public encryption key. This ensures that only B2 can decrypt.
  3. Format the result into a JWT using the relevant standard.
  4. Send the JWT to B2

B2 can now:

  1. Receive the JWT from B1
  2. Decrypt the contents using B2's private encryption key.
  3. Verify the signature within the JWT using the public signing certificate from B1.
  4. Profit?



So far we have covered what JOSE is and seen the mechanism used for transmitting and receiving data using JOSE.


Sounds complicated? Fear not - the CA API Gateway product has you covered. Lets look at the API which takes some data in the form of the body in a POST message and which returns the encrypted/signed result in a JWT.


We will name this API "/to_jose". Below is a screenshot of the policy in its entirety.




Prior to creating any APIs I used the Gateway's "Private Keys" functionality to create both the signing and encryption keypairs:

Private Key Pairs


The subjectDN of each keypair denotes the intended function of the pair.


Starting with assertion #2. This simply takes the body of the POST message ${request.mainpart} and stores it in a context variable called "jwt_payload".


JWT Payload


Assertion #3 creates the JWK using the encryption certificate from the Gateway's keystore. This in turn is stored within the jwks context variable:


JWK Properties


Now that all the pieces are ready it is time to use the "Encode Json Web Token" assertion to perform the encryption and signing. Each page of this assertion are shown below. Note that the final JWT is stored in the context variable 'jwe'.



encode signing

It is not clear why there is a warning for the RSA backed set of signing algorithms. The only argument I could come up with related to performance.


The #5 assertion simple retrieves the 'compact' representation of the JWT from the 'jwe' context variable and copies it to the context variable 'output'.

Finally, the generic 'Return response to sender' assertion returns the JWT to the client.


Here is an example of this endpoint being exercised with the exciting input of {'hello': 'world'}:

# curl -d "{'hello': 'world'}"


Messy right? That's OK - this token isn't meant for human consumption.


Now that we have created a JWT we need to create an endpoint to decrypt it. Here we have the "/from_jose" endpoint:



Assertion #2 is identical to the "/to_jose" endpoint so no need to go into detail there.

Assertion #3 uses the 'jose_encryptionkey' to decrypt the JWT:


And assertion #4 uses the 'jose_signingkey' to perform the signature verification.


All done! All that's left is to poke the response into the return message. For the purposes of this demo I have included additional information such as the header, signature as well as whether or not the signature itself was valid:



OK - moment of truth. Lets push that token to this '/from_jose' endpoint and see if we retrieve our original 'hello world' json data. To minimise the size I've copied the token into a file at /tmp/jwt.


$ curl -d @/tmp/jwt

   "jwt_decrypted": {
   "header": {"typ":"JWT","alg":"RS512"},
   "payload": {'hello': 'world'},
   "signature": "HrV7ZjePA4Ri2X84idE0QuKSS6gq0Q7ioIkInLcmlSGeu6Dhf6DSD9pe3AgiWv8Xbrp-BN59vYrUB2p5pXLkYW_ZKUFSb0de0c4EeLDQdrmRxMEBcyLIquHOk5iBYQR_S-U2jatUacI8Yvdum9EeNyNeOpx6XAMwDGbb5K-CtjRE1HsgMc5SYk9lzQXdxoVKo2XwV1fDR6b5fNG7wtehRn71sFOm51eSClcMzlbJiQRSXhwPk-xsuDjMZyNtC6-bgwWXTnk_lKSh034aCqgtYdnweDtFoMF0w1kjTVPsbm595v6j0mnRl0sFRrdFoTxzvVcqDubWC_ZjdDyNFqG57w",
   "valid": "true"


Sure enough - there is our 'payload' with the original data.



In conclusion, we have walked through what JOSE is as well as covered how to use the built in functionality of the CA Gateway to implement a secure communications protocol using the set of JOSE standards. In practise some minor changes were required (such as manually constructing the JWKs as one side will not have the private keys of the other). In a very short amount of time it was possible to implement a fairly complicated standard and expose APIs which implemented the core functionality.


As for the banks in question, B1 is moving forward with our Gateway and will be implementing it in production, along side a HSM in the coming months. I trust this will be a success and other customers will be interested in leveraging the same capabilities in the Gateway to implement the same within their organisations.


Signing off for now!

- J.



Some or all of the above post was unashamedly copied from the following sources.


Other highly recommended, worthwhile and related reading material