Skip to content

Commit 93a942a

Browse files
fix: parse all transports even if unknown (#15)
The spec requires RP's to accept all transports even unregistered/unknown ones. See https://w3c.github.io/webauthn/#dom-authenticatorattestationresponse-transports-slot.
1 parent 90be0fe commit 93a942a

File tree

4 files changed

+28
-17
lines changed

4 files changed

+28
-17
lines changed

protocol/credential.go

+6-10
Original file line numberDiff line numberDiff line change
@@ -45,14 +45,14 @@ type ParsedPublicKeyCredential struct {
4545
type CredentialCreationResponse struct {
4646
PublicKeyCredential
4747
AttestationResponse AuthenticatorAttestationResponse `json:"response"`
48-
Transport []string `json:"transports,omitempty"`
48+
Transports []string `json:"transports,omitempty"`
4949
}
5050

5151
type ParsedCredentialCreationData struct {
5252
ParsedPublicKeyCredential
53-
Response ParsedAttestationResponse
54-
Raw CredentialCreationResponse
55-
Transport []AuthenticatorTransport `json:"transports,omitempty"`
53+
Response ParsedAttestationResponse
54+
Raw CredentialCreationResponse
55+
Transports []AuthenticatorTransport `json:"transports,omitempty"`
5656
}
5757

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

93-
for _, t := range ccr.Transport {
94-
transport := AuthenticatorTransport(t)
95-
switch transport {
96-
case USB, BLE, NFC, Internal:
97-
pcc.Transport = append(pcc.Transport, transport)
98-
}
93+
for _, t := range ccr.Transports {
94+
pcc.Transports = append(pcc.Transports, AuthenticatorTransport(t))
9995
}
10096

10197
parsedAttestationResponse, err := ccr.AttestationResponse.Parse()

protocol/credential_test.go

+20-5
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,11 @@ func TestParseCredentialCreationResponse(t *testing.T) {
4343
Type: "public-key",
4444
},
4545
RawID: byteID,
46+
ClientExtensionResults: AuthenticationExtensionsClientOutputs{
47+
"appid": true,
48+
},
4649
},
50+
Transports: []AuthenticatorTransport{USB, NFC, "fake"},
4751
Response: ParsedAttestationResponse{
4852
CollectedClientData: CollectedClientData{
4953
Type: CeremonyType("webauthn.create"),
@@ -72,13 +76,17 @@ func TestParseCredentialCreationResponse(t *testing.T) {
7276
ID: "6xrtBhJQW6QU4tOaB4rrHaS2Ks0yDDL_q8jDC16DEjZ-VLVf4kCRkvl2xp2D71sTPYns-exsHQHTy3G-zJRK8g",
7377
},
7478
RawID: byteID,
79+
ClientExtensionResults: AuthenticationExtensionsClientOutputs{
80+
"appid": true,
81+
},
7582
},
7683
AttestationResponse: AuthenticatorAttestationResponse{
7784
AuthenticatorResponse: AuthenticatorResponse{
7885
ClientDataJSON: byteClientDataJSON,
7986
},
8087
AttestationObject: byteAttObject,
8188
},
89+
Transports: []string{"usb", "nfc", "fake"},
8290
},
8391
},
8492
wantErr: false,
@@ -93,22 +101,25 @@ func TestParseCredentialCreationResponse(t *testing.T) {
93101
return
94102
}
95103
if !reflect.DeepEqual(got.ClientExtensionResults, tt.want.ClientExtensionResults) {
96-
t.Errorf("ClientExtensionResults = %v \n want: %v", got, tt.want)
104+
t.Errorf("Extensions = %v \n want: %v", got.ClientExtensionResults, tt.want.ClientExtensionResults)
105+
}
106+
if !reflect.DeepEqual(got.Transports, tt.want.Transports) {
107+
t.Errorf("Transports = %v \n want: %v", got.Transports, tt.want.Transports)
97108
}
98109
if !reflect.DeepEqual(got.ID, tt.want.ID) {
99110
t.Errorf("ID = %v \n want: %v", got, tt.want)
100111
}
101112
if !reflect.DeepEqual(got.ParsedCredential, tt.want.ParsedCredential) {
102-
t.Errorf("ParsedCredential = %v \n want: %v", got, tt.want)
113+
t.Errorf("ParsedCredential = %v \n want: %v", got.ParsedCredential, tt.want.ParsedCredential)
103114
}
104115
if !reflect.DeepEqual(got.ParsedPublicKeyCredential, tt.want.ParsedPublicKeyCredential) {
105-
t.Errorf("ParsedPublicKeyCredential = %v \n want: %v", got, tt.want)
116+
t.Errorf("ParsedPublicKeyCredential = %v \n want: %v", got.ParsedPublicKeyCredential, tt.want.ParsedPublicKeyCredential)
106117
}
107118
if !reflect.DeepEqual(got.Raw, tt.want.Raw) {
108-
t.Errorf("Raw = %v \n want: %v", got, tt.want)
119+
t.Errorf("Raw = %v \n want: %v", got.Raw, tt.want.Raw)
109120
}
110121
if !reflect.DeepEqual(got.RawID, tt.want.RawID) {
111-
t.Errorf("RawID = %v \n want: %v", got, tt.want)
122+
t.Errorf("RawID = %v \n want: %v", got.RawID, tt.want.RawID)
112123
}
113124
// Unmarshall CredentialPublicKey
114125
var pkWant interface{}
@@ -236,6 +247,10 @@ var testCredentialRequestBody = `{
236247
"id":"6xrtBhJQW6QU4tOaB4rrHaS2Ks0yDDL_q8jDC16DEjZ-VLVf4kCRkvl2xp2D71sTPYns-exsHQHTy3G-zJRK8g",
237248
"rawId":"6xrtBhJQW6QU4tOaB4rrHaS2Ks0yDDL_q8jDC16DEjZ-VLVf4kCRkvl2xp2D71sTPYns-exsHQHTy3G-zJRK8g",
238249
"type":"public-key",
250+
"transports":["usb","nfc","fake"],
251+
"clientExtensionResults":{
252+
"appid":true
253+
},
239254
"response":{
240255
"attestationObject":"o2NmbXRkbm9uZWdhdHRTdG10oGhhdXRoRGF0YVjEdKbqkhPJnC90siSSsyDPQCYqlMGpUKA5fyklC2CEHvBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAQOsa7QYSUFukFOLTmgeK6x2ktirNMgwy_6vIwwtegxI2flS1X-JAkZL5dsadg-9bEz2J7PnsbB0B08txvsyUSvKlAQIDJiABIVggLKF5xS0_BntttUIrm2Z2tgZ4uQDwllbdIfrrBMABCNciWCDHwin8Zdkr56iSIh0MrB5qZiEzYLQpEOREhMUkY6q4Vw",
241256
"clientDataJSON":"eyJjaGFsbGVuZ2UiOiJXOEd6RlU4cEdqaG9SYldyTERsYW1BZnFfeTRTMUNaRzFWdW9lUkxBUnJFIiwib3JpZ2luIjoiaHR0cHM6Ly93ZWJhdXRobi5pbyIsInR5cGUiOiJ3ZWJhdXRobi5jcmVhdGUifQ"

protocol/options_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ func TestPublicKeyCredentialRequestOptions_GetAllowedCredentialIDs(t *testing.T)
2626
Timeout: 60,
2727
AllowedCredentials: []CredentialDescriptor{
2828
{
29-
"public-key", []byte("1234"), []AuthenticatorTransport{"usb"},
29+
Type: "public-key", CredentialID: []byte("1234"), Transport: []AuthenticatorTransport{"usb"},
3030
},
3131
},
3232
RelyingPartyID: "test.org",

webauthn/credential.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ func MakeNewCredential(c *protocol.ParsedCredentialCreationData) (*Credential, e
2727
ID: c.Response.AttestationObject.AuthData.AttData.CredentialID,
2828
PublicKey: c.Response.AttestationObject.AuthData.AttData.CredentialPublicKey,
2929
AttestationType: c.Response.AttestationObject.Format,
30-
Transport: c.Transport,
30+
Transport: c.Transports,
3131
Authenticator: Authenticator{
3232
AAGUID: c.Response.AttestationObject.AuthData.AttData.AAGUID,
3333
SignCount: c.Response.AttestationObject.AuthData.Counter,

0 commit comments

Comments
 (0)