AzureAD / azure-activedirectory-identitymodel-extensions-for-dotnet

IdentityModel extensions for .Net
MIT License
1.06k stars 400 forks source link

[Feature Request] JsonWebTokenHandler: Add support for creation of A256KW / A256GCM EncryptionCredentials #2081

Open anblanco opened 1 year ago

anblanco commented 1 year ago

Is your feature request related to a problem? Please describe. I'm working on code that parses a JWT provided by Google Play Integrity.

The token format is

I am able to successfully validate these tokens when using JsonWebTokenHandler.

However, if I try to create a token of this format the an exception is thrown

SecurityKey encryptionKey = new SymmetricSecurityKey(symmetricKeyBytes);
SecurityKey signingKey = new ECDsaSecurityKey(ecdsa);

var jsonWebTokenHandler = new JsonWebTokenHandler();

// A256GCM Encryption
var encryptingCredentials = new EncryptingCredentials(
  key: encryptionKey,
  alg: SecurityAlgorithms.Aes256KW,
  enc: SecurityAlgorithms.Aes256Gcm);

// ES256 Signing
var signingCredentials = new SigningCredentials(
  key: signingKey,
  algorithm: SecurityAlgorithms.EcdsaSha256);

string jwe = jsonWebTokenHandler.CreateToken(payload, signingCredentials, encryptingCredentials);

Exception:
Microsoft.IdentityModel.Tokens.SecurityTokenEncryptionFailedException: IDX10617: Encryption failed. Keywrap is only supported for: 'A128CBC-HS256', 'A192CBC-HS384' and 'A256CBC-HS512'. The content encryption specified is: 'A256GCM'.

Stack Trace: 
JwtTokenUtilities.GetSecurityKey(EncryptingCredentials encryptingCredentials, CryptoProviderFactory cryptoProviderFactory, IDictionary`2 additionalHeaderClaims, Byte[]& wrappedKey)
JsonWebTokenHandler.EncryptTokenPrivate(String innerJwt, EncryptingCredentials encryptingCredentials, String compressionAlgorithm, IDictionary`2 additionalHeaderClaims, String tokenType)
JsonWebTokenHandler.CreateTokenPrivate(String payload, SigningCredentials signingCredentials, EncryptingCredentials encryptingCredentials, String compressionAlgorithm, IDictionary`2 additionalHeaderClaims, IDictionary`2 additionalInnerHeaderClaims, String tokenType)

Describe the solution you'd like I would like to be able to create tokens of this format. My original intention was to write unit tests with test keys to assert that my code could correctly parse these JWTs.

Describe alternatives you've considered As an alternative I used the following as my app logic is agnostic to the JWA used

SecurityKey encryptionKey = new SymmetricSecurityKey(symmetricKeyBytes);
SecurityKey signingKey = new ECDsaSecurityKey(ecdsa);

var jsonWebTokenHandler = new JsonWebTokenHandler();

// A256CBC-HS512 Encryption
var encryptingCredentials = new EncryptingCredentials(
  key: encryptionKey,
  alg: SecurityAlgorithms.Aes256KW,
  enc: SecurityAlgorithms.Aes256CbcHmacSha512);

// ES256 Signing
var signingCredentials = new SigningCredentials(
  key: signingKey,
  algorithm: SecurityAlgorithms.EcdsaSha256);

string jwe = jsonWebTokenHandler.CreateToken(payload, signingCredentials, encryptingCredentials);

Additional context

I also noticed that A256GCM is not listed in the supported algorithms

anblanco commented 1 year ago

So I tried seeing what would happen if I patched my local branch of JwtTokenUtilities to accept A256GCM.

The next exception thrown is

System.NotSupportedException: IDX10715: Encryption using algorithm: 'A256GCM' is not supported.

at AuthenticatedEncryptionProvider.cs

So while we do have the ability to decrypt A256GCM JWTs, it seems that encryption with A256GCM is currently not supported.

brentschmaltz commented 1 year ago

@anblanco what you are seeing is we did not add support for creating JWE's with A256GCM, just validating. There are some internal restrictions for creation with A256GCM, we will check with our crypto board to see if we can support creation at this time.

anblanco commented 1 year ago

@brentschmaltz - Thanks for the context. I did not realize there were intentional restrictions around A256GCM

As an alternative to official library support, what if we allow calling code to provide a custom CryptoProviderFactory?

This code currently throws IDX10617: Encryption failed. Keywrap is only supported for: 'A128CBC-HS256', 'A192CBC-HS384' and 'A256CBC-HS512'. The content encryption specified is: 'A256GCM'

            // A256GCM Encryption
            var encryptingCredentials = new EncryptingCredentials(
                key: encryptionKey,
                alg: SecurityAlgorithms.Aes256KW,
                enc: SecurityAlgorithms.Aes256Gcm);

            encryptingCredentials.CryptoProviderFactory = new CustomCryptoProviderFactory();

If we loosened the restriction in JwtTokenUtilities, then by default

            // A256GCM Encryption
            var encryptingCredentials = new EncryptingCredentials(
                key: encryptionKey,
                alg: SecurityAlgorithms.Aes256KW,
                enc: SecurityAlgorithms.Aes256Gcm);

Would still throw System.NotSupportedException: IDX10715: Encryption using algorithm: 'A256GCM' is not supported., while still allowing consumers to provide their own CrypoProviderFactory