AzureAD / azure-activedirectory-identitymodel-extensions-for-dotnet

IdentityModel extensions for .Net
MIT License
1.06k stars 401 forks source link

Validating a JWT using the PS256 algorithm? #1117

Closed underscoreHao closed 5 years ago

underscoreHao commented 5 years ago

Hello,

The last two days I've been trying to verify a JWT that has been encoded using the PS256 algorithm. I have an implementation for RS256 that's working correctly, but despite my best efforts I couldn't validate a PS256 JWT. I looked and debugged through the code of Microsoft.IdentityModel.Tokens and it seems that although PS256 is in the SecurityAlgorithms.cs, an actual implementation of the validation is missing. Is this on the roadmap? Am I doing something wrong? Perhaps I'm not understanding the difference between RSA256 and PS256 well enough.

Any kind of information on this will be appreciated.

EDIT: I'm supplying an example token

// Encoded
eyJhbGciOiJQUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImtpZDEyMzQifQ.eyJpc3MiOiJmb28uYmFyLnRlc3Rpc3N1ZXIiLCJleHAiOjE1NTEyMDEwNjgsImF0X2hhc2giOiJqaFl3c1pyTnZ0dFNYQnR6QVMtWlNnIn0.yJePyxdJWyydG4HM97oQag6ulGKa5Afw-LHYYEXz7lVy8v0IJD0mSO9WtowlWJIeD2Vvthuj71XUfHsgz0LD9rK0VBucJbd_OiIXpbwPUqBcdj82DNLFXDJfCJnUC-Rv8QP7OUVBvLjvBQ6WYMrx1Qnq8xP6qeL_ohKwRmo6EDhZRkYBz9gFhfha1ZlKcnyR73nXdShwy7OmmyiRvVWPBf_GgSsfz8FNNoKySW1MA4tRa7cl3zPlyCnWyLaZ3kcQsmTqarHG--YXSDF5ozZ_Sx6TkunCxrOYzOFNcPyeIWqI84cemM6TgMBw9jhzMCk7Y4Fzxe5KEYJH4GlGA4s4zg

// Header
{
    "alg": "PS256",
    "typ": "JWT",
    "kid": "kid1234"
}
// Payload
{
    "iss": "foo.bar.testissuer",
    "exp": 1551201068,
    "at_hash": "jhYwsZrNvttSXBtzAS-ZSg"
}

And some of my code

var tokenValidationParameters = new TokenValidationParameters
{
    ValidIssuer = issuer,
    ValidateLifetime = true,
    RequireSignedTokens = true,
    RequireExpirationTime = true,
    ValidateAudience = false,
    ValidateIssuer = true,
    IssuerSigningKeyResolver = (string token, SecurityToken securityToken, string kid, TokenValidationParameters validationParameters) =>
    {
        // Custom kid checks (redacted)

        var rsa = RSA.Create();
        rsa.ImportParameters(new RSAParameters
        {
            Exponent = Base64UrlEncoder.DecodeBytes(matchingKid.E),
            Modulus = Base64UrlEncoder.DecodeBytes(matchingKid.N),
        });
        latestSecurityKeys.Add(matchingKid.Kid, new RsaSecurityKey(rsa));

        var securityKeys = new SecurityKey[1]
        {
            new RsaSecurityKey(rsa)
        };

        return securityKeys;
    }
};

var tokenHandler = new JwtSecurityTokenHandler();
try
{
    var principal = tokenHandler.ValidateToken(token, tokenValidationParameters, out SecurityToken validatedToken);
    return true;
}
catch (SecurityTokenException ex)
{
    // Do something with ex
    return false;
}
brentschmaltz commented 5 years ago

@underscoreHao As best I understand, it's really just a padding mode. Right now we don't support that mode, it's a relatively small amount or work, so we'll leave it active for 5.4.1.

These are the modes we do support for RSA: https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/blob/b152f463d910230859ec67705f11e51af4db4217/src/Microsoft.IdentityModel.Tokens/SupportedAlgorithms.cs#L159

We included the define, so users could recognize this algorithm and use extensibility to add support.

underscoreHao commented 5 years ago

Thank you for putting this on the road map. I used jose-jwt with some custom validation to accomplish what I needed, but I think this is going to be a nice addition to the package in any case.

leastprivilege commented 5 years ago

Could you please prioritize that. The open banking spec recommends PS256. Without support for that, Wilson is out.

brentschmaltz commented 5 years ago

@leastprivilege we marked this as P1, will be in next 5.x release.

GeoK commented 5 years ago

@underscoreHao - PS256 will be available in 5.5.0 release. In case that you would like to try out a preview build and provide early feedback, our nightlies are available here: https://www.myget.org/feed/azureadwebstacknightly/package/nuget/System.IdentityModel.Tokens.Jwt/5.4.1-preview-60518004438

scottbrady91 commented 5 years ago

I was able to create a JWT signed using PS256. That was using the codebase from your PR though. I couldn't find a nightly for v5.x and the v6 nightly didn't contain RSA-PSS support.

brentschmaltz commented 5 years ago

@scottbrady91 @underscoreHao published nightly of 5.5.0 here: https://www.myget.org/feed/azureadwebstacknightly/package/nuget/System.IdentityModel.Tokens.Jwt