From e455efbffdcc22c02aaf9cbee37ca3b476a30eeb Mon Sep 17 00:00:00 2001 From: Marko Bencun Date: Wed, 4 Dec 2019 17:54:37 +0100 Subject: [PATCH] communication/u2fhid: parse frame errors --- communication/u2fhid/error.go | 45 ++++++++++++++++++++++++++++++++++ communication/u2fhid/u2fhid.go | 18 +++++++++++--- 2 files changed, 60 insertions(+), 3 deletions(-) create mode 100644 communication/u2fhid/error.go diff --git a/communication/u2fhid/error.go b/communication/u2fhid/error.go new file mode 100644 index 0000000..c99b592 --- /dev/null +++ b/communication/u2fhid/error.go @@ -0,0 +1,45 @@ +// Copyright 2018-2019 Shift Cryptosecurity AG +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package u2fhid + +import "fmt" + +const ( + errCodeChannelBusy = byte(0x06) + + // errCodeChannelNone = byte(0x00) + // errCodeChannelInvalidCmd = byte(0x01) + // errCodeChannelInvalidPar = byte(0x02) + // errCodeChannelInvalidLen = byte(0x03) + // errCodeChannelInvalidSeq = byte(0x04) + // errCodeChannelMsgTimeout = byte(0x05) + // errCodechannellockRequired = byte(0x0A) + // errCodechannelInvalidCid = byte(0x0B) + // errCodechannelOther = byte(0x7F) +) + +// FrameError is returned when the frame which is read indicates an error. +// The value within is the error code. +type FrameError byte + +// Error implements error. +func (e FrameError) Error() string { + return fmt.Sprintf("frame error: %d", e) +} + +// IsErrBusy returns true if the error code indicates a busy channel. +func (e FrameError) IsErrBusy() bool { + return byte(e) == errCodeChannelBusy +} diff --git a/communication/u2fhid/u2fhid.go b/communication/u2fhid/u2fhid.go index c676fae..8578cf9 100644 --- a/communication/u2fhid/u2fhid.go +++ b/communication/u2fhid/u2fhid.go @@ -27,6 +27,8 @@ import ( const ( writeReportSize = 64 readReportSize = 64 + + cmdError = 0x80 | 0x3F ) const ( @@ -156,12 +158,22 @@ func (communication *Communication) readFrame() ([]byte, error) { if read[0] != 0xff || read[1] != 0 || read[2] != 0 || read[3] != 0 { return nil, errp.Newf("USB command ID mismatch %d %d %d %d", read[0], read[1], read[2], read[3]) } - if read[4] != communication.cmd { - return nil, errp.Newf("USB command frame mismatch (%d, expected %d)", read[4], communication.cmd) - } + data := newBuffer() dataLen := int(read[5])*256 + int(read[6]) data.Write(read[7:readLen]) + + cmd := read[4] + if cmd == cmdError { + errCode := byte(0) + if data.Len() > 0 { + errCode = data.Bytes()[0] + } + return nil, errp.WithStack(FrameError(errCode)) + } + if cmd != communication.cmd { + return nil, errp.Newf("USB command frame mismatch (%d, expected %d)", cmd, communication.cmd) + } idx := len(read) - 7 for idx < dataLen { readLen, err = communication.device.Read(read)