def test_023_agent_keys_vkey_post(self): """Test agent's POST /keys/vkey Interface""" # CV should do this (during CV POST/PUT test) # Running this test might hide problems with the CV sending the V key self.assertIsNotNone( self.V, "Required value not set. Previous step may have failed?") self.assertIsNotNone( public_key, "Required value not set. Previous step may have failed?") encrypted_V = crypto.rsa_encrypt(crypto.rsa_import_pubkey(public_key), str(self.V)) b64_encrypted_V = base64.b64encode(encrypted_V) data = {"encrypted_key": b64_encrypted_V} test_023_agent_keys_vkey_post = RequestsClient( tenant_templ.agent_base_url, tls_enabled=False) response = test_023_agent_keys_vkey_post.post( f"/v{self.api_version}/keys/vkey", data=json.dumps(data), cert="", verify=False) self.assertEqual(response.status_code, 200, "Non-successful Agent vkey post return code!") json_response = response.json() # Ensure response is well-formed self.assertIn("results", json_response, "Malformed response body!")
def test_023_agent_keys_vkey_post(self): """Test agent's POST /v2/keys/vkey Interface""" # CV should do this (during CV POST/PUT test) # Running this test might hide problems with the CV sending the V key global public_key self.assertIsNotNone( self.V, "Required value not set. Previous step may have failed?") self.assertIsNotNone( public_key, "Required value not set. Previous step may have failed?") encrypted_V = crypto.rsa_encrypt(crypto.rsa_import_pubkey(public_key), str(self.V)) b64_encrypted_V = base64.b64encode(encrypted_V) data = {'encrypted_key': b64_encrypted_V} v_json_message = json.dumps(data) params = f"/v{self.api_version}/keys/vkey" response = httpclient_requests.request("POST", "%s" % tenant_templ.cloudagent_ip, tenant_templ.cloudagent_port, params=params, data=v_json_message) self.assertEqual(response.status, 200, "Non-successful Agent vkey post return code!") json_response = json.loads(response.read().decode()) # Ensure response is well-formed self.assertIn("results", json_response, "Malformed response body!")
def test_024_agent_keys_ukey_post(self): """Test agents's POST /v2/keys/ukey Interface""" global public_key self.assertIsNotNone(public_key, "Required value not set. Previous step may have failed?") self.assertIsNotNone(self.U, "Required value not set. Previous step may have failed?") self.assertIsNotNone(self.auth_tag, "Required value not set. Previous step may have failed?") self.assertIsNotNone(self.payload, "Required value not set. Previous step may have failed?") encrypted_U = crypto.rsa_encrypt(crypto.rsa_import_pubkey(public_key), self.U) b64_encrypted_u = base64.b64encode(encrypted_U) data = { 'encrypted_key': b64_encrypted_u, 'auth_tag': self.auth_tag, 'payload': self.payload } test_024_agent_keys_ukey_post = RequestsClient(tenant_templ.agent_base_url, tls_enabled=False) response = test_024_agent_keys_ukey_post.post( f'/v{self.api_version}/keys/ukey', data=json.dumps(data), cert="", verify=False ) self.assertEqual(response.status_code, 200, "Non-successful Agent ukey post return code!") json_response = response.json() # Ensure response is well-formed self.assertIn("results", json_response, "Malformed response body!")
def test_024_agent_keys_ukey_post(self): """Test agents's POST /v2/keys/ukey Interface""" global public_key self.assertIsNotNone(public_key, "Required value not set. Previous step may have failed?") self.assertIsNotNone(self.U, "Required value not set. Previous step may have failed?") self.assertIsNotNone(self.auth_tag, "Required value not set. Previous step may have failed?") self.assertIsNotNone(self.payload, "Required value not set. Previous step may have failed?") encrypted_U = crypto.rsa_encrypt(crypto.rsa_import_pubkey(public_key),self.U) b64_encrypted_u = base64.b64encode(encrypted_U) data = { 'encrypted_key': b64_encrypted_u, 'auth_tag': self.auth_tag, 'payload': self.payload } u_yaml_message = json.dumps(data) params = '/v%s/keys/ukey'% self.api_version response = httpclient_requests.request("POST", "%s"%tenant_templ.cloudagent_ip,tenant_templ.cloudagent_port, params=params, data=u_yaml_message) self.assertEqual(response.status, 200, "Non-successful Agent ukey post return code!") json_response = json.loads(response.read().decode()) # Ensure response is well-formed self.assertIn("results", json_response, "Malformed response body!")
def test_rsa(self): message = b"a secret message!" private = rsa_generate(2048) pubkeypem = rsa_export_pubkey(private) pubkey = rsa_import_pubkey(pubkeypem) keypem = rsa_export_privkey(private) key = rsa_import_privkey(keypem) ciphertext = rsa_encrypt(pubkey, message) plain = rsa_decrypt(key, ciphertext) self.assertEqual(plain, message)
def prepare_v(agent): # be very careful printing K, U, or V as they leak in logs stored on unprotected disks if config.INSECURE_DEBUG: logger.debug("b64_V (non encrypted): %s", agent['v']) if agent.get('b64_encrypted_V', "") != "": b64_encrypted_V = agent['b64_encrypted_V'] logger.debug("Re-using cached encrypted V") else: # encrypt V with the public key b64_encrypted_V = base64.b64encode( crypto.rsa_encrypt(crypto.rsa_import_pubkey(agent['public_key']), base64.b64decode(agent['v']))) agent['b64_encrypted_V'] = b64_encrypted_V # logger.debug("b64_encrypted_V:" + b64_encrypted_V) post_data = {'encrypted_key': b64_encrypted_V} return post_data
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 Agent at {self.cloudagent_ip} with Port {self.cloudagent_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
def do_quote(self): """ Perform TPM quote by GET towards Agent Raises: UserError: Connection handler """ 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) cloudagent_base_url = f'{self.agent_ip}:{self.agent_port}' do_quote = RequestsClient(cloudagent_base_url, tls_enabled=False) response = do_quote.get( params, cert=self.cert ) response_body = response.json() except Exception as e: if response.status_code in (503, 504): numtries += 1 maxr = config.getint('tenant', 'max_retries') if numtries >= maxr: logger.error("Tenant cannot establish connection to agent on %s with port %s", self.agent_ip, self.agent_port) sys.exit() retry = config.getfloat('tenant', 'retry_interval') logger.info("Tenant connection to agent at %s refused %s/%s times, trying again in %s seconds...", self.agent_ip, numtries, maxr, retry) time.sleep(retry) continue raise e break try: if response is not None and response.status_code != 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("Agent_quote received quote: %s", quote) public_key = response_body["results"]["pubkey"] logger.debug("Agent_quote received public key: %s", public_key) # Ensure hash_alg is in accept_tpm_hash_algs list hash_alg = response_body["results"]["hash_alg"] logger.debug("Agent_quote received hash algorithm: %s", hash_alg) if not 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("Agent_quote received encryption algorithm: %s", enc_alg) if not 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("Agent_quote received signing algorithm: %s", sign_alg) if not 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, hash_alg): raise UserError( "TPM Quote from cloud agent is invalid for nonce: %s" % self.nonce) logger.info("Quote from %s validated", self.agent_ip) # encrypt U with the public key 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: %s", 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' cloudagent_base_url = ( f'{self.agent_ip}:{self.agent_port}' ) post_ukey = RequestsClient(cloudagent_base_url, tls_enabled=False) response = post_ukey.post( params, data=u_json_message ) if response.status_code == 503: logger.error("Cannot connect to Agent at %s with Port %s. Connection refused.", self.agent_ip, self.agent_port) sys.exit() elif response.status_code == 504: logger.error("Verifier at %s with Port %s timed out.", self.verifier_ip, self.verifier_port) sys.exit() if response.status_code != 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