from __future__ import annotations import shutil from collections.abc import Generator from importlib import resources from pathlib import Path import pytest import tests.data.cc.analysis import tests.data.common from sec_certs.cert_rules import SARS_IMPLIED_FROM_EAL from sec_certs.dataset.auxiliary_dataset_handling import ( CPEDatasetHandler, CPEMatchDictHandler, CVEDatasetHandler, ProtectionProfileDatasetHandler, ) from sec_certs.dataset.cc import CCDataset from sec_certs.dataset.cpe import CPEDataset from sec_certs.dataset.cve import CVEDataset from sec_certs.heuristics.cc import compute_references from sec_certs.heuristics.common import compute_related_cves, compute_transitive_vulnerabilities from sec_certs.sample.cc import CCCertificate from sec_certs.sample.sar import SAR @pytest.fixture(scope="module") def analysis_data_dir() -> Generator[Path, None, None]: with resources.path(tests.data.cc.analysis, "") as path: yield path @pytest.fixture(scope="module") def processed_cc_dset( analysis_data_dir: Path, cve_dataset: CVEDataset, cpe_dataset: CPEDataset, tmp_path_factory, pp_data_dir: Path ) -> CCDataset: tmp_dir = tmp_path_factory.mktemp("cc_dset") shutil.copytree(analysis_data_dir, tmp_dir, dirs_exist_ok=True) shutil.copy(pp_data_dir / "dataset.json", tmp_dir / "dataset.json") cc_dset = CCDataset.from_json(tmp_dir / "vulnerable_dataset.json") cc_dset.aux_handlers[ProtectionProfileDatasetHandler].root_dir.mkdir(parents=True, exist_ok=True) shutil.copy(tmp_dir / "dataset.json", cc_dset.aux_handlers[ProtectionProfileDatasetHandler].dset_path) cc_dset.aux_handlers[ProtectionProfileDatasetHandler].process_dataset() cc_dset.aux_handlers[CPEMatchDictHandler].dset = {} cc_dset.aux_handlers[CVEDatasetHandler].dset = cve_dataset cc_dset.aux_handlers[CPEDatasetHandler].dset = cpe_dataset cc_dset.extract_data() cc_dset._compute_heuristics_body(skip_schemes=True) return cc_dset @pytest.fixture def reference_dataset(analysis_data_dir) -> CCDataset: return CCDataset.from_json(analysis_data_dir / "reference_dataset.json") @pytest.fixture def transitive_vulnerability_dataset(analysis_data_dir) -> CCDataset: return CCDataset.from_json(analysis_data_dir / "transitive_vulnerability_dataset.json") @pytest.fixture def random_certificate(processed_cc_dset: CCDataset) -> CCCertificate: return processed_cc_dset["ed91ff3e658457fd"] def test_match_cpe(random_certificate: CCCertificate): assert { "cpe:2.3:a:ibm:security_access_manager_for_enterprise_single_sign-on:8.2.2:*:*:*:*:*:*:*" } == random_certificate.heuristics.cpe_matches def test_find_related_cves(processed_cc_dset: CCDataset, random_certificate: CCCertificate): random_certificate.heuristics.cpe_matches = { "cpe:2.3:a:ibm:security_access_manager_for_enterprise_single_sign-on:8.2.2:*:*:*:*:*:*:*" } compute_related_cves( processed_cc_dset.aux_handlers[CPEDatasetHandler].dset, processed_cc_dset.aux_handlers[CVEDatasetHandler].dset, {}, processed_cc_dset.certs.values(), ) assert random_certificate.heuristics.related_cves == {"CVE-2017-1732", "CVE-2019-4513"} def test_find_related_cves_criteria_configuration(processed_cc_dset: CCDataset, random_certificate: CCCertificate): random_certificate.heuristics.cpe_matches = { "cpe:2.3:a:ibm:websphere_application_server:7.0:*:*:*:*:*:*:*", "cpe:2.3:o:ibm:zos:6.0.1:*:*:*:*:*:*:*", } compute_related_cves( processed_cc_dset.aux_handlers[CPEDatasetHandler].dset, processed_cc_dset.aux_handlers[CVEDatasetHandler].dset, {}, processed_cc_dset.certs.values(), ) assert random_certificate.heuristics.related_cves == {"CVE-2010-2325"} def test_version_extraction(random_certificate: CCCertificate): assert random_certificate.heuristics.extracted_versions == {"8.2"} new_cert = CCCertificate( "", "", "IDOneClassIC Card : ID-One Cosmo 64 RSA v5.4 and applet IDOneClassIC v1.0 embedded on P5CT072VOP", "", "", "", None, None, "", "", "", "", set(), set(), None, None, None, ) new_cert.compute_heuristics_version() assert new_cert.heuristics.extracted_versions == {"5.4", "1.0"} def test_cert_lab_heuristics(random_certificate: CCCertificate): assert random_certificate.heuristics.cert_lab == ["BSI"] def test_cert_id_heuristics(random_certificate: CCCertificate): assert random_certificate.heuristics.cert_id == "BSI-DSZ-CC-0683-2014" def test_keywords_heuristics(random_certificate: CCCertificate): assert random_certificate.pdf_data.st_keywords extracted_keywords: dict = random_certificate.pdf_data.st_keywords assert "cc_security_level" in extracted_keywords assert extracted_keywords["cc_security_level"]["EAL"]["EAL3"] == 1 assert "cc_sar" in extracted_keywords assert extracted_keywords["cc_sar"]["ADV"]["ADV_ARC.1"] == 1 assert extracted_keywords["cc_sar"]["ADV"]["ADV_FSP.3"] == 1 assert extracted_keywords["cc_sar"]["ADV"]["ADV_TDS.2"] == 1 assert "symmetric_crypto" in extracted_keywords assert extracted_keywords["symmetric_crypto"]["AES_competition"]["AES"]["AES"] == 2 assert "cipher_mode" in extracted_keywords assert extracted_keywords["cipher_mode"]["CBC"]["CBC"] == 2 def test_single_record_references_heuristics(random_certificate: CCCertificate): # Single record in daset is not affecting nor affected by other records assert not random_certificate.heuristics.report_references.directly_referenced_by assert not random_certificate.heuristics.report_references.indirectly_referenced_by assert not random_certificate.heuristics.report_references.directly_referencing assert not random_certificate.heuristics.report_references.indirectly_referencing def test_reference_dataset(reference_dataset: CCDataset): compute_references(reference_dataset.certs) test_cert = reference_dataset["d1b238729b25d745"] assert test_cert.heuristics.report_references.directly_referenced_by == {"BSI-DSZ-CC-0370-2006"} assert test_cert.heuristics.report_references.indirectly_referenced_by == { "BSI-DSZ-CC-0370-2006", "BSI-DSZ-CC-0517-2009", } assert not test_cert.heuristics.report_references.directly_referencing assert not test_cert.heuristics.report_references.indirectly_referencing def test_direct_transitive_vulnerability_dataset(transitive_vulnerability_dataset: CCDataset): compute_transitive_vulnerabilities(transitive_vulnerability_dataset.certs) assert transitive_vulnerability_dataset["11f77cb31b931a57"].heuristics.direct_transitive_cves == {"CVE-2013-5385"} def test_indirect_transitive_vulnerability_dataset(transitive_vulnerability_dataset: CCDataset): compute_transitive_vulnerabilities(transitive_vulnerability_dataset.certs) assert transitive_vulnerability_dataset["11f77cb31b931a57"].heuristics.indirect_transitive_cves == {"CVE-2013-5385"} def test_sar_object(): alc_flr_one = SAR("ALC_FLR", 1) alc_flr_one_copy = SAR("ALC_FLR", 1) alc_flr_two = SAR("ALC_FLR", 2) assert alc_flr_one == alc_flr_one_copy assert alc_flr_one != alc_flr_two with pytest.raises(ValueError): # does not contain level SAR.from_string("ALC_FLR") with pytest.raises(ValueError): # unknown family SAR.from_string("XALC_FLR") def test_sar_transformation(random_certificate: CCCertificate): assert random_certificate.heuristics.extracted_sars # This one should be taken from security level and not overwritten by stronger SARs in ST assert SAR("ALC_FLR", 1) in random_certificate.heuristics.extracted_sars assert SAR("ALC_FLR", 2) not in random_certificate.heuristics.extracted_sars # This one should be taken from ST and not overwritten by stronger SAR in report assert SAR("ADV_FSP", 3) in random_certificate.heuristics.extracted_sars assert SAR("ADV_FSP", 6) not in random_certificate.heuristics.extracted_sars def test_eal_implied_sar_inference(random_certificate: CCCertificate): assert random_certificate.actual_sars actual_sars = random_certificate.actual_sars eal_3_sars = {SAR(x[0], x[1]) for x in SARS_IMPLIED_FROM_EAL["EAL3"]} assert eal_3_sars.issubset(actual_sars) def test_eal_inference(processed_cc_dset: CCDataset): assert processed_cc_dset["ed91ff3e658457fd"].heuristics.eal == "EAL1" assert processed_cc_dset["95e3850bef32f410"].heuristics.eal == "EAL1+" def test_pp_linking(processed_cc_dset: CCDataset): assert processed_cc_dset["ed91ff3e658457fd"].heuristics.protection_profiles == {"e315e3e834a61448"} assert processed_cc_dset["95e3850bef32f410"].heuristics.protection_profiles == { "b02ed76d2545326a", "c8b175590bb7fdfb", } pp_dset = processed_cc_dset.aux_handlers[ProtectionProfileDatasetHandler].dset assert processed_cc_dset["ed91ff3e658457fd"].protection_profile_links assert processed_cc_dset["95e3850bef32f410"].protection_profile_links assert ( pp_dset["e315e3e834a61448"].web_data.pp_link in processed_cc_dset["ed91ff3e658457fd"].protection_profile_links ) assert ( pp_dset["b02ed76d2545326a"].web_data.pp_link in processed_cc_dset["95e3850bef32f410"].protection_profile_links ) assert ( pp_dset["c8b175590bb7fdfb"].web_data.pp_link in processed_cc_dset["95e3850bef32f410"].protection_profile_links )