def _HandleAUTH(self, reply): # self._lock must be held. if not self._rsa_keys: raise usb_exceptions.DeviceAuthError( 'Device authentication required, no keys available.') # Loop through our keys, signing the last data which is the challenge. for rsa_key in self._rsa_keys: reply = self._HandleReplyChallenge(rsa_key, reply, self._auth_timeout_ms) if reply.header.command_name == 'CNXN': break if reply.header.command_name == 'AUTH': # None of the keys worked, so send a public key. This will prompt to the # user. msg = _AdbMessage.Make('AUTH', _AdbMessageHeader.AUTH_RSAPUBLICKEY, 0, self._rsa_keys[0].GetPublicKey() + '\0') msg.Write(self._usb) try: reply = _AdbMessage.Read(self._usb, self._auth_timeout_ms) except usb_exceptions.ReadFailedError as e: if e.usb_error.value == -7: # Timeout. raise usb_exceptions.DeviceAuthError( 'Accept auth key on device, then retry.') raise self._HandleCNXN(reply)
def _HandleCNXN(self, reply): # self._lock must be held. if reply.header.command_name != 'CNXN': raise usb_exceptions.DeviceAuthError( 'Accept auth key on device, then retry.') if reply.header.arg0 != _AdbMessageHeader.VERSION: raise InvalidResponseError('Unknown CNXN response', reply) self.state = reply.data self.max_packet_size = reply.header.arg1 _LOG.debug('%s._HandleCNXN(): max packet size: %d', self.port_path, self.max_packet_size) for conn in self._connections.itervalues(): conn._HasClosed() self._connections = {}
def Connect(cls, usb, banner=b'notadb', rsa_keys=None, auth_timeout_ms=100): """Establish a new connection to the device. Args: usb: A USBHandle with BulkRead and BulkWrite methods. banner: A string to send as a host identifier. rsa_keys: List of AuthSigner subclass instances to be used for authentication. The device can either accept one of these via the Sign method, or we will send the result of GetPublicKey from the first one if the device doesn't accept any of them. auth_timeout_ms: Timeout to wait for when sending a new public key. This is only relevant when we send a new public key. The device shows a dialog and this timeout is how long to wait for that dialog. If used in automation, this should be low to catch such a case as a failure quickly; while in interactive settings it should be high to allow users to accept the dialog. We default to automation here, so it's low by default. Returns: The device's reported banner. Always starts with the state (device, recovery, or sideload), sometimes includes information after a : with various product information. Raises: usb_exceptions.DeviceAuthError: When the device expects authentication, but we weren't given any valid keys. InvalidResponseError: When the device does authentication in an unexpected way. """ msg = cls(command=b'CNXN', arg0=VERSION, arg1=MAX_ADB_DATA, data=b'host::%s\0' % banner) msg.Send(usb) cmd, arg0, arg1, banner = cls.Read(usb, [b'CNXN', b'AUTH']) if cmd == b'AUTH': if not rsa_keys: raise usb_exceptions.DeviceAuthError( 'Device authentication required, no keys available.') # Loop through our keys, signing the last 'banner' or token. for rsa_key in rsa_keys: if arg0 != AUTH_TOKEN: raise InvalidResponseError( 'Unknown AUTH response: %s %s %s' % (arg0, arg1, banner)) # Do not mangle the banner property here by converting it to a string signed_token = rsa_key.Sign(banner) msg = cls(command=b'AUTH', arg0=AUTH_SIGNATURE, arg1=0, data=signed_token) msg.Send(usb) cmd, arg0, unused_arg1, banner = cls.Read( usb, [b'CNXN', b'AUTH']) if cmd == b'CNXN': return banner # None of the keys worked, so send a public key. msg = cls(command=b'AUTH', arg0=AUTH_RSAPUBLICKEY, arg1=0, data=rsa_keys[0].GetPublicKey() + b'\0') msg.Send(usb) try: cmd, arg0, unused_arg1, banner = cls.Read( usb, [b'CNXN'], timeout_ms=auth_timeout_ms) except usb_exceptions.ReadFailedError as e: if e.usb_error.value == -7: # Timeout. raise usb_exceptions.DeviceAuthError( 'Accept auth key on device, then retry.') raise # This didn't time-out, so we got a CNXN response. return banner return banner