Example #1
0
        //returns: doRetry?
        private bool CheckHeader(byte[] response, out FidoHidMsgType msgType)
        {
            msgType = FidoHidMsgType.Error;
            if (response.Length < 5)
            {
                return(false);
            }
            //ignore messages for other channels
            if (!response.Take(4).SequenceEqual(_channelId))
            {
                return(false);
            }
            msgType = (FidoHidMsgType)response[4];
            if (msgType != FidoHidMsgType.Error)
            {
                return(true);
            }

            if (response.Length < 8)
            {
                throw new FidoException(FidoError.ProtocolViolation, "error message too short");
            }
            var errorCode = (FidoHidError)response[7];

            switch (errorCode)
            {
            case FidoHidError.MessageTimeout: throw new FidoException(FidoError.Timeout);

            case FidoHidError.ChannelBusy: throw new FidoException(FidoError.TokenBusy);

            default: throw new FidoException(FidoError.ProtocolViolation, $"U2FHID Error: [{errorCode}]");
            }
        }
Example #2
0
        private async Task SendRequestAsync(FidoHidMsgType msgType, byte[] data = null)
        {
            if (data == null)
            {
                data = new byte[0];
            }

            var size        = data.Length;
            var payloadData = data.Take(HidReportSize - 7).ToArray();

            var payloadBuilder = new ByteArrayBuilder();

            payloadBuilder.Append(_channelId);
            payloadBuilder.Append((byte)msgType);
            payloadBuilder.Append((byte)(size >> 8 & 0xff));
            payloadBuilder.Append((byte)(size & 0xff));
            payloadBuilder.Append(payloadData);
            payloadBuilder.AppendZerosTill(HidReportSize);


            var report = _hidDevice.CreateReport();

            report.Data = payloadBuilder.GetBytes();
            if (!await _hidDevice.WriteReportAsync(report, HidTimeoutMs).ConfigureAwait(false))
            {
                throw new FidoException(FidoError.InterruptedIO, "Error writing to token");
            }

            var remainingData = data.Skip(HidReportSize - 7).ToArray();
            var seq           = 0;

            while (remainingData.Length > 0)
            {
                payloadData = remainingData.Take(HidReportSize - 5).ToArray();

                payloadBuilder.Clear();
                payloadBuilder.Append(_channelId);
                payloadBuilder.Append((byte)(0x7f & seq));
                payloadBuilder.Append(payloadData);
                payloadBuilder.AppendZerosTill(HidReportSize);

                report      = _hidDevice.CreateReport();
                report.Data = payloadBuilder.GetBytes();
                if (!await _hidDevice.WriteReportAsync(report, HidTimeoutMs).ConfigureAwait(false))
                {
                    throw new FidoException(FidoError.InterruptedIO, "Error writing to token");
                }

                remainingData = remainingData.Skip(HidReportSize - 5).ToArray();
                seq++;
            }
        }
Example #3
0
        private async Task <byte[]> ReadResponseAsync(FidoHidMsgType msgType)
        {
            HidReport      report;
            FidoHidMsgType recvdMsgType;

            do
            {
                report = await _hidDevice.ReadReportAsync(HidTimeoutMs).ConfigureAwait(false);

                if (report.ReadStatus != HidDeviceData.ReadStatus.Success)
                {
                    throw new FidoException(FidoError.InterruptedIO, $"Error reading from token: {report.ReadStatus}");
                }
            } while (!CheckHeader(report.Data, out recvdMsgType));

            if (msgType != recvdMsgType)
            {
                throw new FidoException(FidoError.ProtocolViolation, $"received {recvdMsgType} instead of {msgType}");
            }

            var dataLength  = (report.Data[5] << 8) + report.Data[6];
            var payloadData = report.Data.Skip(7).Take(Math.Min(dataLength, HidReportSize)).ToArray();

            var payload = new ByteArrayBuilder();

            payload.Append(payloadData);
            dataLength -= (int)payload.Length;

            var seq = 0;

            while (dataLength > 0)
            {
                do
                {
                    report = await _hidDevice.ReadReportAsync(HidTimeoutMs).ConfigureAwait(false);

                    if (report.ReadStatus != HidDeviceData.ReadStatus.Success)
                    {
                        throw new FidoException(FidoError.InterruptedIO, $"Error reading from token: {report.ReadStatus}");
                    }
                } while (!CheckHeader(report.Data, out recvdMsgType));

                if ((recvdMsgType & FidoHidMsgType.CommandFlag) > 0)
                {
                    throw new FidoException(FidoError.ProtocolViolation, "fragmented message continuation had command flag set");
                }

                if ((byte)recvdMsgType != (seq & (byte)FidoHidMsgType.SequenceIdMask))
                {
                    throw new FidoException(FidoError.ProtocolViolation, $"received out-of-sequence message: Recvd:0x{(byte)recvdMsgType:X}, seq-nr:{seq}");
                }

                seq++;
                payloadData = report.Data.Skip(5).Take(Math.Min(dataLength, HidReportSize)).ToArray();

                dataLength -= payloadData.Length;
                payload.Append(payloadData);
            }

            return(payload.GetBytes());
        }
Example #4
0
        protected async Task <byte[]> CallAsync(FidoHidMsgType command, byte[] data = null)
        {
            await SendRequestAsync(command, data).ConfigureAwait(false);

            return(await ReadResponseAsync(command).ConfigureAwait(false));
        }