def test_signature_verification(self): """Test the signature verification""" curdir = os.path.dirname(os.path.abspath(__file__)) keydir = os.path.join(curdir, "data", "ima_keys") lines = SIGNATURES.split("\n") # empty keyring keyrings = file_signatures.ImaKeyrings() _, failure = ima.process_measurement_list(AgentAttestState("1"), lines, ima_keyrings=keyrings) self.assertTrue(failure) tenant_keyring = file_signatures.ImaKeyring() keyrings.set_tenant_keyring(tenant_keyring) # add key for 1st entry; 1st entry must be verifiable rsakeyfile = os.path.join(keydir, "rsa2048pub.pem") pubkey, keyidv2 = file_signatures.get_pubkey_from_file(rsakeyfile) tenant_keyring.add_pubkey(pubkey, keyidv2) _, failure = ima.process_measurement_list(AgentAttestState("1"), lines[0:1], ima_keyrings=keyrings) self.assertTrue(not failure) _, failure = ima.process_measurement_list(AgentAttestState("1"), lines[1:2], ima_keyrings=keyrings) self.assertTrue(failure) # add key for 2nd entry; 1st & 2nd entries must be verifiable eckeyfile = os.path.join(keydir, "secp256k1.pem") pubkey, keyidv2 = file_signatures.get_pubkey_from_file(eckeyfile) tenant_keyring.add_pubkey(pubkey, keyidv2) _, failure = ima.process_measurement_list(AgentAttestState("1"), lines[0:2], ima_keyrings=keyrings) self.assertTrue(not failure)
def test_measurment_verification(self): """Test IMA measurement list verification""" lines = MEASUREMENTS.splitlines() lists_map = ima.process_ima_policy(ALLOWLIST, "") lists_map_empty = ima.process_ima_policy(ALLOWLIST_EMPTY, "") _, failure = ima.process_measurement_list(AgentAttestState("1"), lines) self.assertTrue(not failure, "Validation should always work when no allowlist and no keyring is specified") _, failure = ima.process_measurement_list(AgentAttestState("1"), lines, lists_map) self.assertTrue(not failure) # test with list with JSON _, failure = ima.process_measurement_list(AgentAttestState("1"), lines, json.dumps(lists_map)) self.assertTrue(not failure) # No files are in the allowlist -> this should fail _, failure = ima.process_measurement_list(AgentAttestState("1"), lines, lists_map_empty) self.assertTrue(failure)
def test_iterative_attestation(self): """Test that the resulting pcr value is as expected by subsequently feeding a measurement list. The AgentAtestState() will maintain the state of PCR 10. """ lines = MEASUREMENTS.splitlines() agentAttestState = AgentAttestState("1") running_hash = agentAttestState.get_pcr_state(10) for line in lines: parts = line.split(" ") template_hash = codecs.decode(parts[1].encode("utf-8"), "hex") running_hash = hashlib.sha1(running_hash + template_hash).digest() pcrval = codecs.encode(running_hash, "hex").decode("utf-8") ima_hash, _ = ima.process_measurement_list(agentAttestState, [line], pcrval=pcrval) self.assertTrue(ima_hash == pcrval) # Feed empty iterative measurement list simulating 'no new measurement list entries' on attested system ima_hash, _ = ima.process_measurement_list(agentAttestState, [""], pcrval=pcrval) self.assertTrue(ima_hash == pcrval)
def test_ima_buf_verification(self): """The verification of ima-buf entries supporting keys loaded onto keyrings""" list_map = ima.process_allowlists(ALLOWLIST, "") ima_keyrings = file_signatures.ImaKeyrings() self.assertTrue( ima.process_measurement_list(AgentAttestState("1"), KEYRINGS.splitlines(), json.dumps(list_map), ima_keyrings=ima_keyrings) is not None)
def __check_ima(agentAttestState, pcrval, ima_measurement_list, allowlist, ima_keyrings, boot_aggregates, hash_alg): failure = Failure(Component.IMA) logger.info("Checking IMA measurement list on agent: %s", agentAttestState.get_agent_id()) _, ima_failure = ima.process_measurement_list( agentAttestState, ima_measurement_list.split('\n'), allowlist, pcrval=pcrval, ima_keyrings=ima_keyrings, boot_aggregates=boot_aggregates, hash_alg=hash_alg) failure.merge(ima_failure) if not failure: logger.debug("IMA measurement list of agent %s validated", agentAttestState.get_agent_id()) return failure
def test_mixed_verfication(self): """Test verification using allowlist and keys""" lists_map = ima.process_allowlists(ALLOWLIST, "") lists_map_wrong = ima.process_allowlists(ALLOWLIST_WRONG, "") lists_map_empty = ima.process_allowlists(ALLOWLIST_EMPTY, "") lists_map_exclude = ima.process_allowlists(ALLOWLIST, EXCLUDELIST) lists_map_exclude_wrong = ima.process_allowlists( ALLOWLIST_WRONG, EXCLUDELIST) ima_keyrings = file_signatures.ImaKeyrings() empty_keyring = file_signatures.ImaKeyring() # every entry is covered by the allowlist and there's no keyring -> this should pass _, failure = ima.process_measurement_list(AgentAttestState("1"), COMBINED.splitlines(), json.dumps(lists_map)) self.assertTrue(not failure) curdir = os.path.dirname(os.path.abspath(__file__)) keydir = os.path.join(curdir, "data", "ima_keys") tenant_keyring = file_signatures.ImaKeyring() rsakeyfile = os.path.join(keydir, "rsa2048pub.pem") pubkey, keyidv2 = file_signatures.get_pubkey_from_file(rsakeyfile) tenant_keyring.add_pubkey(pubkey, keyidv2) eckeyfile = os.path.join(keydir, "secp256k1.pem") pubkey, keyidv2 = file_signatures.get_pubkey_from_file(eckeyfile) tenant_keyring.add_pubkey(pubkey, keyidv2) ima_keyrings.set_tenant_keyring(tenant_keyring) # entries are not covered by a exclude list -> this should fail _, failure = ima.process_measurement_list(AgentAttestState("1"), COMBINED.splitlines(), ima_keyrings=ima_keyrings) self.assertTrue(failure) # all entries are either covered by allow list or by signature verification -> this should pass _, failure = ima.process_measurement_list(AgentAttestState("1"), COMBINED.splitlines(), json.dumps(lists_map), ima_keyrings=ima_keyrings) self.assertTrue(not failure) # the signature is valid but the hash in the allowlist is wrong -> this should fail _, failure = ima.process_measurement_list(AgentAttestState("1"), SIGNATURES.splitlines(), json.dumps(lists_map_wrong), ima_keyrings=ima_keyrings) self.assertTrue(failure) # the signature is valid and the file is not in the allowlist -> this should pass _, failure = ima.process_measurement_list(AgentAttestState("1"), SIGNATURES.splitlines(), json.dumps(lists_map_empty), ima_keyrings=ima_keyrings) self.assertTrue(not failure) # the signature is invalid but the correct hash is in the allowlist -> this should fail ima_keyrings.set_tenant_keyring(empty_keyring) _, failure = ima.process_measurement_list(AgentAttestState("1"), SIGNATURES.splitlines(), json.dumps(lists_map), ima_keyrings=ima_keyrings) self.assertTrue(failure) # the file has no signature but the hash is correct -> this should pass _, failure = ima.process_measurement_list(AgentAttestState("1"), MEASUREMENTS.splitlines(), json.dumps(lists_map)) self.assertTrue(not failure) # All files are in the exclude list but hashes are invalid -> this should pass _, failure = ima.process_measurement_list( AgentAttestState("1"), MEASUREMENTS.splitlines(), json.dumps(lists_map_exclude_wrong)) self.assertTrue(not failure) # All files are in the exclude list and their signatures are invalid -> this should pass ima_keyrings.set_tenant_keyring(tenant_keyring) _, failure = ima.process_measurement_list( AgentAttestState("1"), SIGNATURES.splitlines(), json.dumps(lists_map_exclude), ima_keyrings=ima_keyrings) self.assertTrue(not failure) # All files are in the exclude list but hashes or signatures are invalid -> this should pass _, failure = ima.process_measurement_list( AgentAttestState("1"), MEASUREMENTS.splitlines(), json.dumps(lists_map_exclude_wrong), ima_keyrings=ima_keyrings, ) self.assertTrue(not failure)