diff --git a/protocol/credential.go b/protocol/credential.go index a43369c..9967904 100644 --- a/protocol/credential.go +++ b/protocol/credential.go @@ -45,12 +45,14 @@ type ParsedPublicKeyCredential struct { type CredentialCreationResponse struct { PublicKeyCredential AttestationResponse AuthenticatorAttestationResponse `json:"response"` + Transports []string `json:"transports,omitempty"` } type ParsedCredentialCreationData struct { ParsedPublicKeyCredential - Response ParsedAttestationResponse - Raw CredentialCreationResponse + Response ParsedAttestationResponse + Transports []AuthenticatorTransport + Raw CredentialCreationResponse } func ParseCredentialCreationResponse(response *http.Request) (*ParsedCredentialCreationData, error) { @@ -88,6 +90,10 @@ func ParseCredentialCreationResponseBody(body io.Reader) (*ParsedCredentialCreat pcc.ID, pcc.RawID, pcc.Type = ccr.ID, ccr.RawID, ccr.Type pcc.Raw = ccr + for _, t := range ccr.Transports { + pcc.Transports = append(pcc.Transports, AuthenticatorTransport(t)) + } + parsedAttestationResponse, err := ccr.AttestationResponse.Parse() if err != nil { return nil, ErrParsingData.WithDetails("Error parsing attestation response") diff --git a/protocol/credential_test.go b/protocol/credential_test.go index a5396b5..f80932b 100644 --- a/protocol/credential_test.go +++ b/protocol/credential_test.go @@ -3,11 +3,12 @@ package protocol import ( "bytes" "encoding/base64" - "github.com/duo-labs/webauthn/protocol/webauthncbor" "io/ioutil" "net/http" "reflect" "testing" + + "github.com/duo-labs/webauthn/protocol/webauthncbor" ) func TestParseCredentialCreationResponse(t *testing.T) { @@ -43,6 +44,7 @@ func TestParseCredentialCreationResponse(t *testing.T) { }, RawID: byteID, }, + Transports: []AuthenticatorTransport{USB, NFC, "fake"}, Response: ParsedAttestationResponse{ CollectedClientData: CollectedClientData{ Type: CeremonyType("webauthn.create"), @@ -78,6 +80,7 @@ func TestParseCredentialCreationResponse(t *testing.T) { }, AttestationObject: byteAttObject, }, + Transports: []string{"usb", "nfc", "fake"}, }, }, wantErr: false, @@ -92,22 +95,25 @@ func TestParseCredentialCreationResponse(t *testing.T) { return } if !reflect.DeepEqual(got.ClientExtensionResults, tt.want.ClientExtensionResults) { - t.Errorf("Extensions = %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{} @@ -235,6 +241,7 @@ var testCredentialRequestBody = `{ "id":"6xrtBhJQW6QU4tOaB4rrHaS2Ks0yDDL_q8jDC16DEjZ-VLVf4kCRkvl2xp2D71sTPYns-exsHQHTy3G-zJRK8g", "rawId":"6xrtBhJQW6QU4tOaB4rrHaS2Ks0yDDL_q8jDC16DEjZ-VLVf4kCRkvl2xp2D71sTPYns-exsHQHTy3G-zJRK8g", "type":"public-key", + "transports":["usb","nfc","fake"], "response":{ "attestationObject":"o2NmbXRkbm9uZWdhdHRTdG10oGhhdXRoRGF0YVjEdKbqkhPJnC90siSSsyDPQCYqlMGpUKA5fyklC2CEHvBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAQOsa7QYSUFukFOLTmgeK6x2ktirNMgwy_6vIwwtegxI2flS1X-JAkZL5dsadg-9bEz2J7PnsbB0B08txvsyUSvKlAQIDJiABIVggLKF5xS0_BntttUIrm2Z2tgZ4uQDwllbdIfrrBMABCNciWCDHwin8Zdkr56iSIh0MrB5qZiEzYLQpEOREhMUkY6q4Vw", "clientDataJSON":"eyJjaGFsbGVuZ2UiOiJXOEd6RlU4cEdqaG9SYldyTERsYW1BZnFfeTRTMUNaRzFWdW9lUkxBUnJFIiwib3JpZ2luIjoiaHR0cHM6Ly93ZWJhdXRobi5pbyIsInR5cGUiOiJ3ZWJhdXRobi5jcmVhdGUifQ" diff --git a/webauthn/credential.go b/webauthn/credential.go index 224bb7f..2953981 100644 --- a/webauthn/credential.go +++ b/webauthn/credential.go @@ -15,16 +15,28 @@ type Credential struct { PublicKey []byte // The attestation format used (if any) by the authenticator when creating the credential. AttestationType string + // Transport types this credential supports. + Transport []protocol.AuthenticatorTransport // The Authenticator information for a given certificate Authenticator Authenticator } +// Descriptor provides the relevant protocol.CredentialDescriptor of this webauthn.Credential. +func (c Credential) Descriptor() protocol.CredentialDescriptor { + return protocol.CredentialDescriptor{ + Type: protocol.PublicKeyCredentialType, + CredentialID: c.ID, + Transport: c.Transport, + } +} + // MakeNewCredential will return a credential pointer on successful validation of a registration response func MakeNewCredential(c *protocol.ParsedCredentialCreationData) (*Credential, error) { newCredential := &Credential{ ID: c.Response.AttestationObject.AuthData.AttData.CredentialID, PublicKey: c.Response.AttestationObject.AuthData.AttData.CredentialPublicKey, AttestationType: c.Response.AttestationObject.Format, + Transport: c.Transports, Authenticator: Authenticator{ AAGUID: c.Response.AttestationObject.AuthData.AttData.AAGUID, SignCount: c.Response.AttestationObject.AuthData.Counter, diff --git a/webauthn/login.go b/webauthn/login.go index 4ce3a88..a2e4185 100644 --- a/webauthn/login.go +++ b/webauthn/login.go @@ -36,10 +36,7 @@ func (webauthn *WebAuthn) BeginLogin(user User, opts ...LoginOption) (*protocol. var allowedCredentials = make([]protocol.CredentialDescriptor, len(credentials)) for i, credential := range credentials { - var credentialDescriptor protocol.CredentialDescriptor - credentialDescriptor.CredentialID = credential.ID - credentialDescriptor.Type = protocol.PublicKeyCredentialType - allowedCredentials[i] = credentialDescriptor + allowedCredentials[i] = credential.Descriptor() } requestOptions := protocol.PublicKeyCredentialRequestOptions{