Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SecurityTokenSignatureKeyNotFoundException when validating JWT signature

I'm trying to implement the OpenID Connect specification for my organisation. I'm using Microsoft's OWIN implementation of OpenID Connect in a test relying party application to verify my implementation of the protocol.

I've exposed the following metadata document:

{
  "issuer": "https://acs.contoso.com/",
  "authorization_endpoint": "http://localhost:53615/oauth2/auth",
  "token_endpoint": "http://localhost:53615/oauth2/token",
  "userinfo_endpoint": "http://localhost:53615/connect/userinfo",
  "jwks_uri": "http://localhost:53615/connect/keys",
  "ui_locales_supported": [
    "en-GB"
  ]
}

The signing key is exposed as this document:

{
  "keys": [
    {
      "n": "xpXxl3M-YkZlzQJdArO1TfOGT2no-UL4dbZ7WuSCNIsSfyGDaqUXjMMHNyq9yD3vp-NCyk8kmn7d5XqHufnceXJM8q4xTrhN3lvywdBSbR-dwXsA-B-MJVgfiK0d_z-mxP9ew2Hj9-KkWbWCzsswlWp3gZ4mB4RGutB1IRSzXVIbvZ-MtKUb6XUDU4LDb_c1xCEXWZxhR-o1a1dLfObH2hHJ-w5y6odGlKtOFx4i4h0u7-Oj5R6k5b2YXEHM0IuYeN0u0sQvrTecokntGzPrvhnKy69I7Z_az5rC5kgloh25D9lTbe4vcRU7FXlYCFYDZsT0_IkGIXRi7brOS4f1ow",
      "e": "AQAB",
      "kty": "RSA",
      "use": "sig",
      "alg": "RS256",
      "kid": "F8A59280B3D13777CC7541B3218480984F421450"
    }
  ]
}

The identity token is being generated using the JwtSecurityToken class and its associated handler, using the X509SigningCredentials class. This code is representative of how the token is constructed and returned to the calling system as a parameter of the response data.

var credentials = new X509SigningCredentials(cert); // My certificate.
var issuedTime = DateTime.UtcNow;
var expiresTime = issuedTime.AddMinutes(5);
var epoch = new DateTime(1970, 01, 01, 0, 0, 0);

var claims = new[]
{
    new Claim("sub", Guid.NewGuid().ToString()),
    new Claim("iat" Math.Floor((issuedTime - epoch).TotalSeconds).ToString()),
    new Claim("nonce", nonce), // Value from client
}

var token = new JwtSecurityToken(
    "https://acs.contoso.com",
    client_id, // Value from client
    claims,
    new Lifetime(issuedTime, expiresTime),
    credentials);

var handler = new JwtSecurityTokenHandler();
parameters.Add("id_token", handler.WriteToken(token)); // Outgoing parameters.

When I attempt to pass the signed token back to the relying party application, the OWIN middleware accepts the POST and attempts to verify the signature of the token. In doing so, the following exception is thrown:

SecurityTokenSignatureKeyNotFoundException: IDX10500: Signature validation failed. Unable to resolve SecurityKeyIdentifier: 'SecurityKeyIdentifier ( IsReadOnly = False, Count = 1, Clause[0] = X509ThumbprintKeyIdentifierClause(Hash = 0xF8A59280B3D13777CC7541B3218480984F421450) ) ', token: '{"typ":"JWT","alg":"RS256","x5t":"-KWSgLPRN3fMdUGzIYSAmE9CFFA"}.{"iss":"https://test.accesscontrol.net/","aud":"test","nbf":1404917162,"exp":1404917462,"sub":"60eb55ec-0699-4068-bfa6-41666fc2b2e9","iat":"1404917162"} RawData: eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6Ii1LV1NnTFBSTjNmTWRVR3pJWVNBbUU5Q0ZGQSJ9.eyJpc3MiOiJodHRwczovL2Fjcy5zdXJlY2xvdWQuY29tLyIsImF1ZCI6InRlc3QiLCJuYmYiOjE0MDQ5MTcxNjIsImV4cCI6MTQwNDkxNzQ2Miwic3ViIjoiNjBlYjU1ZWMtMDY5OS00MDY4LWJmYTYtNDE2NjZmYzJiMmU5IiwiaWF0IjoiMTQwNDkxNzE2MiJ9.xkP0RwlX3CYfU0KhFsVvLJC94WK22DTqNTm71cfjiJ8VUHv3b2YhDqfq70N8mQEyiR8vTR6OQqnO6UqXqX4RXUs6ZkfK9Liv3n9NhCs97wJhP2jfefJYeScYtRmWcNNWSSL7vkm2JXQfwKOQTnOGp-ba04TtI6jVrjhOQXH43eCJ9vNuBUzdD-t8CAdmnbvH0nWpIB8kWbw5v8Sa0aQuxMjJYbLC_2Iw3X13dqnyVjp4fA7eSB8N7c1it0KEB-VKfUqiGD3VecyEZGGZbaGE8rvVet5QrY1lJ3V4yM8j6-xDc5Yndc4swOun0L3D6TYk-8gdVXUJDRjbv1ZuhZltsw'.

The component is still pre-release, so this may be a flaw in the implementation, however I want to assume it's my error until all possibilities have been ruled out.

Is there anything I'm doing which is obviously wrong, or is there something I should do to understand exactly why the signature is failing to be validated?

like image 908
Paul Turner Avatar asked Jul 09 '14 15:07

Paul Turner


People also ask

How are JWT signatures validated?

JWTs are signed so they can't be modified in transit. When an authorization server issues a token, it signs it using a key. When the client receives the ID token, the client validates the signature using a key as well.

When validating a JWT What are some of the claims?

To verify JWT claimsThe issuer ( iss ) claim should match your user pool. For example, a user pool created in the us-east-1 Region will have the following iss value: https://cognito-idp.us-east-1.amazonaws.com/ <userpoolID> . Check the token_use claim.

How do I fix invalid signature on JWT?

For Invalid JWT Signature, check if your service account key has expired. Go to your APIs & Services to add a new key if it has.

How do I verify my JWT access token?

We must send the access token to the OneLogin OIDC app's introspection endpoint to validate the token. If the token is valid, the introspection endpoint will respond with an HTTP 200 response code. The body of the response will also contain an augmented version of the original JWT token's payload.


1 Answers

The problem is nestled in the exception message here:

Clause[0] = X509ThumbprintKeyIdentifierClause(Hash = 0xF8A59280B3D13777CC7541B3218480984F421450)

The token is signed with the default key identifier clause for an X.509 certificate: its thumbprint. The metadata is exposing just the RSA parameters and a name identifier. When the client retrieves the metadata, it sets up an RSA key using this information, not an X.509 thumbprint.

To correct this error, the signing credentials have to be changed to include the correct name identifier:

var credentials = new X509CertificateCredentials(
    cert,
    new SecurityKeyIdentifier(
        new NamedKeySecurityKeyIdentifierClause(
            "kid",
            "F8A59280B3D13777CC7541B3218480984F421450")));

This includes the expected identifier in the signature, and the signature is validated successfully.

like image 57
Paul Turner Avatar answered Sep 17 '22 03:09

Paul Turner