Skip to content
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

Support verifying signature signed using x5c header #59

Closed
punkle opened this issue Feb 25, 2015 · 10 comments · Fixed by #338
Closed

Support verifying signature signed using x5c header #59

punkle opened this issue Feb 25, 2015 · 10 comments · Fixed by #338

Comments

@punkle
Copy link
Contributor

punkle commented Feb 25, 2015

It is currently possible to verify the signature of a jwt token using the x5c header by providing a key finder function. e.g.

jwt_token = ::JWT.decode(token) do |headers|
  OpenSSL::X509::Certificate.new((headers['x5c'].first)).public_key
end

In order to validate the x5c certificate chain in full, I must provide my own implementation. It would be great if ruby-jwt gem could support the validation of the x5c certificate chain natively.

Here is an excerpt from https://tools.ietf.org/html/draft-ietf-jose-json-web-key-41#section-4.7

4.7. "x5c" (X.509 Certificate Chain) Parameter

The "x5c" (X.509 Certificate Chain) member contains a chain of one or
more PKIX certificates [RFC5280]. The certificate chain is
represented as a JSON array of certificate value strings. Each
string in the array is a base64 encoded ([RFC4648] Section 4 -- not
base64url encoded) DER [ITU.X690.1994] PKIX certificate value. The
PKIX certificate containing the key value MUST be the first
certificate. This MAY be followed by additional certificates, with
each subsequent certificate being the one used to certify the
previous one. The key in the first certificate MUST match the public
key represented by other members of the JWK. Use of this member is
OPTIONAL.

@excpt excpt added this to the Version 2.0.0 milestone Feb 25, 2015
@excpt
Copy link
Member

excpt commented Feb 25, 2015

We need to implement JWK for that. You may have a look at the 2.x branch.

@stunney
Copy link

stunney commented Aug 5, 2015

Don't forget, you need the ENTIRE certificate chain in that field. The signing certificate first followed by each intermediate and root CA that owns that one.

@punkle
Copy link
Contributor Author

punkle commented Aug 5, 2015

@stunney It 'MAY' contain the entire certificate chain. The last certificate in the x5c chain could be rooted in a certificate store managed by the entity validating the token.

@stunney
Copy link

stunney commented Aug 5, 2015

You are correct. The first must be the cert that signed the token. The rest are optional.

@aj-michael
Copy link
Member

adding to this, using a keyfinder block is really ugly if you have additionaly options to pass in.

JWT.decode(raw_token, nil, true, additional_options) do |header|
  ...
end

I don't like that I have to pass in a key (nil) that is going to be ignored anyways. Especially since I have to pass in an options has to do full validation in accordance with the RFC. I'm also not a fan of raw booleans, because someone reading my code in the future has no easy way to know what the true refers to.

@itstehkman
Copy link

itstehkman commented May 4, 2019

Hey @punkle @excpt, I'm taking a quick stab at this since I need support for this. Open question:

Should this be implementing x5c as specified in JWS (RFC-7515) or as specified in JWK?

JWS spec for x5c:

The "x5c" (X.509 certificate chain) Header Parameter contains the
   X.509 public key certificate or certificate chain [RFC5280]
   corresponding to the key used to digitally sign the JWS.  The
   certificate or certificate chain is represented as a JSON array of
   certificate value strings.  Each string in the array is a
   base64-encoded (Section 4 of [RFC4648] -- not base64url-encoded) DER
   [ITU.X690.2008] PKIX certificate value.  The certificate containing
   the public key corresponding to the key used to digitally sign the
   JWS MUST be the first certificate.  This MAY be followed by
   additional certificates, with each subsequent certificate being the
   one used to certify the previous one.  The recipient MUST validate
   the certificate chain according to RFC 5280 [RFC5280] and consider
   the certificate or certificate chain to be invalid if any validation
   failure occurs.  Use of this Header Parameter is OPTIONAL.

JWK spec for x5c:

The "x5c" (X.509 certificate chain) parameter contains a chain of one
   or more PKIX certificates [RFC5280].  The certificate chain is
   represented as a JSON array of certificate value strings.  Each
   string in the array is a base64-encoded (Section 4 of [RFC4648] --
   not base64url-encoded) DER [ITU.X690.1994] PKIX certificate value.
   The PKIX certificate containing the key value MUST be the first
   certificate.  This MAY be followed by additional certificates, with
   each subsequent certificate being the one used to certify the
   previous one.  The key in the first certificate MUST match the public
   key represented by other members of the JWK.  Use of this member is
   OPTIONAL.

   As with the "x5u" member, optional JWK members providing key usage,
   algorithm, or other information MAY also be present when the "x5c"
   member is used.  If other members are present, the contents of those
   members MUST be semantically consistent with the related fields in
   the first certificate.  See the last paragraph of Section 4.6 for
   additional guidance on this.

the main difference being that the JWK spec also wants you to supply the public key in one of the JWK fields, which feels redundant to me since it is already in the x5c field's first cert.

@itstehkman
Copy link

Ping @punkle @excpt

@punkle
Copy link
Contributor Author

punkle commented May 17, 2019

@itstehkman I am not very familiar with the specs. Can both be supported?

@excpt
Copy link
Member

excpt commented May 19, 2019

@itstehkman I would go for the JWS RFC 7515 specs. This should keep things as simple and should avoid the redundancy.

@itstehkman
Copy link

Sounds good! After taking a look at most common implementations, they use the JWK RFC. I can probably do this in two parts - first part supporting the JWK implementation, then the pure JWS implementation too.

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

Successfully merging a pull request may close this issue.

6 participants