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(protocol): use strict base64 encoding #129

Open
wants to merge 5 commits into
base: master
Choose a base branch
from

Conversation

james-d-elliott
Copy link
Member

This ensures the strict version of base64 is used for all encoding/decoding.

This ensures the strict version of base64 is used for all encoding/decoding.
@james-d-elliott james-d-elliott requested a review from a team as a code owner February 22, 2023 00:49
@glacuesta-sa
Copy link

Can we get this merged? I found an issue related to this.

I'm receiving an incorrect base64 encoded string challenge on enrollment which breaks when trying to use js atob function decode:
image

@glacuesta-sa
Copy link

2bBvMMTz0HWhb_mva-EfeoojgjhlmJ02hY8OEPi2yUU should be instead:
2bBvMMTz0HWhb/mva+EfeoojgjhlmJ02hY8OEPi2yUU=

@glacuesta-sa
Copy link

I asked about this a few months ago and got an official response from FIDO devs group
https://groups.google.com/a/fidoalliance.org/g/fido-dev/c/d1QIuKtj4IQ/m/aKPw5j0WAAAJ

@james-d-elliott
Copy link
Member Author

james-d-elliott commented Aug 1, 2023

Sorry but this is not related. This only enforces the use of zero'd padding bits during decoding as per RFC4648 Section 3.5: Canonical Encoding, not the padding or URL encoding. The encoding issues were already addressed months ago in 0.6.0, 0.7.0, and 0.7.1, and are as far as I am aware are entirely in-line with the relevant standards sections (to be linked).

Should also point out + is a completely invalid base64 URL encoding character. The correct value is 2bBvMMTz0HWhb_mva-EfeoojgjhlmJ02hY8OEPi2yUU. Which your linked discussion confirms. See RFC4648 Section 5: Base 64 Encoding with URL and Filename Safe Alphabet which describes the URL safe variant. See also the spec sections which confirm this:

From 3. Dependencies see Base64url encoding:

Base64url encoding

The term Base64url Encoding refers to the base64 encoding using the URL- and filename-safe character set defined in Section 5 of [[RFC4648]](https://www.w3.org/TR/webauthn-2/#biblio-rfc4648), with all trailing '=' characters omitted (as permitted by Section 3.2) and without the inclusion of any line breaks, whitespace, or other additional characters.

Specific Excerpts:

  • section 5 of RFC4648
  • with all trailing '=' characters omitted

From 5.1.3. Create a New Credential - PublicKeyCredential’s Create Method:

  1. Let collectedClientData be a new CollectedClientData instance whose fields are:

type

The string "webauthn.create".

challenge

The [base64url encoding](https://www.w3.org/TR/webauthn-2/#base64url-encoding) of options.[challenge](https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialcreationoptions-challenge).

Please feel free to open a discussion if you want to discuss this further.

@james-d-elliott
Copy link
Member Author

james-d-elliott commented Aug 2, 2023

If you can provide evidence via the webauthn and referenced specifications that I'm wrong feel free to open an issue, otherwise you can open a discussion where I can more clearly explain it.

Just because worked previously with your code does not mean it was actually correct. The current code works with popular well maintained libraries such as SimpleWebauthn, and passes conformance testing.

And what you said about + and \ is wrong, you can check that on any Base64 URL validator, it will mark - and _ as errors and when converting it it will convert to + and / .

I mean.. I could be wrong. But the specifications I linked seem crystal clear that I'm not from my perspective, when you add in the fact that the + and / are characters from standard encoding and that those characters are often special for web / filesystem usage it seems clear too.

I would not have expected the go developers to have made the same mistake for so long either:

import (
	"encoding/base64"
	"testing"

	"github.com/stretchr/testify/assert"
)

func TestBase64URL(t *testing.T) {
	testCases := []struct {
		name     string
		have     string
		encoding *base64.Encoding
		expected string
	}{
		{
			"ShouldDecodeWithUnderscoresAndHyphens",
			"2bBvMMTz0HWhb_mva-EfeoojgjhlmJ02hY8OEPi2yUU",
			base64.RawURLEncoding,
			"",
		},
		{
			"ShouldErrorWithPlusAndSlash",
			"2bBvMMTz0HWhb/mva+EfeoojgjhlmJ02hY8OEPi2yUU=",
			base64.RawURLEncoding,
			"illegal base64 data at input byte 13",
		},
		{
			"ShouldErrorWithPlusAndSlashWithoutPadding",
			"2bBvMMTz0HWhb/mva+EfeoojgjhlmJ02hY8OEPi2yUU",
			base64.RawURLEncoding,
			"illegal base64 data at input byte 13",
		},
		{
			"ShouldErrorWithPlusAndSlashURLEncoding",
			"2bBvMMTz0HWhb/mva+EfeoojgjhlmJ02hY8OEPi2yUU=",
			base64.URLEncoding,
			"illegal base64 data at input byte 13",
		},
		{
			"ShouldErrorWithPlusAndSlashWithoutPaddingURLEncoding",
			"2bBvMMTz0HWhb/mva+EfeoojgjhlmJ02hY8OEPi2yUU",
			base64.URLEncoding,
			"illegal base64 data at input byte 13",
		},
	}

	for _, tc := range testCases {
		t.Run(tc.name, func(t *testing.T) {
			_, err := tc.encoding.DecodeString(tc.have)

			if len(tc.expected) == 0 {
				assert.NoError(t, err)
			} else {
				assert.EqualError(t, err, tc.expected)
			}
		})
	}
}

@go-webauthn go-webauthn locked as off-topic and limited conversation to collaborators Aug 2, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants