Esempio n. 1
0
    def __init__(self, hid_device, read_timeout_secs=3.0):
        self.hid_device = hid_device

        in_size = hid_device.GetInReportDataLength()
        out_size = hid_device.GetOutReportDataLength()
        if in_size != out_size:
            raise errors.HardwareError(
                'unsupported device with different in/out packet sizes.')
        if in_size == 0:
            raise errors.HardwareError('unable to determine packet size')

        self.packet_size = in_size
        self.read_timeout_secs = read_timeout_secs
        self.logger = logging.getLogger('pyu2f.hidtransport')

        self.InternalInit()
Esempio n. 2
0
    def InternalRecv(self):
        """Receives a message from the device, including defragmenting it."""
        first_read = self.InternalReadFrame()
        first_packet = UsbHidTransport.InitPacket.FromWireFormat(
            self.packet_size, first_read)

        data = first_packet.payload
        to_read = first_packet.size - len(first_packet.payload)

        seq = 0
        while to_read > 0:
            next_read = self.InternalReadFrame()
            next_packet = UsbHidTransport.ContPacket.FromWireFormat(
                self.packet_size, next_read)
            if self.cid != next_packet.cid:
                # Skip over packets that are for communication with other clients.
                # HID is broadcast, so we see potentially all communication from the
                # device.  For well-behaved devices, these should be BUSY messages
                # sent to other clients of the device because at this point we're
                # in mid-message transit.
                continue

            if seq != next_packet.seq:
                raise errors.HardwareError('Packets received out of order')

            # This packet for us at this point, so debit it against our
            # balance of bytes to read.
            to_read -= len(next_packet.payload)

            data.extend(next_packet.payload)
            seq += 1

        # truncate incomplete frames
        data = data[0:first_packet.size]
        return (first_packet.cmd, data)
Esempio n. 3
0
    def Register(self, app_id, challenge, registered_keys):
        """Registers app_id with the security key.

    Executes the U2F registration flow with the security key.

    Args:
      app_id: The app_id to register the security key against.
      challenge: Server challenge passed to the security key.
      registered_keys: List of keys already registered for this app_id+user.

    Returns:
      RegisterResponse with key_handle and attestation information in it (
        encoded in FIDO U2F binary format within registration_data field).

    Raises:
      U2FError: There was some kind of problem with registration (e.g.
        the device was already registered or there was a timeout waiting
        for the test of user presence).
    """
        client_data = model.ClientData(model.ClientData.TYP_REGISTRATION,
                                       challenge, self.origin)
        challenge_param = self.InternalSHA256(client_data.GetJson())
        app_param = self.InternalSHA256(app_id)

        for key in registered_keys:
            try:
                # skip non U2F_V2 keys
                if key.version != u'U2F_V2':
                    continue
                resp = self.security_key.CmdAuthenticate(
                    challenge_param, app_param, key.key_handle, True)
                # check_only mode CmdAuthenticate should always raise some
                # exception
                raise errors.HardwareError('Should Never Happen')

            except errors.TUPRequiredError:
                # This indicates key was valid.  Thus, no need to register
                raise errors.U2FError(errors.U2FError.DEVICE_INELIGIBLE)
            except errors.InvalidKeyHandleError as e:
                # This is the case of a key for a different token, so we just ignore it.
                pass
            except errors.HardwareError as e:
                raise errors.U2FError(errors.U2FError.BAD_REQUEST, e)

        # Now register the new key
        for _ in range(30):
            try:
                resp = self.security_key.CmdRegister(challenge_param,
                                                     app_param)
                return model.RegisterResponse(resp, client_data)
            except errors.TUPRequiredError as e:
                self.security_key.CmdWink()
                time.sleep(0.5)
            except errors.HardwareError as e:
                raise errors.U2FError(errors.U2FError.BAD_REQUEST, e)

        raise errors.U2FError(errors.U2FError.TIMEOUT)