Skip to content

Add support for x5t and x5t#S256 header #669

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 8 commits into
base: main
Choose a base branch
from

Conversation

hieuk09
Copy link
Contributor

@hieuk09 hieuk09 commented Apr 4, 2025

Description

Close #562

Checklist

Before the PR can be merged be sure the following are checked:

  • There are tests for the fix or feature added/changed
  • A description of the changes and a reference to the PR has been added to CHANGELOG.md. More details in the CONTRIBUTING.md

@hieuk09 hieuk09 force-pushed the feature/add-x5t branch 3 times, most recently from f6e2067 to 28a5e72 Compare April 4, 2025 22:13
@anakinj
Copy link
Member

anakinj commented Apr 7, 2025

@hieuk09 Did you have some reference for how this should work? Could take a look at that to educate myself a bit.

@anakinj
Copy link
Member

anakinj commented Apr 7, 2025

@hieuk09 Did you have some reference for how this should work? Could take a look at that to educate myself a bit.

Now when looking closer at the changes I found some links...

@hieuk09
Copy link
Contributor Author

hieuk09 commented Apr 7, 2025

Thank you for the detailed review. I'll take a look and fix all the comments tomorrow.

@hieuk09
Copy link
Contributor Author

hieuk09 commented Apr 9, 2025

@anakinj could you have another review?

Copy link
Member

@anakinj anakinj left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the JWK approach is interesting. Im a bit concerned that we are cutting some corners here, as the x5* fields are pretty certificate specific and we are currently only dealing with keypairs.

jwk = @jwks.find { |key| key_matcher.call(key) }

return jwk if jwk

# Second try, invalidate for backwards compatibility
@jwks = JWT::JWK::Set.new(@jwks_loader.call(invalidate: true, kid_not_found: true, kid: kid))
@jwks = JWT::JWK::Set.new(@jwks_loader.call(invalidate: true, kid_not_found: true, key_field => kid))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could cause some problems as the keyloader could always be expecting the kid. Also do we will start invalidating 3 times if nothing is found.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also the line above where we do call with the key_field could cause backwards compatibility issues.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could cause some problems as the keyloader could always be expecting the kid

I think it's fine because we only call the JWKS loader with other key fields if token header does not contain kid. I think most of the JWKS endpoints support kid by default.

Also do we will start invalidating 3 times if nothing is found.

No, we only invalidating once. Basically, if kid field exists in token header, we only match using kid. Otherwise, if x5t exists and there is no kid, we'll match using x5t.

Also the line above where we do call with the key_field could cause backwards compatibility issues.

Could you clarify on what could be the compatibility issues? I change key_for signature but I added key_field as optional parameter so it should be backward-compatible. I may miss other scenarios, so please let me know.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right! It happens only once. Now the gem is dictating the lookup order, so if the key contains both kid and x5 headers we'll never try the x5 lookups.

I feel this key lookup is already so complicated, cant wrap my head around this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's right, the gem is dictating the lookup order. Currently I couldn't think of a better way to do this. Do you have any suggestions?

Copy link
Member

@anakinj anakinj Apr 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For use via the JWT.decode method the predefined order is fine i think.

What about having the order as a option when initializing the keyfinder (with the current order as the default).

Then the new token object approach could be easily customized.

key_finder = JWT::JWK::KeyFinder.new(jwks: JWT::JWK::Set.new(jwk), key_fields: [:kid, :x5t])
encoded_token = JWT::EncodedToken.new(token.jwt)
encoded_token.verify!(signature: { algorithm: 'RS256', key_finder: key_finder})

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, that's a good idea. Let me work on that.


# First try without invalidation to facilitate application caching
@jwks ||= JWT::JWK::Set.new(@jwks_loader.call(kid: kid))
@jwks ||= JWT::JWK::Set.new(@jwks_loader.call(key_field => kid))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

key_field should probably be set to :kid at before this is called if @allow_nil_kid is true

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if it's too late to drop the @allow_nil_kid option for the 3.0 version... 🤔

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would simplify this complicated piece of machinery....

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the approach in #669 (comment) could address the above problem, too 🤔

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Support x5t in place of kid
2 participants