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_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 doRegisterAgent(registrar_ip, registrar_port, agent_id, tpm_version, pub_ek, ekcert, pub_aik, pub_ek_tpm=None, aik_name=None): data = { 'ek': pub_ek, 'ekcert': ekcert, 'aik': pub_aik, 'aik_name': aik_name, 'ek_tpm': pub_ek_tpm, 'tpm_version': tpm_version, } response = None try: client = RequestsClient(f'{registrar_ip}:{registrar_port}', tls_enabled) response = client.post(f'/agents/{agent_id}', cert=tls_cert_info, data=json.dumps(data), verify=False) response_body = response.json() if response.status_code != 200: logger.error( f"Error: unexpected http response code from Registrar Server: {response.status_code}" ) keylime_logging.log_http_response(logger, logging.ERROR, response_body) return None logger.info(f"Agent registration requested for {agent_id}") if "results" not in response_body: logger.critical( f"Error: unexpected http response body from Registrar Server: {response.status_code}" ) return None if "blob" not in response_body["results"]: logger.critical( f"Error: did not receive blob from Registrar Server: {response.status_code}" ) return None return response_body["results"]["blob"] except Exception as e: if response and response.status_code == 503: logger.error( f"Agent cannot establish connection to registrar at {registrar_ip}:{registrar_port}" ) sys.exit() else: logger.exception(e) return None
def test_034_cv_agent_post_invalid_exclude_list(self): """Test CV's POST /v2/agents/{UUID} Interface""" self.assertIsNotNone(self.V, "Required value not set. Previous step may have failed?") b64_v = base64.b64encode(self.V) # Set unsupported regex in exclude list allowlist = {'exclude': ['*']} data = { 'v': b64_v, 'cloudagent_ip': tenant_templ.cloudagent_ip, 'cloudagent_port': tenant_templ.cloudagent_port, 'tpm_policy': json.dumps(self.tpm_policy), 'vtpm_policy': json.dumps(self.vtpm_policy), 'allowlist': json.dumps(allowlist), 'ima_sign_verification_keys': '', 'metadata': json.dumps(self.metadata), 'revocation_key': self.revocation_key, 'accept_tpm_hash_algs': config.get('tenant', 'accept_tpm_hash_algs').split(','), 'accept_tpm_encryption_algs': config.get('tenant', 'accept_tpm_encryption_algs').split(','), 'accept_tpm_signing_algs': config.get('tenant', 'accept_tpm_signing_algs').split(','), } client = RequestsClient(tenant_templ.verifier_base_url, tls_enabled) response = client.post( f'/v{self.api_version}/agents/{tenant_templ.agent_uuid}', cert=tenant_templ.cert, data=json.dumps(data), verify=False ) self.assertEqual(response.status_code, 400, "Successful CV agent Post return code!") # Ensure response is well-formed json_response = response.json() self.assertIn("results", json_response, "Malformed response body!")
def test_010_reg_agent_post(self): """Test registrar's POST /v2/agents/{UUID} Interface""" global keyblob, aik, vtpm, ek # Change CWD for TPM-related operations cwd = os.getcwd() config.ch_dir(config.WORK_DIR, None) _ = secure_mount.mount() # Initialize the TPM with AIK (ek, ekcert, aik, ek_tpm, aik_name) = tpm.tpm_init(self_activate=False, config_pw=config.get('cloud_agent', 'tpm_ownerpassword')) vtpm = tpm.is_vtpm() # Seed RNG (root only) if config.REQUIRE_ROOT: tpm.init_system_rand() # Handle virtualized and emulated TPMs if ekcert is None: if vtpm: ekcert = 'virtual' elif tpm.is_emulator(): ekcert = 'emulator' # Get back to our original CWD config.ch_dir(cwd, None) data = { 'ek': ek, 'ekcert': ekcert, 'aik': aik, 'aik_name': aik_name, 'ek_tpm': ek_tpm, 'tpm_version': tpm.VERSION, } test_010_reg_agent_post = RequestsClient( tenant_templ.registrar_base_url, tls_enabled=False) response = test_010_reg_agent_post.post( f'/v{self.api_version}/agents/{tenant_templ.agent_uuid}', data=json.dumps(data), cert="", verify=False) self.assertEqual(response.status_code, 200, "Non-successful Registrar agent Add return code!") json_response = response.json() # Ensure response is well-formed self.assertIn("results", json_response, "Malformed response body!") self.assertIn("blob", json_response["results"], "Malformed response body!") keyblob = json_response["results"]["blob"] self.assertIsNotNone(keyblob, "Malformed response body!")
def test_030_cv_agent_post(self): """Test CV's POST /agents/{UUID} Interface""" self.assertIsNotNone( self.V, "Required value not set. Previous step may have failed?") b64_v = base64.b64encode(self.V) data = { "v": b64_v, "cloudagent_ip": tenant_templ.cloudagent_ip, "cloudagent_port": tenant_templ.cloudagent_port, "tpm_policy": json.dumps(self.tpm_policy), "ima_policy_bundle": json.dumps(self.ima_policy_bundle), "ima_sign_verification_keys": "", "mb_refstate": None, "metadata": json.dumps(self.metadata), "revocation_key": self.revocation_key, "accept_tpm_hash_algs": config.get("tenant", "accept_tpm_hash_algs").split(","), "accept_tpm_encryption_algs": config.get("tenant", "accept_tpm_encryption_algs").split(","), "accept_tpm_signing_algs": config.get("tenant", "accept_tpm_signing_algs").split(","), "supported_version": tenant_templ.supported_version, "ak_tpm": aik_tpm, "mtls_cert": mtls_cert, } test_030_cv_agent_post = RequestsClient(tenant_templ.verifier_base_url, tls_enabled) response = test_030_cv_agent_post.post( f"/v{self.api_version}/agents/{tenant_templ.agent_uuid}", data=json.dumps(data), cert=tenant_templ.cert, verify=False, ) self.assertEqual(response.status_code, 200, "Non-successful CV agent Post return code!") json_response = response.json() # Ensure response is well-formed self.assertIn("results", json_response, "Malformed response body!") time.sleep(10)
def test_010_reg_agent_post(self): """Test registrar's POST /agents/{UUID} Interface""" global keyblob, vtpm, tpm_instance, ek_tpm, aik_tpm contact_ip = "127.0.0.1" contact_port = 9002 tpm_instance = tpm_main.tpm() # Change CWD for TPM-related operations cwd = os.getcwd() config.ch_dir(config.WORK_DIR, None) _ = secure_mount.mount() # Initialize the TPM with AIK (ekcert, ek_tpm, aik_tpm) = tpm_instance.tpm_init( self_activate=False, config_pw=config.get('cloud_agent', 'tpm_ownerpassword')) vtpm = tpm_instance.is_vtpm() # Handle virtualized and emulated TPMs if ekcert is None: if vtpm: ekcert = 'virtual' elif tpm_instance.is_emulator(): ekcert = 'emulator' # Get back to our original CWD config.ch_dir(cwd, None) data = { 'ekcert': ekcert, 'aik_tpm': aik_tpm, 'ip': contact_ip, 'port': contact_port } if ekcert is None or ekcert == 'emulator': data['ek_tpm'] = ek_tpm test_010_reg_agent_post = RequestsClient( tenant_templ.registrar_base_url, tls_enabled=False) response = test_010_reg_agent_post.post( f'/v{self.api_version}/agents/{tenant_templ.agent_uuid}', data=json.dumps(data), cert="", verify=False) self.assertEqual(response.status_code, 200, "Non-successful Registrar agent Add return code!") json_response = response.json() # Ensure response is well-formed self.assertIn("results", json_response, "Malformed response body!") self.assertIn("blob", json_response["results"], "Malformed response body!") keyblob = json_response["results"]["blob"] self.assertIsNotNone(keyblob, "Malformed response body!")
def test_010_reg_agent_post(self): """Test registrar's POST /agents/{UUID} Interface""" global keyblob, tpm_instance, ek_tpm, aik_tpm contact_ip = "127.0.0.1" contact_port = 9002 tpm_instance = tpm_main.tpm() # Change CWD for TPM-related operations cwd = os.getcwd() fs_util.ch_dir(config.WORK_DIR) _ = secure_mount.mount() # Create a mTLS cert for testing global mtls_cert rsa_key = crypto.rsa_generate(2048) valid_util = datetime.datetime.utcnow() + datetime.timedelta(days=(360 * 5)) mtls_cert = crypto.generate_selfsigned_cert("TEST_CERT", rsa_key, valid_util).public_bytes( serialization.Encoding.PEM ) # Initialize the TPM with AIK (ekcert, ek_tpm, aik_tpm) = tpm_instance.tpm_init( self_activate=False, config_pw=config.get("cloud_agent", "tpm_ownerpassword") ) # Handle emulated TPMs if ekcert is None: if tpm_instance.is_emulator(): ekcert = "emulator" # Get back to our original CWD fs_util.ch_dir(cwd) data = {"ekcert": ekcert, "aik_tpm": aik_tpm, "ip": contact_ip, "port": contact_port, "mtls_cert": mtls_cert} if ekcert is None or ekcert == "emulator": data["ek_tpm"] = ek_tpm test_010_reg_agent_post = RequestsClient(tenant_templ.registrar_base_url, tls_enabled=False) response = test_010_reg_agent_post.post( f"/v{self.api_version}/agents/{tenant_templ.agent_uuid}", data=json.dumps(data), cert="", verify=False ) self.assertEqual(response.status_code, 200, "Non-successful Registrar agent Add return code!") json_response = response.json() # Ensure response is well-formed self.assertIn("results", json_response, "Malformed response body!") self.assertIn("blob", json_response["results"], "Malformed response body!") keyblob = json_response["results"]["blob"] self.assertIsNotNone(keyblob, "Malformed response body!")
def test_030_cv_agent_post(self): """Test CV's POST /v2/agents/{UUID} Interface""" self.assertIsNotNone( self.V, "Required value not set. Previous step may have failed?") b64_v = base64.b64encode(self.V) data = { 'v': b64_v, 'cloudagent_ip': tenant_templ.cloudagent_ip, 'cloudagent_port': tenant_templ.cloudagent_port, 'tpm_policy': json.dumps(self.tpm_policy), 'vtpm_policy': json.dumps(self.vtpm_policy), 'allowlist': json.dumps(self.allowlist), 'ima_sign_verification_keys': '', 'mb_refstate': None, 'metadata': json.dumps(self.metadata), 'revocation_key': self.revocation_key, 'accept_tpm_hash_algs': config.get('tenant', 'accept_tpm_hash_algs').split(','), 'accept_tpm_encryption_algs': config.get('tenant', 'accept_tpm_encryption_algs').split(','), 'accept_tpm_signing_algs': config.get('tenant', 'accept_tpm_signing_algs').split(','), } test_030_cv_agent_post = RequestsClient(tenant_templ.verifier_base_url, tls_enabled) response = test_030_cv_agent_post.post( f'/agents/{tenant_templ.agent_uuid}', data=json.dumps(data), cert=tenant_templ.cert, verify=False) self.assertEqual(response.status_code, 200, "Non-successful CV agent Post return code!") json_response = response.json() # Ensure response is well-formed self.assertIn("results", json_response, "Malformed response body!") time.sleep(10)
def doRegisterAgent(registrar_ip, registrar_port, agent_id, ek_tpm, ekcert, aik_tpm): data = { 'ekcert': ekcert, 'aik_tpm': aik_tpm, } if ekcert is None or ekcert == 'emulator': data['ek_tpm'] = ek_tpm response = None try: client = RequestsClient(f'{registrar_ip}:{registrar_port}', tls_enabled) response = client.post(f'/agents/{agent_id}', cert=tls_cert_info, data=json.dumps(data), verify=False) response_body = response.json() if response.status_code != 200: logger.error( "Error: unexpected http response code from Registrar Server: %s", response.status_code) keylime_logging.log_http_response(logger, logging.ERROR, response_body) return None logger.info("Agent registration requested for %s", agent_id) if "results" not in response_body: logger.critical( "Error: unexpected http response body from Registrar Server: %s", response.status_code) return None if "blob" not in response_body["results"]: logger.critical( "Error: did not receive blob from Registrar Server: %s", response.status_code) return None return response_body["results"]["blob"] except Exception as e: if response and response.status_code == 503: logger.error( "Agent cannot establish connection to registrar at %s:%s", registrar_ip, registrar_port) sys.exit() else: logger.exception(e) return None
def do_cv(self): """ Initiaite v, agent_id and ip and initiate the cloudinit sequence """ b64_v = base64.b64encode(self.V).decode('utf-8') logger.debug("b64_v:" + b64_v) data = { 'v': b64_v, 'cloudagent_ip': self.cv_cloudagent_ip, 'cloudagent_port': self.agent_port, 'tpm_policy': json.dumps(self.tpm_policy), 'vtpm_policy': json.dumps(self.vtpm_policy), 'allowlist': json.dumps(self.allowlist), 'metadata': json.dumps(self.metadata), 'revocation_key': self.revocation_key, 'accept_tpm_hash_algs': self.accept_tpm_hash_algs, 'accept_tpm_encryption_algs': self.accept_tpm_encryption_algs, 'accept_tpm_signing_algs': self.accept_tpm_signing_algs, } json_message = json.dumps(data) do_cv = RequestsClient(self.verifier_base_url, self.tls_enabled) response = do_cv.post((f'/agents/{self.agent_uuid}'), data=json_message, cert=self.cert, verify=False) if response.status_code == 503: logger.error( f"Cannot connect to Verifier at {self.verifier_ip} with Port {self.verifier_port}. Connection refused." ) sys.exit() elif response.status_code == 504: logger.error( f"Verifier at {self.verifier_ip} with Port {self.verifier_port} timed out." ) sys.exit() if response.status_code == 409: # this is a conflict, need to update or delete it logger.error( f"Agent {self.agent_uuid} already existed at CV. Please use delete or update." ) sys.exit() elif response.status_code != 200: keylime_logging.log_http_response(logger, logging.ERROR, response.json()) logger.error( f"POST command response: {response.status} Unexpected response from Cloud Verifier: {response.read()}" ) sys.exit()
def do_add_allowlist(self, args): if 'allowlist_name' not in args or not args['allowlist_name']: raise UserError('allowlist_name is required to add an allowlist') allowlist_name = args['allowlist_name'] self.process_allowlist(args) data = { 'tpm_policy': json.dumps(self.tpm_policy), 'vtpm_policy': json.dumps(self.vtpm_policy), 'allowlist': json.dumps(self.allowlist) } body = json.dumps(data) cv_client = RequestsClient(self.verifier_base_url, self.tls_enabled) response = cv_client.post(f'/allowlists/{allowlist_name}', data=body, cert=self.cert, verify=False) print(response.json())
def test_025_cv_allowlist_post(self): """Test CV's POST /allowlist/{name} Interface""" data = { "name": "test-allowlist", "tpm_policy": json.dumps(self.tpm_policy), "ima_policy": json.dumps(self.allowlist), } cv_client = RequestsClient(tenant_templ.verifier_base_url, tls_enabled) response = cv_client.post( f"/v{self.api_version}/allowlists/test-allowlist", data=json.dumps(data), cert=tenant_templ.cert, verify=False, ) self.assertEqual(response.status_code, 201, "Non-successful CV allowlist Post return code!") json_response = response.json() # Ensure response is well-formed self.assertIn("results", json_response, "Malformed response body!")
def test_034_cv_agent_post_invalid_exclude_list(self): """Test CV's POST /agents/{UUID} Interface""" self.assertIsNotNone(self.V, "Required value not set. Previous step may have failed?") b64_v = base64.b64encode(self.V) # Set unsupported regex in exclude list allowlist = {"exclude": ["*"]} data = { "v": b64_v, "mb_refstate": None, "cloudagent_ip": tenant_templ.cloudagent_ip, "cloudagent_port": tenant_templ.cloudagent_port, "tpm_policy": json.dumps(self.tpm_policy), "allowlist": json.dumps(allowlist), "ima_sign_verification_keys": "", "metadata": json.dumps(self.metadata), "revocation_key": self.revocation_key, "accept_tpm_hash_algs": config.get("tenant", "accept_tpm_hash_algs").split(","), "accept_tpm_encryption_algs": config.get("tenant", "accept_tpm_encryption_algs").split(","), "accept_tpm_signing_algs": config.get("tenant", "accept_tpm_signing_algs").split(","), "supported_version": tenant_templ.supported_version, } client = RequestsClient(tenant_templ.verifier_base_url, tls_enabled) response = client.post( f"/v{self.api_version}/agents/{tenant_templ.agent_uuid}", cert=tenant_templ.cert, data=json.dumps(data), verify=False, ) self.assertEqual(response.status_code, 400, "Successful CV agent Post return code!") # Ensure response is well-formed json_response = response.json() self.assertIn("results", json_response, "Malformed response body!")
def doRegisterAgent(registrar_ip, registrar_port, agent_id, ek_tpm, ekcert, aik_tpm, mtls_cert=None, contact_ip=None, contact_port=None): data = { "ekcert": ekcert, "aik_tpm": aik_tpm, } if ekcert is None or ekcert == "emulator": data["ek_tpm"] = ek_tpm if mtls_cert is not None: data["mtls_cert"] = mtls_cert else: logger.error( "Most actions require the agent to have mTLS enabled, but no cert was provided!" ) if contact_ip is not None: data["ip"] = contact_ip if contact_port is not None: data["port"] = contact_port response = None try: client = RequestsClient(f"{registrar_ip}:{registrar_port}", tls_enabled, ignore_hostname=True) response = client.post(f"/v{api_version}/agents/{agent_id}", cert=tls_cert_info, data=json.dumps(data), verify=ca_cert) response_body = response.json() if response.status_code != 200: logger.error( "Error: unexpected http response code from Registrar Server: %s", response.status_code) keylime_logging.log_http_response(logger, logging.ERROR, response_body) return None logger.info("Agent registration requested for %s", agent_id) if "results" not in response_body: logger.critical( "Error: unexpected http response body from Registrar Server: %s", response.status_code) return None if "blob" not in response_body["results"]: logger.critical( "Error: did not receive blob from Registrar Server: %s", response.status_code) return None return response_body["results"]["blob"] except Exception as e: if response and response.status_code == 503: logger.error( "Agent cannot establish connection to registrar at %s:%s", registrar_ip, registrar_port) sys.exit() else: logger.exception(e) return None
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