azure-activedirectory-identitymodel-extensions-for-dotnet icon indicating copy to clipboard operation
azure-activedirectory-identitymodel-extensions-for-dotnet copied to clipboard

Extra characters at the end of encrypted JWT tokens don't prevent them from being considered valid

Open kevinchalet opened this issue 3 years ago • 5 comments

Hey,

Yesterday, the following report was posted on the OpenIddict repository: https://github.com/openiddict/openiddict-core/issues/1254.

I was able to reproduce it on my machine and confirmed this was caused by IdentityModel. It looks like IdentityModel doesn't reject a JWE payload if it contains extra characters after the authentication tag.

Here's a repro:

using System.Diagnostics;
using System.Security.Claims;
using System.Security.Cryptography;
using Microsoft.IdentityModel.JsonWebTokens;
using Microsoft.IdentityModel.Tokens;

namespace ConsoleApp13
{
    class Program
    {
        static void Main(string[] args)
        {
            var identity = new ClaimsIdentity(TokenValidationParameters.DefaultAuthenticationType);
            var signingKey = new RsaSecurityKey(RSA.Create(2048))
            {
                KeyId = "id1"
            };

            var encryptionKey = new RsaSecurityKey(RSA.Create(2048))
            {
                KeyId = "id2"
            };

            var handler = new JsonWebTokenHandler();
            var token = handler.CreateToken(new SecurityTokenDescriptor
            {
                Audience = "audience",
                Issuer = "issuer",
                EncryptingCredentials = new EncryptingCredentials(encryptionKey, SecurityAlgorithms.RsaOAEP, SecurityAlgorithms.Aes256CbcHmacSha512),
                SigningCredentials = new SigningCredentials(signingKey, SecurityAlgorithms.RsaSha256Signature),
                Subject = identity
            });

            var parameters = new TokenValidationParameters
            {
                ValidAudience = "audience",
                ValidIssuer = "issuer",
                TokenDecryptionKey = encryptionKey,
                IssuerSigningKey = signingKey
            };

            var result = handler.ValidateToken(token + "A", parameters);
            Debug.Assert(!result.IsValid, "The token shouldn't be considered valid.");
        }
    }
}

@brentschmaltz @jennyf19 could you please take a look?

kevinchalet avatar May 04 '21 19:05 kevinchalet

Kévin,

Nice to hear from you, ill have a look. Sometimes there are insignificant bits. For example, for a JWS some of the last bits can be changed due to Base64Eencoding or Base64UrlEncoding. What is significant is if ANY bit in the CypherText can be changed.

Brent.

From: Kévin Chalet @.> Sent: Tuesday, May 4, 2021 12:27 PM To: AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet @.> Cc: BrentSchmaltz @.>; Mention @.> Subject: [AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet] Extra characters at the end of encrypted JWT tokens don't prevent them from being considered valid (#1641)

Hey,

Yesterday, the following report was posted on the OpenIddict repository: openiddict/openiddict-core#1254https://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgithub.com%2Fopeniddict%2Fopeniddict-core%2Fissues%2F1254&data=04%7C01%7C%7Ca73ddfbaa47e4925eb8308d90f329de9%7C84df9e7fe9f640afb435aaaaaaaaaaaa%7C1%7C0%7C637557532331923810%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&sdata=5AXZvIKW7Gg9rnekAsvpf26c4fbqjjZnqp1fnwjjd70%3D&reserved=0.

I was able to reproduce it on my machine and confirmed this was caused by IdentityModel. It looks like IdentityModel doesn't reject a JWE payload if it contains extra characters after the authentication tag.

Here's a repro:

using System.Diagnostics;

using System.Security.Claims;

using System.Security.Cryptography;

using Microsoft.IdentityModel.JsonWebTokens;

using Microsoft.IdentityModel.Tokens;

namespace ConsoleApp13

{

class Program

{

    static void Main(string[] args)

    {

        var identity = new ClaimsIdentity(TokenValidationParameters.DefaultAuthenticationType);

        var signingKey = new RsaSecurityKey(RSA.Create(2048))

        {

            KeyId = "id1"

        };



        var encryptionKey = new RsaSecurityKey(RSA.Create(2048))

        {

            KeyId = "id2"

        };



        var handler = new JsonWebTokenHandler();

        var token = handler.CreateToken(new SecurityTokenDescriptor

        {

            Audience = "audience",

            Issuer = "issuer",

            EncryptingCredentials = new EncryptingCredentials(encryptionKey, SecurityAlgorithms.RsaOAEP, SecurityAlgorithms.Aes256CbcHmacSha512),

            SigningCredentials = new SigningCredentials(signingKey, SecurityAlgorithms.RsaSha256Signature),

            Subject = identity

        });



        var parameters = new TokenValidationParameters

        {

            ValidAudience = "audience",

            ValidIssuer = "issuer",

            TokenDecryptionKey = encryptionKey,

            IssuerSigningKey = signingKey

        };



        var result = handler.ValidateToken(token + "A", parameters);

        Debug.Assert(!result.IsValid, "The token shouldn't be considered valid.");

    }

}

}

@brentschmaltzhttps://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgithub.com%2Fbrentschmaltz&data=04%7C01%7C%7Ca73ddfbaa47e4925eb8308d90f329de9%7C84df9e7fe9f640afb435aaaaaaaaaaaa%7C1%7C0%7C637557532331923810%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&sdata=FGSwSXE%2FM41IBReLrD%2Bt4eV7ABBU7PrBR4DYZl%2BcokI%3D&reserved=0 @jennyf19https://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgithub.com%2Fjennyf19&data=04%7C01%7C%7Ca73ddfbaa47e4925eb8308d90f329de9%7C84df9e7fe9f640afb435aaaaaaaaaaaa%7C1%7C0%7C637557532331933804%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&sdata=upQoD5Koi90tZDc9cMn0WoU1TdR7AUbRda50hHyKHqM%3D&reserved=0 could you please take a look?

You are receiving this because you were mentioned. Reply to this email directly, view it on GitHubhttps://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgithub.com%2FAzureAD%2Fazure-activedirectory-identitymodel-extensions-for-dotnet%2Fissues%2F1641&data=04%7C01%7C%7Ca73ddfbaa47e4925eb8308d90f329de9%7C84df9e7fe9f640afb435aaaaaaaaaaaa%7C1%7C0%7C637557532331943802%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&sdata=agwqzl0eAmJBCm8rFdNtit9xYgs9v82K8NyHokNFlu8%3D&reserved=0, or unsubscribehttps://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgithub.com%2Fnotifications%2Funsubscribe-auth%2FAAYGQRNGP4GEAGC4ZZLWFH3TMBDA7ANCNFSM44DJZ56A&data=04%7C01%7C%7Ca73ddfbaa47e4925eb8308d90f329de9%7C84df9e7fe9f640afb435aaaaaaaaaaaa%7C1%7C0%7C637557532331943802%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&sdata=oVzEx%2BqTgOCYAHncpRUZzSw%2Br4na1uop%2Fu9GAxgqazg%3D&reserved=0.

brentschmaltz avatar May 05 '21 19:05 brentschmaltz

@brentschmaltz awesome, thanks!

Sometimes there are insignificant bits.

That was my feeling too, but in this particular case, the "extra last bits" are considered by IdentityModel as being part of the authentication tag (which is expected since it's technically part of it):

image

I suspect IdentityModel correctly base64decodes it but only uses a fixed-size array copy that ignores the extra bytes before calling the crypto primitives. Feeding the crypto primitives with the original tag or adding a check in IdentityModel to ensure the authentication tag length matches the expected length would certainly help fix that issue.

kevinchalet avatar May 06 '21 16:05 kevinchalet

Someone else emailed me to tell me they were concerned about this behavior. Do you have any news?

kevinchalet avatar Jun 19 '21 13:06 kevinchalet

@kevinchalet nothing yet, should get some time soon.

brentschmaltz avatar Jul 12 '21 21:07 brentschmaltz

Duplicate of #2201

jmprieur avatar Apr 21 '24 18:04 jmprieur