def _read_resp(self, cid, cmd): resp = b'.' header = cid + int2byte(TYPE_INIT | cmd) while resp and resp[:5] != header: resp_vals = _read_timeout(self.handle, HID_RPT_SIZE) resp = b''.join(int2byte(v) for v in resp_vals) if resp[:5] == cid + int2byte(STAT_ERR): raise U2FHIDError(byte2int(resp[7])) if not resp: raise exc.DeviceError("Invalid response from device!") data_len = (byte2int(resp[5]) << 8) + byte2int(resp[6]) data = resp[7:min(7 + data_len, HID_RPT_SIZE)] data_len -= len(data) seq = 0 while data_len > 0: resp_vals = _read_timeout(self.handle, HID_RPT_SIZE) resp = b''.join(int2byte(v) for v in resp_vals) if resp[:4] != cid: raise exc.DeviceError("Wrong CID from device!") if byte2int(resp[4]) != seq & 0x7f: raise exc.DeviceError("Wrong SEQ from device!") seq += 1 new_data = resp[5:min(5 + data_len, HID_RPT_SIZE)] data_len -= len(new_data) data += new_data return data
def _read_resp(self, cid, cmd): resp = b'.' header = cid + int2byte(TYPE_INIT | cmd) while resp and resp[:5] != header: resp_vals = _read_timeout(self.handle, HID_RPT_SIZE) resp = b''.join(int2byte(v) for v in resp_vals) if resp[:5] == cid + int2byte(STAT_ERR): raise U2FHIDError(byte2int(resp[6])) if not resp: raise exc.DeviceError("Invalid response from device!") data_len = (byte2int(resp[5]) << 8) + byte2int(resp[6]) data = resp[7:min(7 + data_len, HID_RPT_SIZE)] data_len -= len(data) seq = 0 while data_len > 0: resp_vals = _read_timeout(self.handle, HID_RPT_SIZE) resp = b''.join(int2byte(v) for v in resp_vals) if resp[:4] != cid: raise exc.DeviceError("Wrong CID from device!") if byte2int(resp[4:5]) != seq & 0x7f: raise exc.DeviceError("Wrong SEQ from device!") seq += 1 new_data = resp[5:min(5 + data_len, HID_RPT_SIZE)] data_len -= len(new_data) data += new_data return data
def _send_req(self, cid, cmd, data): size = len(data) bc_l = int2byte(size & 0xff) bc_h = int2byte(size >> 8 & 0xff) payload = cid + int2byte(TYPE_INIT | cmd) + bc_h + bc_l + \ data[:HID_RPT_SIZE - 7] payload += b'\0' * (HID_RPT_SIZE - len(payload)) self.handle.write([0] + [byte2int(c) for c in payload]) data = data[HID_RPT_SIZE - 7:] seq = 0 while len(data) > 0: payload = cid + int2byte(0x7f & seq) + data[:HID_RPT_SIZE - 5] payload += b'\0' * (HID_RPT_SIZE - len(payload)) self.handle.write([0] + [byte2int(c) for c in payload]) data = data[HID_RPT_SIZE - 5:] seq += 1
def _authenticate(self, data): client_param = data[:32] app_param = data[32:64] kh_len = byte2int(data[64]) key_handle = _b16text(data[65:65 + kh_len]) if key_handle not in self.data['keys']: raise ValueError("Unknown key handle!") # Unwrap: unwrapped = self.data['keys'][key_handle] if app_param != base64.b16decode(unwrapped['app_param']): raise ValueError("Incorrect app param!") priv_pem = unwrapped['priv_key'].encode('ascii') privu = serialization.load_pem_private_key( priv_pem, password=None, backend=default_backend(), ) # Increment counter self.data['counter'] += 1 self._persist() # Create signature touch = b'\x01' # Always indicate user presence counter = struct.pack('>I', self.data['counter']) signer = privu.signer(ec.ECDSA(hashes.SHA256())) signer.update(app_param + touch + counter + client_param) signature = signer.finalize() raw_response = touch + counter + signature return raw_response
def _authenticate(self, data): client_param = data[:32] app_param = data[32:64] kh_len = byte2int(data[64]) key_handle = _b16text(data[65:65+kh_len]) if key_handle not in self.data['keys']: raise ValueError("Unknown key handle!") # Unwrap: unwrapped = self.data['keys'][key_handle] if app_param != base64.b16decode(unwrapped['app_param']): raise ValueError("Incorrect app param!") priv_pem = unwrapped['priv_key'].encode('ascii') privu = serialization.load_pem_private_key( priv_pem, password=None, backend=default_backend(), ) # Increment counter self.data['counter'] += 1 self._persist() # Create signature touch = b'\x01' # Always indicate user presence counter = struct.pack('>I', self.data['counter']) signer = privu.signer(ec.ECDSA(hashes.SHA256())) signer.update(app_param + touch + counter + client_param) signature = signer.finalize() raw_response = touch + counter + signature return raw_response
def init(self): nonce = os.urandom(8) resp = self.call(CMD_INIT, nonce) timeout = time() + 2.0 while (len(resp) != 17 or resp[:8] != nonce): if timeout < time(): raise exc.DeviceError('Wrong INIT response from device') sleep(0.1) resp = self._read_resp(self.cid, CMD_INIT) self.cid = resp[8:12] self.capabilities = byte2int(resp[16])