diff --git a/protocol/authenticator.go b/protocol/authenticator.go index dbdbcf5..c889c80 100644 --- a/protocol/authenticator.go +++ b/protocol/authenticator.go @@ -7,7 +7,10 @@ import ( "github.com/duo-labs/webauthn/protocol/webauthncbor" ) -var minAuthDataLength = 37 +var ( + minAuthDataLength = 37 + minAttestedAuthLength = 55 +) // Authenticators respond to Relying Party requests by returning an object derived from the // AuthenticatorResponse interface. See ยง5.2. Authenticator Responses @@ -158,8 +161,11 @@ func (a *AuthenticatorData) Unmarshal(rawAuthData []byte) error { remaining := len(rawAuthData) - minAuthDataLength if a.Flags.HasAttestedCredentialData() { - if len(rawAuthData) > minAuthDataLength { - a.unmarshalAttestedData(rawAuthData) + if len(rawAuthData) > minAttestedAuthLength { + validError := a.unmarshalAttestedData(rawAuthData) + if validError != nil { + return validError + } attDataLen := len(a.AttData.AAGUID) + 2 + len(a.AttData.CredentialID) + len(a.AttData.CredentialPublicKey) remaining = remaining - attDataLen } else { @@ -188,11 +194,15 @@ func (a *AuthenticatorData) Unmarshal(rawAuthData []byte) error { } // If Attestation Data is present, unmarshall that into the appropriate public key structure -func (a *AuthenticatorData) unmarshalAttestedData(rawAuthData []byte) { +func (a *AuthenticatorData) unmarshalAttestedData(rawAuthData []byte) error { a.AttData.AAGUID = rawAuthData[37:53] idLength := binary.BigEndian.Uint16(rawAuthData[53:55]) + if len(rawAuthData) < int(55+idLength) { + return ErrBadRequest.WithDetails("Authenticator attestation data length too short") + } a.AttData.CredentialID = rawAuthData[55 : 55+idLength] a.AttData.CredentialPublicKey = unmarshalCredentialPublicKey(rawAuthData[55+idLength:]) + return nil } // Unmarshall the credential's Public Key into CBOR encoding diff --git a/protocol/authenticator_test.go b/protocol/authenticator_test.go index bc42b04..941ef52 100644 --- a/protocol/authenticator_test.go +++ b/protocol/authenticator_test.go @@ -184,9 +184,10 @@ func TestAuthenticatorData_unmarshalAttestedData(t *testing.T) { rawAuthData []byte } tests := []struct { - name string - fields fields - args args + name string + fields fields + args args + wantErr bool }{ // TODO: Add test cases. } @@ -199,7 +200,9 @@ func TestAuthenticatorData_unmarshalAttestedData(t *testing.T) { AttData: tt.fields.AttData, ExtData: tt.fields.ExtData, } - a.unmarshalAttestedData(tt.args.rawAuthData) + if err := a.unmarshalAttestedData(tt.args.rawAuthData); (err != nil) != tt.wantErr { + t.Errorf("AuthenticatorData.unmarshalAttestedData() error = %v, wantErr %v", err, tt.wantErr) + } }) } }