Skip to content

Commit

Permalink
fix: parse all transports even if unknown (#15)
Browse files Browse the repository at this point in the history
The spec requires RP's to accept all transports even unregistered/unknown ones. See https://w3c.github.io/webauthn/#dom-authenticatorattestationresponse-transports-slot.
  • Loading branch information
james-d-elliott committed Mar 1, 2022
1 parent 90be0fe commit 93a942a
Show file tree
Hide file tree
Showing 4 changed files with 28 additions and 17 deletions.
16 changes: 6 additions & 10 deletions protocol/credential.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,14 @@ type ParsedPublicKeyCredential struct {
type CredentialCreationResponse struct {
PublicKeyCredential
AttestationResponse AuthenticatorAttestationResponse `json:"response"`
Transport []string `json:"transports,omitempty"`
Transports []string `json:"transports,omitempty"`
}

type ParsedCredentialCreationData struct {
ParsedPublicKeyCredential
Response ParsedAttestationResponse
Raw CredentialCreationResponse
Transport []AuthenticatorTransport `json:"transports,omitempty"`
Response ParsedAttestationResponse
Raw CredentialCreationResponse
Transports []AuthenticatorTransport `json:"transports,omitempty"`
}

func ParseCredentialCreationResponse(response *http.Request) (*ParsedCredentialCreationData, error) {
Expand Down Expand Up @@ -90,12 +90,8 @@ func ParseCredentialCreationResponseBody(body io.Reader) (*ParsedCredentialCreat
pcc.ID, pcc.RawID, pcc.Type, pcc.ClientExtensionResults = ccr.ID, ccr.RawID, ccr.Type, ccr.ClientExtensionResults
pcc.Raw = ccr

for _, t := range ccr.Transport {
transport := AuthenticatorTransport(t)
switch transport {
case USB, BLE, NFC, Internal:
pcc.Transport = append(pcc.Transport, transport)
}
for _, t := range ccr.Transports {
pcc.Transports = append(pcc.Transports, AuthenticatorTransport(t))
}

parsedAttestationResponse, err := ccr.AttestationResponse.Parse()
Expand Down
25 changes: 20 additions & 5 deletions protocol/credential_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,11 @@ func TestParseCredentialCreationResponse(t *testing.T) {
Type: "public-key",
},
RawID: byteID,
ClientExtensionResults: AuthenticationExtensionsClientOutputs{
"appid": true,
},
},
Transports: []AuthenticatorTransport{USB, NFC, "fake"},
Response: ParsedAttestationResponse{
CollectedClientData: CollectedClientData{
Type: CeremonyType("webauthn.create"),
Expand Down Expand Up @@ -72,13 +76,17 @@ func TestParseCredentialCreationResponse(t *testing.T) {
ID: "6xrtBhJQW6QU4tOaB4rrHaS2Ks0yDDL_q8jDC16DEjZ-VLVf4kCRkvl2xp2D71sTPYns-exsHQHTy3G-zJRK8g",
},
RawID: byteID,
ClientExtensionResults: AuthenticationExtensionsClientOutputs{
"appid": true,
},
},
AttestationResponse: AuthenticatorAttestationResponse{
AuthenticatorResponse: AuthenticatorResponse{
ClientDataJSON: byteClientDataJSON,
},
AttestationObject: byteAttObject,
},
Transports: []string{"usb", "nfc", "fake"},
},
},
wantErr: false,
Expand All @@ -93,22 +101,25 @@ func TestParseCredentialCreationResponse(t *testing.T) {
return
}
if !reflect.DeepEqual(got.ClientExtensionResults, tt.want.ClientExtensionResults) {
t.Errorf("ClientExtensionResults = %v \n want: %v", got, tt.want)
t.Errorf("Extensions = %v \n want: %v", got.ClientExtensionResults, tt.want.ClientExtensionResults)
}
if !reflect.DeepEqual(got.Transports, tt.want.Transports) {
t.Errorf("Transports = %v \n want: %v", got.Transports, tt.want.Transports)
}
if !reflect.DeepEqual(got.ID, tt.want.ID) {
t.Errorf("ID = %v \n want: %v", got, tt.want)
}
if !reflect.DeepEqual(got.ParsedCredential, tt.want.ParsedCredential) {
t.Errorf("ParsedCredential = %v \n want: %v", got, tt.want)
t.Errorf("ParsedCredential = %v \n want: %v", got.ParsedCredential, tt.want.ParsedCredential)
}
if !reflect.DeepEqual(got.ParsedPublicKeyCredential, tt.want.ParsedPublicKeyCredential) {
t.Errorf("ParsedPublicKeyCredential = %v \n want: %v", got, tt.want)
t.Errorf("ParsedPublicKeyCredential = %v \n want: %v", got.ParsedPublicKeyCredential, tt.want.ParsedPublicKeyCredential)
}
if !reflect.DeepEqual(got.Raw, tt.want.Raw) {
t.Errorf("Raw = %v \n want: %v", got, tt.want)
t.Errorf("Raw = %v \n want: %v", got.Raw, tt.want.Raw)
}
if !reflect.DeepEqual(got.RawID, tt.want.RawID) {
t.Errorf("RawID = %v \n want: %v", got, tt.want)
t.Errorf("RawID = %v \n want: %v", got.RawID, tt.want.RawID)
}
// Unmarshall CredentialPublicKey
var pkWant interface{}
Expand Down Expand Up @@ -236,6 +247,10 @@ var testCredentialRequestBody = `{
"id":"6xrtBhJQW6QU4tOaB4rrHaS2Ks0yDDL_q8jDC16DEjZ-VLVf4kCRkvl2xp2D71sTPYns-exsHQHTy3G-zJRK8g",
"rawId":"6xrtBhJQW6QU4tOaB4rrHaS2Ks0yDDL_q8jDC16DEjZ-VLVf4kCRkvl2xp2D71sTPYns-exsHQHTy3G-zJRK8g",
"type":"public-key",
"transports":["usb","nfc","fake"],
"clientExtensionResults":{
"appid":true
},
"response":{
"attestationObject":"o2NmbXRkbm9uZWdhdHRTdG10oGhhdXRoRGF0YVjEdKbqkhPJnC90siSSsyDPQCYqlMGpUKA5fyklC2CEHvBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAQOsa7QYSUFukFOLTmgeK6x2ktirNMgwy_6vIwwtegxI2flS1X-JAkZL5dsadg-9bEz2J7PnsbB0B08txvsyUSvKlAQIDJiABIVggLKF5xS0_BntttUIrm2Z2tgZ4uQDwllbdIfrrBMABCNciWCDHwin8Zdkr56iSIh0MrB5qZiEzYLQpEOREhMUkY6q4Vw",
"clientDataJSON":"eyJjaGFsbGVuZ2UiOiJXOEd6RlU4cEdqaG9SYldyTERsYW1BZnFfeTRTMUNaRzFWdW9lUkxBUnJFIiwib3JpZ2luIjoiaHR0cHM6Ly93ZWJhdXRobi5pbyIsInR5cGUiOiJ3ZWJhdXRobi5jcmVhdGUifQ"
Expand Down
2 changes: 1 addition & 1 deletion protocol/options_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ func TestPublicKeyCredentialRequestOptions_GetAllowedCredentialIDs(t *testing.T)
Timeout: 60,
AllowedCredentials: []CredentialDescriptor{
{
"public-key", []byte("1234"), []AuthenticatorTransport{"usb"},
Type: "public-key", CredentialID: []byte("1234"), Transport: []AuthenticatorTransport{"usb"},
},
},
RelyingPartyID: "test.org",
Expand Down
2 changes: 1 addition & 1 deletion webauthn/credential.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ func MakeNewCredential(c *protocol.ParsedCredentialCreationData) (*Credential, e
ID: c.Response.AttestationObject.AuthData.AttData.CredentialID,
PublicKey: c.Response.AttestationObject.AuthData.AttData.CredentialPublicKey,
AttestationType: c.Response.AttestationObject.Format,
Transport: c.Transport,
Transport: c.Transports,
Authenticator: Authenticator{
AAGUID: c.Response.AttestationObject.AuthData.AttData.AAGUID,
SignCount: c.Response.AttestationObject.AuthData.Counter,
Expand Down

0 comments on commit 93a942a

Please sign in to comment.