Exemple #1
0
    def InternalInit(self):
        """Initializes the device and obtains channel id."""
        self.cid = UsbHidTransport.U2FHID_BROADCAST_CID
        nonce = bytearray(os.urandom(8))
        r = self.InternalExchange(UsbHidTransport.U2FHID_INIT, nonce)
        if len(r) < 17:
            raise errors.HidError('unexpected init reply len')
        if r[0:8] != nonce:
            raise errors.HidError('nonce mismatch')
        self.cid = bytearray(r[8:12])

        self.u2fhid_version = r[12]
Exemple #2
0
    def Write(self, packet):
        """See base class."""
        if len(packet) != self.GetOutReportDataLength():
            raise errors.HidError(
                "Packet length must match report data length.")

        packet_data = [0] + packet  # Prepend the zero-byte (report ID)
        out = bytes(bytearray(packet_data))
        num_written = wintypes.DWORD()
        ret = (kernel32.WriteFile(self.dev, out, len(out),
                                  ctypes.byref(num_written), None))
        if num_written.value != len(out):
            raise errors.HidError("Failed to write complete packet.  " +
                                  "Expected %d, but got %d" %
                                  (len(out), num_written.value))
        if not ret:
            raise ctypes.WinError()
Exemple #3
0
    def InternalExchange(self, cmd, payload_in):
        """Sends and receives a message from the device."""
        # make a copy because we destroy it below
        self.logger.debug('payload: ' + str(list(payload_in)))
        payload = bytearray()
        payload[:] = payload_in
        for _ in range(2):
            self.InternalSend(cmd, payload)
            ret_cmd, ret_payload = self.InternalRecv()

            if ret_cmd == UsbHidTransport.U2FHID_ERROR:
                if ret_payload == UsbHidTransport.ERR_CHANNEL_BUSY:
                    time.sleep(0.5)
                    continue
                raise errors.HidError('Device error: %d' % int(ret_payload[0]))
            elif ret_cmd != cmd:
                raise errors.HidError('Command mismatch!')

            return ret_payload
        raise errors.HidError('Device Busy.  Please retry')
Exemple #4
0
def GetValueLength(rd, pos):
  """Get value length for a key in rd.

  For a key at position pos in the Report Descriptor rd, return the length
  of the associated value.  This supports both short and long format
  values.

  Args:
    rd: Report Descriptor
    pos: The position of the key in rd.

  Returns:
    (key_size, data_len) where key_size is the number of bytes occupied by
    the key and data_len is the length of the value associated by the key.
  """
  rd = bytearray(rd)
  key = rd[pos]
  if key == LONG_ITEM_ENCODING:
    # If the key is tagged as a long item (0xfe), then the format is
    # [key (1 byte)] [data len (1 byte)] [item tag (1 byte)] [data (n # bytes)].
    # Thus, the entire key record is 3 bytes long.
    if pos + 1 < len(rd):
      return (3, rd[pos + 1])
    else:
      raise errors.HidError('Malformed report descriptor')

  else:
    # If the key is tagged as a short item, then the item tag and data len are
    # packed into one byte.  The format is thus:
    # [tag (high 4 bits)] [type (2 bits)] [size code (2 bits)] [data (n bytes)].
    # The size code specifies 1,2, or 4 bytes (0x03 means 4 bytes).
    code = key & 0x03
    if code <= 0x02:
      return (1, code)
    elif code == 0x03:
      return (1, 4)

  raise errors.HidError('Cannot happen')
Exemple #5
0
def ReadLsbBytes(rd, offset, value_size):
    """Reads value_size bytes from rd at offset, least signifcant byte first."""

    encoding = None
    if value_size == 1:
        encoding = '<B'
    elif value_size == 2:
        encoding = '<H'
    elif value_size == 4:
        encoding = '<L'
    else:
        raise errors.HidError('Invalid value size specified')

    ret, = struct.unpack(encoding, rd[offset:offset + value_size])
    return ret
  def Read(self):
    """See base class."""
    buf = ctypes.create_string_buffer(self.desc.internal_max_in_report_len)
    num_read = wintypes.DWORD()
    ret = kernel32.ReadFile(
        self.dev, buf, len(buf), ctypes.byref(num_read), None)

    if num_read.value != self.desc.internal_max_in_report_len:
      raise errors.HidError("Failed to read full length report from device.")

    if not ret:
      raise ctypes.WinError()

    # Convert the string buffer to a list of numbers.  Throw away the first
    # byte, which is the report id (which we don't care about).
    return list(bytearray(buf[1:]))
Exemple #7
0
class GUID(ctypes.Structure):
    _fields_ = [("Data1", ctypes.c_ulong), ("Data2", ctypes.c_ushort),
                ("Data3", ctypes.c_ushort), ("Data4", ctypes.c_ubyte * 8)]


# On Windows, SetupAPI.h packs structures differently in 64bit and
# 32bit mode.  In 64bit mode, thestructures are packed on 8 byte
# boundaries, while in 32bit mode, they are packed on 1 byte boundaries.
# This is important to get right for some API calls that fill out these
# structures.
if platform.architecture()[0] == "64bit":
    SETUPAPI_PACK = 8
elif platform.architecture()[0] == "32bit":
    SETUPAPI_PACK = 1
else:
    raise errors.HidError("Unknown architecture: %s" %
                          platform.architecture()[0])


class DeviceInterfaceData(ctypes.Structure):
    _fields_ = [("cbSize", wintypes.DWORD), ("InterfaceClassGuid", GUID),
                ("Flags", wintypes.DWORD),
                ("Reserved", ctypes.POINTER(ctypes.c_ulong))]
    _pack_ = SETUPAPI_PACK


class DeviceInterfaceDetailData(ctypes.Structure):
    _fields_ = [("cbSize", wintypes.DWORD), ("DevicePath", ctypes.c_byte * 1)]
    _pack_ = SETUPAPI_PACK


class HidAttributes(ctypes.Structure):