-
Notifications
You must be signed in to change notification settings - Fork 10.2k
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
OpenIdConnectHandler can't decrypt token with RSA-OAEP-256 and A128GCM #60367
Comments
I have narrowed the problem down to where it fails. It seems like in the // Type: Microsoft.IdentityModel.Tokens.SupportedAlgorithms
// Assembly: Microsoft.IdentityModel.Tokens, Version=8.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35 |
I tried adding support for decrypting config.TokenValidationParameters = new TokenValidationParameters
{
TokenDecryptionKeys = new[] { rsaSec }
}; I also changed to use my custom privateKey.CryptoProviderFactory.CustomCryptoProvider = new OAEP256CryptoProvider(); Here's the implementation of my custom public class OAEP256CryptoProvider : ICryptoProvider
{
public const string OAEP_256 = "RSA-OAEP-256";
public bool IsSupportedAlgorithm(string algorithm, params object[] args)
{
return (algorithm == OAEP_256);
}
public object Create(string algorithm, params object[] args)
{
return new RsaOaepKeyWrapProvider(args[0] as SecurityKey, algorithm);
}
public void Release(object cryptoInstance)
{
}
private class RsaOaepKeyWrapProvider : KeyWrapProvider
{
public RsaOaepKeyWrapProvider(SecurityKey key, string algorithm)
{
Key = (RsaSecurityKey) key;
Algorithm = algorithm;
}
protected override void Dispose(bool disposing)
{
}
public override byte[] UnwrapKey(byte[] keyBytes)
{
return Key.Rsa.Decrypt(keyBytes, RSAEncryptionPadding.OaepSHA256);
}
public override byte[] WrapKey(byte[] keyBytes)
{
return Key.Rsa.Encrypt(keyBytes, RSAEncryptionPadding.OaepSHA256);
}
public override string Algorithm { get; }
public override string Context { get; set; }
public override RsaSecurityKey Key { get; }
}
} The code runs, but fails when unwrapping the key in some interop code: Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectHandler[17]
Exception occurred while processing message.
Microsoft.IdentityModel.Tokens.SecurityTokenKeyWrapException: IDX10618: Key unwrap failed using decryption Keys: 'Microsoft.IdentityModel.Tokens.RsaSecurityKey, KeyId: '<redacted>', InternalId: '<redacted>'.
'.
Exceptions caught:
'Interop+AppleCrypto+AppleCFErrorCryptographicException: The operation couldn’t be completed. (OSStatus error -50 - RSAdecrypt wrong input (err -27))
at Interop.AppleCrypto.ExecuteTransform(ReadOnlySpan`1 source, SecKeyTransform transform)
at Interop.AppleCrypto.RsaDecrypt(SafeSecKeyRefHandle privateKey, Byte[] data, RSAEncryptionPadding padding)
at OAEP256CryptoProvider.RsaOaepKeyWrapProvider.UnwrapKey(Byte[] keyBytes) in /Users/s/code/help/signicat-oidc-test/SignicatOidcExample/RsaOaep256Provider.cs:line 40
at Microsoft.IdentityModel.JsonWebTokens.JsonWebTokenHandler.GetContentEncryptionKeys(JsonWebToken jwtToken, TokenValidationParameters validationParameters, BaseConfiguration configuration)
'.
token: '<redacted>'. Not sure if this helps... |
I got a little further by generating a new pair of private/public JWKs. I also added the following in my "DYLD_LIBRARY_PATH": "/opt/homebrew/opt/openssl@3/lib" This helped, but now I have a different error. For some reason it's trying to load IDX10603: Decryption failed. Keys tried: 'Microsoft.IdentityModel.Tokens.SymmetricSecurityKey, KeyId: '', InternalId: 'fmIqRm1c3l_jwDj0DWm_njH32y6hChS-lHNecA82-1A'.
'.
Exceptions caught:
'System.TypeInitializationException: The type initializer for 'Microsoft.IdentityModel.Tokens.AesGcm' threw an exception.
---> System.DllNotFoundException: Unable to load shared library 'BCrypt.dll' or one of its dependencies. In order to help diagnose loading problems, consider setting the DYLD_PRINT_LIBRARIES environment variable:
dlopen(/usr/local/share/dotnet/shared/Microsoft.NETCore.App/9.0.2/BCrypt.dll.dylib, 0x0001): tried: '/opt/homebrew/opt/openssl@3/lib/BCrypt.dll.dylib' (no such file), '/usr/local/share/dotnet/shared/Microsoft.NETCore.App/9.0.2/BCrypt.dll.dylib' (no such file), '/System/Volumes/Preboot/Cryptexes/OS/usr/local/share/dotnet/shared/Microsoft.NETCore.App/9.0.2/BCrypt.dll.dylib' (no such file), '/usr/local/share/dotnet/shared/Microsoft.NETCore.App/9.0.2/BCrypt.dll.dylib' (no such file)
dlopen(/Users/s/code/d/e/f/bin/Debug/net9.0/BCrypt.dll.dylib, 0x0001): tried: '/opt/homebrew/opt/openssl@3/lib/BCrypt.dll.dylib' (no such file), '/Users/s/code/d/e/SignicatOidcExample/bin/Debug/net9.0/BCrypt.dll.dylib' (no such file), '/System/Volumes/Preboot/Cryptexes/OS/Users/s/code/d/e/SignicatOidcExample/bin/Debug/net9.0/BCrypt.dll.dylib' (no such file), '/Users/s/code/d/e/SignicatOidcExample/bin/Debug/net9.0/BCrypt.dll.dylib' (no such file)
dlopen(BCrypt.dll.dylib, 0x0001): tried: '/opt/homebrew/opt/openssl@3/lib/BCrypt.dll.dylib' (no such file), 'BCrypt.dll.dylib' (no such file), '/System/Volumes/Preboot/Cryptexes/OSBCrypt.dll.dylib' (no such file), '/usr/lib/BCrypt.dll.dylib' (no such file, not in dyld cache), 'BCrypt.dll.dylib' (no such file)
dlopen(/usr/local/share/dotnet/shared/Microsoft.NETCore.App/9.0.2/libBCrypt.dll.dylib, 0x0001): tried: '/opt/homebrew/opt/openssl@3/lib/libBCrypt.dll.dylib' (no such file), '/usr/local/share/dotnet/shared/Microsoft.NETCore.App/9.0.2/libBCrypt.dll.dylib' (no such file), '/System/Volumes/Preboot/Cryptexes/OS/usr/local/share/dotnet/shared/Microsoft.NETCore.App/9.0.2/libBCrypt.dll.dylib' (no such file), '/usr/local/share/dotnet/shared/Microsoft.NETCore.App/9.0.2/libBCrypt.dll.dylib' (no such file)
dlopen(/Users/s/code/d/e/SignicatOidcExample/bin/Debug/net9.0/libBCrypt.dll.dylib, 0x0001): tried: '/opt/homebrew/opt/openssl@3/lib/libBCrypt.dll.dylib' (no such file), '/Users/s/code/d/e/SignicatOidcExample/bin/Debug/net9.0/libBCrypt.dll.dylib' (no such file), '/System/Volumes/Preboot/Cryptexes/OS/Users/s/code/d/e/SignicatOidcExample/bin/Debug/net9.0/libBCrypt.dll.dylib' (no such file), '/Users/s/code/d/e/SignicatOidcExample/bin/Debug/net9.0/libBCrypt.dll.dylib' (no such file)
dlopen(libBCrypt.dll.dylib, 0x0001): tried: '/opt/homebrew/opt/openssl@3/lib/libBCrypt.dll.dylib' (no such file), 'libBCrypt.dll.dylib' (no such file), '/System/Volumes/Preboot/Cryptexes/OSlibBCrypt.dll.dylib' (no such file), '/usr/lib/libBCrypt.dll.dylib' (no such file, not in dyld cache), 'libBCrypt.dll.dylib' (no such file)
dlopen(/usr/local/share/dotnet/shared/Microsoft.NETCore.App/9.0.2/BCrypt.dll, 0x0001): tried: '/opt/homebrew/opt/openssl@3/lib/BCrypt.dll' (no such file), '/usr/local/share/dotnet/shared/Microsoft.NETCore.App/9.0.2/BCrypt.dll' (no such file), '/System/Volumes/Preboot/Cryptexes/OS/usr/local/share/dotnet/shared/Microsoft.NETCore.App/9.0.2/BCrypt.dll' (no such file), '/usr/local/share/dotnet/shared/Microsoft.NETCore.App/9.0.2/BCrypt.dll' (no such file)
dlopen(/Users/s/code/d/e/SignicatOidcExample/bin/Debug/net9.0/BCrypt.dll, 0x0001): tried: '/opt/homebrew/opt/openssl@3/lib/BCrypt.dll' (no such file), '/Users/s/code/d/e/SignicatOidcExample/bin/Debug/net9.0/BCrypt.dll' (no such file), '/System/Volumes/Preboot/Cryptexes/OS/Users/s/code/d/e/SignicatOidcExample/bin/Debug/net9.0/BCrypt.dll' (no such file), '/Users/s/code/d/e/SignicatOidcExample/bin/Debug/net9.0/BCrypt.dll' (no such file)
dlopen(BCrypt.dll, 0x0001): tried: '/opt/homebrew/opt/openssl@3/lib/BCrypt.dll' (no such file), 'BCrypt.dll' (no such file), '/System/Volumes/Preboot/Cryptexes/OSBCrypt.dll' (no such file), '/usr/lib/BCrypt.dll' (no such file, not in dyld cache), 'BCrypt.dll' (no such file)
dlopen(/usr/local/share/dotnet/shared/Microsoft.NETCore.App/9.0.2/libBCrypt.dll, 0x0001): tried: '/opt/homebrew/opt/openssl@3/lib/libBCrypt.dll' (no such file), '/usr/local/share/dotnet/shared/Microsoft.NETCore.App/9.0.2/libBCrypt.dll' (no such file), '/System/Volumes/Preboot/Cryptexes/OS/usr/local/share/dotnet/shared/Microsoft.NETCore.App/9.0.2/libBCrypt.dll' (no such file), '/usr/local/share/dotnet/shared/Microsoft.NETCore.App/9.0.2/libBCrypt.dll' (no such file)
dlopen(/Users/s/code/d/e/SignicatOidcExample/bin/Debug/net9.0/libBCrypt.dll, 0x0001): tried: '/opt/homebrew/opt/openssl@3/lib/libBCrypt.dll' (no such file), '/Users/s/code/d/e/SignicatOidcExample/bin/Debug/net9.0/libBCrypt.dll' (no such file), '/System/Volumes/Preboot/Cryptexes/OS/Users/s/code/d/e/SignicatOidcExample/bin/Debug/net9.0/libBCrypt.dll' (no such file), '/Users/s/code/d/e/SignicatOidcExample/bin/Debug/net9.0/libBCrypt.dll' (no such file)
dlopen(libBCrypt.dll, 0x0001): tried: '/opt/homebrew/opt/openssl@3/lib/libBCrypt.dll' (no such file), 'libBCrypt.dll' (no such file), '/System/Volumes/Preboot/Cryptexes/OSlibBCrypt.dll' (no such file), '/usr/lib/libBCrypt.dll' (no such file, not in dyld cache), 'libBCrypt.dll' (no such file)
at Microsoft.IdentityModel.Tokens.Interop.BCrypt.BCryptOpenAlgorithmProvider(SafeAlgorithmHandle& phAlgorithm, String pszAlgId, String pszImplementation, Int32 dwFlags)
at Microsoft.IdentityModel.Tokens.Cng.BCryptOpenAlgorithmProvider(String pszAlgId, String pszImplementation, OpenAlgorithmProviderFlags dwFlags)
at Microsoft.IdentityModel.Tokens.AesBCryptModes.<>c__DisplayClass0_0.<OpenAesAlgorithm>b__0()
at System.Lazy`1.ViaFactory(LazyThreadSafetyMode mode)
at System.Lazy`1.ExecutionAndPublication(LazyHelper executionAndPublication, Boolean useDefaultConstructor)
at System.Lazy`1.CreateValue()
at Microsoft.IdentityModel.Tokens.AesGcm..cctor()
--- End of inner exception stack trace ---
at Microsoft.IdentityModel.Tokens.AesGcm.ImportKey(Byte[] key)
at Microsoft.IdentityModel.Tokens.AesGcm..ctor(Byte[] key)
at Microsoft.IdentityModel.Tokens.AuthenticatedEncryptionProvider.CreateAesGcmInstance()
at Microsoft.IdentityModel.Tokens.DisposableObjectPool`1.CreateInstance()
at Microsoft.IdentityModel.Tokens.DisposableObjectPool`1.Allocate()
at Microsoft.IdentityModel.Tokens.AuthenticatedEncryptionProvider.DecryptWithAesGcm(Byte[] ciphertext, Byte[] authenticatedData, Byte[] iv, Byte[] authenticationTag)
at Microsoft.IdentityModel.Tokens.AuthenticatedEncryptionProvider.Decrypt(Byte[] ciphertext, Byte[] authenticatedData, Byte[] iv, Byte[] authenticationTag)
at Microsoft.IdentityModel.JsonWebTokens.JwtTokenUtilities.DecryptToken(CryptoProviderFactory cryptoProviderFactory, SecurityKey key, String encAlg, Byte[] ciphertext, Byte[] headerAscii, Byte[] initializationVector, Byte[] authenticationTag)
at Microsoft.IdentityModel.JsonWebTokens.JwtTokenUtilities.DecryptJwtToken(SecurityToken securityToken, TokenValidationParameters validationParameters, JwtTokenDecryptionParameters decryptionParameters)
'.
token: 'null' |
Based on the cyrptography documentation it says |
I managed to get it working by implementing my own private class Net8AlgorithmProvider : AuthenticatedEncryptionProvider
{
public Net8AlgorithmProvider(SecurityKey key, string algorithm) : base(key, algorithm)
{
}
protected override bool IsSupportedAlgorithm(SecurityKey key, string algorithm)
{
return algorithm == SecurityAlgorithms.Aes128Gcm;
}
public override AuthenticatedEncryptionResult Encrypt(byte[] plaintext, byte[] authenticatedData, byte[]? iv)
{
throw new NotImplementedException();
}
public override byte[] Decrypt(byte[] ciphertext, byte[] authenticatedData, byte[] iv, byte[] authenticationTag)
{
var clearBytes = new byte[ciphertext.Length];
using var aesGcm = new AesGcm(GetKeyBytes(Key));
aesGcm.Decrypt(iv, ciphertext, authenticationTag, clearBytes, authenticatedData);
return clearBytes;
}
} I had to expand the public class OAEP256CryptoProvider : ICryptoProvider
{
public const string OAEP_256 = "RSA-OAEP-256";
public const string AES_128 = "A128GCM";
public bool IsSupportedAlgorithm(string algorithm, params object[] args)
{
return algorithm is OAEP_256 or SecurityAlgorithms.Aes128Gcm;
}
public object Create(string algorithm, params object[] args)
{
if (algorithm == OAEP_256)
{
return new RsaOaepKeyWrapProvider(args[0] as SecurityKey, algorithm);
}
else if (algorithm == SecurityAlgorithms.Aes128Gcm)
{
return new Net8AlgorithmProvider((SecurityKey)args[0], algorithm);
}
else
{
return null;
}
}
public void Release(object cryptoInstance)
{
}
} I would love to understand why I need to do this, and why it's not working natively... |
Also, based on this, it should work on Mac? |
Is there an existing issue for this?
Describe the bug
I'm trying to connect and authenticate users through an OIDC server. I'm getting a valid ID-token in response from the OIDC server. However, I'm struggling with getting decryption of the token to work.
Relevant OIDC setup code:
If I use .NET 6, I'm guessing the
SecurityTokenValidator
will be used, and I get the following error message:If I use .NET 8, the
JsonWebTokenHandler
is used by default, and I get the following error message (which makes sense, since that was changed in .NET 7 or 8:I'm not sure why this isn't working? And the error message when using
SecurityTokenValidator
doesn't really make sense to me, but maybe it doesn't support thisenc
ogalg
so it skips using this decryption key?This I've checked:
kid
as the private key I haveAnother problem is that the token as part of the exception generated is corrupt (it only has 4 parts). Not sure why that happens, and/or if it's misleading.
Example header of token:
Expected Behavior
I would expect the token to be correctly decrypted.
Steps To Reproduce
I would love to provide a reproduction, but I don't have any OIDC server I can use for that, and I would need to expose a private key as well...
Exceptions (if any)
IDX10609: Decryption failed. No Keys tried: token: '<redacted>'.
.NET Version
6 and 8
Anything else?
IDE: JetBrains Rider 2024.3.5
The text was updated successfully, but these errors were encountered: