cryptographyc#-8.0identitymodel

KeyVaultCryptoProvider.Create method is failing when we upgrade to .net core 8.0


We have below code snippet to generate a token using Azure KeyVault Key. Same method is used in .net core 6.0 and .net core 8.0.

public string GenerateJwtToken(DateTime expiryDateTime, Microsoft.IdentityModel.Tokens.SecurityKey securityKey) 
{ 
    SigningCredentials signingCredentials = new SigningCredentials(securityKey,SecurityAlgorithms.RsaSha256) 
    { 
    CryptoProviderFactory = new CryptoProviderFactory { CustomCryptoProvider = new Microsoft.IdentityModel.KeyVaultExtensions.KeyVaultCryptoProvider() } };

    SecurityTokenDescriptor tokenDescriptor = new SecurityTokenDescriptor
    {
        IssuedAt = DateTime.UtcNow,
        Expires = expiryDateTime,
        SigningCredentials = signingCredentials
    };
    
    string token = new JsonWebTokenHandler().CreateToken(tokenDescriptor);    
    return token;
}

In .net core 6.0, it works without any error, but 8.0 it throws below error.

System.MethodAccessException: Attempt by method 'Microsoft.IdentityModel.KeyVaultExtensions.KeyVaultCryptoProvider.Create(System.String, System.Object[])' to access method 'Microsoft.IdentityModel.Tokens.CryptoProviderFactory.ShouldCacheSignatureProvider(Microsoft.IdentityModel.Tokens.SignatureProvider)' failed.
         at Microsoft.IdentityModel.KeyVaultExtensions.KeyVaultCryptoProvider.Create(String algorithm, Object[] args)
         at Microsoft.IdentityModel.Tokens.CryptoProviderFactory.CreateSignatureProvider(SecurityKey key, String algorithm, Boolean willCreateSignatures, Boolean cacheProvider)
         at Microsoft.IdentityModel.Tokens.CryptoProviderFactory.CreateForSigning(SecurityKey key, String algorithm, Boolean cacheProvider)
         at Microsoft.IdentityModel.Tokens.CryptoProviderFactory.CreateForSigning(SecurityKey key, String algorithm)
         at Microsoft.IdentityModel.JsonWebTokens.JwtTokenUtilities.CreateSignature(ReadOnlySpan`1 data, Span`1 destination, SigningCredentials signingCredentials, Int32& bytesWritten)
         at Microsoft.IdentityModel.JsonWebTokens.JsonWebTokenHandler.CreateToken(SecurityTokenDescriptor tokenDescriptor, Boolean setdefaultTimesOnTokenCreation, Int32 tokenLifetimeInMinutes)
         at Microsoft.IdentityModel.JsonWebTokens.JsonWebTokenHandler.CreateToken(SecurityTokenDescriptor tokenDescriptor)

We tried different way to generate key using JwtSecurityToken and JwtSecurityTokenHandler().WriteToken(token). Below is the result, we ended up

System.Security.Cryptography.CryptographicException: Unknown error (0xc100000d) at System.Security.Cryptography.RSABCrypt.TrySignHash(ReadOnlySpan1 hash, Span1 destination, HashAlgorithmName hashAlgorithm, RSASignaturePadding padding, Int32& bytesWritten) at System.Security.Cryptography.RSA.SignHash(ReadOnlySpan1 hash, Span1 destination, HashAlgorithmName hashAlgorithm, RSASignaturePadding padding) at System.Security.Cryptography.RSABCrypt.SignHash(Byte[] hash, HashAlgorithmName hashAlgorithm, RSASignaturePadding padding) at Microsoft.IdentityModel.Tokens.AsymmetricAdapter.SignRsa(Byte[] bytes) at Microsoft.IdentityModel.Tokens.AsymmetricAdapter.Sign(Byte[] bytes) at Microsoft.IdentityModel.Tokens.AsymmetricSignatureProvider.Sign(Byte[] input) at Microsoft.IdentityModel.JsonWebTokens.JwtTokenUtilities.CreateEncodedSignature(String input, SigningCredentials signingCredentials) at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.WriteToken(SecurityToken token)

The code snippet used is here

        SigningCredentials signingCredentials = new SigningCredentials(new RsaSecurityKey(new Azure.Security.KeyVault.Keys.Key.ToRSA()), SecurityAlgorithms.RsaSha256);

        JwtSecurityToken token = new JwtSecurityToken(claims: claims, signingCredentials: signingCredentials);

        return new JwtSecurityTokenHandler().WriteToken(token);

I would require some help here to mitigate this version confusions.

Please let me know if any further details are required. Please note: All the required libraries are updated to latest available version.


Solution

  • Problem is solved. When you retrieve from Azure KeyVault, along with KeyVaultKey value, create CryptographyClient as well.

    keyClient = new(vaultUri: new Uri(keyVaultUri), credential: new DefaultAzureCredential(new DefaultAzureCredentialOptions()
                    {
                        AdditionallyAllowedTenants = { tenatId }
                    }));
    
    cryptoClient = new CryptographyClient(keyClient.GetKey(keyName).Value.Id, new DefaultAzureCredential(new DefaultAzureCredentialOptions()
                    {
                        AdditionallyAllowedTenants = { tenatId }
                    }));
    

    Then in logic side use below

    JwtSecurityToken token = new(claims: claims, notBefore: iat, expires: expiryDateTime, signingCredentials: new SigningCredentials(new RsaSecurityKey(objCryptoClient.CreateRSA()), SecurityAlgorithms.RsaSha256));
    
    return new JwtSecurityTokenHandler().WriteToken(token);
    

    This solved the issue. But I presume that Microsoft has to resolve library issues to go back to the previous "SecurityKey" class-based approaches.