Enhancements coming soon in JWT Policies

There are some changes and enhancements coming in the JWT policies in Apigee Edge.

The Highlights:

  • New algorithms: ECDSA and PSS
  • JWS is now supported
  • Critical Headers
  • VerifyJWT and VerifyJWS now support a JWKS uri
  • For Generate*, key encryption algorithms beyond DES-EDE3-CBC
  • dynamic top level claims

And here are some details:

  1. New algorithms: ECDSA and PSS
    The Elliptic Curve algorithms and the RSASSA-PSS algorithms defined in the JWA spec are now supported in the GenerateJWT and VerifyJWT policies. The ECDSA algorithms use a type of public/private keypair that is similar to RSA keys, but not the same. These keys are known as elliptic curve keys. While an RSA key of various bit strength can be used with RS256, RS384, and RS512, the EC key is specific to the algorithm strength. So you need to use a distinct key for each of ES256 ES384 and ES512. Consult the openssl documentation for details on how to construct keypairs for ECDSA.
    The RSASSA-PSS algorithm is very similar to the RSASSA-PKCS1_5 algorithm, the only difference is in the padding that is applied to the plaintext. You can use the same RSA keys with PS256, PS384, and PS512 that you have used with RS256, RS384, and RS512. I won't make specific recommendations on whether you should use RS* or PS*, but I will point out that the UK OpenBanking is insisting on PS* over RS* for better security.
  2. JWS is now supported
    While the idea of signed JWT is very well understood, a signed JWT is really just a special case of a JWS. JWS describes how to sign "anything". A JWT signs a JSON payload, but a JWS can have a payload of any type, including a stream of bytes that does not represent a JSON or a string at all. This is handy when you have image data or other binary data that you'd like to sign.
    Apigee Edge now includes new policies with names GenerateJWS, VerifyJWS and DecodeJWS which are analogs to the JWT policies. The JWS policies support all the same key types and algorithms as JWT, including the newly supported ECDSA and PSS algorithms. The policies support detached content or embedded content. See the JWS spec for more details.
  3. Critical Headers
    In the JWS header (don't be misled, the JWS header applies to the general case JWS as well as to the specific case of JWT), there are a number of properties with "well known" meanings. Such properties include typ, alg, and kid, referring to the type of the payload (which can take values like "JWT" or "JOSE") the algorithm used ("RS256", "ES384", etc), and the identifier of the key used to sign the payload and header.
    The "crit" header is also now supported by the Apigee Edge policies. The crit header specifies headers that MUST be understood by the receiving party. You can generate JWT (or JWS) containing headers with the crit property, and you can verify JWT that have headers with the crit property. Check the documentation for how this all works.
  4. VerifyJWT and VerifyJWS now support a JWKS uri
    You can now specify the uri of a public endpoint that returns a JWKS payload, in the verify* policies. This will tell the policy to retrieve the JWKS from the endpoint, and then verify the inbound JWT or JWS based on the public keys specified in the JWKS. This is really handy. Previously, you had to retrieve the JWKS "manually" with a preceding ServiceCallout policy. This is now automatic inside the Verify* policies.
  5. For Generate*, key encryption algorithms beyond DES-EDE3-CBC
    It is possible to specify encrypted private keys (either RSA or ECDSA types) to the Generate policies. Previously the only encryption algorithm supported was DES-EDE3-CBC. Now you can encrypt your private keys with a myriad of algorithms supported by openssl, including: -aes-128-cbc aes-128-cfb aes-128-ofb aes-192-cbc aes-192-cfb aes-192-ofb aes-256-cbc aes-256-cfb aes-256-ofb aes128 aes192 aes256 bf bf-cbc bf-cfb bf-ofb blowfish des des-cbc des-cfb des-ede-cbc des-ede-cfb des-ede-ofb des-ede3-cbc des-ede3-cfb des-ede3-ofb des-ofb des3 rc2 rc2-40-cbc rc2-64-cbc rc2-cbc rc2-cfb rc2-ofb . Note, not all crypto algorithms supported by openssl for encrypting private keys are supported by the generate* policies. Among those not supported: -aes-128-cfb1 aes-128-cfb8 aes-128-ctr aes-128-ecb aes-128-gcm aes-128-xts aes-192-cfb1 aes-192-cfb8 aes-192-ctr aes-192-ecb aes-192-gcm aes-256-cfb1 aes-256-cfb8 aes-256-ctr aes-256-ecb aes-256-gcm aes-256-xts bf-ecb camellia-128-cbc camellia-128-cfb camellia-128-cfb1 camellia-128-cfb8 camellia-128-ecb camellia-128-ofb camellia-192-cbc camellia-192-cfb camellia-192-cfb1 camellia-192-cfb8 camellia-192-ecb camellia-192-ofb camellia-256-cbc camellia-256-cfb camellia-256-cfb1 camellia-256-cfb8 camellia-256-ecb camellia-256-ofb camellia128 camellia192 camellia256 cast cast-cbc cast5-cbc cast5-cfb cast5-ecb cast5-ofb chacha des-cfb1 des-cfb8 des-ecb des-ede des-ede3 des-ede3-cfb1 des-ede3-cfb8 desx desx-cbc gost89 gost89-cnt gost89-ecb id-aes128-GCM id-aes192-GCM id-aes256-GCM rc2-ecb rc4 rc4-40 rc4-hmac-md5
  6. dynamic top level claims
    You can add an element like <AdditionalClaims ref='variable_containing_json_blob'/> into either the Generate* or the Verify* policies in order to specify a dynamic set of claims to generate or verify. Previously the names of the claims needed to be known and specified at policy configuration time, while the values could be dynamic; now, both the names and the values can be dynamic. This also applies to claims for the signed header.

There is one case in which we have tightened the security around JWT (and JWS) - involving HS* algorithms. Previously the policies allowed weak keys when signing. Now, the keys must have the minimum size - 32 bytes for HS256, 48 for HS384 and 64 for HS512. With the upgrade, you will now get an error at runtime if you try to sign or verify with HS* using a key of insufficient length. To avoid this, use a stronger key.

Not included in this update is any support for JWE. Encrypted JSON Web Tokens are not yet natively supported by Apigee Edge builtin policies.

Check the release notes when they become available for full details.

Comments
yves_scotto
Participant I

Is there any way to manage the Algorithm type dynamically in GenerateJWT Apigee policy ?


I tried

<Algorithm>{my_alg}</Algorithm>

<Algorithm>my_alg</Algorithm>

<Algorithm ref="my_alg"/>

<Algorithm>

<Value ref="my_alg"/>

</Algorithm>

Thanks

dchiesa1
Staff

No, there is no way to do that.

And that is by design. The algorithm family is fixed. This is to prevent a well-known attack vector on JWT, in which the sender asserts the algorithm and asks that the receiver verify the signature using the asserted algorithm. This is bad practice, so we decided to "discourage it" by not providing the possibility to specify the algorithm by reference.

what is your real use-case?

yves_scotto
Participant I

I develop an oauth proxy which delivers JWT token or opaque token according to a custom attribut set in the each product. This proxy is common for products of my organization?

For opaque token I need and oauthV2 policy

For JWT I need 2 policies :

- one for HS_* algorithm

- one for others

If the <Algorithm> is hardcoded and if I want to be able to manage all algorithms I need to implement... 12 policies 😞

dchiesa1
Staff

I understand the situation you're describing. Apigee JWT policies do not support dynamic specification of the JWT algorithm; this is done to prevent a well-known security problem with the *use* of JWT. It is not a security issue within JWT; but acceptance of a dynamically-specified (client specified) algorithm is a common pitfall in JWT usage . The design of the JWT policies was intended to avoid that class of pitfall.

This is generally a good tradeoff, even if it doesn't satisfy your specific desires. In my experience, organizations do not support all of the various signature algorithms stipulated in the JWA specification (IETF RFC 7518), all of which are supported in the Apigee JWT policies. Instead, the organization evaluates the algorithms and the key management requirements supporting each of them, and chooses one algorithm as preferred.

  • A good example is the UK OpenBanking standard, which evaluated the signature algorithms and selected ES256 as preferred. UKOB disallows HMAC algorithms and RSASSA algorithms, but allows PS256 if for some reason management of Elliptic Curve keys is not practical.
  • Another good example is cloud Sign-in systems by Google and Azure. In both cases, there is no choice for algorithm; it is always RS256.

I regret that your chosen design would require 12 policies; even so, I think the design decision taken with the Apigee JWT policies is still the correct one. In the Apigee JWT policies, there is no support for specifying the accepted, allowable algorithms at runtime via a variable, and that will not change.

If the <Algorithm> is hardcoded and if I want to be able to manage all algorithms I need to implement... 12 policies :-(

Yes, and I think this is a case of YAGNI. If you would like to avoid the 12 policies, then I suggest that you restrict the set of Algorithms you support in your APIs.

yves_scotto
Participant I

Thank you Dino for this advice

A last question: I work on 4.19.01.00 on premice version. It seems that this version support only HS256 and RS256 right ?

Thanks a lot

Yves

dchiesa1
Staff

That is correct. The expanded set of algorithms (ECDSA and PSS) will be available in 19.06, I believe.

Version history
Last update:
‎04-16-2019 09:56 AM
Updated by: