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

fix(challenge): urlsafe base64 encoding #82

Merged
merged 3 commits into from
Dec 17, 2022

Conversation

matoous
Copy link
Contributor

@matoous matoous commented Dec 6, 2022

This fixes issue with wrong encoding being used for the challenge. According to the specs1 the challenge should be base64 url-safe encoded. Until now, the package used std encoding which uses slightly different set of characters. This was reported in the linked issue and we also encountered the same issue when testing our implementation of webauthn e2e using github.com/descope/virtualwebauthn.

The commit removes the custom type for challenge and instead passes around the challenge url-safe base64 encoded right from the point of creation. Because the string is fully valid it can be safely used in json as well as stored in redis or other possible storage implementations that might be used by the clients of the library.

I tried to keep the tests as close to the original as possible. In some cases that required transforming the challenge back to bytes considering the previously used padding to be part of the bytes and then re-encoding into url-safe base64 string.

Fix: duo-labs/webauthn#128

Footnotes

  1. https://www.w3.org/TR/webauthn-2/#dom-collectedclientdata-challenge

This fixes issue with wrong encoding being used for the challenge.
According to the specs[^1] the challenge should be base64 url-safe
encoded. Until now, the package used std encoding which uses slightly
different set of characters. This was reported in the linked issue
and we also encountered the same issue when testing our implementation
of webauthn e2e using github.com/descope/virtualwebauthn.

The commit removes the custom type for challenge and instead passes
around the challenge url-safe base64 encoded right from the point of
creation. Because the string is fully valid it can be safely used
in json as well as stored in redis or other possible storage
implementations that might be used by the clients of the library.

I tried to keep the tests as close to the original as possible.
In some cases that required transforming the challenge back to bytes
considering the previously used padding to be part of the bytes
and then re-encoding into url-safe base64 string.

[^1]: https://www.w3.org/TR/webauthn-2/#dom-collectedclientdata-challenge

Fix: duo-labs/webauthn#128
@matoous matoous requested a review from a team as a code owner December 6, 2022 17:13
@james-d-elliott
Copy link
Member

Hey Matouš! Thanks for contributing! I am relatively certain this change concept is correct. Have you checked this with existing credentials and new credentials by chance? I will probably do so if not just to ensure there are no weird issues.

@matoous
Copy link
Contributor Author

matoous commented Dec 6, 2022

@james-d-elliott I only tested the whole thing using an integration test setup we (@ company) have with https://github.com/descope/virtualwebauthn. We are currently working on webauthn capabilities and don't yet have the front end ready so I sadly don't have better way to test this end to end in real browser scenario. On the other hand, the https://github.com/descope/virtualwebauthn is what complained about the non-user-safe encoding and now our tests pass so I am confident the changes fix the issue. Still, if you please have a way to test this in real scenario, please do 🙏

@matoous
Copy link
Contributor Author

matoous commented Dec 12, 2022

@james-d-elliott please let me know if I should do any further testing or if any changes are required.

@james-d-elliott
Copy link
Member

Hey I definitely will in the next few days, works just been a bit busy. I had a few questions mostly.

@james-d-elliott
Copy link
Member

So after taking a closer look I'm not entirely sure what this changes, there is zero reduction in the use of base64.StdEncoding, it's just moved the use of base64.RawURLEncoding to other areas as far as I can see. Can you show a test which fails prior to this change that demonstrates the need for these specific changes or maybe explain what I'm missing?

@james-d-elliott
Copy link
Member

Oh I think I see.. because of the JSON Marshal.

Copy link
Member

@james-d-elliott james-d-elliott 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 this mostly looks good. The reason it's not encoding it correctly is because the Challenge type is defined as a URLEncodedBase64 but the go compiler actually treats it as a []byte (you'll be able to see that Challenge lacks the implementation of the json.Marshaler and json.Unmarshaler interfaces). There are multiple ways to work around this, we can use a struct with the following signature:

type Challenge struct {
	URLEncodedBase64
}

Or we can get rid of it entirely like you have.

Or we can replace all instances of it with URLEncodedBase64 which may be an better change overall? My suggestions show (roughly) how to do this.

protocol/assertion_test.go Outdated Show resolved Hide resolved
protocol/assertion_test.go Outdated Show resolved Hide resolved
protocol/attestation_test.go Outdated Show resolved Hide resolved
protocol/challenge.go Outdated Show resolved Hide resolved
protocol/challenge.go Outdated Show resolved Hide resolved
webauthn/registration.go Outdated Show resolved Hide resolved
protocol/options.go Outdated Show resolved Hide resolved
protocol/credential_test.go Outdated Show resolved Hide resolved
protocol/credential_test.go Outdated Show resolved Hide resolved
protocol/client_test.go Outdated Show resolved Hide resolved
@matoous matoous force-pushed the md/128 branch 2 times, most recently from 4f766d8 to da684bb Compare December 16, 2022 13:31
@matoous
Copy link
Contributor Author

matoous commented Dec 16, 2022

@james-d-elliott thanks for suggestions, applied and adjusted. It's way closer now to the initial implementation.

@james-d-elliott
Copy link
Member

@james-d-elliott thanks for suggestions, applied and adjusted. It's way closer now to the initial implementation.

That's what I was going for. Thanks a lot! I'll do a final pass today and merge this hopefully.

Copy link
Member

@james-d-elliott james-d-elliott left a comment

Choose a reason for hiding this comment

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

LGTM

@tobiaszheller
Copy link
Contributor

Hey, just want to leave some information in case someone updates from v0.5.0 to v.0.6.0, this PR will cause breaking changes on server - client connection if your client expects base64 instead of base64url encoding.
I think it was not mention explicitly in release notes (or maybe it's not needed on pre v1).

Anyway, thanks for keeping it inline with spec now :)

@james-d-elliott
Copy link
Member

I'm on the fence as to if this was the breaking change or the change which introduced this bug was the breaking change. I'm more than willing to make special note of it in the release notes but I'm inclined to decline the idea this is breaking (specifically from a semver standpoint) as anytime something we're not doing to spec we will have the same expectations in many instances; but the spec is the contract.

I'll do some research regarding #93 however.

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.

Challenge: urlsafe vs standard base64
3 participants