Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions build/commonTest.props
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="$(MicrosoftNETTestSdkVersion)" />
<PackageReference Include="Moq" Version="$(MoqVersion)" />
<PackageReference Include="Newtonsoft.Json" Version="$(NewtonsoftVersion)" />
<PackageReference Include="xunit" Version="$(XunitVersion)" />
<PackageReference Include="xunit.runner.console" Version="$(XunitRunnerConsoleVersion)" />
Expand Down
1 change: 1 addition & 0 deletions build/dependenciesTest.props
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
<DotNetCoreAppRuntimeVersion>2.1.30</DotNetCoreAppRuntimeVersion>
<MicrosoftAzureKeyVaultCryptographyVersion>3.0.5</MicrosoftAzureKeyVaultCryptographyVersion>
<MicrosoftNETTestSdkVersion>17.11.1</MicrosoftNETTestSdkVersion>
<MoqVersion>4.16.1</MoqVersion>
<NetStandardVersion>2.0.3</NetStandardVersion>
<NewtonsoftVersion>13.0.3</NewtonsoftVersion>
<OpenTelemetryVersion>1.6.0</OpenTelemetryVersion>
Expand Down
Empty file.
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,13 @@ internal ValidationResult<string> DecryptToken(
ValidationError.GetCurrentStackFrame());
}

(IList<SecurityKey>? contentEncryptionKeys, ValidationError? validationError) result =
(IList<SecurityKey>? ContentEncryptionKeys, ValidationError? ValidationError) result =
GetContentEncryptionKeys(jwtToken, validationParameters, configuration, callContext);

if (result.validationError != null)
return result.validationError.AddCurrentStackFrame();
if (result.ValidationError != null)
return result.ValidationError.AddCurrentStackFrame();

if (result.contentEncryptionKeys == null || result.contentEncryptionKeys.Count == 0)
if (result.ContentEncryptionKeys == null || result.ContentEncryptionKeys.Count == 0)
{
return new ValidationError(
new MessageDetail(
Expand All @@ -68,15 +68,12 @@ internal ValidationResult<string> DecryptToken(
ValidationError.GetCurrentStackFrame());
}

var decryptionParameters = CreateJwtTokenDecryptionParameters(jwtToken, result.ContentEncryptionKeys);

return JwtTokenUtilities.DecryptJwtToken(
jwtToken,
validationParameters,
new JwtTokenDecryptionParameters
{
DecompressionFunction = JwtTokenUtilities.DecompressToken,
Keys = result.contentEncryptionKeys,
MaximumDeflateSize = MaximumTokenSizeInBytes
},
decryptionParameters,
callContext);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -344,15 +344,28 @@ private string DecryptToken(JsonWebToken jwtToken, TokenValidationParameters val
throw LogHelper.LogExceptionMessage(new SecurityTokenException(LogHelper.FormatInvariant(TokenLogMessages.IDX10612)));

var keys = GetContentEncryptionKeys(jwtToken, validationParameters, configuration);
return JwtTokenUtilities.DecryptJwtToken(
jwtToken,
validationParameters,
new JwtTokenDecryptionParameters
{
DecompressionFunction = JwtTokenUtilities.DecompressToken,
Keys = keys,
MaximumDeflateSize = MaximumTokenSizeInBytes
});

var decryptionParameters = CreateJwtTokenDecryptionParameters(jwtToken, keys);

return JwtTokenUtilities.DecryptJwtToken(jwtToken, validationParameters, decryptionParameters);
}

private JwtTokenDecryptionParameters CreateJwtTokenDecryptionParameters(JsonWebToken jwtToken, IEnumerable<SecurityKey> keys)
{
return new JwtTokenDecryptionParameters
{
Alg = jwtToken.Alg,
AuthenticationTagBytes = jwtToken.AuthenticationTagBytes,
CipherTextBytes = jwtToken.CipherTextBytes,
DecompressionFunction = JwtTokenUtilities.DecompressToken,
Enc = jwtToken.Enc,
EncodedToken = jwtToken.EncodedToken,
HeaderAsciiBytes = jwtToken.HeaderAsciiBytes,
InitializationVectorBytes = jwtToken.InitializationVectorBytes,
MaximumDeflateSize = MaximumTokenSizeInBytes,
Keys = keys,
Zip = jwtToken.Zip,
};
}

private static SecurityKey ResolveTokenDecryptionKeyFromConfig(JsonWebToken jwtToken, BaseConfiguration configuration)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
using System;
using System.Text;
using Microsoft.IdentityModel.Tokens;
using TokenLogMessages = Microsoft.IdentityModel.Tokens.LogMessages;

namespace Microsoft.IdentityModel.JsonWebTokens
{
Expand Down Expand Up @@ -120,7 +119,7 @@ internal static ValidationResult<string> DecryptJwtToken(
#pragma warning restore CA1031 // Do not catch general exception types
{
return new ValidationError(
new MessageDetail(TokenLogMessages.IDX10679, zipAlgorithm),
new MessageDetail(GetIDX10679LogMessage(zipAlgorithm)),
ValidationFailureType.TokenDecryptionFailed,
typeof(SecurityTokenDecompressionFailedException),
ValidationError.GetCurrentStackFrame(),
Expand Down
78 changes: 25 additions & 53 deletions src/Microsoft.IdentityModel.JsonWebTokens/JwtTokenUtilities.cs
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,12 @@ internal static string DecompressToken(byte[] tokenBytes, string algorithm, int

var decompressedBytes = compressionProvider.Decompress(tokenBytes);

return decompressedBytes != null ? Encoding.UTF8.GetString(decompressedBytes) : throw LogHelper.LogExceptionMessage(new SecurityTokenDecompressionFailedException(LogHelper.FormatInvariant(TokenLogMessages.IDX10679, LogHelper.MarkAsNonPII(algorithm))));
return decompressedBytes != null ? Encoding.UTF8.GetString(decompressedBytes) : throw LogHelper.LogExceptionMessage(new SecurityTokenDecompressionFailedException(GetIDX10679LogMessage(algorithm)));
}

private static string GetIDX10679LogMessage(string algorithm)
{
return LogHelper.FormatInvariant(TokenLogMessages.IDX10679, LogHelper.MarkAsNonPII(algorithm));
}

/// <summary>
Expand Down Expand Up @@ -275,61 +280,28 @@ internal static string DecryptJwtToken(

try
{
// The JsonWebTokenHandler will set the JsonWebToken and those values will be used.
// The JwtSecurityTokenHandler will calculate values and set the values on DecryptionParameters.

// JsonWebToken from JsonWebTokenHandler
if (securityToken is JsonWebToken jsonWebToken)
if (!cryptoProviderFactory.IsSupportedAlgorithm(decryptionParameters.Enc, key))
{
if (!cryptoProviderFactory.IsSupportedAlgorithm(jsonWebToken.Enc, key))
{
if (LogHelper.IsEnabled(EventLogLevel.Warning))
LogHelper.LogWarning(TokenLogMessages.IDX10611, LogHelper.MarkAsNonPII(decryptionParameters.Enc), LogHelper.MarkAsNonPII(key.KeyId));

algorithmNotSupportedByCryptoProvider = true;
continue;
}
if (LogHelper.IsEnabled(EventLogLevel.Warning))
LogHelper.LogWarning(TokenLogMessages.IDX10611, LogHelper.MarkAsNonPII(decryptionParameters.Enc), LogHelper.MarkAsNonPII(key.KeyId));

Validators.ValidateAlgorithm(jsonWebToken.Enc, key, securityToken, validationParameters);
decryptedTokenBytes = DecryptToken(
cryptoProviderFactory,
key,
jsonWebToken.Enc,
jsonWebToken.CipherTextBytes,
jsonWebToken.HeaderAsciiBytes,
jsonWebToken.InitializationVectorBytes,
jsonWebToken.AuthenticationTagBytes);

zipAlgorithm = jsonWebToken.Zip;
decryptionSucceeded = true;
break;
algorithmNotSupportedByCryptoProvider = true;
continue;
}
// JwtSecurityToken from JwtSecurityTokenHandler
else
{
if (!cryptoProviderFactory.IsSupportedAlgorithm(decryptionParameters.Enc, key))
{
if (LogHelper.IsEnabled(EventLogLevel.Warning))
LogHelper.LogWarning(TokenLogMessages.IDX10611, LogHelper.MarkAsNonPII(decryptionParameters.Enc), LogHelper.MarkAsNonPII(key.KeyId));

algorithmNotSupportedByCryptoProvider = true;
continue;
}

Validators.ValidateAlgorithm(decryptionParameters.Enc, key, securityToken, validationParameters);
decryptedTokenBytes = DecryptToken(
cryptoProviderFactory,
key,
decryptionParameters.Enc,
decryptionParameters.CipherTextBytes,
decryptionParameters.HeaderAsciiBytes,
decryptionParameters.InitializationVectorBytes,
decryptionParameters.AuthenticationTagBytes);

zipAlgorithm = decryptionParameters.Zip;
decryptionSucceeded = true;
break;
}
Validators.ValidateAlgorithm(decryptionParameters.Enc, key, securityToken, validationParameters);
decryptedTokenBytes = DecryptToken(
cryptoProviderFactory,
key,
decryptionParameters.Enc,
decryptionParameters.CipherTextBytes,
decryptionParameters.HeaderAsciiBytes,
decryptionParameters.InitializationVectorBytes,
decryptionParameters.AuthenticationTagBytes);

zipAlgorithm = decryptionParameters.Zip;
decryptionSucceeded = true;
break;
}
catch (Exception ex)
{
Expand Down Expand Up @@ -361,7 +333,7 @@ internal static string DecryptJwtToken(
}
catch (Exception ex)
{
throw LogHelper.LogExceptionMessage(new SecurityTokenDecompressionFailedException(LogHelper.FormatInvariant(TokenLogMessages.IDX10679, zipAlgorithm), ex));
throw LogHelper.LogExceptionMessage(new SecurityTokenDecompressionFailedException(GetIDX10679LogMessage(zipAlgorithm), ex));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@

<ItemGroup>
<AdditionalFiles Include="InternalAPI.Shipped.txt" />
<AdditionalFiles Include="InternalAPI.Unshipped.txt" />
</ItemGroup>

<ItemGroup Condition="'$(TargetFrameworkIdentifier)' == '.NETCoreApp'">
Expand Down
11 changes: 9 additions & 2 deletions src/System.IdentityModel.Tokens.Jwt/JwtSecurityTokenHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1762,7 +1762,14 @@ protected string DecryptToken(JwtSecurityToken jwtToken, TokenValidationParamete

var keys = GetContentEncryptionKeys(jwtToken, validationParameters);

return JwtTokenUtilities.DecryptJwtToken(jwtToken, validationParameters, new JwtTokenDecryptionParameters
var decryptionParameters = CreateJwtTokenDecryptionParameters(jwtToken, keys);

return JwtTokenUtilities.DecryptJwtToken(jwtToken, validationParameters, decryptionParameters);
}

private JwtTokenDecryptionParameters CreateJwtTokenDecryptionParameters(JwtSecurityToken jwtToken, IEnumerable<SecurityKey> keys)
{
return new JwtTokenDecryptionParameters
{
Alg = jwtToken.Header.Alg,
AuthenticationTagBytes = Base64UrlEncoder.DecodeBytes(jwtToken.RawAuthenticationTag),
Expand All @@ -1775,7 +1782,7 @@ protected string DecryptToken(JwtSecurityToken jwtToken, TokenValidationParamete
MaximumDeflateSize = MaximumTokenSizeInBytes,
Keys = keys,
Zip = jwtToken.Header.Zip,
});
};
}

internal IEnumerable<SecurityKey> GetContentEncryptionKeys(JwtSecurityToken jwtToken, TokenValidationParameters validationParameters)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,6 @@
<AssemblyOriginatorKeyFile>$(MSBuildThisFileDirectory)..\..\build\35MSSharedLib1024.snk</AssemblyOriginatorKeyFile>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Moq" Version="4.16.1" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\src\Microsoft.IdentityModel.Abstractions\Microsoft.IdentityModel.Abstractions.csproj" />
</ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using Microsoft.IdentityModel.Logging;
using Microsoft.IdentityModel.Protocols;
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
using Microsoft.IdentityModel.TestUtils;
Expand Down Expand Up @@ -2797,6 +2798,7 @@ public static TheoryData<CreateTokenTheoryData> RoundTripJWEDirectTestCases
EncryptingCredentials = Default.SymmetricEncryptingCredentials,
ExpectedException = ExpectedException.SecurityTokenDecryptionFailedException("IDX10603:")
},
GetTokenTheoryDataWithKeyId(),
new CreateTokenTheoryData()
{
TestId = "EncryptionAlgorithmNotSupported",
Expand All @@ -2812,6 +2814,38 @@ public static TheoryData<CreateTokenTheoryData> RoundTripJWEDirectTestCases
ExpectedException = ExpectedException.SecurityTokenDecryptionFailedException("IDX10619:")
},
};

static CreateTokenTheoryData GetTokenTheoryDataWithKeyId()
{
var validationParameters = new TokenValidationParameters
{
IssuerSigningKey = Default.SymmetricSigningKey256,
TokenDecryptionKey = NotDefault.SymmetricSigningKey256,
};

var keysAttempted = new StringBuilder().AppendLine(validationParameters.TokenDecryptionKey.KeyId);
var incompleteExceptionMessage = new MessageDetail(
Tokens.LogMessages.IDX10603,
LogHelper.MarkAsNonPII(keysAttempted.ToString()),
string.Empty, // Using empty since actual exception contains file paths, which are machine specific.
string.Empty) // Using empty since EncodedToken is not available and the message is getting used partially below.
.Message;
// Get partial messages as the actual exception message contains file paths.
var partialExceptionMessage = incompleteExceptionMessage.Substring(
0,
incompleteExceptionMessage.IndexOf(validationParameters.TokenDecryptionKey.KeyId) + validationParameters.TokenDecryptionKey.KeyId.Length);

return new CreateTokenTheoryData()
{
TestId = "EncryptionKey-Not-Found-Returns-KeyId-In-Error-Message",
IsValid = false,
ValidationParameters = validationParameters,
Payload = Default.PayloadString,
SigningCredentials = Default.SymmetricSigningCredentials,
EncryptingCredentials = Default.SymmetricEncryptingCredentials,
ExpectedException = ExpectedException.SecurityTokenDecryptionFailedException(partialExceptionMessage)
};
}
}
}

Expand Down
Loading
Loading