def do_verify(self): challenge = TPM_Utilities.random_password(20) numtries = 0 while True: try: params = f'/keys/verify?challenge={challenge}' response = httpclient_requests.request("GET", "%s" % (self.cloudagent_ip), self.cloudagent_port, params=params) except Exception as e: if response == 503 or 504: numtries += 1 maxr = config.getint('tenant', 'max_retries') if numtries >= maxr: logger.error( f"Cannot establish connection to agent on {self.cloudagent_ip} with port {self.cloudagent_port}" ) exit() retry = config.getfloat('tenant', 'retry_interval') logger.info( f"Verifier connection to agent at {self.cloudagent_ip} refused {numtries}/{maxr} times, trying again in {retry} seconds..." ) time.sleep(retry) continue else: raise (e) response_body = json.loads(response.read().decode()) if response.status == 200: if "results" not in response_body or 'hmac' not in response_body[ 'results']: logger.critical( f"Error: unexpected http response body from Cloud Agent: {response.status}" ) break mac = response_body['results']['hmac'] ex_mac = crypto.do_hmac(self.K, challenge) if mac == ex_mac: logger.info("Key derivation successful") else: logger.error("Key derivation failed") else: keylime_logging.log_http_response(logger, logging.ERROR, response_body) retry = config.getfloat('tenant', 'retry_interval') logger.warning( f"Key derivation not yet complete...trying again in {retry} seconds...Ctrl-C to stop" ) time.sleep(retry) continue break
def prepare_get_quote(agent): """This method encapsulates the action required to invoke a quote request on the Cloud Agent. This method is part of the polling loop of the thread launched on Tenant POST. """ agent['nonce'] = TPM_Utilities.random_password(20) params = { 'nonce': agent['nonce'], 'mask': agent['tpm_policy']['mask'], 'vmask': agent['vtpm_policy']['mask'], } return params
def do_quote(self): """initiaite v, agent_id and ip initiate the cloudinit sequence""" self.nonce = TPM_Utilities.random_password(20) numtries = 0 response = None # Note: We need a specific retry handler (perhaps in common), no point having localised unless we have too. while True: try: #params = '/quotes/identity?nonce=%s'%(self.nonce) params = f'/quotes/identity?nonce={self.nonce}' response = httpclient_requests.request("GET", "%s"%(self.cloudagent_ip), self.cloudagent_port, params=params, context=None) response_body = json.loads(response.read().decode()) except Exception as e: if response == 503 or response == 504: numtries+=1 maxr = config.getint('tenant','max_retries') if numtries >= maxr: logger.error(f"tenant cannot establish connection to agent on {self.cloudagent_ip} with port {self.cloudagent_port}") exit() retry = config.getfloat('tenant','retry_interval') logger.info(f"tenant connection to agent at {self.cloudagent_ip} refused {numtries}/{maxr} times, trying again in {retry} seconds...") time.sleep(retry) continue else: raise(e) break try: if response is not None and response.status != 200: raise UserError("Status command response: %d Unexpected response from Cloud Agent."%response.status) if "results" not in response_body: raise UserError("Error: unexpected http response body from Cloud Agent: %s"%str(response.status)) quote = response_body["results"]["quote"] logger.debug(f"agent_quote received quote: {quote}") public_key = response_body["results"]["pubkey"] logger.debug(f"agent_quote received public key: {public_key}") # Get tpm_version, hash_alg tpm_version = response_body["results"]["tpm_version"] logger.debug(f"agent_quote received tpm version: {str(tpm_version)}") # Ensure hash_alg is in accept_tpm_hash_algs list hash_alg = response_body["results"]["hash_alg"] logger.debug(f"agent_quote received hash algorithm: {hash_alg}") if not Hash_Algorithms.is_accepted(hash_alg, config.get('tenant','accept_tpm_hash_algs').split(',')): raise UserError("TPM Quote is using an unaccepted hash algorithm: %s"%hash_alg) # Ensure enc_alg is in accept_tpm_encryption_algs list enc_alg = response_body["results"]["enc_alg"] logger.debug(f"agent_quote received encryption algorithm: {enc_alg}") if not Encrypt_Algorithms.is_accepted(enc_alg, config.get('tenant','accept_tpm_encryption_algs').split(',')): raise UserError("TPM Quote is using an unaccepted encryption algorithm: %s"%enc_alg) # Ensure sign_alg is in accept_tpm_encryption_algs list sign_alg = response_body["results"]["sign_alg"] logger.debug(f"agent_quote received signing algorithm: {sign_alg}") if not Sign_Algorithms.is_accepted(sign_alg, config.get('tenant','accept_tpm_signing_algs').split(',')): raise UserError("TPM Quote is using an unaccepted signing algorithm: %s"%sign_alg) if not self.validate_tpm_quote(public_key, quote, tpm_version, hash_alg): raise UserError("TPM Quote from cloud agent is invalid for nonce: %s"%self.nonce) logger.info(f"Quote from {self.cloudagent_ip} validated") # encrypt U with the public key # encrypted_U = crypto.rsa_encrypt(crypto.rsa_import_pubkey(public_key),str(self.U)) encrypted_U = crypto.rsa_encrypt(crypto.rsa_import_pubkey(public_key),self.U) b64_encrypted_u = base64.b64encode(encrypted_U) logger.debug("b64_encrypted_u: " + b64_encrypted_u.decode('utf-8')) data = { 'encrypted_key': b64_encrypted_u, 'auth_tag': self.auth_tag } if self.payload is not None: data['payload']=self.payload u_json_message = json.dumps(data) #post encrypted U back to CloudAgent params = '/keys/ukey' response = httpclient_requests.request("POST", "%s"%(self.cloudagent_ip), self.cloudagent_port, params=params, data=u_json_message) if response == 503: logger.error(f"Cannot connect to Verifier at {self.cloudverifier_ip} with Port {self.cloudverifier_port}. Connection refused.") exit() elif response == 504: logger.error(f"Verifier at {self.cloudverifier_ip} with Port {self.cloudverifier_port} timed out.") exit() if response.status != 200: keylime_logging.log_http_response(logger,logging.ERROR,response_body) raise UserError("Posting of Encrypted U to the Cloud Agent failed with response code %d" %response.status) except Exception as e: self.do_cvstop() raise e