使用X509Certificate解密JWT令牌时出现IDX10659错误

5

我正在创建一个网络服务和相关客户端,将使用由X509证书加密的JWT。当我使用对称密钥来加密和解密令牌时,一切都运行良好。然而,我想在生产中使用基于X509证书的加密方式,但尝试使用其中一种时,出现以下异常:

在.NET Core上运行时:

Microsoft.IdentityModel.Tokens.SecurityTokenKeyWrapException: 
IDX10659: UnwrapKey failed, exception from crypto operation: 
'Internal.Cryptography.CryptoThrowHelper+WindowsCryptographicException: 
Key does not exist'

当在 .NET Framework 4.7 上运行时(请注意内部异常的不同):

Microsoft.IdentityModel.Tokens.SecurityTokenKeyWrapException: 
IDX10659: UnwrapKey failed, exception from crypto operation: 
'System.Security.Cryptography.CryptographicException: 
Error occurred while decoding OAEP padding.'

SymmetricSecurityKey 切换到 X509SecurityKey 只需要更改为 EncryptingCredentials 的实例提供的值,所以我期望一切都可以正常工作。

这是生成令牌的代码:

public string Generate(NodeEntitlements entitlements)
{
    if (entitlements == null)
    {
        throw new ArgumentNullException(nameof(entitlements));
    }

    var claims = CreateClaims(entitlements);
    var claimsIdentity = new ClaimsIdentity(claims);

    var securityTokenDescriptor = new SecurityTokenDescriptor
    {
        Subject = claimsIdentity,
        NotBefore = entitlements.NotBefore.UtcDateTime,
        Expires = entitlements.NotAfter.UtcDateTime,
        IssuedAt = DateTimeOffset.Now.UtcDateTime,
        Issuer = "https://example.com",
        Audience = "https://example.com",
        SigningCredentials = SigningCredentials,
        EncryptingCredentials = EncryptingCredentials
    };

    var handler = new JwtSecurityTokenHandler();
    var token = handler.CreateToken(securityTokenDescriptor);
    return handler.WriteToken(token);
}

这里是验证相同令牌的代码(我已经在抛出异常的行上添加了注释):

public VerificationResult Verify(string tokenString)
{
    var validationParameters = new TokenValidationParameters
    {
        ValidateAudience = true,
        ValidAudience = "https://example.com",
        ValidateIssuer = true,
        ValidIssuer = "https://example.com",
        ValidateLifetime = true,
        RequireExpirationTime = true,
        RequireSignedTokens = SigningKey != null,
        ClockSkew = TimeSpan.FromSeconds(60),
        IssuerSigningKey = SigningKey,
        ValidateIssuerSigningKey = SigningKey != null,
        TokenDecryptionKey = EncryptionKey
    };

    try
    {
        var handler = new JwtSecurityTokenHandler();

        // Exception is thrown here
        var principal = 
            handler.ValidateToken(tokenString, validationParameters, out var token);

        var entitlementIdClaim = principal.FindFirst("id");
        if (entitlementIdClaim == null)
        {
            return VerificationResult.IdentifierNotPresent;
        }

        return VerificationResult.Valid;
    }
    catch (SecurityTokenException ex)
    {
        Console.WriteLine(ex);
        return VerificationResult.InvalidToken;
    }
}

根据证书创建EncryptingCredentials

public static EncryptingCredentials CreateCertificateEncryptionCredentials()
{
    var certificate = FindCertificate();
    var key = new X509SecurityKey(certificate);
    var result = new EncryptingCredentials(
        key, SecurityAlgorithms.RsaOAEP, SecurityAlgorithms.Aes256CbcHmacSha512);
    return result;
}

这些方法来自于我从原始代码中提取出来的最小复现(GitHub链接); 这里有很多代码需要发布,但大部分只是基础设施。该复现完全在进程内运行,不使用任何ASP.NET内容。
我已经使用多个不同的X509Certficates在三台不同的计算机上,在两个不同的用户帐户下重现了问题,因此我认为我已经排除了证书作为问题源。每个测试中端到端签名都正常工作,这表明证书的公钥和私钥都可以正确访问。
为什么只有使用X509SecurityKey而不是SymmetricSecurityKey时解密失败?
使用X509Certficates加密/解密JWT令牌的正确方法是什么?或者,如何解决这个问题?
更新:简化了复现异常的代码。
1个回答

2

尝试使用以下方法:

new RsaSecurityKey(certificate.GetRSAPrivateKey().ExportParameters(true));

使用 X509SecurityKey 的替代方法。

实现中存在一个bug,它不允许对RSA密钥进行JIT解包。


我已经报告了这个错误 - 请查看ID为IDX10659的错误,当使用X509Certificate解密JWT令牌时 - Bevan
刚遇到了这个问题。在 Linux 容器中,.net core 3.1 正常工作,但在 Windows 主机上,相同的 SDK 出现了上述错误。这个解决方法(?)有所帮助。此外,还需要使用 new X509Certificate(..., X509KeyStorageFlags.Exportable) - Pasi Savolainen
Bevan和Kiwidev,谢谢,这真的很有帮助。 - Nikhil

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接