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

Issue with JWK Validation: Leading Zero in Coordinates #18

Closed
Useserall opened this issue Feb 26, 2024 · 12 comments
Closed

Issue with JWK Validation: Leading Zero in Coordinates #18

Useserall opened this issue Feb 26, 2024 · 12 comments
Labels
bug Something isn't working

Comments

@Useserall
Copy link

Useserall commented Feb 26, 2024

We have encountered a problem where loading JSON Web Keys (JWKs) results in the following error message:

"failed to validate JSON Web Key: failed to validate JWK: marshaled JWK does not match original JWK"

The JWK is set as follows:

                "kty": "EC",
                "crv": "P-256",
                "alg": "ES256"

Upon investigation, we found that the problem lies in one of the key coordinates starting with a leading zero. For example:
The x coordinate starts with "ALTu..." After the coordinate is changed with the following function

func base64urlTrailingPadding(s string) ([]byte, error) {
the result looks like:
[0 180 238...]

However, after calling Set.Bytes() on this value, the leading zero disappears..

X: new(big.Int).SetBytes(x),

When converting the result back to bytes we see the following result:
[180 238...]

This discrepancy leads to the original error message because the deepEqual check here no longer validates correctly.

jwkset/jwk.go

Line 311 in b0b8e8b

ok := reflect.DeepEqual(j.marshal, marshalled)

We recommend addressing this issue by ensuring consistent handling of leading zeros in key coordinates during JWK validation.

We hope to hear soon from you!

Kind regards,
Hauke

@MicahParks
Copy link
Owner

MicahParks commented Feb 26, 2024

Hello, thank you for opening this issue.

Are you able to share where you got this JWK from? If it's a public vendor such as an AWS product, Okta, Auth0, etc, I would like to send them an email regarding RFC compliance.

The reason this happened is because the JWK being used is non-RFC compliant regarding padding with leading zeros. Please see this note in the README.md and these lines of RFC 7518:

The octet sequence MUST utilize the minimum number of octets needed to represent the value.

I know saying "the JWK is non-RFC compliant" isn't a satisfying answer. I plan on adding a work-around for non-RFC compliant JWK with leading padding similar to the trailing padding issue. Unfortunately, this is unlikely to happen today, but is likely to happen before the week is over.

Edit:
This is incorrect. This JWK parameter is not a Base64urlUInt, it's a base64url encoding.

@Useserall
Copy link
Author

Hello @MicahParks and thank you for your quick reply!

Yes I can share that - the JWK comes from backstage: https://github.com/backstage/backstage
I asked our developers if they knew if a third party library was being used and they replied that internally it appears to be using: https://github.com/panva/jose in version 4.11.1.

If I hear something different or have any updates I will come back to you on this.

I completely agree and would equally ask them to change their method of creating JWKs as they are not RFC compliant.

That would be great, thank you very much!

Kind regards,
Hauke

@raskad
Copy link

raskad commented Feb 26, 2024

Hi @MicahParks,

I took a look at the RFC 7518. I might be missing something since I did not read it fully, but to me the section on the "x" and "y" parameters sounds like they should be represented as a fixed length base64url encoded string:

6.2.1.2. "x" (X Coordinate) Parameter

The "x" (x coordinate) parameter contains the x coordinate for the
Elliptic Curve point. It is represented as the base64url encoding of
the octet string representation of the coordinate, as defined in
Section 2.3.5 of SEC1 [SEC1]. The length of this octet string MUST
be the full size of a coordinate for the curve specified in the "crv"
parameter. For example, if the value of "crv" is "P-521", the octet
string must be 66 octets long.

As far as I can see the Base64urlUInt is only used in the parameters "n", "e", "d", "p", "q", "dp", "dq", "qi", the "r" (Prime Factor), "d" (Factor CRT Exponent) and "t" (Factor CRT Coefficient).

Again I may be totally wrong here because I only looked for that term.

@MicahParks
Copy link
Owner

@raskad thank you for politely pointing that out.

It does look like these JWK parameters are defined by base64url encoding as defined by RFC 7518 Section 1.1, not Base64urlUInt, which is defined differently in Section 2.

I'm going to mark this issue as bug.

@MicahParks MicahParks added the bug Something isn't working label Feb 26, 2024
@MicahParks
Copy link
Owner

It's a shame that the RFC did not define some of these JWK parameters as Base64urlUInt or some other type like Base64urlInt for values that could be negative.

Looking at *ecdsa.PublicKey for example, the X, and Y fields are represented as *big.Int and the most natural way to turn that into the JWK parameter using Golang is always going to strip and leading zeros, unless the leading zeros are added manually.

The new validation method I'm working on will be comparing the affected JWK parameters *big.Int types. This technically would be the wrong way to compare Base64url Encoding, but I think it's safe to assume this comparison will be correct for certain JWK parameters, such as "x" and "y", also there's doesn't seem to be any other way to compare values since it's impossible to know how many leading zeros are added when JWKs come from other projects.

@raskad
Copy link

raskad commented Feb 27, 2024

The new validation method I'm working on will be comparing the affected JWK parameters *big.Int types.

That was also my first idea when I took a look at the code.

also there's doesn't seem to be any other way to compare values since it's impossible to know how many leading zeros are added when JWKs come from other projects.

From my reading of the descriptions of "x" and "y", in theory they must have a fixed length corresponding to the crv right? The length of this octet string MUST be the full size of a coordinate for the curve specified in the "crv" parameter. I'm not 100% read up on the code, but maybe there could be a check when parsing the jwk to verify that "x" and "y" have the specified length and then later you could add the leading zeroes up to that point? But I'm not sure if that actually improves anything.

@MicahParks
Copy link
Owner

@raskad I think the line you pointed out from RFC 7518 Section 6.2.1.2 is likely something I overlooked when implemented the affected portion of JWK.

The length of this octet string MUST be the full size of a coordinate for the curve specified in the "crv" parameter.

If I am reading this correctly and remember what exists in the code base today. I also need to check how JWK parameters that are marked as Base64url Encoding are treated. I am concerned some/all are being treated as Base64urlUInt when JSON marshaling or unmarshaling, they could be in a different format and I'm not sure the Golang methods being used are appropriate. .Bytes and .SetBytes

I am going to sign off for the night, but plan on looking at this further tomorrow.

If you want to take a peek at the work-in-progress branch, you can find that here: jwk-validation-rework. I am not attached to this WIP branch. Suggestions or pull requests that take a different approach are welcome.

@MicahParks
Copy link
Owner

Addressing a subset of the questions posed by this issue is this PR: #19

The PR is meant to comply with the octet length requirements for ECDSA JWK parameters as discussed in this issue.

I encourage any interested parties to review, comment, and emoji react on the PR.

I am still investigating Base64urlUInt vs Base64url Encoding and if this project is in full RFC compliance regarding that.

@MicahParks
Copy link
Owner

Please see the newly release version v0.5.13. This should resolve the original issue. Thank you all again for opening this issue! If the issue has been solved to your satisfaction, please close the issue. I'll close it sometime in the future if there is no activity.

I've made two new issues relevant to this discussion.

  1. Rework validation: Change how JWK validation works #20
  2. Investigating Base64urlUInt vs Base64url Encoding and if this project is in full RFC compliance: Investigate if this project is in full RFC compliance for JWK parameters using Base64urlUInt vs Base64url Encoding #21

renovate bot added a commit to nobl9/nobl9-go that referenced this issue Mar 5, 2024
[![Mend
Renovate](https://app.renovatebot.com/images/banner.svg)](https://renovatebot.com)

This PR contains the following updates:

| Package | Change | Age | Adoption | Passing | Confidence |
|---|---|---|---|---|---|
| [github.com/MicahParks/jwkset](https://togithub.com/MicahParks/jwkset)
| `v0.5.12` -> `v0.5.13` |
[![age](https://developer.mend.io/api/mc/badges/age/go/github.com%2fMicahParks%2fjwkset/v0.5.13?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![adoption](https://developer.mend.io/api/mc/badges/adoption/go/github.com%2fMicahParks%2fjwkset/v0.5.13?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![passing](https://developer.mend.io/api/mc/badges/compatibility/go/github.com%2fMicahParks%2fjwkset/v0.5.12/v0.5.13?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![confidence](https://developer.mend.io/api/mc/badges/confidence/go/github.com%2fMicahParks%2fjwkset/v0.5.12/v0.5.13?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
| [github.com/aws/aws-sdk-go](https://togithub.com/aws/aws-sdk-go) |
`v1.50.30` -> `v1.50.31` |
[![age](https://developer.mend.io/api/mc/badges/age/go/github.com%2faws%2faws-sdk-go/v1.50.31?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![adoption](https://developer.mend.io/api/mc/badges/adoption/go/github.com%2faws%2faws-sdk-go/v1.50.31?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![passing](https://developer.mend.io/api/mc/badges/compatibility/go/github.com%2faws%2faws-sdk-go/v1.50.30/v1.50.31?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![confidence](https://developer.mend.io/api/mc/badges/confidence/go/github.com%2faws%2faws-sdk-go/v1.50.30/v1.50.31?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|

---

### Release Notes

<details>
<summary>MicahParks/jwkset (github.com/MicahParks/jwkset)</summary>

###
[`v0.5.13`](https://togithub.com/MicahParks/jwkset/releases/tag/v0.5.13)

[Compare
Source](https://togithub.com/MicahParks/jwkset/compare/v0.5.12...v0.5.13)

The purpose of this release is to correctly pad EC JWK parameters with
leading zeros where required by RFC 7518.

For `"x"` and `"y"`:

> The length of this octet string MUST be the full size of a coordinate
for the curve specified in the "crv" parameter. For example, if the
value of "crv" is "P-521", the octet string must be 66 octets long.

For `"d"`:

> The length of this octet string MUST be ceiling(log-base-2(n)/8)
octets (where n is the order of the curve).

This is to bring the project into RFC compliance with RFC 7518 Section
[6.2.1.2](https://datatracker.ietf.org/doc/html/rfc7518#section-6.2.1.2),
[6.2.1.3](https://datatracker.ietf.org/doc/html/rfc7518#section-6.2.1.3),
and
[6.2.2.1](https://datatracker.ietf.org/doc/html/rfc7518#section-6.2.2.1).

Relevant issues:

-
[MicahParks/jwkset#18

#### What's Changed

- Required leading zeros in ECDSA keys by
[@&#8203;MicahParks](https://togithub.com/MicahParks) in
[MicahParks/jwkset#19

**Full Changelog**:
MicahParks/jwkset@v0.5.12...v0.5.13

</details>

<details>
<summary>aws/aws-sdk-go (github.com/aws/aws-sdk-go)</summary>

###
[`v1.50.31`](https://togithub.com/aws/aws-sdk-go/blob/HEAD/CHANGELOG.md#Release-v15031-2024-03-04)

[Compare
Source](https://togithub.com/aws/aws-sdk-go/compare/v1.50.30...v1.50.31)

\===

##### Service Client Updates

-   `service/cloudformation`: Updates service API and documentation
- Add DetailedStatus field to DescribeStackEvents and DescribeStacks
APIs
-   `service/fsx`: Updates service API and documentation
-   `service/organizations`: Updates service API and documentation
    -   Documentation update for AWS Organizations

</details>

---

### Configuration

📅 **Schedule**: Branch creation - "after 10pm every weekday,before 5am
every weekday,every weekend" (UTC), Automerge - At any time (no schedule
defined).

🚦 **Automerge**: Enabled.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

👻 **Immortal**: This PR will be recreated if closed unmerged. Get
[config help](https://togithub.com/renovatebot/renovate/discussions) if
that's undesired.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR has been generated by [Mend
Renovate](https://www.mend.io/free-developer-tools/renovate/). View
repository job log
[here](https://developer.mend.io/github/nobl9/nobl9-go).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzNy4yMjAuMiIsInVwZGF0ZWRJblZlciI6IjM3LjIyMC4yIiwidGFyZ2V0QnJhbmNoIjoibWFpbiJ9-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
@Useserall
Copy link
Author

Hi again @MicahParks,

thanks for your update and the new version, we appreciate you work!
Is it possible that you update the dependency on this project also in your keyfunc project?

That would help us too. Thanks and kind regards!

@MicahParks
Copy link
Owner

MicahParks commented Mar 5, 2024

@Useserall please see keyfunc v3.2.6.

Edit, actually use 3.2.7. I forgot to run go mod tidy.

renovate bot added a commit to nobl9/nobl9-go that referenced this issue Mar 12, 2024
[![Mend
Renovate](https://app.renovatebot.com/images/banner.svg)](https://renovatebot.com)

This PR contains the following updates:

| Package | Change | Age | Adoption | Passing | Confidence |
|---|---|---|---|---|---|
| [github.com/MicahParks/jwkset](https://togithub.com/MicahParks/jwkset)
| `v0.5.14` -> `v0.5.15` |
[![age](https://developer.mend.io/api/mc/badges/age/go/github.com%2fMicahParks%2fjwkset/v0.5.15?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![adoption](https://developer.mend.io/api/mc/badges/adoption/go/github.com%2fMicahParks%2fjwkset/v0.5.15?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![passing](https://developer.mend.io/api/mc/badges/compatibility/go/github.com%2fMicahParks%2fjwkset/v0.5.14/v0.5.15?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![confidence](https://developer.mend.io/api/mc/badges/confidence/go/github.com%2fMicahParks%2fjwkset/v0.5.14/v0.5.15?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
|
[github.com/MicahParks/keyfunc/v3](https://togithub.com/MicahParks/keyfunc)
| `v3.2.8` -> `v3.2.9` |
[![age](https://developer.mend.io/api/mc/badges/age/go/github.com%2fMicahParks%2fkeyfunc%2fv3/v3.2.9?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![adoption](https://developer.mend.io/api/mc/badges/adoption/go/github.com%2fMicahParks%2fkeyfunc%2fv3/v3.2.9?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![passing](https://developer.mend.io/api/mc/badges/compatibility/go/github.com%2fMicahParks%2fkeyfunc%2fv3/v3.2.8/v3.2.9?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![confidence](https://developer.mend.io/api/mc/badges/confidence/go/github.com%2fMicahParks%2fkeyfunc%2fv3/v3.2.8/v3.2.9?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|

---

### Release Notes

<details>
<summary>MicahParks/jwkset (github.com/MicahParks/jwkset)</summary>

###
[`v0.5.15`](https://togithub.com/MicahParks/jwkset/releases/tag/v0.5.15):
Less strict validation

[Compare
Source](https://togithub.com/MicahParks/jwkset/compare/v0.5.14...v0.5.15)

The purpose of this release is to use less strict validation for JWK.
This will allow users to work with non-RFC compliant JWK Sets for small
padding mistakes.

Two padding related reasons for this are:

1.  Mandatory leading padding for ECDSA JWK parameters.
2.  A common mistake adding leading padding to RSA JWK parameter "n".

For padding specifically, this project is only comparing integers after
they are parsed from Base64 raw URL encoding by default. To turn on
strict validation, there will be a new field on jwkset.ValidateOptions
named StrictPadding.

An example for `1` would be a bug in this project were mandatory leading
padding was absent:
[MicahParks/jwkset#18

An example for `2` would be a Firebase service that was reported to be
incompatible with this project:
[MicahParks/jwkset#23

Relevant issues:

-
[MicahParks/jwkset#23
-
[MicahParks/jwkset#20
-
[MicahParks/jwkset#18

Relevant pull requests:

-
[MicahParks/jwkset#24

</details>

<details>
<summary>MicahParks/keyfunc (github.com/MicahParks/keyfunc/v3)</summary>

###
[`v3.2.9`](https://togithub.com/MicahParks/keyfunc/compare/v3.2.8...v3.2.9)

[Compare
Source](https://togithub.com/MicahParks/keyfunc/compare/v3.2.8...v3.2.9)

</details>

---

### Configuration

📅 **Schedule**: Branch creation - "after 10pm every weekday,before 5am
every weekday,every weekend" (UTC), Automerge - At any time (no schedule
defined).

🚦 **Automerge**: Enabled.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

👻 **Immortal**: This PR will be recreated if closed unmerged. Get
[config help](https://togithub.com/renovatebot/renovate/discussions) if
that's undesired.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR has been generated by [Mend
Renovate](https://www.mend.io/free-developer-tools/renovate/). View
repository job log
[here](https://developer.mend.io/github/nobl9/nobl9-go).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzNy4yMzAuMCIsInVwZGF0ZWRJblZlciI6IjM3LjIzMC4wIiwidGFyZ2V0QnJhbmNoIjoibWFpbiJ9-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
@MicahParks
Copy link
Owner

MicahParks commented Mar 12, 2024

With the newest release, v0.5.15, ECDSA keys produced by this project will have the proper padding in the relevant JWK parameters. This project will also work with all keys regardless of leading padding on ECDSA JWK parameters.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

3 participants