diff options
| author | Ján Jančár | 2022-07-12 01:46:27 +0200 |
|---|---|---|
| committer | GitHub | 2022-07-12 01:46:27 +0200 |
| commit | bf94b0ea4c245af115f011a9fedf1f9aac8ad706 (patch) | |
| tree | 2f6cc2c8da52c2863f6eb30b91f0c5a7a20c9ead | |
| parent | 3d17e0f3bebab559db7bfda6fc1288cdca1aee34 (diff) | |
| parent | 9a4407c19735e284eeb34a18ab7c4f4b46ee0bd1 (diff) | |
| download | sec-certs-bf94b0ea4c245af115f011a9fedf1f9aac8ad706.tar.gz sec-certs-bf94b0ea4c245af115f011a9fedf1f9aac8ad706.tar.zst sec-certs-bf94b0ea4c245af115f011a9fedf1f9aac8ad706.zip | |
Merge pull request #246 from crocs-muni/fix/fips-algos
Harmonize FIPS code
26 files changed, 1335 insertions, 1431 deletions
diff --git a/fips_cli.py b/fips_cli.py index 56c78e89..a01fde08 100755 --- a/fips_cli.py +++ b/fips_cli.py @@ -20,7 +20,18 @@ logger = logging.getLogger(__name__) required=True, nargs=-1, type=click.Choice( - ["new-run", "all", "build", "convert", "update", "pdf-scan", "table-search", "analysis", "graphs"], + [ + "new-run", + "all", + "build", + "convert", + "algorithms", + "update", + "pdf-scan", + "table-search", + "analysis", + "graphs", + ], case_sensitive=False, ), ) @@ -55,7 +66,6 @@ logger = logging.getLogger(__name__) type=str, help="Name of the json object to be created in the <<output>> directory. Defaults to <<timestamp>>.json.", ) -@click.option("--no-download-algs", "no_download_algs", help="Don't fetch new algorithm implementations", is_flag=True) @click.option("--redo-web-scan", "redo_web_scan", help="Redo HTML webpage scan from scratch", is_flag=True) @click.option("--redo-keyword-scan", "redo_keyword_scan", help="Redo PDF keyword scan from scratch", is_flag=True) @click.option( @@ -92,7 +102,9 @@ def main( 'update' Load a previously used dataset (created by 'build') and update it with nonprocessed entries from NIST pages. - Both options download the files needed for analysis. + 'algorithms' Download the FIPS algorithms from NIST pages. + + These options download the files needed for analysis. Analysis preparation: @@ -151,7 +163,7 @@ def main( sys.exit(1) r_actions = ( - {"convert", "pdf-scan", "table-search", "analysis", "graphs"} + {"algorithms", "convert", "pdf-scan", "table-search", "analysis", "graphs"} if "all" in actions or "new-run" in actions else set(actions) ) @@ -177,7 +189,7 @@ def main( name=json_name, description=f"Full FIPS dataset snapshot {datetime.now().date()}", ) - dset.get_certs_from_web(no_download_algorithms=no_download_algs) + dset.get_certs_from_web() inputpath = dset.json_path output = None @@ -190,9 +202,7 @@ def main( assert inputpath dset = FIPSDataset.from_json(inputpath) - assert dset.algorithms - - logger.info(f"Have dataset with {len(dset)} certs and {len(dset.algorithms)} algorithms.") + logger.info(f"Have dataset with {len(dset)} certs.") if output: logger.warning( "You provided both inputpath and outputpath, dataset will be copied to outputpath (without data)" @@ -201,7 +211,10 @@ def main( dset.to_json(output) if "update" in actions: - dset.get_certs_from_web(no_download_algorithms=no_download_algs, update=True, redo_web_scan=redo_web_scan) + dset.get_certs_from_web(update=True, redo_web_scan=redo_web_scan) + + if "algorithms" in actions: + dset.process_algorithms() if "convert" in actions or "update" in actions: warn_if_missing_poppler() diff --git a/sec_certs/constants.py b/sec_certs/constants.py index 784ea18a..72b12d08 100644 --- a/sec_certs/constants.py +++ b/sec_certs/constants.py @@ -1,5 +1,4 @@ import re -from enum import Enum RESPONSE_OK = 200 RETURNCODE_OK = "ok" @@ -12,25 +11,32 @@ MIN_CC_HTML_SIZE = 5000000 MIN_CC_CSV_SIZE = 700000 MIN_CC_PP_DATASET_SIZE = 2500000 - -class CertFramework(Enum): - CC = "Common Criteria" - FIPS = "FIPS" - - CPE_VERSION_NA = "-" FIPS_BASE_URL = "https://csrc.nist.gov" -FIPS_MODULE_URL = "https://csrc.nist.gov/projects/cryptographic-module-validation-program/certificate/" -FIPS_NOT_AVAILABLE_CERT_SIZE = 10000 -FIPS_ALG_URL = "https://csrc.nist.gov/projects/cryptographic-algorithm-validation-program/validation-search?searchMode=implementation&page=" +FIPS_CMVP_URL = FIPS_BASE_URL + "/projects/cryptographic-module-validation-program" +FIPS_CAVP_URL = FIPS_BASE_URL + "/projects/Cryptographic-Algorithm-Validation-Program" +FIPS_MODULE_URL = FIPS_CMVP_URL + "/certificate/{}" +FIPS_ALG_SEARCH_URL = FIPS_CAVP_URL + "/validation-search?searchMode=implementation&page=" +FIPS_SP_URL = "https://csrc.nist.gov/CSRC/media/projects/cryptographic-module-validation-program/documents/security-policies/140sp{}.pdf" +FIPS_ACTIVE_MODULES_URL = ( + FIPS_CMVP_URL + "/validated-modules/search?SearchMode=Advanced&CertificateStatus=Active&ValidationYear=0" +) +FIPS_HISTORICAL_MODULES_URL = ( + FIPS_CMVP_URL + "/validated-modules/search?SearchMode=Advanced&CertificateStatus=Historical&ValidationYear=0" +) +FIPS_REVOKED_MODULES_URL = ( + FIPS_CMVP_URL + "/validated-modules/search?SearchMode=Advanced&CertificateStatus=Revoked&ValidationYear=0" +) +FIPS_ALG_URL = FIPS_CAVP_URL + "/details?source={}&number={}" +FIPS_IUT_URL = "https://csrc.nist.gov/Projects/cryptographic-module-validation-program/modules-in-process/IUT-List" +FIPS_MIP_URL = ( + "https://csrc.nist.gov/Projects/cryptographic-module-validation-program/modules-in-process/Modules-In-Process-List" +) -FIPS_MIP_STATUS_RE = re.compile(r"^(?P<status>[a-zA-Z ]+?) +\((?P<since>\d{1,2}/\d{1,2}/\d{4})\)$") +FIPS_DOWNLOAD_DELAY = 1 -TAG_MATCH_COUNTER = "count" -TAG_MATCH_MATCHES = "matches" - -TAG_CERT_HEADER_PROCESSED = "cert_header_processed" +FIPS_MIP_STATUS_RE = re.compile(r"^(?P<status>[a-zA-Z ]+?) +\((?P<since>\d{1,2}/\d{1,2}/\d{4})\)$") TAG_CERT_ID = "cert_id" TAG_CC_SECURITY_LEVEL = "cc_security_level" @@ -41,24 +47,8 @@ TAG_CERT_ITEM_VERSION = "cert_item_version" TAG_DEVELOPER = "developer" TAG_REFERENCED_PROTECTION_PROFILES = "ref_protection_profiles" TAG_HEADER_MATCH_RULES = "match_rules" -TAG_PP_TITLE = "pp_title" -TAG_PP_GENERAL_STATUS = "pp_general_status" -TAG_PP_VERSION_NUMBER = "pp_version_number" -TAG_PP_ID = "pp_id" -TAG_PP_ID_REGISTRATOR = "pp_id_registrator" -TAG_PP_DATE = "pp_date" -TAG_PP_AUTHORS = "pp_authors" -TAG_PP_REGISTRATOR = "pp_registrator" -TAG_PP_REGISTRATOR_SIMPLIFIED = "pp_registrator_simplified" -TAG_PP_SPONSOR = "pp_sponsor" -TAG_PP_EDITOR = "pp_editor" -TAG_PP_REVIEWER = "pp_reviewer" -TAG_KEYWORDS = "keywords" - FILE_ERRORS_STRATEGY = "surrogateescape" -STOP_ON_UNEXPECTED_NUMS = False -APPEND_DETAILED_MATCH_MATCHES = False MAX_ALLOWED_MATCH_LENGTH = 300 LINE_SEPARATOR = " " diff --git a/sec_certs/dataset/common_criteria.py b/sec_certs/dataset/common_criteria.py index ee686428..dfeb28bf 100644 --- a/sec_certs/dataset/common_criteria.py +++ b/sec_certs/dataset/common_criteria.py @@ -600,7 +600,7 @@ class CCDataset(Dataset[CommonCriteriaCert], ComplexSerializableType): cat_dict = {x: y for (x, y) in zip(cc_table_ids, cc_categories)} with file.open("r") as handle: - soup = BeautifulSoup(handle, "html5lib") + soup = BeautifulSoup(handle, "html.parser") certs = {} for key, val in cat_dict.items(): diff --git a/sec_certs/dataset/fips.py b/sec_certs/dataset/fips.py index 57e2c697..64fd636e 100644 --- a/sec_certs/dataset/fips.py +++ b/sec_certs/dataset/fips.py @@ -6,6 +6,7 @@ from typing import Any, Dict, List, Optional, Set from bs4 import BeautifulSoup, NavigableString from graphviz import Digraph +from sec_certs import constants from sec_certs.config.configuration import config from sec_certs.dataset.dataset import Dataset from sec_certs.dataset.fips_algorithm import FIPSAlgorithmDataset @@ -34,17 +35,12 @@ class FIPSDataset(Dataset[FIPSCertificate], ComplexSerializableType): super().__init__(certs, root_dir, name, description) self.keywords: Dict[str, Dict] = {} self.algorithms: Optional[FIPSAlgorithmDataset] = None - self.new_files = 0 @property def _policies_dir(self) -> Path: return self.root_dir / "security_policies" @property - def _fragments_dir(self) -> Path: - return self.root_dir / "fragments" - - @property def _algs_dir(self) -> Path: return self.web_dir / "algorithms" @@ -53,9 +49,9 @@ class FIPSDataset(Dataset[FIPSCertificate], ComplexSerializableType): Returns list of certificates that match given name. :param str module_name: name to search for - :return List[FIPSCertificate]: List of certificates with web_scan.module_name == module_name + :return List[FIPSCertificate]: List of certificates with web_data.module_name == module_name """ - return [crt for crt in self if crt.web_scan.module_name == module_name] + return [crt for crt in self if crt.web_data.module_name == module_name] @serialize def pdf_scan(self, redo: bool = False) -> None: @@ -67,30 +63,15 @@ class FIPSDataset(Dataset[FIPSCertificate], ComplexSerializableType): """ logger.info("Entering PDF scan.") - self._fragments_dir.mkdir(parents=True, exist_ok=True) - keywords = cert_processing.process_parallel( FIPSCertificate.find_keywords, - [cert for cert in self.certs.values() if not cert.pdf_scan.keywords or redo], + [cert for cert in self.certs.values() if not cert.pdf_data.keywords or redo], config.n_threads, use_threading=False, progress_bar_desc="Scanning PDF files", ) for keyword, cert in keywords: - self.certs[cert.dgst].pdf_scan.keywords = keyword - - def _match_algs(self) -> Dict[str, int]: - output = {} - for cert in self.certs.values(): - # if the pdf has not been processed, no matching can be done - if not cert.pdf_scan.keywords or not cert.state.txt_state: - continue - - output[cert.dgst] = FIPSCertificate.match_web_algs_to_pdf(cert) - cert.heuristics.unmatched_algs = output[cert.dgst] - - output = {k: v for k, v in output.items() if v != 0} - return output + self.certs[cert.dgst].pdf_data.keywords = keyword def download_all_pdfs(self, cert_ids: Optional[Set[str]] = None) -> None: """ @@ -107,9 +88,7 @@ class FIPSDataset(Dataset[FIPSCertificate], ComplexSerializableType): if not (self._policies_dir / f"{cert_id}.pdf").exists() or ( fips_dgst(cert_id) in self.certs and not self.certs[fips_dgst(cert_id)].state.txt_state ): - sp_urls.append( - f"https://csrc.nist.gov/CSRC/media/projects/cryptographic-module-validation-program/documents/security-policies/140sp{cert_id}.pdf" - ) + sp_urls.append(constants.FIPS_SP_URL.format(cert_id)) sp_paths.append(self._policies_dir / f"{cert_id}.pdf") logger.info(f"downloading {len(sp_urls)} module pdf files") cert_processing.process_parallel( @@ -118,19 +97,14 @@ class FIPSDataset(Dataset[FIPSCertificate], ComplexSerializableType): config.n_threads, progress_bar_desc="Downloading PDF files", ) - self.new_files += len(sp_urls) - def _download_all_htmls(self, cert_ids: Set[str]) -> List[str]: + def _download_all_htmls(self, cert_ids: Set[str]) -> None: html_paths, html_urls = [], [] - new_files = [] self.web_dir.mkdir(exist_ok=True) for cert_id in cert_ids: if not (self.web_dir / f"{cert_id}.html").exists(): - html_urls.append( - f"https://csrc.nist.gov/projects/cryptographic-module-validation-program/certificate/{cert_id}" - ) + html_urls.append(constants.FIPS_MODULE_URL.format(cert_id)) html_paths.append(self.web_dir / f"{cert_id}.html") - new_files.append(cert_id) logger.info(f"downloading {len(html_urls)} module html files") failed = cert_processing.process_parallel( @@ -141,7 +115,6 @@ class FIPSDataset(Dataset[FIPSCertificate], ComplexSerializableType): ) failed = [c for c in failed if c] - self.new_files += len(html_urls) if len(failed) != 0: logger.info(f"Download failed for {len(failed)} files. Retrying...") cert_processing.process_parallel( @@ -150,7 +123,6 @@ class FIPSDataset(Dataset[FIPSCertificate], ComplexSerializableType): config.n_threads, progress_bar_desc="Downloading HTML files again", ) - return new_files @serialize def convert_all_pdfs(self) -> None: @@ -176,18 +148,11 @@ class FIPSDataset(Dataset[FIPSCertificate], ComplexSerializableType): Path("fips_modules_historical.html"), Path("fips_modules_revoked.html"), ] + helpers.download_file(constants.FIPS_ACTIVE_MODULES_URL, Path(self.web_dir / "fips_modules_active.html")) helpers.download_file( - "https://csrc.nist.gov/projects/cryptographic-module-validation-program/validated-modules/search?SearchMode=Advanced&CertificateStatus=Active&ValidationYear=0", - Path(self.web_dir / "fips_modules_active.html"), - ) - helpers.download_file( - "https://csrc.nist.gov/projects/cryptographic-module-validation-program/validated-modules/search?SearchMode=Advanced&CertificateStatus=Historical&ValidationYear=0", - Path(self.web_dir / "fips_modules_historical.html"), - ) - helpers.download_file( - "https://csrc.nist.gov/projects/cryptographic-module-validation-program/validated-modules/search?SearchMode=Advanced&CertificateStatus=Revoked&ValidationYear=0", - Path(self.web_dir / "fips_modules_revoked.html"), + constants.FIPS_HISTORICAL_MODULES_URL, Path(self.web_dir / "fips_modules_historical.html") ) + helpers.download_file(constants.FIPS_REVOKED_MODULES_URL, Path(self.web_dir / "fips_modules_revoked.html")) # Parse those files and get list of currently processable files (always) cert_ids: Set[str] = set() @@ -196,14 +161,10 @@ class FIPSDataset(Dataset[FIPSCertificate], ComplexSerializableType): return cert_ids - def _download_neccessary_files(self, cert_ids: Set[str]) -> None: - self._download_all_htmls(cert_ids) - self.download_all_pdfs(cert_ids) - def _get_certificates_from_html(self, html_file: Path, update: bool = False) -> Set[str]: logger.info(f"Getting certificate ids from {html_file}") with open(html_file, "r", encoding="utf-8") as handle: - html = BeautifulSoup(handle.read(), "html5lib") + html = BeautifulSoup(handle.read(), "html.parser") table = [x for x in html.find(id="searchResultsTable").tbody.contents if x != "\n"] entries: Set[str] = set() @@ -218,11 +179,11 @@ class FIPSDataset(Dataset[FIPSCertificate], ComplexSerializableType): return entries @serialize - def web_scan(self, cert_ids: Set[int], redo: bool = False) -> None: + def web_scan(self, cert_ids: Set[str], redo: bool = False) -> None: """ Creates FIPSCertificate object from the relevant html file that must be downlaoded. - :param Set[int] cert_ids: Cert ids to create FIPSCertificate objects for. + :param Set[str] cert_ids: Cert ids to create FIPSCertificate objects for. :param bool redo: whether to re-attempt with failed certificates, defaults to False """ logger.info("Entering web scan.") @@ -230,10 +191,9 @@ class FIPSDataset(Dataset[FIPSCertificate], ComplexSerializableType): dgst = fips_dgst(cert_id) self.certs[dgst] = FIPSCertificate.from_html_file( self.web_dir / f"{cert_id}.html", - FIPSCertificate.State( + FIPSCertificate.InternalState( (self._policies_dir / str(cert_id)).with_suffix(".pdf"), (self.web_dir / str(cert_id)).with_suffix(".html"), - (self._fragments_dir / str(cert_id)).with_suffix(".txt"), False, None, False, @@ -262,21 +222,18 @@ class FIPSDataset(Dataset[FIPSCertificate], ComplexSerializableType): len(dset), len(dset.algorithms) if dset.algorithms is not None else 0, ) - # TODO: Fixme, this is really costly - # logger.info("The dataset does not contain the results of the dependency analysis - calculating them now...") - # dset.finalize_results() return dset def _set_local_paths(self) -> None: cert: FIPSCertificate for cert in self.certs.values(): - cert.set_local_paths(self._policies_dir, self.web_dir, self._fragments_dir) + cert.set_local_paths(self._policies_dir, self.web_dir) @serialize def get_certs_from_web( self, + # TODO: REMOVE THIS TEST ARGUMENT, OMG! test: Optional[Path] = None, - no_download_algorithms: bool = False, update: bool = False, redo_web_scan=False, ) -> None: @@ -286,7 +243,6 @@ class FIPSDataset(Dataset[FIPSCertificate], ComplexSerializableType): Args: test (Optional[Path], optional): Path to dataset used in testing. Defaults to None. - no_download_algorithms (bool, optional): Whether to reuse CAVP algorithm dataset. Defaults to False. update (bool, optional): Whether to update dataset with new entries. Defaults to False. redo_web_scan (bool, optional): Whether to redo the `web-scan` functionality. Defaults to False. """ @@ -299,19 +255,22 @@ class FIPSDataset(Dataset[FIPSCertificate], ComplexSerializableType): # Download files containing all available module certs (always) cert_ids = self._prepare_dataset(test, update) - if not no_download_algorithms: - aset = FIPSAlgorithmDataset({}, Path(self.root_dir / "web" / "algorithms"), "algorithms", "sample algs") - aset.get_certs_from_web() - logger.info(f"Finished parsing. Have algorithm dataset with {len(aset)} algorithm numbers.") - - self.algorithms = aset - logger.info("Downloading certificate html and security policies") - self._download_neccessary_files(cert_ids) + self._download_all_htmls(cert_ids) + self.download_all_pdfs(cert_ids) self.web_scan(cert_ids, redo=redo_web_scan) @serialize + def process_algorithms(self): + logger.info("Processing FIPS algorithms.") + self.algorithms = FIPSAlgorithmDataset( + {}, Path(self.root_dir / "web" / "algorithms"), "algorithms", "sample algs" + ) + self.algorithms.get_certs_from_web() + logger.info(f"Finished parsing. Have algorithm dataset with {len(self.algorithms)} algorithm numbers.") + + @serialize def extract_certs_from_tables(self, high_precision: bool) -> List[Path]: """ Function that extracts algorithm IDs from tables in security policies files. @@ -335,48 +294,48 @@ class FIPSDataset(Dataset[FIPSCertificate], ComplexSerializableType): for state, cert, algorithms in result: certificate = self.certs[cert.dgst] certificate.state.tables_done = state - certificate.pdf_scan.algorithms += algorithms + certificate.pdf_data.algorithms = algorithms return not_decoded - def _remove_algorithms_from_extracted_data(self) -> None: + def _compute_heuristics_clean_ids(self) -> None: for cert in self.certs.values(): - cert.remove_algorithms() + self._clean_cert_ids(cert) + + def _extract_metadata(self): + certs_to_process = [x for x in self] + res = cert_processing.process_parallel( + FIPSCertificate.extract_sp_metadata, + certs_to_process, + config.n_threads, + use_threading=False, + progress_bar_desc="Extracting security policy metadata", + ) + for r in res: + self.certs[r.dgst] = r def _unify_algorithms(self) -> None: for certificate in self.certs.values(): - new_algorithms: List[Dict] = [] - united_algorithms = [ - x - for x in ( - (certificate.web_scan.algorithms if certificate.web_scan.algorithms is not None else []) - + certificate.pdf_scan.algorithms - ) - if x != {"Certificate": []} - ] - for algorithm in united_algorithms: - if isinstance(algorithm, dict): - new_algorithms.append(algorithm) - else: - new_algorithms.append({"Certificate": [algorithm]}) - certificate.heuristics.algorithms = new_algorithms - - # returns True if candidates should _not_ be matched + certificate.heuristics.algorithms = set() + if certificate.web_data.algorithms: + certificate.heuristics.algorithms.update(certificate.web_data.algorithms) + if certificate.pdf_data.algorithms: + certificate.heuristics.algorithms.update(certificate.pdf_data.algorithms) def _compare_certs(self, current_certificate: FIPSCertificate, other_id: str) -> bool: other_dgst = fips_dgst(other_id) other_cert = self.certs[other_dgst] if ( - current_certificate.web_scan.date_validation is None + current_certificate.web_data.date_validation is None or other_cert is None - or other_cert.web_scan.date_validation is None + or other_cert.web_data.date_validation is None ): raise RuntimeError("Building of the dataset probably failed - this should not be happening.") - cert_first = current_certificate.web_scan.date_validation[0] - cert_last = current_certificate.web_scan.date_validation[-1] - conn_first = other_cert.web_scan.date_validation[0] - conn_last = other_cert.web_scan.date_validation[-1] + cert_first = current_certificate.web_data.date_validation[0] + cert_last = current_certificate.web_data.date_validation[-1] + conn_first = other_cert.web_data.date_validation[0] + conn_last = other_cert.web_data.date_validation[-1] return ( cert_first.year - conn_first.year > config.year_difference_between_validations @@ -384,25 +343,23 @@ class FIPSDataset(Dataset[FIPSCertificate], ComplexSerializableType): or cert_first.year < conn_first.year ) - def _remove_false_positives_for_cert(self, current_cert: FIPSCertificate) -> None: - if current_cert.heuristics.keywords is None: - raise RuntimeError("Dataset was probably not built correctly - this should not be happening.") - for rule in current_cert.heuristics.keywords["fips_cert_id"]: - matches = current_cert.heuristics.keywords["fips_cert_id"][rule] - current_cert.heuristics.keywords["fips_cert_id"][rule] = [ - cert_id - for cert_id in matches - if self._validate_id(current_cert, cert_id.replace("Cert.", "").replace("cert.", "").lstrip("#CA0 ")) - and cert_id != current_cert.cert_id - ] + def _clean_cert_ids(self, current_cert: FIPSCertificate) -> None: + current_cert.clean_cert_ids() + if not current_cert.state.txt_state: + return + current_cert.heuristics.clean_cert_ids = { + cert_id: count + for cert_id, count in current_cert.pdf_data.clean_cert_ids.items() + if self._validate_id(current_cert, cert_id.replace("Cert.", "").replace("cert.", "").lstrip("#CA0 ")) + and cert_id != current_cert.cert_id + } @staticmethod def _match_with_algorithm(processed_cert: FIPSCertificate, cert_candidate_id: str) -> bool: - for cert_alg in processed_cert.heuristics.algorithms: - for certificate in cert_alg["Certificate"]: - curr_id = "".join(filter(str.isdigit, certificate)) - if curr_id == cert_candidate_id: - return False + for alg_type, cert_id in processed_cert.heuristics.algorithms: + curr_id = "".join(filter(str.isdigit, cert_id)) + if curr_id == cert_candidate_id: + return False return True def _validate_id(self, processed_cert: FIPSCertificate, cert_candidate_id: str) -> bool: @@ -425,45 +382,34 @@ class FIPSDataset(Dataset[FIPSCertificate], ComplexSerializableType): if not FIPSDataset._match_with_algorithm(processed_cert, cert_candidate_id): return False - algs = self.algorithms.certs[cert_candidate_id] + algs = self.algorithms.certs_for_id(int(cert_candidate_id)) for current_alg in algs: - if current_alg.vendor is None or processed_cert.web_scan.vendor is None: + if current_alg.vendor is None or processed_cert.web_data.vendor is None: raise RuntimeError("Dataset was probably not built correctly - this should not be happening.") - if FIPSCertificate.get_compare(processed_cert.web_scan.vendor) == FIPSCertificate.get_compare( + if FIPSCertificate.get_compare(processed_cert.web_data.vendor) == FIPSCertificate.get_compare( current_alg.vendor ): return False return True - def _validate_results(self) -> None: - """ - Function that validates results and finds the final connection output - """ - + def _compute_dependencies(self) -> None: def pdf_lookup(cert): return set( filter( lambda x: x, map( lambda cid: "".join(filter(str.isdigit, cid)), - cert.heuristics.keywords["fips_cert_id"]["Cert"], + cert.heuristics.clean_cert_ids, ), ) ) def web_lookup(cert): return set( - filter(lambda x: x, map(lambda cid: "".join(filter(str.isdigit, cid)), cert.web_scan.mentioned_certs)) + filter(lambda x: x, map(lambda cid: "".join(filter(str.isdigit, cid)), cert.web_data.mentioned_certs)) ) - current_cert: FIPSCertificate - - for current_cert in self.certs.values(): - if not current_cert.state.txt_state: - continue - self._remove_false_positives_for_cert(current_cert) - finder = DependencyFinder() finder.fit(self.certs, lambda cert: cert.cert_id, pdf_lookup) # type: ignore @@ -485,9 +431,10 @@ class FIPSDataset(Dataset[FIPSCertificate], ComplexSerializableType): :param bool perform_cpe_heuristics: If CPE heuristics shall be computed, defaults to True """ logger.info("Entering 'analysis' and building connections between certificates.") + self._extract_metadata() self._unify_algorithms() - self._remove_algorithms_from_extracted_data() - self._validate_results() + self._compute_heuristics_clean_ids() + self._compute_dependencies() if perform_cpe_heuristics: _, _, cve_dset = self.compute_cpe_heuristics() self.compute_related_cves(use_nist_cpe_matching_dict=use_nist_cpe_matching_dict, cve_dset=cve_dset) @@ -495,38 +442,38 @@ class FIPSDataset(Dataset[FIPSCertificate], ComplexSerializableType): def _highlight_vendor_in_dot(self, dot: Digraph, current_dgst: str, highlighted_vendor: str) -> None: current_cert = self.certs[current_dgst] - if current_cert.web_scan.vendor != highlighted_vendor: + if current_cert.web_data.vendor != highlighted_vendor: return dot.attr("node", color="red") - if current_cert.web_scan.status == "Revoked": + if current_cert.web_data.status == "Revoked": dot.attr("node", color="grey32") - if current_cert.web_scan.status == "Historical": + if current_cert.web_data.status == "Historical": dot.attr("node", color="gold3") def _add_colored_node(self, dot: Digraph, current_dgst: str, highlighted_vendor: str) -> None: current_cert = self.certs[current_dgst] dot.attr("node", color="lightgreen") - if current_cert.web_scan.status == "Revoked": + if current_cert.web_data.status == "Revoked": dot.attr("node", color="lightgrey") - if current_cert.web_scan.status == "Historical": + if current_cert.web_data.status == "Historical": dot.attr("node", color="gold") self._highlight_vendor_in_dot(dot, current_dgst, highlighted_vendor) dot.node( str(current_cert.cert_id), - label=str(current_cert.cert_id) + " " + current_cert.web_scan.vendor - if current_cert.web_scan.vendor is not None - else "" + " " + (current_cert.web_scan.module_name if current_cert.web_scan.module_name else ""), + label=str(current_cert.cert_id) + " " + current_cert.web_data.vendor + if current_cert.web_data.vendor is not None + else "" + " " + (current_cert.web_data.module_name if current_cert.web_data.module_name else ""), ) def _get_processed_list(self, connection_list: str, dgst: str) -> List[str]: - attr = {"pdf": "pdf_scan", "web": "web_scan", "heuristics": "heuristics"}[connection_list] - return getattr(self.certs[dgst], attr).connections + attr = {"st": "st_references", "web": "web_references"}[connection_list] + return getattr(self.certs[dgst].heuristics, attr).directly_referencing def _create_dot_graph( self, output_file_name: str, - connection_list: str = "heuristics", + connection_list: str = "st", highlighted_vendor: str = "Red Hat®, Inc.", show: bool = True, ) -> None: @@ -537,8 +484,7 @@ class FIPSDataset(Dataset[FIPSCertificate], ComplexSerializableType): :param show: display graph right on screen :param highlighted_vendor: vendor whose certificates should be highlighted in red color :param output_file_name: prefix to "connections", "connections.pdf", "single" and "single.pdf" - :param connection_list: 'heuristics', 'web', or 'pdf' - plots a graph from this source - default - heuristics + :param connection_list: 'st' or 'web' - plots a graph from this source """ dot = Digraph(comment="Certificate ecosystem") single_dot = Digraph(comment="Modules with no dependencies") @@ -566,9 +512,9 @@ class FIPSDataset(Dataset[FIPSCertificate], ComplexSerializableType): self._highlight_vendor_in_dot(dot, key, highlighted_vendor) single_dot.node( key, - label=str(cert.cert_id) + "\r\n" + cert.web_scan.vendor - if cert.web_scan.vendor is not None - else "" + ("\r\n" + cert.web_scan.module_name if cert.web_scan.module_name else ""), + label=str(cert.cert_id) + "\r\n" + cert.web_data.vendor + if cert.web_data.vendor is not None + else "" + ("\r\n" + cert.web_data.module_name if cert.web_data.module_name else ""), ) for key in self.certs: @@ -623,9 +569,9 @@ class FIPSDataset(Dataset[FIPSCertificate], ComplexSerializableType): def plot_graphs(self, show: bool = False) -> None: """ Plots FIPS graphs. - # TODO: Currently broken, see https://github.com/crocs-muni/sec-certs/issues/211 - :param bool show: If plots should be showed with .show() method, defaults to False + + :param bool show: If plots should be shown with .show() method, defaults to False """ self._create_dot_graph("full_graph", show=show) self._create_dot_graph("web_only_graph", "web", show=show) - self._create_dot_graph("pdf_only_graph", "pdf", show=show) + self._create_dot_graph("st_only_graph", "st", show=show) diff --git a/sec_certs/dataset/fips_algorithm.py b/sec_certs/dataset/fips_algorithm.py index f0ddca6c..caaa5a7b 100644 --- a/sec_certs/dataset/fips_algorithm.py +++ b/sec_certs/dataset/fips_algorithm.py @@ -1,7 +1,6 @@ -import json import logging from pathlib import Path -from typing import Dict, List, Union +from typing import Any, Dict, List, Optional, Set from bs4 import BeautifulSoup @@ -10,7 +9,8 @@ from sec_certs import constants as constants from sec_certs.config.configuration import config from sec_certs.dataset.dataset import Dataset from sec_certs.sample.fips import FIPSCertificate -from sec_certs.serialization.json import ComplexSerializableType, CustomJSONDecoder, CustomJSONEncoder +from sec_certs.sample.fips_algorithm import FIPSAlgorithm +from sec_certs.serialization.json import ComplexSerializableType from sec_certs.utils import helpers as helpers from sec_certs.utils import parallel_processing as cert_processing @@ -18,35 +18,48 @@ logger = logging.getLogger(__name__) class FIPSAlgorithmDataset(Dataset, ComplexSerializableType): + certs: Dict[str, FIPSAlgorithm] - certs: Dict[str, List] # type: ignore # noqa + def __init__( + self, + certs: Dict[str, FIPSAlgorithm] = dict(), + root_dir: Optional[Path] = None, + name: str = "dataset name", + description: str = "dataset_description", + ): + super().__init__(certs, root_dir, name, description) + self._id_map: Dict[int, List[str]] = {} def get_certs_from_web(self): self.root_dir.mkdir(exist_ok=True) algs_paths, algs_urls = [], [] # get first page to find out how many pages there are - helpers.download_file(constants.FIPS_ALG_URL + "1", self.root_dir / "page1.html") + res = helpers.download_file(constants.FIPS_ALG_SEARCH_URL + "1", self.root_dir / "page1.html") + if res != 200: + logger.error("Couldn't download first page of algo dataset") with open(self.root_dir / "page1.html", "r") as alg_file: soup = BeautifulSoup(alg_file.read(), "html.parser") - num_pages = soup.select("span[data-total-pages]")[0].attrs + num_pages_elem = soup.select("span[data-total-pages]")[0].attrs - for i in range(2, int(num_pages["data-total-pages"]) + 1): + num_pages = int(num_pages_elem["data-total-pages"]) + + for i in range(2, num_pages + 1): if not (self.root_dir / f"page{i}.html").exists(): - algs_urls.append(constants.FIPS_ALG_URL + str(i)) + algs_urls.append(constants.FIPS_ALG_SEARCH_URL + str(i)) algs_paths.append(self.root_dir / f"page{i}.html") # get the last page, always - helpers.download_file( - constants.FIPS_ALG_URL + num_pages["data-total-pages"], - self.root_dir / f"page{int(num_pages['data-total-pages'])}.html", - ) - logger.info(f"downloading {len(algs_urls)} algs html files") + algs_urls.append(constants.FIPS_ALG_SEARCH_URL + str(num_pages)) + algs_paths.append(self.root_dir / f"page{num_pages}.html") + + logger.info(f"Downloading {len(algs_urls)} algo html files") cert_processing.process_parallel( FIPSCertificate.download_html_page, list(zip(algs_urls, algs_paths)), config.n_threads ) + logger.info(f"Parsing {len(algs_urls)} algo html files") self.parse_html() @staticmethod @@ -88,42 +101,42 @@ class FIPSAlgorithmDataset(Dataset, ComplexSerializableType): ) alg_type, alg_id = split_alg(validation) - fips_alg = FIPSCertificate.Algorithm(alg_id, vendor, product, alg_type, date) - if alg_id not in self.certs: - self.certs[alg_id] = [] - self.certs[alg_id].append(fips_alg) + fips_alg = FIPSAlgorithm(alg_id, vendor, product, alg_type, date) + self.certs[fips_alg.dgst] = fips_alg + # And now rebuild the id map + self._build_id_map() - def convert_all_pdfs(self): - raise NotImplementedError("Not meant to be implemented") + def _build_id_map(self): + for cert in self.certs.values(): + self._id_map.setdefault(cert.cert_id, []) + self._id_map[cert.cert_id].append(cert.dgst) - def download_all_pdfs(self): + def _get_certs_from_name(self, name: str) -> List[FIPSAlgorithm]: raise NotImplementedError("Not meant to be implemented") - @property - def serialized_attributes(self) -> List[str]: - return ["certs"] + def _set_local_paths(self) -> None: + pass @classmethod - def from_dict(cls, dct: Dict): - certs = dct["certs"] - - directory = dct["_root_dir"] if "_root_dir" in dct else "" - dset = cls(certs, Path(directory), "algorithms", "algorithms used in dataset") + def from_dict(cls, dct: Dict[str, Any]) -> "FIPSAlgorithmDataset": + dset: FIPSAlgorithmDataset = super().from_dict(dct) + dset._build_id_map() return dset - def to_dict(self): - return self.__dict__ + def convert_all_pdfs(self): + raise NotImplementedError("Not meant to be implemented") - def to_json(self, output_path: Union[str, Path] = None): - if not output_path: - output_path = self.json_path - with Path(output_path).open("w") as handle: - json.dump(self, handle, indent=4, cls=CustomJSONEncoder) + def download_all_pdfs(self, cert_ids: Optional[Set[str]] = None) -> None: + raise NotImplementedError("Not meant to be implemented") - @classmethod - def from_json(cls, input_path: Union[str, Path]): - input_path = Path(input_path) - with input_path.open("r") as handle: - dset = json.load(handle, cls=CustomJSONDecoder) - dset.root_dir = input_path.parent.absolute() - return dset + def __getitem__(self, item: str) -> FIPSAlgorithm: + return self.certs.__getitem__(item) + + def __setitem__(self, key: str, value: FIPSAlgorithm): + self.certs.__setitem__(key, value) + + def certs_for_id(self, cert_id: int) -> List[FIPSAlgorithm]: + if cert_id in self._id_map: + return [self.certs[x] for x in self._id_map[cert_id]] + else: + return [] diff --git a/sec_certs/model/evaluation.py b/sec_certs/model/evaluation.py index bafb911e..d419850f 100644 --- a/sec_certs/model/evaluation.py +++ b/sec_certs/model/evaluation.py @@ -30,7 +30,7 @@ def compute_precision(y: np.ndarray, y_pred: np.ndarray, **kwargs) -> float: prec.append(1.0) else: prec.append(len(set_true.intersection(set_pred)) / len(set_true)) - return np.mean(prec) + return np.mean(prec) # type: ignore def evaluate( @@ -56,8 +56,8 @@ def evaluate( predicted_cpes = set() predicted_cpes_dict = {x: cpe_dset[x].title if cpe_dset[x].title else x for x in predicted_cpes} - cert_name = cert.name if isinstance(cert, CommonCriteriaCert) else cert.web_scan.module_name - vendor = cert.manufacturer if isinstance(cert, CommonCriteriaCert) else cert.web_scan.vendor + cert_name = cert.name if isinstance(cert, CommonCriteriaCert) else cert.web_data.module_name + vendor = cert.manufacturer if isinstance(cert, CommonCriteriaCert) else cert.web_data.vendor record = { "certificate_name": cert_name, "vendor": vendor, diff --git a/sec_certs/sample/__init__.py b/sec_certs/sample/__init__.py index 91352a78..3188c1a1 100644 --- a/sec_certs/sample/__init__.py +++ b/sec_certs/sample/__init__.py @@ -7,6 +7,7 @@ from sec_certs.sample.common_criteria import CommonCriteriaCert from sec_certs.sample.cpe import CPE, cached_cpe from sec_certs.sample.cve import CVE from sec_certs.sample.fips import FIPSCertificate +from sec_certs.sample.fips_algorithm import FIPSAlgorithm from sec_certs.sample.fips_iut import IUTEntry, IUTSnapshot from sec_certs.sample.fips_mip import MIPEntry, MIPSnapshot, MIPStatus from sec_certs.sample.protection_profile import ProtectionProfile @@ -19,6 +20,7 @@ __all__ = [ "cached_cpe", "CVE", "FIPSCertificate", + "FIPSAlgorithm", "IUTEntry", "IUTSnapshot", "MIPEntry", diff --git a/sec_certs/sample/cc_maintenance_update.py b/sec_certs/sample/cc_maintenance_update.py index 4196c157..1ff28fb8 100644 --- a/sec_certs/sample/cc_maintenance_update.py +++ b/sec_certs/sample/cc_maintenance_update.py @@ -26,7 +26,7 @@ class CommonCriteriaMaintenanceUpdate(CommonCriteriaCert, ComplexSerializableTyp st_link: str, state: Optional[CommonCriteriaCert.InternalState], pdf_data: Optional[CommonCriteriaCert.PdfData], - heuristics: Optional[CommonCriteriaCert.CCHeuristics], + heuristics: Optional[CommonCriteriaCert.Heuristics], related_cert_digest: str, maintenance_date: date, ): diff --git a/sec_certs/sample/common_criteria.py b/sec_certs/sample/common_criteria.py index 504bdf4e..afb0bf29 100644 --- a/sec_certs/sample/common_criteria.py +++ b/sec_certs/sample/common_criteria.py @@ -19,7 +19,9 @@ import sec_certs.utils.pdf import sec_certs.utils.sanitization from sec_certs import constants as constants from sec_certs.cert_rules import SARS_IMPLIED_FROM_EAL, cc_rules, security_level_csv_scan -from sec_certs.sample.certificate import Certificate, Heuristics, References, logger +from sec_certs.sample.certificate import Certificate +from sec_certs.sample.certificate import Heuristics as BaseHeuristics +from sec_certs.sample.certificate import References, logger from sec_certs.sample.protection_profile import ProtectionProfile from sec_certs.sample.sar import SAR from sec_certs.serialization.json import ComplexSerializableType @@ -41,7 +43,7 @@ class DependencyType(Enum): class CommonCriteriaCert( - Certificate["CommonCriteriaCert", "CommonCriteriaCert.CCHeuristics"], + Certificate["CommonCriteriaCert", "CommonCriteriaCert.Heuristics"], PandasSerializableType, ComplexSerializableType, ): @@ -315,7 +317,7 @@ class CommonCriteriaCert( return self.processed_cert_id if self.processed_cert_id else self.keywords_cert_id @dataclass - class CCHeuristics(Heuristics, ComplexSerializableType): + class Heuristics(BaseHeuristics, ComplexSerializableType): """ Class for various heuristics related to CommonCriteriaCert """ @@ -381,7 +383,7 @@ class CommonCriteriaCert( maintenance_updates: Optional[Set[MaintenanceReport]], state: Optional[InternalState], pdf_data: Optional[PdfData], - heuristics: Optional[CCHeuristics], + heuristics: Optional[Heuristics], ): super().__init__() @@ -405,7 +407,7 @@ class CommonCriteriaCert( self.maintenance_updates = maintenance_updates self.state = self.InternalState() if not state else state self.pdf_data = self.PdfData() if not pdf_data else pdf_data - self.heuristics: CommonCriteriaCert.CCHeuristics = self.CCHeuristics() if not heuristics else heuristics + self.heuristics: CommonCriteriaCert.Heuristics = self.Heuristics() if not heuristics else heuristics @property def dgst(self) -> str: @@ -490,7 +492,7 @@ class CommonCriteriaCert( """ Merges with other CC sample. Assuming they come from different sources, e.g., csv and html. Assuming that html source has better protection profiles, they overwrite CSV info - On other values (apart from maintenances, see TODO below) the sanity checks are made. + On other values the sanity checks are made. """ if self != other: logger.warning( diff --git a/sec_certs/sample/fips.py b/sec_certs/sample/fips.py index 6d9b0589..ed9a90f8 100644 --- a/sec_certs/sample/fips.py +++ b/sec_certs/sample/fips.py @@ -5,7 +5,7 @@ import re from dataclasses import dataclass, field from datetime import datetime from pathlib import Path -from typing import Any, ClassVar, Dict, List, Optional, Pattern, Set, Tuple, Union +from typing import Any, Dict, List, Optional, Pattern, Set, Tuple, Union import requests from bs4 import BeautifulSoup, NavigableString, Tag @@ -19,13 +19,183 @@ import sec_certs.utils.pdf import sec_certs.utils.tables from sec_certs.cert_rules import fips_rules from sec_certs.config.configuration import config -from sec_certs.sample.certificate import Certificate, Heuristics, References, logger +from sec_certs.sample.certificate import Certificate +from sec_certs.sample.certificate import Heuristics as BaseHeuristics +from sec_certs.sample.certificate import References, logger from sec_certs.sample.cpe import CPE from sec_certs.serialization.json import ComplexSerializableType from sec_certs.utils.helpers import fips_dgst -class FIPSCertificate(Certificate["FIPSCertificate", "FIPSCertificate.FIPSHeuristics"], ComplexSerializableType): +class _FIPSHTMLParser: + @staticmethod + def parse_html_main(current_div: Tag, html_items_found: Dict) -> None: + pairs = { + "Module Name": "module_name", + "Standard": "standard", + "Status": "status", + "Sunset Date": "date_sunset", + "Validation Dates": "date_validation", + "Overall Level": "level", + "Caveat": "caveat", + "Security Level Exceptions": "exceptions", + "Module Type": "module_type", + "Embodiment": "embodiment", + "FIPS Algorithms": "algorithms", + # "Allowed Algorithms": "algorithms", + # "Other Algorithms": "algorithms", + "Tested Configuration(s)": "tested_conf", + "Description": "description", + "Historical Reason": "historical_reason", + "Hardware Versions": "hw_versions", + "Firmware Versions": "fw_versions", + "Revoked Reason": "revoked_reason", + "Revoked Link": "revoked_link", + "Software Versions": "sw_versions", + "Product URL": "product_url", + } + title = current_div.find("div", class_="col-md-3").text.strip() + content = ( + current_div.find("div", class_="col-md-9") + .text.strip() + .replace("\n", "") + .replace("\t", "") + .replace(" ", " ") + ) + + if title in pairs: + if "date_sunset" == pairs[title]: + html_items_found[pairs[title]] = parser.parse(content).date() + + elif "caveat" in pairs[title]: + html_items_found[pairs[title]] = content + html_items_found["mentioned_certs"].update(_FIPSHTMLParser.parse_caveat(content)) + + elif "FIPS Algorithms" in title: + html_items_found["algorithms"].update( + _FIPSHTMLParser.parse_table(current_div.find("div", class_="col-md-9")) + ) + + elif "Algorithms" in title or "Description" in title: + html_items_found["algorithms"].update(_FIPSHTMLParser.parse_description(content)) + if "Description" in title: + html_items_found["description"] = content + + elif "tested_conf" in pairs[title] or "exceptions" in pairs[title]: + html_items_found[pairs[title]] = [ + x.text for x in current_div.find("div", class_="col-md-9").find_all("li") + ] + else: + html_items_found[pairs[title]] = content + + @staticmethod + def parse_vendor(current_div: Tag, html_items_found: Dict, current_file: Path) -> None: + vendor_string = current_div.find("div", "panel-body").find("a") + + if not vendor_string: + vendor_string = list(current_div.find("div", "panel-body").children)[0].strip() + html_items_found["vendor_www"] = "" + else: + html_items_found["vendor_www"] = vendor_string.get("href") + vendor_string = vendor_string.text.strip() + + html_items_found["vendor"] = vendor_string + if html_items_found["vendor"] == "": + logger.warning(f"NO VENDOR FOUND {current_file}") + + @staticmethod + def parse_lab(current_div: Tag, html_items_found: Dict, current_file: Path) -> None: + html_items_found["lab"] = list(current_div.find("div", "panel-body").children)[0].strip() + html_items_found["nvlap_code"] = ( + list(current_div.find("div", "panel-body").children)[2].strip().split("\n")[1].strip() + ) + + if html_items_found["lab"] == "": + logger.warning(f"NO LAB FOUND {current_file}") + + if html_items_found["nvlap_code"] == "": + logger.warning(f"NO NVLAP CODE FOUND {current_file}") + + @staticmethod + def parse_related_files(current_div: Tag, html_items_found: Dict) -> None: + links = current_div.find_all("a") + html_items_found["security_policy_www"] = constants.FIPS_BASE_URL + links[0].get("href") + + if len(links) == 2: + html_items_found["certificate_www"] = constants.FIPS_BASE_URL + links[1].get("href") + + @staticmethod + def normalize(items: Dict) -> None: + items["module_type"] = items["module_type"].lower().replace("-", " ").title() + items["embodiment"] = items["embodiment"].lower().replace("-", " ").replace("stand alone", "standalone").title() + + @staticmethod + def parse_validation_dates(current_div: Tag, html_items_found: Dict) -> None: + table = current_div.find("table") + rows = table.find("tbody").findAll("tr") + html_items_found["date_validation"] = [parser.parse(td.text).date() for td in [row.find("td") for row in rows]] + + @staticmethod + def parse_caveat(current_text: str) -> Dict[str, Dict[str, int]]: + """ + Parses content of "Caveat" of FIPS CMVP .html file + + :param str current_text: text of "Caveat" + :return Dict[str, Dict[str, int]]: dictionary of all found algorithm IDs + """ + ids_found: Dict[str, Dict[str, int]] = {} + r_key = r"(?P<word>\w+)?\s?(?:#\s?|Cert\.?(?!.\s)\s?|Certificate\s?)+(?P<id>\d+)" + for m in re.finditer(r_key, current_text): + if m.group("word") and m.group("word").lower() in {"rsa", "shs", "dsa", "pkcs", "aes"}: + continue + if m.group("id") in ids_found: + ids_found[m.group("id")]["count"] += 1 + else: + ids_found[m.group("id")] = {"count": 1} + + return ids_found + + @staticmethod + def parse_table(element: Union[Tag, NavigableString]) -> Set[Tuple[Optional[str], str]]: + """ + Parses content of <table> tags in FIPS .html CMVP page + + :param Union[Tag, NavigableString] element: text in <table> tags + :return: set of all found algorithm IDs + """ + + found_items = set() + trs = element.find_all("tr") + for tr in trs: + tds = tr.find_all("td") + cert_ids = _FIPSHTMLParser.extract_algorithm_certificates(tds[1].text) + name = tds[0].text + for cert_id in cert_ids: + found_items.add((name, cert_id)) + + return found_items + + @staticmethod + def parse_description(current_text: str) -> Set[Tuple[Optional[str], str]]: + return set(map(lambda x: (None, x), _FIPSHTMLParser.extract_algorithm_certificates(current_text))) + + @staticmethod + def extract_algorithm_certificates(current_text: str) -> Set[str]: + """ + Parses table of FIPS (non) allowed algorithms + + :param str current_text: Contents of the table + :return: A list of found algorithm ids. + """ + set_items = set() + reg = r"(?:#[CcAa]?\s?|(?:Cert)\.?[^. ]*?\s?)(?:[CcAa]\s)?(?P<id>\d+)" + for m in re.finditer(reg, current_text): + set_items.add(m.group()) + + return set_items + + +class FIPSCertificate(Certificate["FIPSCertificate", "FIPSCertificate.Heuristics"], ComplexSerializableType): """ Data structure for common FIPS 140 certificate. Contains several inner classes that layer the data logic. Can be serialized into/from json (`ComplexSerializableType`). @@ -33,20 +203,15 @@ class FIPSCertificate(Certificate["FIPSCertificate", "FIPSCertificate.FIPSHeuris the certificate can handle itself. `FIPSDataset` class then instrument this functionality. """ - FIPS_BASE_URL: ClassVar[str] = "https://csrc.nist.gov" - FIPS_MODULE_URL: ClassVar[ - str - ] = "https://csrc.nist.gov/projects/cryptographic-module-validation-program/certificate/" - @dataclass(eq=True) - class State(ComplexSerializableType): + # TODO: Include sp_pdf_hash and sp_txt_hash. + class InternalState(ComplexSerializableType): """ Holds state of the `FIPSCertificate` """ sp_path: Path html_path: Path - fragment_path: Path tables_done: bool file_status: Optional[bool] txt_state: bool @@ -55,14 +220,12 @@ class FIPSCertificate(Certificate["FIPSCertificate", "FIPSCertificate.FIPSHeuris self, sp_path: Union[str, Path], html_path: Union[str, Path], - fragment_path: Union[str, Path], tables_done: bool, file_status: Optional[bool], txt_state: bool, ): self.sp_path = Path(sp_path) self.html_path = Path(html_path) - self.fragment_path = Path(fragment_path) self.tables_done = tables_done self.file_status = file_status self.txt_state = txt_state @@ -71,41 +234,14 @@ class FIPSCertificate(Certificate["FIPSCertificate", "FIPSCertificate.FIPSHeuris self, sp_dir: Optional[Union[str, Path]], html_dir: Optional[Union[str, Path]], - fragment_dir: Optional[Union[str, Path]], ) -> None: if sp_dir is not None: self.state.sp_path = (Path(sp_dir) / (str(self.cert_id))).with_suffix(".pdf") if html_dir is not None: self.state.html_path = (Path(html_dir) / (str(self.cert_id))).with_suffix(".html") - if fragment_dir is not None: - self.state.fragment_path = (Path(fragment_dir) / (str(self.cert_id))).with_suffix(".txt") - - @dataclass(eq=True) - class Algorithm(ComplexSerializableType): - """ - Data structure for algorithm of `FIPSCertificate` - """ - - cert_id: str - vendor: str - implementation: str - algorithm_type: str - date: str - - @property - def dgst(self) -> str: - # certs in dataset are in format { id: [FIPSAlgorithm] }, there is only one type of algorithm - # for each id - return self.algorithm_type - - def __repr__(self) -> str: - return self.algorithm_type + " algorithm #" + self.cert_id + " created by " + self.vendor - - def __str__(self) -> str: - return str(self.algorithm_type + " algorithm #" + self.cert_id + " created by " + self.vendor) @dataclass(eq=True) - class WebScan(ComplexSerializableType): + class WebData(ComplexSerializableType): """ Data structure for data obtained from scanning certificate webpage at NIST.gov """ @@ -120,7 +256,7 @@ class FIPSCertificate(Certificate["FIPSCertificate", "FIPSCertificate.FIPSHeuris exceptions: Optional[List[str]] module_type: Optional[str] embodiment: Optional[str] - algorithms: Optional[List[Dict[str, str]]] + algorithms: Optional[Set[Tuple[Optional[str], str]]] tested_conf: Optional[List[str]] description: Optional[str] mentioned_certs: Optional[Dict[str, Dict[str, int]]] @@ -138,18 +274,6 @@ class FIPSCertificate(Certificate["FIPSCertificate", "FIPSCertificate.FIPSHeuris sw_versions: Optional[str] product_url: Optional[str] - @property - def dgst(self) -> str: - # certs in dataset are in format { id: [FIPSAlgorithm] }, there is only one type of algorithm - # for each id - return helpers.get_first_16_bytes_sha256( - self.product_url - if self.product_url is not None - else "" + self.vendor_www - if self.vendor_www is not None - else "" - ) - def __repr__(self) -> str: return ( self.module_name @@ -160,29 +284,19 @@ class FIPSCertificate(Certificate["FIPSCertificate", "FIPSCertificate.FIPSHeuris ) def __str__(self) -> str: - return ( - self.module_name - if self.module_name is not None - else "" + " created by " + self.vendor - if self.vendor is not None - else "" - ) # type: ignore + return repr(self) @dataclass(eq=True) - class PdfScan(ComplexSerializableType): + class PdfData(ComplexSerializableType): """ Data structure that holds data obtained from scanning pdf files (or their converted txt documents). """ cert_id: int keywords: Dict - algorithms: List - - @property - def dgst(self) -> str: - # certs in dataset are in format { id: [FIPSAlgorithm] }, there is only one type of algorithm - # for each id - return helpers.get_first_16_bytes_sha256(str(self.keywords)) + algorithms: Set[Tuple[Optional[str], str]] + clean_cert_ids: Dict[str, int] + st_metadata: Optional[Dict[str, Any]] = field(default=None) def __repr__(self) -> str: return str(self.cert_id) @@ -191,14 +305,15 @@ class FIPSCertificate(Certificate["FIPSCertificate", "FIPSCertificate.FIPSHeuris return str(self.cert_id) @dataclass(eq=True) - class FIPSHeuristics(Heuristics, ComplexSerializableType): + class Heuristics(BaseHeuristics, ComplexSerializableType): """ Data structure that holds data obtained by processing the certificate and applying various heuristics. """ keywords: Dict[str, Dict] - algorithms: List[Dict[str, Dict]] + algorithms: Set[Tuple[Optional[str], str]] unmatched_algs: int + clean_cert_ids: Dict[str, int] extracted_versions: Optional[Set[str]] = field(default=None) cpe_matches: Optional[Set[str]] = field(default=None) @@ -209,13 +324,7 @@ class FIPSCertificate(Certificate["FIPSCertificate", "FIPSCertificate.FIPSHeuris web_references: References = field(default_factory=References) @property - def serialized_attributes(self) -> List[str]: - return copy.deepcopy(super().serialized_attributes) - - @property def dgst(self) -> str: - # certs in dataset are in format { id: [FIPSAlgorithm] }, there is only one type of algorithm - # for each id return helpers.get_first_16_bytes_sha256(str(self.keywords)) def __str__(self) -> str: @@ -231,50 +340,41 @@ class FIPSCertificate(Certificate["FIPSCertificate", "FIPSCertificate.FIPSHeuris # TODO: Fix type errors, they exist because FIPS uses this as property to change variable names, while CC and abstract class have variables @property def manufacturer(self) -> Optional[str]: # type: ignore - return self.web_scan.vendor + return self.web_data.vendor @property def name(self) -> Optional[str]: # type: ignore - return self.web_scan.module_name + return self.web_data.module_name @property def label_studio_title(self) -> str: return ( "Vendor: " - + str(self.web_scan.vendor) + + str(self.web_data.vendor) + "\n" + "Module name: " - + str(self.web_scan.module_name) + + str(self.web_data.module_name) + "\n" + "HW version: " - + str(self.web_scan.hw_version) + + str(self.web_data.hw_version) + "\n" + "FW version: " - + str(self.web_scan.fw_version) + + str(self.web_data.fw_version) ) - @staticmethod - def download_security_policy(cert: Tuple[str, Path]) -> None: - """ - Downloads security policy file from web. Staticmethod to allow for parametrization. - """ - exit_code = helpers.download_file(*cert, delay=1) - if exit_code != requests.codes.ok: - logger.error(f"Failed to download security policy from {cert[0]}, code: {exit_code}") - def __init__( self, cert_id: int, - web_scan: FIPSCertificate.WebScan, - pdf_scan: FIPSCertificate.PdfScan, - heuristics: FIPSCertificate.FIPSHeuristics, - state: State, + web_data: FIPSCertificate.WebData, + pdf_data: FIPSCertificate.PdfData, + heuristics: FIPSCertificate.Heuristics, + state: InternalState, ): super().__init__() self.cert_id = cert_id - self.web_scan = web_scan - self.pdf_scan = pdf_scan - self.heuristics: FIPSCertificate.FIPSHeuristics = heuristics + self.web_data = web_data + self.pdf_data = pdf_data + self.heuristics = heuristics self.state = state @classmethod @@ -287,251 +387,32 @@ class FIPSCertificate(Certificate["FIPSCertificate", "FIPSCertificate.FIPSHeuris """ new_dct = dct.copy() - if new_dct["web_scan"].date_validation: - new_dct["web_scan"].date_validation = [parser.parse(x).date() for x in new_dct["web_scan"].date_validation] + if new_dct["web_data"].date_validation: + new_dct["web_data"].date_validation = [parser.parse(x).date() for x in new_dct["web_data"].date_validation] - if new_dct["web_scan"].date_sunset: - new_dct["web_scan"].date_sunset = parser.parse(new_dct["web_scan"].date_sunset).date() + if new_dct["web_data"].date_sunset: + new_dct["web_data"].date_sunset = parser.parse(new_dct["web_data"].date_sunset).date() return super(cls, FIPSCertificate).from_dict(new_dct) - @staticmethod - def download_html_page(cert: Tuple[str, Path]) -> Optional[Tuple[str, Path]]: - """ - Wrapper for downloading a file. `delay=1` introduced to avoid problems with requests at NIST.gov - - :param Tuple[str, Path] cert: tuple url, output_path - :return Optional[Tuple[str, Path]]: None on success, `cert` on failure. - """ - exit_code = helpers.download_file(*cert, delay=1) - if exit_code != requests.codes.ok: - logger.error(f"Failed to download html page from {cert[0]}, code: {exit_code}") - return cert - return None - - @staticmethod - def _initialize_dictionary() -> Dict[str, Any]: - return { - "module_name": None, - "standard": None, - "status": None, - "date_sunset": None, - "date_validation": None, - "level": None, - "caveat": None, - "exceptions": None, - "module_type": None, - "embodiment": None, - "tested_conf": None, - "description": None, - "vendor": None, - "vendor_www": None, - "lab": None, - "lab_nvlap": None, - "historical_reason": None, - "revoked_reason": None, - "revoked_link": None, - "algorithms": [], - "mentioned_certs": {}, - "tables_done": False, - "security_policy_www": None, - "certificate_www": None, - "hw_versions": None, - "fw_versions": None, - "sw_versions": None, - "product_url": None, - } - - @staticmethod - def parse_caveat(current_text: str) -> Dict[str, Dict[str, int]]: - """ - Parses content of "Caveat" of FIPS CMVP .html file - - :param str current_text: text of "Caveat" - :return Dict[str, Dict[str, int]]: dictionary of all found algorithm IDs - """ - ids_found: Dict[str, Dict[str, int]] = {} - r_key = r"(?P<word>\w+)?\s?(?:#\s?|Cert\.?(?!.\s)\s?|Certificate\s?)+(?P<id>\d+)" - for m in re.finditer(r_key, current_text): - if m.group("word") and m.group("word").lower() in {"rsa", "shs", "dsa", "pkcs", "aes"}: - continue - if m.group("id") in ids_found: - ids_found[m.group("id")]["count"] += 1 - else: - ids_found[m.group("id")] = {"count": 1} - - return ids_found - - @staticmethod - def extract_algorithm_certificates(current_text: str, in_pdf: bool = False) -> List[Optional[Dict[str, List[str]]]]: - """ - Parses table of FIPS (non) allowed algorithms - - :param str current_text: Contents of the table - :param bool in_pdf: Specifies whether the table was found in a PDF security policies file, defaults to False - :return List[Optional[Dict[str, List[str]]]]: List containing one element - dictionary with all parsed algorithm cert ids - """ - set_items = set() - if in_pdf: - reg = r"(?:#?\s?|(?:Cert)\.?[^. ]*?\s?)(?:[CcAa]\s)?(?P<id>[CcAa]? ?\d+)" - else: - reg = r"(?:#[CcAa]?\s?|(?:Cert)\.?[^. ]*?\s?)(?:[CcAa]\s)?(?P<id>\d+)" - for m in re.finditer(reg, current_text): - set_items.add(m.group()) - - return [{"Certificate": list(set_items)}] if len(set_items) > 0 else [] - - @staticmethod - def parse_table(element: Union[Tag, NavigableString]) -> List[Dict[str, Any]]: - """ - Parses content of <table> tags in FIPS .html CMVP page - - :param Union[Tag, NavigableString] element: text in <table> tags - :return List[Dict[str, Any]]: list of all found algorithm IDs - """ - - found_items = [] - trs = element.find_all("tr") - for tr in trs: - tds = tr.find_all("td") - cert = FIPSCertificate.extract_algorithm_certificates(tds[1].text) - if cert is None: - continue - found_items.append( - { - "Name": tds[0].text, - "Certificate": cert[0]["Certificate"] if cert != [] and cert[0] is not None else [], - "Links": [str(x) for x in tds[1].find_all("a")], - "Raw": str(tr), - } - ) - - return found_items - - @staticmethod - def _parse_html_main(current_div: Tag, html_items_found: Dict, pairs: Dict[str, str]) -> None: - title = current_div.find("div", class_="col-md-3").text.strip() - content = ( - current_div.find("div", class_="col-md-9") - .text.strip() - .replace("\n", "") - .replace("\t", "") - .replace(" ", " ") - ) - - if title in pairs: - if "date_sunset" == pairs[title]: - html_items_found[pairs[title]] = parser.parse(content).date() - - elif "caveat" in pairs[title]: - html_items_found[pairs[title]] = content - html_items_found["mentioned_certs"].update(FIPSCertificate.parse_caveat(content)) - - elif "FIPS Algorithms" in title: - html_items_found["algorithms"] += FIPSCertificate.parse_table( - current_div.find("div", class_="col-md-9") - ) - - elif "Algorithms" in title or "Description" in title: - html_items_found["algorithms"] += FIPSCertificate.extract_algorithm_certificates(content) - if "Description" in title: - html_items_found["description"] = content - - elif "tested_conf" in pairs[title] or "exceptions" in pairs[title]: - html_items_found[pairs[title]] = [ - x.text for x in current_div.find("div", class_="col-md-9").find_all("li") - ] - else: - html_items_found[pairs[title]] = content - - @staticmethod - def _parse_vendor(current_div: Tag, html_items_found: Dict, current_file: Path) -> None: - vendor_string = current_div.find("div", "panel-body").find("a") - - if not vendor_string: - vendor_string = list(current_div.find("div", "panel-body").children)[0].strip() - html_items_found["vendor_www"] = "" - else: - html_items_found["vendor_www"] = vendor_string.get("href") - vendor_string = vendor_string.text.strip() - - html_items_found["vendor"] = vendor_string - if html_items_found["vendor"] == "": - logger.warning(f"NO VENDOR FOUND {current_file}") - - @staticmethod - def _parse_lab(current_div: Tag, html_items_found: Dict, current_file: Path) -> None: - html_items_found["lab"] = list(current_div.find("div", "panel-body").children)[0].strip() - html_items_found["nvlap_code"] = ( - list(current_div.find("div", "panel-body").children)[2].strip().split("\n")[1].strip() - ) - - if html_items_found["lab"] == "": - logger.warning(f"NO LAB FOUND {current_file}") - - if html_items_found["nvlap_code"] == "": - logger.warning(f"NO NVLAP CODE FOUND {current_file}") - - @staticmethod - def parse_related_files(current_div: Tag, html_items_found: Dict) -> None: - links = current_div.find_all("a") - html_items_found["security_policy_www"] = constants.FIPS_BASE_URL + links[0].get("href") - - if len(links) == 2: - html_items_found["certificate_www"] = constants.FIPS_BASE_URL + links[1].get("href") - - @staticmethod - def _normalize(items: Dict) -> None: - items["module_type"] = items["module_type"].lower().replace("-", " ").title() - items["embodiment"] = items["embodiment"].lower().replace("-", " ").replace("stand alone", "standalone").title() - - @staticmethod - def _parse_validation_dates(current_div: Tag, html_items_found: Dict) -> None: - table = current_div.find("table") - rows = table.find("tbody").findAll("tr") - html_items_found["date_validation"] = [parser.parse(td.text).date() for td in [row.find("td") for row in rows]] - @classmethod def from_html_file( - cls, file: Path, state: State, initialized: FIPSCertificate = None, redo: bool = False + cls, file: Path, state: InternalState, initialized: FIPSCertificate = None, redo: bool = False ) -> FIPSCertificate: """ Constructs FIPSCertificate object from html file. :param Path file: path to the html file to use for initialization - :param State state: state of the certificate + :param InternalState state: state of the certificate :param FIPSCertificate initialized: possibly partially initialized FIPSCertificate, defaults to None :param bool redo: if the method should be reattempted in case of failure, defaults to False :return FIPSCertificate: resulting `FIPSCertificate` object. """ - pairs = { - "Module Name": "module_name", - "Standard": "standard", - "Status": "status", - "Sunset Date": "date_sunset", - "Validation Dates": "date_validation", - "Overall Level": "level", - "Caveat": "caveat", - "Security Level Exceptions": "exceptions", - "Module Type": "module_type", - "Embodiment": "embodiment", - "FIPS Algorithms": "algorithms", - "Allowed Algorithms": "algorithms", - "Other Algorithms": "algorithms", - "Tested Configuration(s)": "tested_conf", - "Description": "description", - "Historical Reason": "historical_reason", - "Hardware Versions": "hw_versions", - "Firmware Versions": "fw_versions", - "Revoked Reason": "revoked_reason", - "Revoked Link": "revoked_link", - "Software Versions": "sw_versions", - "Product URL": "product_url", - } + if not initialized: items_found = FIPSCertificate._initialize_dictionary() items_found["cert_id"] = int(file.stem) else: - items_found = initialized.web_scan.__dict__ + items_found = initialized.web_data.__dict__ items_found["cert_id"] = initialized.cert_id items_found["revoked_reason"] = None items_found["revoked_link"] = None @@ -547,26 +428,26 @@ class FIPSCertificate(Certificate["FIPSCertificate", "FIPSCertificate.FIPSHeuris text = sec_certs.utils.extract.load_cert_html_file(str(file)) soup = BeautifulSoup(text, "html.parser") for div in soup.find_all("div", class_="row padrow"): - FIPSCertificate._parse_html_main(div, items_found, pairs) + _FIPSHTMLParser.parse_html_main(div, items_found) for div in soup.find_all("div", class_="panel panel-default")[1:]: if div.find("h4", class_="panel-title").text == "Vendor": - FIPSCertificate._parse_vendor(div, items_found, file) + _FIPSHTMLParser.parse_vendor(div, items_found, file) if div.find("h4", class_="panel-title").text == "Lab": - FIPSCertificate._parse_lab(div, items_found, file) + _FIPSHTMLParser.parse_lab(div, items_found, file) if div.find("h4", class_="panel-title").text == "Related Files": - FIPSCertificate.parse_related_files(div, items_found) + _FIPSHTMLParser.parse_related_files(div, items_found) if div.find("h4", class_="panel-title").text == "Validation History": - FIPSCertificate._parse_validation_dates(div, items_found) + _FIPSHTMLParser.parse_validation_dates(div, items_found) - FIPSCertificate._normalize(items_found) + _FIPSHTMLParser.normalize(items_found) return FIPSCertificate( items_found["cert_id"], - FIPSCertificate.WebScan( + FIPSCertificate.WebData( items_found["module_name"] if "module_name" in items_found else None, items_found["standard"] if "standard" in items_found else None, items_found["status"] if "status" in items_found else None, @@ -595,16 +476,79 @@ class FIPSCertificate(Certificate["FIPSCertificate", "FIPSCertificate.FIPSHeuris items_found["sw_versions"] if "sw_versions" in items_found else None, items_found["product_url"] if "product_url" in items_found else None, ), - FIPSCertificate.PdfScan( + FIPSCertificate.PdfData( items_found["cert_id"], - {} if not initialized else initialized.pdf_scan.keywords, - [] if not initialized else initialized.pdf_scan.algorithms, + {} if not initialized else initialized.pdf_data.keywords, + set() if not initialized else initialized.pdf_data.algorithms, + {} if not initialized else initialized.pdf_data.clean_cert_ids, ), - FIPSCertificate.FIPSHeuristics(dict(), [], 0), + FIPSCertificate.Heuristics(dict(), set(), 0, {}), state, ) @staticmethod + def download_html_page(cert: Tuple[str, Path]) -> Optional[Tuple[str, Path]]: + """ + Wrapper for downloading a file. `delay=1` introduced to avoid problems with requests at NIST.gov + + :param Tuple[str, Path] cert: tuple url, output_path + :return Optional[Tuple[str, Path]]: None on success, `cert` on failure. + """ + exit_code = helpers.download_file(*cert, delay=constants.FIPS_DOWNLOAD_DELAY) + if exit_code != requests.codes.ok: + logger.error(f"Failed to download html page from {cert[0]}, code: {exit_code}") + return cert + return None + + @staticmethod + def download_security_policy(cert: Tuple[str, Path]) -> None: + """ + Downloads security policy file from web. Staticmethod to allow for parametrization. + """ + exit_code = helpers.download_file(*cert, delay=constants.FIPS_DOWNLOAD_DELAY) + if exit_code != requests.codes.ok: + logger.error(f"Failed to download security policy from {cert[0]}, code: {exit_code}") + + @staticmethod + def extract_sp_metadata(cert: FIPSCertificate) -> FIPSCertificate: + """Extract the PDF metadata from the security policy. Staticmethod to allow for parametrization.""" + response, cert.pdf_data.st_metadata = sec_certs.utils.pdf.extract_pdf_metadata(cert.state.sp_path) + return cert + + @staticmethod + def _initialize_dictionary() -> Dict[str, Any]: + return { + "module_name": None, + "standard": None, + "status": None, + "date_sunset": None, + "date_validation": None, + "level": None, + "caveat": None, + "exceptions": None, + "module_type": None, + "embodiment": None, + "tested_conf": None, + "description": None, + "vendor": None, + "vendor_www": None, + "lab": None, + "lab_nvlap": None, + "historical_reason": None, + "revoked_reason": None, + "revoked_link": None, + "algorithms": set(), + "mentioned_certs": {}, + "tables_done": False, + "security_policy_www": None, + "certificate_www": None, + "hw_versions": None, + "fw_versions": None, + "sw_versions": None, + "product_url": None, + } + + @staticmethod def convert_pdf_file(tup: Tuple[FIPSCertificate, Path, Path]) -> FIPSCertificate: """ Converts pdf file of FIPSCertificate. Staticmethod to allow for paralelization. @@ -631,56 +575,26 @@ class FIPSCertificate(Certificate["FIPSCertificate", "FIPSCertificate.FIPSHeuris return keywords, cert @staticmethod - def match_web_algs_to_pdf(cert: FIPSCertificate) -> int: - """ - Finds algorithms in FIPSCertificate. Staticmethod to allow for parallelization. - - :param FIPSCertificate cert: cert to search for algorithms. - :return int: number of identified algorithms. - """ - algs_vals = list(cert.pdf_scan.keywords["rules_fips_algorithms"].values()) - table_vals = [x["Certificate"] for x in cert.pdf_scan.algorithms] - tables = [x.strip() for y in table_vals for x in y] - iterable = [alg for x in algs_vals for alg in list(x.keys())] - iterable += tables - all_algorithms = set() - for x in iterable: - if "#" in x: - # erase everything until "#" included and take digits - all_algorithms.add("".join(filter(str.isdigit, x[x.index("#") + 1 :]))) - else: - all_algorithms.add("".join(filter(str.isdigit, x))) - not_found = [] - - if cert.web_scan.algorithms is None: - raise RuntimeError(f"Algorithms were not found for cert {cert.cert_id} - this should not be happening.") - - for alg_list in [a["Certificate"] for a in cert.web_scan.algorithms]: - for web_alg in alg_list: - if "".join(filter(str.isdigit, web_alg)) not in all_algorithms: - not_found.append(web_alg) - return len(not_found) - - @staticmethod - def _remove_platforms(text_to_parse: str) -> str: - pat = re.compile(r"(?:(?:modification|revision|change) history|version control)\n[\s\S]*?", re.IGNORECASE) - for match in pat.finditer(text_to_parse): - text_to_parse = text_to_parse.replace(match.group(), "x" * len(match.group())) - return text_to_parse - - @staticmethod - def analyze_tables(tup: Tuple[FIPSCertificate, bool]) -> Tuple[bool, FIPSCertificate, List]: + def analyze_tables(tup: Tuple[FIPSCertificate, bool]) -> Tuple[bool, FIPSCertificate, Set]: # noqa: C901 """ Searches for tables in pdf documents of the instance. :param Tuple[FIPSCertificate, bool] tup: certificate object, whether to use high precision results or approx. results - :return Tuple[bool, FIPSCertificate, List]: True on success / False otherwise, modified cert object, List of processed tables. + :return Tuple[bool, FIPSCertificate, Set]: True on success / False otherwise, modified cert object, List of processed tables. """ + + def extract_algorithm_certificates(current_text): + set_items = set() + reg = r"(?:#?\s?|(?:Cert)\.?[^. ]*?\s?)(?:[CcAa]\s)?(?P<id>[CcAa]? ?\d+)" + for m in re.finditer(reg, current_text): + set_items.add(m.group()) + return set(map(lambda x: (None, x), set_items)) + cert, precision = tup if (not precision and cert.state.tables_done) or ( precision and cert.heuristics.unmatched_algs < config.cert_threshold ): - return cert.state.tables_done, cert, [] + return cert.state.tables_done, cert, set() cert_file = cert.state.sp_path txt_file = cert_file.with_suffix(".pdf.txt") @@ -688,7 +602,7 @@ class FIPSCertificate(Certificate["FIPSCertificate", "FIPSCertificate.FIPSHeuris tables = sec_certs.utils.tables.find_tables(f.read(), txt_file) all_pages = precision and cert.heuristics.unmatched_algs > config.cert_threshold # bool value - lst: List = [] + lst: Set = set() if tables: try: data = read_pdf(cert_file, pages="all" if all_pages else tables, silent=True) @@ -706,27 +620,15 @@ class FIPSCertificate(Certificate["FIPSCertificate", "FIPSCertificate.FIPSHeuris for df in data: for col in range(len(df.columns)): if "cert" in df.columns[col].lower() or "algo" in df.columns[col].lower(): - tmp = FIPSCertificate.extract_algorithm_certificates( - df.iloc[:, col].to_string(index=False), True - ) - lst += tmp if tmp != [{"Certificate": []}] else [] + tmp = extract_algorithm_certificates(df.iloc[:, col].to_string(index=False)) + lst.update(tmp) # Parse again if someone picks not so descriptive column names - tmp = FIPSCertificate.extract_algorithm_certificates(df.to_string(index=False)) - lst += tmp if tmp != [{"Certificate": []}] else [] + tmp = extract_algorithm_certificates(df.to_string(index=False)) + lst.update(tmp) return True, cert, lst - def _create_alg_set(self) -> Set[str]: - result: Set[str] = set() - - if self.web_scan.algorithms is None: - raise RuntimeError(f"Algorithms were not found for cert {self.cert_id} - this should not be happening.") - - for alg in self.web_scan.algorithms: - result.update(cert for cert in alg["Certificate"]) - return result - def _process_to_pop(self, reg_to_match: Pattern, cert: str, to_pop: Set[str]) -> None: - for found in self.heuristics.keywords["fips_certlike"]["Certlike"]: + for found in self.pdf_data.keywords["fips_certlike"]["Certlike"]: match_in_found = reg_to_match.search(found) match_in_cert = reg_to_match.search(cert) if ( @@ -736,39 +638,40 @@ class FIPSCertificate(Certificate["FIPSCertificate", "FIPSCertificate.FIPSHeuris ): to_pop.add(cert) - for alg_cert in self.heuristics.algorithms: - for cert_no in alg_cert["Certificate"]: - if int("".join(filter(str.isdigit, cert_no))) == int("".join(filter(str.isdigit, cert))): - to_pop.add(cert) + for alg_type, cert_no in self.heuristics.algorithms: + if int("".join(filter(str.isdigit, cert_no))) == int("".join(filter(str.isdigit, cert))): + to_pop.add(cert) - def remove_algorithms(self) -> None: + def clean_cert_ids(self) -> None: """ - Removes algorithms from the certificate. + Removes algorithm mentions from the cert_id rule matches and stores them into clean_cert_id matches. """ self.state.file_status = True - if not self.pdf_scan.keywords: + if not self.pdf_data.keywords: return - self.heuristics.keywords = copy.deepcopy(self.pdf_scan.keywords) + matches = copy.deepcopy(self.pdf_data.keywords["fips_cert_id"]["Cert"]) + + alg_set: Set[str] = set() + if self.web_data.algorithms is None: + raise RuntimeError(f"Algorithms were not found for cert {self.cert_id} - this should not be happening.") + + for alg_type, cert_no in self.web_data.algorithms: + alg_set.update(cert_no) - # # TODO figure out why can't I delete this - # if self.web_scan.mentioned_certs: - # for item, value in self.web_scan.mentioned_certs.items(): - # self.heuristics.keywords["fips_cert_id"].update({"caveat_item": {item: value}}) - # - alg_set = self._create_alg_set() for cert_rule in fips_rules["fips_cert_id"]["Cert"]: to_pop = set() - for cert in self.heuristics.keywords["fips_cert_id"]["Cert"]: + for cert in matches: if cert in alg_set: to_pop.add(cert) continue self._process_to_pop(cert_rule, cert, to_pop) for r in to_pop: - self.heuristics.keywords["fips_cert_id"]["Cert"].pop(r, None) + matches.pop(r, None) - self.heuristics.keywords["fips_cert_id"]["Cert"].pop("#" + str(self.cert_id), None) + matches.pop("#" + str(self.cert_id), None) + self.pdf_data.clean_cert_ids = matches @staticmethod def get_compare(vendor: str) -> str: @@ -785,10 +688,10 @@ class FIPSCertificate(Certificate["FIPSCertificate", "FIPSCertificate.FIPSHeuris Heuristically computes the version of the product. """ versions_for_extraction = "" - if self.web_scan.module_name: - versions_for_extraction += f" {self.web_scan.module_name}" - if self.web_scan.hw_version: - versions_for_extraction += f" {self.web_scan.hw_version}" - if self.web_scan.fw_version: - versions_for_extraction += f" {self.web_scan.fw_version}" + if self.web_data.module_name: + versions_for_extraction += f" {self.web_data.module_name}" + if self.web_data.hw_version: + versions_for_extraction += f" {self.web_data.hw_version}" + if self.web_data.fw_version: + versions_for_extraction += f" {self.web_data.fw_version}" self.heuristics.extracted_versions = helpers.compute_heuristics_version(versions_for_extraction) diff --git a/sec_certs/sample/fips_algorithm.py b/sec_certs/sample/fips_algorithm.py new file mode 100644 index 00000000..fcfd42b6 --- /dev/null +++ b/sec_certs/sample/fips_algorithm.py @@ -0,0 +1,31 @@ +from dataclasses import dataclass + +from sec_certs import constants +from sec_certs.serialization.json import ComplexSerializableType + + +@dataclass(eq=True) +class FIPSAlgorithm(ComplexSerializableType): + """ + Data structure for algorithm of `FIPSCertificate` + """ + + cert_id: int + vendor: str + implementation: str + algorithm_type: str + date: str + + @property + def dgst(self) -> str: + return f"{self.algorithm_type}#{self.cert_id}" + + @property + def page_url(self) -> str: + return constants.FIPS_ALG_URL.format(self.algorithm_type, self.cert_id) + + def __repr__(self) -> str: + return f"FIPSAlgorithm({self.dgst})" + + def __str__(self) -> str: + return f"{self.algorithm_type} algorithm # {self.cert_id} created by {self.vendor}" diff --git a/sec_certs/sample/fips_iut.py b/sec_certs/sample/fips_iut.py index 3182585c..2fab9a56 100644 --- a/sec_certs/sample/fips_iut.py +++ b/sec_certs/sample/fips_iut.py @@ -6,6 +6,7 @@ from typing import Dict, Iterator, List, Mapping, Optional, Set, Union import requests from bs4 import BeautifulSoup, Tag +from sec_certs import constants from sec_certs.serialization.json import ComplexSerializableType from sec_certs.utils.helpers import to_utc @@ -132,10 +133,9 @@ class IUTSnapshot(ComplexSerializableType): @classmethod def from_web(cls) -> "IUTSnapshot": - iut_url = "https://csrc.nist.gov/Projects/cryptographic-module-validation-program/modules-in-process/IUT-List" - iut_resp = requests.get(iut_url) + iut_resp = requests.get(constants.FIPS_IUT_URL) if iut_resp.status_code != 200: - raise ValueError("Getting MIP snapshot failed") + raise ValueError(f"Getting IUT snapshot failed: {iut_resp.status_code}") snapshot_date = to_utc(datetime.now()) return cls.from_page(iut_resp.content, snapshot_date) diff --git a/sec_certs/sample/fips_mip.py b/sec_certs/sample/fips_mip.py index 0a95c74e..4bb33904 100644 --- a/sec_certs/sample/fips_mip.py +++ b/sec_certs/sample/fips_mip.py @@ -8,6 +8,7 @@ from typing import Dict, Iterator, List, Mapping, Optional, Set, Union import requests from bs4 import BeautifulSoup, Tag +from sec_certs import constants from sec_certs.constants import FIPS_MIP_STATUS_RE from sec_certs.serialization.json import ComplexSerializableType from sec_certs.utils.helpers import to_utc @@ -208,10 +209,9 @@ class MIPSnapshot(ComplexSerializableType): @classmethod def from_web(cls) -> "MIPSnapshot": - mip_url = "https://csrc.nist.gov/Projects/cryptographic-module-validation-program/modules-in-process/Modules-In-Process-List" - mip_resp = requests.get(mip_url) + mip_resp = requests.get(constants.FIPS_MIP_URL) if mip_resp.status_code != 200: - raise ValueError("Getting MIP snapshot failed") + raise ValueError(f"Getting MIP snapshot failed: {mip_resp.status_code}") snapshot_date = to_utc(datetime.now()) return cls.from_page(mip_resp.content, snapshot_date) diff --git a/sec_certs/serialization/json.py b/sec_certs/serialization/json.py index 1664f799..bca80643 100644 --- a/sec_certs/serialization/json.py +++ b/sec_certs/serialization/json.py @@ -3,12 +3,14 @@ import json from datetime import date from functools import wraps from pathlib import Path -from typing import Any, Callable, Dict, List, Optional, Type, TypeVar, Union +from typing import Any, Callable, Dict, List, Optional, Tuple, Type, TypeVar, Union T = TypeVar("T") class ComplexSerializableType: + __slots__: Tuple[str] + def __init__(self, *args, **kwargs): pass @@ -72,10 +74,21 @@ def serialize(func: Callable): return inner_func +def _class_fullname(obj: Any) -> str: + if isinstance(obj, type): + klass = obj + else: + klass = obj.__class__ + module = klass.__module__ + if module == "builtins": + return klass.__qualname__ + return module + "." + klass.__qualname__ + + class CustomJSONEncoder(json.JSONEncoder): def default(self, obj): if isinstance(obj, ComplexSerializableType): - return {**{"_type": type(obj).__name__}, **obj.to_dict()} + return {**{"_type": _class_fullname(obj)}, **obj.to_dict()} if isinstance(obj, dict): return obj if isinstance(obj, set): @@ -98,7 +111,7 @@ class CustomJSONDecoder(json.JSONDecoder): def __init__(self, *args, **kwargs): json.JSONDecoder.__init__(self, object_hook=self.object_hook, *args, **kwargs) - self.serializable_complex_types = {x.__name__: x for x in ComplexSerializableType.__subclasses__()} + self.serializable_complex_types = {_class_fullname(x): x for x in ComplexSerializableType.__subclasses__()} def object_hook(self, obj): if "_type" in obj and obj["_type"] == "Set": @@ -106,5 +119,7 @@ class CustomJSONDecoder(json.JSONDecoder): if "_type" in obj and obj["_type"] in self.serializable_complex_types.keys(): complex_type = obj.pop("_type") return self.serializable_complex_types[complex_type].from_dict(obj) + elif "_type" in obj: + print(obj) return obj diff --git a/sec_certs/utils/extract.py b/sec_certs/utils/extract.py index 97568867..dce82ca5 100644 --- a/sec_certs/utils/extract.py +++ b/sec_certs/utils/extract.py @@ -581,25 +581,11 @@ def search_only_headers_canada(filepath: Path): # noqa: C901 return constants.RETURNCODE_OK, items_found -def search_files(folder: str) -> Iterator[str]: - for root, _, files in os.walk(folder): +def search_files(folder: Union[str, Path]) -> Iterator[str]: + for root, _, files in os.walk(str(folder)): yield from [os.path.join(root, x) for x in files] -def save_modified_cert_file(target_file: Union[str, Path], modified_cert_file_text: str, is_unicode_text: bool) -> None: - if is_unicode_text: - write_file = Path(target_file).open("w", encoding="utf8", errors="replace") - else: - write_file = Path(target_file).open("w", errors="replace") - - try: - write_file.write(modified_cert_file_text) - except UnicodeEncodeError: - logger.error("UnicodeDecodeError while writing file fragments back") - finally: - write_file.close() - - def flatten_matches(dct: Dict) -> Dict: """ Function to flatten dictionary of matches. diff --git a/sec_certs/utils/helpers.py b/sec_certs/utils/helpers.py index faaaef0d..3e3e2bb9 100644 --- a/sec_certs/utils/helpers.py +++ b/sec_certs/utils/helpers.py @@ -34,7 +34,7 @@ def download_file( time.sleep(delay) # See https://github.com/psf/requests/issues/3953 for header justification r = requests.get( - url, allow_redirects=True, timeout=constants.REQUEST_TIMEOUT, stream=True, headers={"Accept-Encoding": None} + url, allow_redirects=True, timeout=constants.REQUEST_TIMEOUT, stream=True, headers={"Accept-Encoding": None} # type: ignore ) ctx: Any if show_progress_bar: @@ -48,6 +48,7 @@ def download_file( ) else: ctx = nullcontext + if r.status_code == requests.codes.ok: with ctx() as pbar: with output.open("wb") as f: diff --git a/sec_certs/utils/pdf.py b/sec_certs/utils/pdf.py index 11d09947..0f272d1b 100644 --- a/sec_certs/utils/pdf.py +++ b/sec_certs/utils/pdf.py @@ -10,7 +10,7 @@ from typing import Any, Dict, Optional, Tuple import pdftotext import pikepdf from PyPDF2 import PdfFileReader -from PyPDF2.generic import BooleanObject, FloatObject, IndirectObject, NumberObject +from PyPDF2.generic import BooleanObject, ByteStringObject, FloatObject, IndirectObject, NumberObject, TextStringObject from sec_certs import constants as constants from sec_certs.constants import ( @@ -156,6 +156,13 @@ def extract_pdf_metadata(filepath: Path) -> Tuple[str, Optional[Dict[str, Any]]] elif isinstance(val, IndirectObject) and not nope_out: # Let's make sure to nope out in case of cycles val = map_metadata_value(val.getObject(), nope_out=True) + elif isinstance(val, TextStringObject): + val = str(val) + elif isinstance(val, ByteStringObject): + try: + val = val.decode("utf-8") + except UnicodeDecodeError: + val = str(val) else: val = str(val) return val @@ -183,6 +190,7 @@ def extract_pdf_metadata(filepath: Path) -> Tuple[str, Optional[Dict[str, Any]]] for key, val in pdf_document_info.items(): metadata[str(key)] = map_metadata_value(val) + # Get the hyperlinks in the PDF annots = [page.get("/Annots", []) for page in pdf.pages] annots = reduce(lambda x, y: x + y, annots) links = set() @@ -193,7 +201,7 @@ def extract_pdf_metadata(filepath: Path) -> Tuple[str, Optional[Dict[str, Any]]] note = a link = note.get("/A", {}).get("/URI") if link: - links.add(link) + links.add(map_metadata_value(link)) metadata["pdf_hyperlinks"] = links except Exception as e: diff --git a/tests/data/test_cc_heuristics/auxillary_datasets/cpe_dataset.json b/tests/data/test_cc_heuristics/auxillary_datasets/cpe_dataset.json index 24d22194..559a3b57 100644 --- a/tests/data/test_cc_heuristics/auxillary_datasets/cpe_dataset.json +++ b/tests/data/test_cc_heuristics/auxillary_datasets/cpe_dataset.json @@ -1,30 +1,30 @@ { - "_type": "CPEDataset", + "_type": "sec_certs.dataset.cpe.CPEDataset", "was_enhanced_with_vuln_cpes": true, "cpes": { "cpe:2.3:a:ibm:security_access_manager_for_enterprise_single_sign-on:8.2.2:*:*:*:*:*:*:*": { - "_type": "CPE", + "_type": "sec_certs.sample.cpe.CPE", "uri": "cpe:2.3:a:ibm:security_access_manager_for_enterprise_single_sign-on:8.2.2:*:*:*:*:*:*:*", "title": "IBM Security Access Manager For Enterprise Single Sign-On 8.2.2", "start_version": null, "end_version": null }, "cpe:2.3:a:ibm:security_key_lifecycle_manager:2.6.0.1:*:*:*:*:*:*:*": { - "_type": "CPE", + "_type": "sec_certs.sample.cpe.CPE", "uri": "cpe:2.3:a:ibm:security_key_lifecycle_manager:2.6.0.1:*:*:*:*:*:*:*", "title": "IBM Security Key Lifecycle Manager 2.6.0.1", "start_version": null, "end_version": null }, "cpe:2.3:a:semperplugins:all_in_one_seo_pack:1.3.6.4:*:*:*:*:wordpress:*:*": { - "_type": "CPE", + "_type": "sec_certs.sample.cpe.CPE", "uri": "cpe:2.3:a:semperplugins:all_in_one_seo_pack:1.3.6.4:*:*:*:*:wordpress:*:*", "title": "Semper Plugins All in One SEO Pack 1.3.6.4 for WordPress", "start_version": null, "end_version": null }, "cpe:2.3:a:tracker-software:pdf-xchange_lite_printer:6.0.320.0:*:*:*:*:*:*:*": { - "_type": "CPE", + "_type": "sec_certs.sample.cpe.CPE", "uri": "cpe:2.3:a:tracker-software:pdf-xchange_lite_printer:6.0.320.0:*:*:*:*:*:*:*", "title": "Tracker Software PDF-XChange Lite Printer 6.0.320.0", "start_version": null, diff --git a/tests/data/test_cc_heuristics/auxillary_datasets/cve_dataset.json b/tests/data/test_cc_heuristics/auxillary_datasets/cve_dataset.json index 08bd614c..b71d5c62 100644 --- a/tests/data/test_cc_heuristics/auxillary_datasets/cve_dataset.json +++ b/tests/data/test_cc_heuristics/auxillary_datasets/cve_dataset.json @@ -1,12 +1,12 @@ { - "_type": "CVEDataset", + "_type": "sec_certs.dataset.cve.CVEDataset", "cves": { "CVE-2017-1732": { - "_type": "CVE", + "_type": "sec_certs.sample.cve.CVE", "cve_id": "CVE-2017-1732", "vulnerable_cpes": [ { - "_type": "CPE", + "_type": "sec_certs.sample.cpe.CPE", "uri": "cpe:2.3:a:ibm:security_access_manager_for_enterprise_single_sign-on:8.2.2:*:*:*:*:*:*:*", "title": "IBM Security Access Manager For Enterprise Single Sign-On 8.2.2", "start_version": null, @@ -14,7 +14,7 @@ } ], "impact": { - "_type": "Impact", + "_type": "sec_certs.sample.cve.CVE.Impact", "base_score": 5.3, "severity": "MEDIUM", "exploitability_score": 3.9, @@ -29,11 +29,11 @@ } }, "CVE-2019-4513": { - "_type": "CVE", + "_type": "sec_certs.sample.cve.CVE", "cve_id": "CVE-2019-4513", "vulnerable_cpes": [ { - "_type": "CPE", + "_type": "sec_certs.sample.cpe.CPE", "uri": "cpe:2.3:a:ibm:security_access_manager_for_enterprise_single_sign-on:8.2.2:*:*:*:*:*:*:*", "title": "IBM Security Access Manager For Enterprise Single Sign-On 8.2.2", "start_version": null, @@ -41,7 +41,7 @@ } ], "impact": { - "_type": "Impact", + "_type": "sec_certs.sample.cve.CVE.Impact", "base_score": 8.2, "severity": "HIGH", "exploitability_score": 3.9, diff --git a/tests/data/test_cc_heuristics/dependency_dataset.json b/tests/data/test_cc_heuristics/dependency_dataset.json index 044da1c7..3122a40a 100644 --- a/tests/data/test_cc_heuristics/dependency_dataset.json +++ b/tests/data/test_cc_heuristics/dependency_dataset.json @@ -1,7 +1,7 @@ { - "_type": "CCDataset", + "_type": "sec_certs.dataset.common_criteria.CCDataset", "state": { - "_type": "DatasetInternalState", + "_type": "sec_certs.dataset.common_criteria.CCDataset.DatasetInternalState", "meta_sources_parsed": false, "pdfs_downloaded": false, "pdfs_converted": false, @@ -14,7 +14,7 @@ "n_certs": 3, "certs": [ { - "_type": "CommonCriteriaCert", + "_type": "sec_certs.sample.common_criteria.CommonCriteriaCert", "dgst": "c30de3192d2e8ec2", "status": "archived", "category": "Other Devices and Systems", @@ -43,7 +43,7 @@ "elements": [] }, "state": { - "_type": "InternalState", + "_type": "sec_certs.sample.common_criteria.CommonCriteriaCert.InternalState", "st_download_ok": true, "report_download_ok": true, "st_convert_ok": true, @@ -57,7 +57,7 @@ "report_txt_hash": "460e8010dbc8f5de5b87bf96fd45c71cfd9f3869f34ca6ac1ab02cbd70d2523f" }, "pdf_data": { - "_type": "PdfData", + "_type": "sec_certs.sample.common_criteria.CommonCriteriaCert.PdfData", "report_metadata": { "pdf_file_size_bytes": 393439, "pdf_is_encrypted": false, @@ -469,7 +469,7 @@ } }, "heuristics": { - "_type": "CCHeuristics", + "_type": "sec_certs.sample.common_criteria.CommonCriteriaCert.Heuristics", "extracted_versions": { "_type": "Set", "elements": [ @@ -484,14 +484,14 @@ ], "cert_id": "BSI-DSZ-CC-0517-2009", "st_references": { - "_type": "References", + "_type": "sec_certs.sample.certificate.References", "directly_referenced_by": null, "indirectly_referenced_by": null, "directly_referencing": null, "indirectly_referencing": null }, "report_references": { - "_type": "References", + "_type": "sec_certs.sample.certificate.References", "directly_referenced_by": null, "indirectly_referenced_by": null, "directly_referencing": { @@ -513,57 +513,57 @@ "_type": "Set", "elements": [ { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ADV_FSP", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ADV_HLD", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ADV_RCR", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "AGD_ADM", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "AGD_USR", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ALC_FLR", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ATE_COV", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ATE_FUN", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ATE_IND", "level": 2 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "AVA_SOF", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "AVA_VLA", "level": 1 } @@ -574,7 +574,7 @@ } }, { - "_type": "CommonCriteriaCert", + "_type": "sec_certs.sample.common_criteria.CommonCriteriaCert", "dgst": "53fe111411edfa45", "status": "archived", "category": "Other Devices and Systems", @@ -603,7 +603,7 @@ "elements": [] }, "state": { - "_type": "InternalState", + "_type": "sec_certs.sample.common_criteria.CommonCriteriaCert.InternalState", "st_download_ok": true, "report_download_ok": true, "st_convert_ok": true, @@ -617,7 +617,7 @@ "report_txt_hash": "0535df1c56fb4f87153cbffee51ba4d77fac47a6f17f024aa7d9df461028bc65" }, "pdf_data": { - "_type": "PdfData", + "_type": "sec_certs.sample.common_criteria.CommonCriteriaCert.PdfData", "report_metadata": { "pdf_file_size_bytes": 296713, "pdf_is_encrypted": false, @@ -1058,7 +1058,7 @@ } }, "heuristics": { - "_type": "CCHeuristics", + "_type": "sec_certs.sample.common_criteria.CommonCriteriaCert.Heuristics", "extracted_versions": { "_type": "Set", "elements": [ @@ -1073,14 +1073,14 @@ ], "cert_id": "BSI-DSZ-CC-0370-2006", "st_references": { - "_type": "References", + "_type": "sec_certs.sample.certificate.References", "directly_referenced_by": null, "indirectly_referenced_by": null, "directly_referencing": null, "indirectly_referencing": null }, "report_references": { - "_type": "References", + "_type": "sec_certs.sample.certificate.References", "directly_referenced_by": { "_type": "Set", "elements": [ @@ -1111,97 +1111,97 @@ "_type": "Set", "elements": [ { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ADV_FSP", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ADV_HLD", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ADV_RCR", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "AGD_ADM", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "AGD_USR", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ALC_FLR", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ASE_DES", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ASE_ENV", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ASE_INT", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ASE_OBJ", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ASE_PPC", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ASE_REQ", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ASE_SRE", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ASE_TSS", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ATE_COV", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ATE_FUN", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ATE_IND", "level": 2 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "AVA_SOF", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "AVA_VLA", "level": 1 } @@ -1212,7 +1212,7 @@ } }, { - "_type": "CommonCriteriaCert", + "_type": "sec_certs.sample.common_criteria.CommonCriteriaCert", "dgst": "692e91451741ef49", "status": "archived", "category": "Other Devices and Systems", @@ -1241,7 +1241,7 @@ "elements": [] }, "state": { - "_type": "InternalState", + "_type": "sec_certs.sample.common_criteria.CommonCriteriaCert.InternalState", "st_download_ok": true, "report_download_ok": true, "st_convert_ok": true, @@ -1255,7 +1255,7 @@ "report_txt_hash": "11e1262fd8f5df1b140f5e8813883b71447503781399427b35adbbecd00b4d63" }, "pdf_data": { - "_type": "PdfData", + "_type": "sec_certs.sample.common_criteria.CommonCriteriaCert.PdfData", "report_metadata": { "pdf_file_size_bytes": 628533, "pdf_is_encrypted": false, @@ -1690,7 +1690,7 @@ } }, "heuristics": { - "_type": "CCHeuristics", + "_type": "sec_certs.sample.common_criteria.CommonCriteriaCert.Heuristics", "extracted_versions": { "_type": "Set", "elements": [ @@ -1705,14 +1705,14 @@ ], "cert_id": "BSI-DSZ-CC-0325-2006", "st_references": { - "_type": "References", + "_type": "sec_certs.sample.certificate.References", "directly_referenced_by": null, "indirectly_referenced_by": null, "directly_referencing": null, "indirectly_referencing": null }, "report_references": { - "_type": "References", + "_type": "sec_certs.sample.certificate.References", "directly_referenced_by": { "_type": "Set", "elements": [ @@ -1743,97 +1743,97 @@ "_type": "Set", "elements": [ { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ADV_FSP", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ADV_HLD", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ADV_RCR", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "AGD_ADM", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "AGD_USR", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ALC_FLR", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ASE_DES", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ASE_ENV", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ASE_INT", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ASE_OBJ", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ASE_PPC", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ASE_REQ", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ASE_SRE", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ASE_TSS", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ATE_COV", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ATE_FUN", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ATE_IND", "level": 2 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "AVA_SOF", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "AVA_VLA", "level": 1 } diff --git a/tests/data/test_cc_heuristics/dependency_vulnerability_dataset.json b/tests/data/test_cc_heuristics/dependency_vulnerability_dataset.json index 672f888a..d2782e51 100644 --- a/tests/data/test_cc_heuristics/dependency_vulnerability_dataset.json +++ b/tests/data/test_cc_heuristics/dependency_vulnerability_dataset.json @@ -1,7 +1,7 @@ { - "_type": "CCDataset", + "_type": "sec_certs.dataset.common_criteria.CCDataset", "state": { - "_type": "DatasetInternalState", + "_type": "sec_certs.dataset.common_criteria.CCDataset.DatasetInternalState", "meta_sources_parsed": false, "pdfs_downloaded": false, "pdfs_converted": false, @@ -14,7 +14,7 @@ "n_certs": 3, "certs": [ { - "_type": "CommonCriteriaCert", + "_type": "sec_certs.sample.common_criteria.CommonCriteriaCert", "dgst": "d0705c9e6fbaeba3", "status": "active", "category": "Operating Systems", @@ -38,7 +38,7 @@ "_type": "Set", "elements": [ { - "_type": "ProtectionProfile", + "_type": "sec_certs.sample.protection_profile.ProtectionProfile", "pp_name": "Operating System Protection Profile, Version 2.0", "pp_link": "https://www.commoncriteriaportal.org/files/ppfiles/pp0067b_pdf.pdf", "pp_ids": [ @@ -52,7 +52,7 @@ "elements": [] }, "state": { - "_type": "InternalState", + "_type": "sec_certs.sample.common_criteria.CommonCriteriaCert.InternalState", "st_download_ok": true, "report_download_ok": true, "st_convert_ok": true, @@ -66,7 +66,7 @@ "report_txt_hash": "9d360141a98e764b15855f519b456c4e4639f993c4f8b5ab67e9c8ae7fbfc9e4" }, "pdf_data": { - "_type": "PdfData", + "_type": "sec_certs.sample.common_criteria.CommonCriteriaCert.PdfData", "report_metadata": { "pdf_file_size_bytes": 1235750, "pdf_is_encrypted": false, @@ -1061,7 +1061,7 @@ } }, "heuristics": { - "_type": "CCHeuristics", + "_type": "sec_certs.sample.common_criteria.CommonCriteriaCert.Heuristics", "extracted_versions": { "_type": "Set", "elements": [ @@ -1099,14 +1099,14 @@ ], "cert_id": "BSI-DSZ-CC-0874-2014", "st_references": { - "_type": "References", + "_type": "sec_certs.sample.certificate.References", "directly_referenced_by": null, "indirectly_referenced_by": null, "directly_referencing": null, "indirectly_referencing": null }, "report_references": { - "_type": "References", + "_type": "sec_certs.sample.certificate.References", "directly_referenced_by": { "_type": "Set", "elements": [ @@ -1148,167 +1148,167 @@ "_type": "Set", "elements": [ { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ADV_ARC", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ADV_FSP", "level": 4 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ADV_IMP", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ADV_INT", "level": 3 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ADV_SPM", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ADV_TDS", "level": 3 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "AGD_OPE", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "AGD_PRE", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ALC_CMC", "level": 4 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ALC_CMS", "level": 4 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ALC_DEL", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ALC_DVS", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ALC_FLR", "level": 3 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ALC_LCD", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ALC_TAT", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "APE_CCL", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "APE_ECD", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "APE_INT", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "APE_OBJ", "level": 2 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "APE_REQ", "level": 2 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "APE_SPD", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ASE_CCL", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ASE_ECD", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ASE_INT", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ASE_OBJ", "level": 2 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ASE_REQ", "level": 2 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ASE_SPD", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ASE_TSS", "level": 2 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ATE_COV", "level": 2 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ATE_DPT", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ATE_FUN", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ATE_IND", "level": 2 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "AVA_VAN", "level": 3 } @@ -1329,7 +1329,7 @@ } }, { - "_type": "CommonCriteriaCert", + "_type": "sec_certs.sample.common_criteria.CommonCriteriaCert", "dgst": "011796336c7b94de", "status": "archived", "category": "Operating Systems", @@ -1358,7 +1358,7 @@ "elements": [] }, "state": { - "_type": "InternalState", + "_type": "sec_certs.sample.common_criteria.CommonCriteriaCert.InternalState", "st_download_ok": true, "report_download_ok": true, "st_convert_ok": true, @@ -1372,7 +1372,7 @@ "report_txt_hash": "dd120ba7667c2385839c96ee70c56f2a4d464fc95e3ea2818d31b3347d06fd4f" }, "pdf_data": { - "_type": "PdfData", + "_type": "sec_certs.sample.common_criteria.CommonCriteriaCert.PdfData", "report_metadata": { "pdf_file_size_bytes": 1178202, "pdf_is_encrypted": false, @@ -2015,7 +2015,7 @@ } }, "heuristics": { - "_type": "CCHeuristics", + "_type": "sec_certs.sample.common_criteria.CommonCriteriaCert.Heuristics", "extracted_versions": { "_type": "Set", "elements": [ @@ -2041,14 +2041,14 @@ ], "cert_id": "BSI-DSZ-CC-0875-2015", "st_references": { - "_type": "References", + "_type": "sec_certs.sample.certificate.References", "directly_referenced_by": null, "indirectly_referenced_by": null, "directly_referencing": null, "indirectly_referencing": null }, "report_references": { - "_type": "References", + "_type": "sec_certs.sample.certificate.References", "directly_referenced_by": { "_type": "Set", "elements": [ @@ -2089,167 +2089,167 @@ "_type": "Set", "elements": [ { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ADV_ARC", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ADV_FSP", "level": 5 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ADV_IMP", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ADV_INT", "level": 2 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ADV_SPM", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ADV_TDS", "level": 4 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "AGD_OPE", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "AGD_PRE", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ALC_CMC", "level": 4 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ALC_CMS", "level": 5 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ALC_DEL", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ALC_DVS", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ALC_FLR", "level": 3 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ALC_LCD", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ALC_TAT", "level": 2 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "APE_CCL", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "APE_ECD", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "APE_INT", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "APE_OBJ", "level": 2 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "APE_REQ", "level": 2 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "APE_SPD", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ASE_CCL", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ASE_ECD", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ASE_INT", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ASE_OBJ", "level": 2 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ASE_REQ", "level": 2 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ASE_SPD", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ASE_TSS", "level": 2 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ATE_COV", "level": 2 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ATE_DPT", "level": 3 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ATE_FUN", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ATE_IND", "level": 2 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "AVA_VAN", "level": 4 } @@ -2270,7 +2270,7 @@ } }, { - "_type": "CommonCriteriaCert", + "_type": "sec_certs.sample.common_criteria.CommonCriteriaCert", "dgst": "ebc77980250ee68f", "status": "active", "category": "Operating Systems", @@ -2294,7 +2294,7 @@ "_type": "Set", "elements": [ { - "_type": "ProtectionProfile", + "_type": "sec_certs.sample.protection_profile.ProtectionProfile", "pp_name": "Operating System Protection Profile, Version 2.0", "pp_link": "https://www.commoncriteriaportal.org/files/ppfiles/pp0067b_pdf.pdf", "pp_ids": [ @@ -2308,7 +2308,7 @@ "elements": [] }, "state": { - "_type": "InternalState", + "_type": "sec_certs.sample.common_criteria.CommonCriteriaCert.InternalState", "st_download_ok": true, "report_download_ok": true, "st_convert_ok": true, @@ -2322,7 +2322,7 @@ "report_txt_hash": "0a7c65e3d11f082c8f75aba7de0079c0b1aa5e67bb28d4635cbcaa4cd200d1c2" }, "pdf_data": { - "_type": "PdfData", + "_type": "sec_certs.sample.common_criteria.CommonCriteriaCert.PdfData", "report_metadata": { "pdf_file_size_bytes": 1932018, "pdf_is_encrypted": false, @@ -3381,7 +3381,7 @@ } }, "heuristics": { - "_type": "CCHeuristics", + "_type": "sec_certs.sample.common_criteria.CommonCriteriaCert.Heuristics", "extracted_versions": { "_type": "Set", "elements": [ @@ -3406,14 +3406,14 @@ ], "cert_id": "BSI-DSZ-CC-0948-2017", "st_references": { - "_type": "References", + "_type": "sec_certs.sample.certificate.References", "directly_referenced_by": null, "indirectly_referenced_by": null, "directly_referencing": null, "indirectly_referencing": null }, "report_references": { - "_type": "References", + "_type": "sec_certs.sample.certificate.References", "directly_referenced_by": null, "indirectly_referenced_by": null, "directly_referencing": { @@ -3441,167 +3441,167 @@ "_type": "Set", "elements": [ { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ADV_ARC", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ADV_FSP", "level": 4 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ADV_IMP", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ADV_INT", "level": 3 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ADV_SPM", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ADV_TDS", "level": 3 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "AGD_OPE", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "AGD_PRE", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ALC_CMC", "level": 4 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ALC_CMS", "level": 4 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ALC_DEL", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ALC_DVS", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ALC_FLR", "level": 3 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ALC_LCD", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ALC_TAT", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "APE_CCL", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "APE_ECD", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "APE_INT", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "APE_OBJ", "level": 2 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "APE_REQ", "level": 2 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "APE_SPD", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ASE_CCL", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ASE_ECD", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ASE_INT", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ASE_OBJ", "level": 2 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ASE_REQ", "level": 2 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ASE_SPD", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ASE_TSS", "level": 2 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ATE_COV", "level": 2 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ATE_DPT", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ATE_FUN", "level": 1 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "ATE_IND", "level": 2 }, { - "_type": "SAR", + "_type": "sec_certs.sample.sar.SAR", "family": "AVA_VAN", "level": 3 } diff --git a/tests/data/test_cc_heuristics/vulnerable_dataset.json b/tests/data/test_cc_heuristics/vulnerable_dataset.json index f6fc18bb..e4c3e393 100644 --- a/tests/data/test_cc_heuristics/vulnerable_dataset.json +++ b/tests/data/test_cc_heuristics/vulnerable_dataset.json @@ -1,7 +1,7 @@ { - "_type": "CCDataset", + "_type": "sec_certs.dataset.common_criteria.CCDataset", "state": { - "_type": "DatasetInternalState", + "_type": "sec_certs.dataset.common_criteria.CCDataset.DatasetInternalState", "meta_sources_parsed": true, "pdfs_downloaded": false, "pdfs_converted": false, @@ -13,7 +13,7 @@ "description": "sample dataset description", "n_certs": 1, "certs": [{ - "_type": "CommonCriteriaCert", + "_type": "sec_certs.sample.common_criteria.CommonCriteriaCert", "dgst": "c01e5375331b25dc", "status": "active", "category": "Access Control Devices and Systems", @@ -36,7 +36,7 @@ "protection_profiles": [], "maintenance_updates": [], "state": { - "_type": "InternalState", + "_type": "sec_certs.sample.common_criteria.CommonCriteriaCert.InternalState", "st_download_ok": true, "report_download_ok": true, "st_convert_ok": true, @@ -46,7 +46,7 @@ "errors": [] }, "pdf_data": { - "_type": "PdfData", + "_type": "sec_certs.sample.common_criteria.CommonCriteriaCert.PdfData", "report_metadata": null, "st_metadata": null, "report_frontpage": null, @@ -55,7 +55,7 @@ "st_keywords": null }, "heuristics": { - "_type": "CCHeuristics", + "_type": "sec_certs.sample.common_criteria.CommonCriteriaCert.Heuristics", "extracted_versions": [ "8.2" ], diff --git a/tests/data/test_cc_oop/fictional_cert.json b/tests/data/test_cc_oop/fictional_cert.json index 7d74759c..eff37f01 100644 --- a/tests/data/test_cc_oop/fictional_cert.json +++ b/tests/data/test_cc_oop/fictional_cert.json @@ -1,5 +1,5 @@ { - "_type": "CommonCriteriaCert", + "_type": "sec_certs.sample.common_criteria.CommonCriteriaCert", "dgst": "a9ccb81a92e547dc", "status": "archived", "category": "Sample category", @@ -18,7 +18,7 @@ "protection_profiles": { "_type": "Set", "elements": [{ - "_type": "ProtectionProfile", + "_type": "sec_certs.sample.protection_profile.ProtectionProfile", "pp_name": "sample_pp", "pp_link": "https://sample.pp", "pp_ids": null @@ -27,7 +27,7 @@ "maintenance_updates": { "_type": "Set", "elements": [{ - "_type": "MaintenanceReport", + "_type": "sec_certs.sample.common_criteria.CommonCriteriaCert.MaintenanceReport", "maintenance_date": "1900-01-01", "maintenance_title": "Sample maintenance", "maintenance_report_link": "https://maintenance.up", @@ -35,7 +35,7 @@ }] }, "state": { - "_type": "InternalState", + "_type": "sec_certs.sample.common_criteria.CommonCriteriaCert.InternalState", "st_download_ok": true, "report_download_ok": true, "st_convert_ok": true, @@ -49,7 +49,7 @@ "report_txt_hash": null }, "pdf_data": { - "_type": "PdfData", + "_type": "sec_certs.sample.common_criteria.CommonCriteriaCert.PdfData", "report_metadata": null, "st_metadata": null, "report_frontpage": null, @@ -58,7 +58,7 @@ "st_keywords": null }, "heuristics": { - "_type": "CCHeuristics", + "_type": "sec_certs.sample.common_criteria.CommonCriteriaCert.Heuristics", "extracted_versions": null, "cpe_matches": null, "verified_cpe_matches": null, @@ -69,14 +69,14 @@ "direct_dependency_cves": null, "indirect_dependency_cves": null, "report_references": { - "_type": "References", + "_type": "sec_certs.sample.certificate.References", "directly_referenced_by": null, "directly_referencing": null, "indirectly_referenced_by": null, "indirectly_referencing": null }, "st_references": { - "_type": "References", + "_type": "sec_certs.sample.certificate.References", "directly_referenced_by": null, "directly_referencing": null, "indirectly_referenced_by": null, diff --git a/tests/data/test_cc_oop/toy_dataset.json b/tests/data/test_cc_oop/toy_dataset.json index 91669453..da63500f 100644 --- a/tests/data/test_cc_oop/toy_dataset.json +++ b/tests/data/test_cc_oop/toy_dataset.json @@ -1,7 +1,7 @@ { - "_type": "CCDataset", + "_type": "sec_certs.dataset.common_criteria.CCDataset", "state": { - "_type": "DatasetInternalState", + "_type": "sec_certs.dataset.common_criteria.CCDataset.DatasetInternalState", "meta_sources_parsed": true, "pdfs_downloaded": false, "pdfs_converted": false, @@ -13,7 +13,7 @@ "description": "toy dataset description", "n_certs": 2, "certs": [{ - "_type": "CommonCriteriaCert", + "_type": "sec_certs.sample.common_criteria.CommonCriteriaCert", "dgst": "309ac2fd7f2dcf17", "status": "active", "category": "Access Control Devices and Systems", @@ -42,7 +42,7 @@ "elements": [] }, "state": { - "_type": "InternalState", + "_type": "sec_certs.sample.common_criteria.CommonCriteriaCert.InternalState", "st_download_ok": true, "report_download_ok": true, "st_convert_ok": true, @@ -56,7 +56,7 @@ "report_txt_hash": null }, "pdf_data": { - "_type": "PdfData", + "_type": "sec_certs.sample.common_criteria.CommonCriteriaCert.PdfData", "report_metadata": null, "st_metadata": null, "report_frontpage": null, @@ -65,7 +65,7 @@ "st_keywords": null }, "heuristics": { - "_type": "CCHeuristics", + "_type": "sec_certs.sample.common_criteria.CommonCriteriaCert.Heuristics", "extracted_versions": null, "cpe_matches": null, "verified_cpe_matches": null, @@ -76,14 +76,14 @@ "direct_dependency_cves": null, "indirect_dependency_cves": null, "report_references": { - "_type": "References", + "_type": "sec_certs.sample.certificate.References", "directly_referenced_by": null, "directly_referencing": null, "indirectly_referenced_by": null, "indirectly_referencing": null }, "st_references": { - "_type": "References", + "_type": "sec_certs.sample.certificate.References", "directly_referenced_by": null, "directly_referencing": null, "indirectly_referenced_by": null, @@ -92,7 +92,7 @@ } }, { - "_type": "CommonCriteriaCert", + "_type": "sec_certs.sample.common_criteria.CommonCriteriaCert", "dgst": "8cf86948f02f047d", "status": "active", "category": "Access Control Devices and Systems", @@ -112,7 +112,7 @@ "protection_profiles": { "_type": "Set", "elements": [{ - "_type": "ProtectionProfile", + "_type": "sec_certs.sample.protection_profile.ProtectionProfile", "pp_name": "Korean National Protection Profile for Single Sign On V1.0", "pp_link": "https://www.commoncriteriaportal.org/files/ppfiles/KECS-PP-0822-2017%20Korean%20National%20PP%20for%20Single%20Sign%20On%20V1.0(eng).pdf", "pp_ids": null @@ -123,7 +123,7 @@ "elements": [] }, "state": { - "_type": "InternalState", + "_type": "sec_certs.sample.common_criteria.CommonCriteriaCert.InternalState", "st_download_ok": true, "report_download_ok": true, "st_convert_ok": true, @@ -137,7 +137,7 @@ "report_txt_hash": null }, "pdf_data": { - "_type": "PdfData", + "_type": "sec_certs.sample.common_criteria.CommonCriteriaCert.PdfData", "report_metadata": null, "st_metadata": null, "report_frontpage": null, @@ -146,7 +146,7 @@ "st_keywords": null }, "heuristics": { - "_type": "CCHeuristics", + "_type": "sec_certs.sample.common_criteria.CommonCriteriaCert.Heuristics", "extracted_versions": null, "cpe_matches": null, "verified_cpe_matches": null, @@ -157,14 +157,14 @@ "direct_dependency_cves": null, "indirect_dependency_cves": null, "report_references": { - "_type": "References", + "_type": "sec_certs.sample.certificate.References", "directly_referenced_by": null, "directly_referencing": null, "indirectly_referenced_by": null, "indirectly_referencing": null }, "st_references": { - "_type": "References", + "_type": "sec_certs.sample.certificate.References", "directly_referenced_by": null, "directly_referencing": null, "indirectly_referenced_by": null, diff --git a/tests/data/test_fips_oop/algorithms.json b/tests/data/test_fips_oop/algorithms.json index f3f44df5..825f3009 100644 --- a/tests/data/test_fips_oop/algorithms.json +++ b/tests/data/test_fips_oop/algorithms.json @@ -1,513 +1,490 @@ { - "_type": "FIPSAlgorithmDataset", - "certs": { - "2351": [ - { - "_type": "Algorithm", - "cert_id": "2351", - "date": "9/21/2018", - "implementation": "Apple CoreCrypto Kernel Module v9.0 for ARM (iOS12, A11 Bionic, Assembler_VNG)", - "algorithm_type": "DRBG", - "vendor": "Apple Inc." - }, - { - "_type": "Algorithm", - "cert_id": "2351", - "date": "11/27/2015", - "implementation": "Apple iOS CoreCrypto Kernel Module (Optimized SHA, A6)", - "algorithm_type": "HMAC", - "vendor": "Apple Inc." - }, - { - "_type": "Algorithm", - "cert_id": "2351", - "date": "1/27/2017", - "implementation": "OpenSSL using assembler for AES and SHA", - "algorithm_type": "RSA", - "vendor": "Canonical Ltd." - }, - { - "_type": "Algorithm", - "cert_id": "2351", - "date": "1/19/2017", - "implementation": "Junos FIPS Version Junos 15.1 X49 - Dataplane_CN7020", - "algorithm_type": "TDES", - "vendor": "Juniper Networks, Inc." - }, - { - "_type": "Algorithm", - "cert_id": "2351", - "date": "3/8/2013", - "implementation": "Samsung OpenSSL Cryptographic Module", - "algorithm_type": "AES", - "vendor": "Samsung Electronics Co., Ltd" - }, - { - "_type": "Algorithm", - "cert_id": "2351", - "date": "3/7/2014", - "implementation": "Symantec PGP Cryptographic Engine", - "algorithm_type": "SHS", - "vendor": "Symantec Corporation" - } - ], - "2352": [ - { - "_type": "Algorithm", - "cert_id": "2352", - "date": "9/21/2018", - "implementation": "Apple CoreCrypto Kernel Module v9.0 for ARM (iOS12, A10X Fusion, Assembler_VNG)", - "algorithm_type": "DRBG", - "vendor": "Apple Inc." - }, - { - "_type": "Algorithm", - "cert_id": "2352", - "date": "3/8/2013", - "implementation": "AES-256 Core", - "algorithm_type": "AES", - "vendor": "Altera Canada" - }, - { - "_type": "Algorithm", - "cert_id": "2352", - "date": "11/27/2015", - "implementation": "Apple iOS CoreCrypto Kernel Module (Optimized SHA, A6X)", - "algorithm_type": "HMAC", - "vendor": "Apple Inc." - }, - { - "_type": "Algorithm", - "cert_id": "2352", - "date": "1/27/2017", - "implementation": "OpenSSL using support from Power ISA 2.07 for AES and SHA", - "algorithm_type": "RSA", - "vendor": "Canonical Ltd." - }, - { - "_type": "Algorithm", - "cert_id": "2352", - "date": "1/19/2017", - "implementation": "Junos FIPS Version Junos 15.1 X49 - Dataplane_CN7130", - "algorithm_type": "TDES", - "vendor": "Juniper Networks, Inc." - }, - { - "_type": "Algorithm", - "cert_id": "2352", - "date": "3/21/2014", - "implementation": "Karnak SHA in Hardware", - "algorithm_type": "SHS", - "vendor": "Seagate Technology, LLC." - } - ], - "2600": [ - { - "_type": "Algorithm", - "cert_id": "2600", - "date": "12/15/2017", - "implementation": "Apple iOS CoreCrypto v8 Kernel Module (Generic Software Implementation)", - "algorithm_type": "TDES", - "vendor": "Apple Inc." - }, - { - "_type": "Algorithm", - "cert_id": "2600", - "date": "6/10/2016", - "implementation": "IOS Common Cryptographic Module (IC2M) Algorithm Module", - "algorithm_type": "HMAC", - "vendor": "Cisco Systems, Inc." - }, - { - "_type": "Algorithm", - "cert_id": "2600", - "date": "8/16/2013", - "implementation": "Blade System Virtual Connect", - "algorithm_type": "AES", - "vendor": "Hewlett-Packard Development Company, L.P." - }, - { - "_type": "Algorithm", - "cert_id": "2600", - "date": "12/5/2014", - "implementation": "Cryptographic Security Kernel", - "algorithm_type": "SHS", - "vendor": "IBM Corporation" - }, - { - "_type": "Algorithm", - "cert_id": "2600", - "date": "9/1/2017", - "implementation": "IBM z/OS(R) Cryptographic Services System SSL - 31bit", - "algorithm_type": "RSA", - "vendor": "IBM Corporation" - } - ], - "2601": [ - { - "_type": "Algorithm", - "cert_id": "2601", - "date": "12/5/2014", - "implementation": "SHA256 Library on Canon MFP Security Chip", - "algorithm_type": "SHS", - "vendor": "Canon Inc." - }, - { - "_type": "Algorithm", - "cert_id": "2601", - "date": "8/16/2013", - "implementation": "Dell AppAssure Crypto Library", - "algorithm_type": "AES", - "vendor": "Dell, Inc." - }, - { - "_type": "Algorithm", - "cert_id": "2601", - "date": "6/10/2016", - "implementation": "EFJ Communication Cryptographic Library", - "algorithm_type": "HMAC", - "vendor": "EFJohnson Technologies" - }, - { - "_type": "Algorithm", - "cert_id": "2601", - "date": "9/1/2017", - "implementation": "IBM z/OS(R) Cryptographic Services System SSL - 64bit", - "algorithm_type": "RSA", - "vendor": "IBM Corporation" - }, - { - "_type": "Algorithm", - "cert_id": "2601", - "date": "12/22/2017", - "implementation": "Oracle Linux 7 GnuTLS C Implementation", - "algorithm_type": "TDES", - "vendor": "Oracle Corporation" - } - ], - "2602": [ - { - "_type": "Algorithm", - "cert_id": "2602", - "date": "12/22/2017", - "implementation": "Apple tvOS CoreCrypto Kernel Module v8.0 (Generic Software Implementation)", - "algorithm_type": "TDES", - "vendor": "Apple Inc." - }, - { - "_type": "Algorithm", - "cert_id": "2602", - "date": "6/10/2016", - "implementation": "FIPS-ALGORITHMS.1.5.0v", - "algorithm_type": "HMAC", - "vendor": "Mercury Systems" - }, - { - "_type": "Algorithm", - "cert_id": "2602", - "date": "8/16/2013", - "implementation": "RSA BSAFE\u00ae Crypto-J Software Module", - "algorithm_type": "AES", - "vendor": "RSA Security, Inc." - }, - { - "_type": "Algorithm", - "cert_id": "2602", - "date": "12/5/2014", - "implementation": "SHA Library", - "algorithm_type": "SHS", - "vendor": "Sage Microelectronics Corp" - }, - { - "_type": "Algorithm", - "cert_id": "2602", - "date": "9/1/2017", - "implementation": "Bouncy Castle FIPS Java API", - "algorithm_type": "RSA", - "vendor": "Legion of the Bouncy Castle Inc." - } - ], - "2700": [ - { - "_type": "Algorithm", - "cert_id": "2700", - "date": "3/13/2015", - "implementation": "Apple OSX CoreCrypto Module (Generic, Xeon)", - "algorithm_type": "SHS", - "vendor": "Apple Inc." - }, - { - "_type": "Algorithm", - "cert_id": "2700", - "date": "10/21/2016", - "implementation": "Axway OpenSSL", - "algorithm_type": "HMAC", - "vendor": "Axway Inc." - }, - { - "_type": "Algorithm", - "cert_id": "2700", - "date": "11/30/2017", - "implementation": "Brocade Fabric OS FIPS Cryptographic Module", - "algorithm_type": "RSA", - "vendor": "Brocade Communications Systems LLC" - }, - { - "_type": "Algorithm", - "cert_id": "2700", - "date": "3/30/2018", - "implementation": "Junos OS 17.4R1-S1 - Dataplane", - "algorithm_type": "TDES", - "vendor": "Juniper Networks, Inc." - }, - { - "_type": "Algorithm", - "cert_id": "2700", - "date": "11/29/2013", - "implementation": "VMware NSS Cryptographic Module", - "algorithm_type": "AES", - "vendor": "VMware, Inc." - } - ], - "2701": [ - { - "_type": "Algorithm", - "cert_id": "2701", - "date": "3/30/2018", - "implementation": "Security Builder GSE-J Crypto Core", - "algorithm_type": "TDES", - "vendor": "BlackBerry Certicom" - }, - { - "_type": "Algorithm", - "cert_id": "2701", - "date": "11/30/2017", - "implementation": "ngfips_rsa", - "algorithm_type": "RSA", - "vendor": "Cavium, Inc." - }, - { - "_type": "Algorithm", - "cert_id": "2701", - "date": "10/28/2016", - "implementation": "Cisco_SSL_Implementation-1", - "algorithm_type": "HMAC", - "vendor": "Cisco Systems, Inc." - }, - { - "_type": "Algorithm", - "cert_id": "2701", - "date": "3/13/2015", - "implementation": "RSA BSAFE\u00ae Crypto-J JSAFE and JCE Software Module", - "algorithm_type": "SHS", - "vendor": "RSA, The Security Division of EMC" - }, - { - "_type": "Algorithm", - "cert_id": "2701", - "date": "11/29/2013", - "implementation": "VMware Cryptographic Module", - "algorithm_type": "AES", - "vendor": "VMware, Inc." - } - ], - "2702": [ - { - "_type": "Algorithm", - "cert_id": "2702", - "date": "3/30/2018", - "implementation": "Security Builder GSE-J Crypto Core", - "algorithm_type": "TDES", - "vendor": "BlackBerry Certicom" - }, - { - "_type": "Algorithm", - "cert_id": "2702", - "date": "11/30/2017", - "implementation": "DELPHI RSA2048 Signature Verification Algorithm Implementation", - "algorithm_type": "RSA", - "vendor": "DELPHI" - }, - { - "_type": "Algorithm", - "cert_id": "2702", - "date": "12/6/2013", - "implementation": "RSA BSAFE Crypto-J", - "algorithm_type": "AES", - "vendor": "McAfee, Inc." - }, - { - "_type": "Algorithm", - "cert_id": "2702", - "date": "10/28/2016", - "implementation": "OpenSSL Crypto Library", - "algorithm_type": "HMAC", - "vendor": "MikroM GmbH" - }, - { - "_type": "Algorithm", - "cert_id": "2702", - "date": "3/13/2015", - "implementation": "OpenSSL FIPS Object Module", - "algorithm_type": "SHS", - "vendor": "OpenSSL Validation Services, Inc." - } - ], - "3415": [ - { - "_type": "Algorithm", - "cert_id": "3415", - "date": "1/26/2018", - "implementation": "Apple Secure Key Store CoreCrypto Module (Generic Software Implementation)", - "algorithm_type": "HMAC", - "vendor": "Apple Inc." - }, - { - "_type": "Algorithm", - "cert_id": "3415", - "date": "6/5/2015", - "implementation": "Motorola Solutions Subscriber \u00b5Mace AES256", - "algorithm_type": "AES", - "vendor": "Motorola Solutions Inc" - }, - { - "_type": "Algorithm", - "cert_id": "3415", - "date": "11/18/2016", - "implementation": "Secure Parser Library", - "algorithm_type": "SHS", - "vendor": "Security First Corp." - } - ], - "3426": [ - { - "_type": "Algorithm", - "cert_id": "3426", - "date": "6/11/2015", - "implementation": "Apple iOS CoreCrypto Module (KeyWrap A8 32 bit)", - "algorithm_type": "AES", - "vendor": "Apple Inc." - }, - { - "_type": "Algorithm", - "cert_id": "3426", - "date": "12/2/2016", - "implementation": "Apple iOS CoreCrypto Module (Generic)", - "algorithm_type": "SHS", - "vendor": "Apple Inc." - }, - { - "_type": "Algorithm", - "cert_id": "3426", - "date": "1/26/2018", - "implementation": "Apple Secure Key Store CoreCrypto Module (VNG)", - "algorithm_type": "HMAC", - "vendor": "Apple Inc." - } - ], - "3427": [ - { - "_type": "Algorithm", - "cert_id": "3427", - "date": "12/2/2016", - "implementation": "Apple iOS CoreCrypto Module (Generic)", - "algorithm_type": "SHS", - "vendor": "Apple Inc." - }, - { - "_type": "Algorithm", - "cert_id": "3427", - "date": "1/26/2018", - "implementation": "Forcepoint NGFW FIPS Java API", - "algorithm_type": "HMAC", - "vendor": "Forcepoint" - }, - { - "_type": "Algorithm", - "cert_id": "3427", - "date": "6/11/2015", - "implementation": "HP ESKM OpenSSL", - "algorithm_type": "AES", - "vendor": "Hewlett Packard Enterprise" - } - ], - "3447": [ - { - "_type": "Algorithm", - "cert_id": "3447", - "date": "12/2/2016", - "implementation": "Apple OSX CoreCrypto Module (Optimized SHA nosse)", - "algorithm_type": "SHS", - "vendor": "Apple Inc." - }, - { - "_type": "Algorithm", - "cert_id": "3447", - "date": "7/2/2015", - "implementation": "FireEye Algorithms Implementation", - "algorithm_type": "AES", - "vendor": "FireEye, Inc." - }, - { - "_type": "Algorithm", - "cert_id": "3447", - "date": "2/9/2018", - "implementation": "OpenSSL (no AVX2/AVX/AESNI/SSSE3, x86_64, 64-bit library)", - "algorithm_type": "HMAC", - "vendor": "Red Hat, Inc." - } - ], - "3451": [ - { - "_type": "Algorithm", - "cert_id": "3451", - "date": "12/2/2016", - "implementation": "Apple OSX CoreCrypto Module (Optimized SHA nosse)", - "algorithm_type": "SHS", - "vendor": "Apple Inc." - }, - { - "_type": "Algorithm", - "cert_id": "3451", - "date": "7/2/2015", - "implementation": "OpenSSL FIPS Object Module", - "algorithm_type": "AES", - "vendor": "OpenSSL Software Foundation, Inc." - }, - { - "_type": "Algorithm", - "cert_id": "3451", - "date": "2/9/2018", - "implementation": "OpenSSL (no AVX2/AVX/AESNI, x86_64, 64-bit library)", - "algorithm_type": "HMAC", - "vendor": "Red Hat, Inc." - } - ], - "3464": [ - { - "_type": "Algorithm", - "cert_id": "3464", - "date": "12/9/2016", - "implementation": "Apple OSX CoreCrypto Module (Generic)", - "algorithm_type": "SHS", - "vendor": "Apple Inc." - }, - { - "_type": "Algorithm", - "cert_id": "3464", - "date": "7/10/2015", - "implementation": "Security Builder Linux Kernel Crypto Core", - "algorithm_type": "AES", - "vendor": "Certicom Corp." - }, - { - "_type": "Algorithm", - "cert_id": "3464", - "date": "2/9/2018", - "implementation": "HPE Secure Encryption Engine v1.1", - "algorithm_type": "HMAC", - "vendor": "Hewlett-Packard Development Company, L.P." - } - ] - } + "_type": "sec_certs.dataset.fips_algorithm.FIPSAlgorithmDataset", + "timestamp": "2022-07-11 17:17:38.998647", + "sha256_digest": "not implemented", + "name": "", + "description": "", + "n_certs": 60, + "certs": [ + { + "_type": "sec_certs.sample.fips_algorithm.FIPSAlgorithm", + "cert_id": "3415", + "vendor": "Apple Inc.", + "implementation": "Apple Secure Key Store CoreCrypto Module (Generic Software Implementation)", + "algorithm_type": "HMAC", + "date": "1/26/2018" + }, + { + "_type": "sec_certs.sample.fips_algorithm.FIPSAlgorithm", + "cert_id": "2702", + "vendor": "MikroM GmbH", + "implementation": "OpenSSL Crypto Library", + "algorithm_type": "HMAC", + "date": "10/28/2016" + }, + { + "_type": "sec_certs.sample.fips_algorithm.FIPSAlgorithm", + "cert_id": "2602", + "vendor": "Sage Microelectronics Corp", + "implementation": "SHA Library", + "algorithm_type": "SHS", + "date": "12/5/2014" + }, + { + "_type": "sec_certs.sample.fips_algorithm.FIPSAlgorithm", + "cert_id": "2701", + "vendor": "Cisco Systems, Inc.", + "implementation": "Cisco_SSL_Implementation-1", + "algorithm_type": "HMAC", + "date": "10/28/2016" + }, + { + "_type": "sec_certs.sample.fips_algorithm.FIPSAlgorithm", + "cert_id": "2352", + "vendor": "Altera Canada", + "implementation": "AES-256 Core", + "algorithm_type": "AES", + "date": "3/8/2013" + }, + { + "_type": "sec_certs.sample.fips_algorithm.FIPSAlgorithm", + "cert_id": "2600", + "vendor": "IBM Corporation", + "implementation": "Cryptographic Security Kernel", + "algorithm_type": "SHS", + "date": "12/5/2014" + }, + { + "_type": "sec_certs.sample.fips_algorithm.FIPSAlgorithm", + "cert_id": "2352", + "vendor": "Apple Inc.", + "implementation": "Apple iOS CoreCrypto Kernel Module (Optimized SHA, A6X)", + "algorithm_type": "HMAC", + "date": "11/27/2015" + }, + { + "_type": "sec_certs.sample.fips_algorithm.FIPSAlgorithm", + "cert_id": "2700", + "vendor": "VMware, Inc.", + "implementation": "VMware NSS Cryptographic Module", + "algorithm_type": "AES", + "date": "11/29/2013" + }, + { + "_type": "sec_certs.sample.fips_algorithm.FIPSAlgorithm", + "cert_id": "3415", + "vendor": "Security First Corp.", + "implementation": "Secure Parser Library", + "algorithm_type": "SHS", + "date": "11/18/2016" + }, + { + "_type": "sec_certs.sample.fips_algorithm.FIPSAlgorithm", + "cert_id": "2600", + "vendor": "Hewlett-Packard Development Company, L.P.", + "implementation": "Blade System Virtual Connect", + "algorithm_type": "AES", + "date": "8/16/2013" + }, + { + "_type": "sec_certs.sample.fips_algorithm.FIPSAlgorithm", + "cert_id": "2352", + "vendor": "Seagate Technology, LLC.", + "implementation": "Karnak SHA in Hardware", + "algorithm_type": "SHS", + "date": "3/21/2014" + }, + { + "_type": "sec_certs.sample.fips_algorithm.FIPSAlgorithm", + "cert_id": "2602", + "vendor": "Apple Inc.", + "implementation": "Apple tvOS CoreCrypto Kernel Module v8.0 (Generic Software Implementation)", + "algorithm_type": "TDES", + "date": "12/22/2017" + }, + { + "_type": "sec_certs.sample.fips_algorithm.FIPSAlgorithm", + "cert_id": "2702", + "vendor": "McAfee, Inc.", + "implementation": "RSA BSAFE Crypto-J", + "algorithm_type": "AES", + "date": "12/6/2013" + }, + { + "_type": "sec_certs.sample.fips_algorithm.FIPSAlgorithm", + "cert_id": "2351", + "vendor": "Apple Inc.", + "implementation": "Apple iOS CoreCrypto Kernel Module (Optimized SHA, A6)", + "algorithm_type": "HMAC", + "date": "11/27/2015" + }, + { + "_type": "sec_certs.sample.fips_algorithm.FIPSAlgorithm", + "cert_id": "2600", + "vendor": "IBM Corporation", + "implementation": "IBM z/OS(R) Cryptographic Services System SSL - 31bit", + "algorithm_type": "RSA", + "date": "9/1/2017" + }, + { + "_type": "sec_certs.sample.fips_algorithm.FIPSAlgorithm", + "cert_id": "2701", + "vendor": "RSA, The Security Division of EMC", + "implementation": "RSA BSAFE® Crypto-J JSAFE and JCE Software Module", + "algorithm_type": "SHS", + "date": "3/13/2015" + }, + { + "_type": "sec_certs.sample.fips_algorithm.FIPSAlgorithm", + "cert_id": "3427", + "vendor": "Hewlett Packard Enterprise", + "implementation": "HP ESKM OpenSSL", + "algorithm_type": "AES", + "date": "6/11/2015" + }, + { + "_type": "sec_certs.sample.fips_algorithm.FIPSAlgorithm", + "cert_id": "2700", + "vendor": "Axway Inc.", + "implementation": "Axway OpenSSL", + "algorithm_type": "HMAC", + "date": "10/21/2016" + }, + { + "_type": "sec_certs.sample.fips_algorithm.FIPSAlgorithm", + "cert_id": "2701", + "vendor": "BlackBerry Certicom", + "implementation": "Security Builder GSE-J Crypto Core", + "algorithm_type": "TDES", + "date": "3/30/2018" + }, + { + "_type": "sec_certs.sample.fips_algorithm.FIPSAlgorithm", + "cert_id": "2701", + "vendor": "Cavium, Inc.", + "implementation": "ngfips_rsa", + "algorithm_type": "RSA", + "date": "11/30/2017" + }, + { + "_type": "sec_certs.sample.fips_algorithm.FIPSAlgorithm", + "cert_id": "3426", + "vendor": "Apple Inc.", + "implementation": "Apple iOS CoreCrypto Module (KeyWrap A8 32 bit)", + "algorithm_type": "AES", + "date": "6/11/2015" + }, + { + "_type": "sec_certs.sample.fips_algorithm.FIPSAlgorithm", + "cert_id": "3451", + "vendor": "OpenSSL Software Foundation, Inc.", + "implementation": "OpenSSL FIPS Object Module", + "algorithm_type": "AES", + "date": "7/2/2015" + }, + { + "_type": "sec_certs.sample.fips_algorithm.FIPSAlgorithm", + "cert_id": "2702", + "vendor": "BlackBerry Certicom", + "implementation": "Security Builder GSE-J Crypto Core", + "algorithm_type": "TDES", + "date": "3/30/2018" + }, + { + "_type": "sec_certs.sample.fips_algorithm.FIPSAlgorithm", + "cert_id": "2602", + "vendor": "RSA Security, Inc.", + "implementation": "RSA BSAFE® Crypto-J Software Module", + "algorithm_type": "AES", + "date": "8/16/2013" + }, + { + "_type": "sec_certs.sample.fips_algorithm.FIPSAlgorithm", + "cert_id": "2601", + "vendor": "EFJohnson Technologies", + "implementation": "EFJ Communication Cryptographic Library", + "algorithm_type": "HMAC", + "date": "6/10/2016" + }, + { + "_type": "sec_certs.sample.fips_algorithm.FIPSAlgorithm", + "cert_id": "2601", + "vendor": "Dell, Inc.", + "implementation": "Dell AppAssure Crypto Library", + "algorithm_type": "AES", + "date": "8/16/2013" + }, + { + "_type": "sec_certs.sample.fips_algorithm.FIPSAlgorithm", + "cert_id": "2600", + "vendor": "Cisco Systems, Inc.", + "implementation": "IOS Common Cryptographic Module (IC2M) Algorithm Module", + "algorithm_type": "HMAC", + "date": "6/10/2016" + }, + { + "_type": "sec_certs.sample.fips_algorithm.FIPSAlgorithm", + "cert_id": "2700", + "vendor": "Juniper Networks, Inc.", + "implementation": "Junos OS 17.4R1-S1 - Dataplane", + "algorithm_type": "TDES", + "date": "3/30/2018" + }, + { + "_type": "sec_certs.sample.fips_algorithm.FIPSAlgorithm", + "cert_id": "3447", + "vendor": "Apple Inc.", + "implementation": "Apple OSX CoreCrypto Module (Optimized SHA nosse)", + "algorithm_type": "SHS", + "date": "12/2/2016" + }, + { + "_type": "sec_certs.sample.fips_algorithm.FIPSAlgorithm", + "cert_id": "3447", + "vendor": "FireEye, Inc.", + "implementation": "FireEye Algorithms Implementation", + "algorithm_type": "AES", + "date": "7/2/2015" + }, + { + "_type": "sec_certs.sample.fips_algorithm.FIPSAlgorithm", + "cert_id": "3426", + "vendor": "Apple Inc.", + "implementation": "Apple Secure Key Store CoreCrypto Module (VNG)", + "algorithm_type": "HMAC", + "date": "1/26/2018" + }, + { + "_type": "sec_certs.sample.fips_algorithm.FIPSAlgorithm", + "cert_id": "2351", + "vendor": "Apple Inc.", + "implementation": "Apple CoreCrypto Kernel Module v9.0 for ARM (iOS12, A11 Bionic, Assembler_VNG)", + "algorithm_type": "DRBG", + "date": "9/21/2018" + }, + { + "_type": "sec_certs.sample.fips_algorithm.FIPSAlgorithm", + "cert_id": "3447", + "vendor": "Red Hat, Inc.", + "implementation": "OpenSSL (no AVX2/AVX/AESNI/SSSE3, x86_64, 64-bit library)", + "algorithm_type": "HMAC", + "date": "2/9/2018" + }, + { + "_type": "sec_certs.sample.fips_algorithm.FIPSAlgorithm", + "cert_id": "2351", + "vendor": "Canonical Ltd.", + "implementation": "OpenSSL using assembler for AES and SHA", + "algorithm_type": "RSA", + "date": "1/27/2017" + }, + { + "_type": "sec_certs.sample.fips_algorithm.FIPSAlgorithm", + "cert_id": "2700", + "vendor": "Apple Inc.", + "implementation": "Apple OSX CoreCrypto Module (Generic, Xeon)", + "algorithm_type": "SHS", + "date": "3/13/2015" + }, + { + "_type": "sec_certs.sample.fips_algorithm.FIPSAlgorithm", + "cert_id": "2602", + "vendor": "Mercury Systems", + "implementation": "FIPS-ALGORITHMS.1.5.0v", + "algorithm_type": "HMAC", + "date": "6/10/2016" + }, + { + "_type": "sec_certs.sample.fips_algorithm.FIPSAlgorithm", + "cert_id": "3451", + "vendor": "Apple Inc.", + "implementation": "Apple OSX CoreCrypto Module (Optimized SHA nosse)", + "algorithm_type": "SHS", + "date": "12/2/2016" + }, + { + "_type": "sec_certs.sample.fips_algorithm.FIPSAlgorithm", + "cert_id": "3464", + "vendor": "Hewlett-Packard Development Company, L.P.", + "implementation": "HPE Secure Encryption Engine v1.1", + "algorithm_type": "HMAC", + "date": "2/9/2018" + }, + { + "_type": "sec_certs.sample.fips_algorithm.FIPSAlgorithm", + "cert_id": "2351", + "vendor": "Symantec Corporation", + "implementation": "Symantec PGP Cryptographic Engine", + "algorithm_type": "SHS", + "date": "3/7/2014" + }, + { + "_type": "sec_certs.sample.fips_algorithm.FIPSAlgorithm", + "cert_id": "3427", + "vendor": "Apple Inc.", + "implementation": "Apple iOS CoreCrypto Module (Generic)", + "algorithm_type": "SHS", + "date": "12/2/2016" + }, + { + "_type": "sec_certs.sample.fips_algorithm.FIPSAlgorithm", + "cert_id": "3427", + "vendor": "Forcepoint", + "implementation": "Forcepoint NGFW FIPS Java API", + "algorithm_type": "HMAC", + "date": "1/26/2018" + }, + { + "_type": "sec_certs.sample.fips_algorithm.FIPSAlgorithm", + "cert_id": "2700", + "vendor": "Brocade Communications Systems LLC", + "implementation": "Brocade Fabric OS FIPS Cryptographic Module", + "algorithm_type": "RSA", + "date": "11/30/2017" + }, + { + "_type": "sec_certs.sample.fips_algorithm.FIPSAlgorithm", + "cert_id": "2702", + "vendor": "DELPHI", + "implementation": "DELPHI RSA2048 Signature Verification Algorithm Implementation", + "algorithm_type": "RSA", + "date": "11/30/2017" + }, + { + "_type": "sec_certs.sample.fips_algorithm.FIPSAlgorithm", + "cert_id": "2601", + "vendor": "Oracle Corporation", + "implementation": "Oracle Linux 7 GnuTLS C Implementation", + "algorithm_type": "TDES", + "date": "12/22/2017" + }, + { + "_type": "sec_certs.sample.fips_algorithm.FIPSAlgorithm", + "cert_id": "2352", + "vendor": "Apple Inc.", + "implementation": "Apple CoreCrypto Kernel Module v9.0 for ARM (iOS12, A10X Fusion, Assembler_VNG)", + "algorithm_type": "DRBG", + "date": "9/21/2018" + }, + { + "_type": "sec_certs.sample.fips_algorithm.FIPSAlgorithm", + "cert_id": "2600", + "vendor": "Apple Inc.", + "implementation": "Apple iOS CoreCrypto v8 Kernel Module (Generic Software Implementation)", + "algorithm_type": "TDES", + "date": "12/15/2017" + }, + { + "_type": "sec_certs.sample.fips_algorithm.FIPSAlgorithm", + "cert_id": "2352", + "vendor": "Canonical Ltd.", + "implementation": "OpenSSL using support from Power ISA 2.07 for AES and SHA", + "algorithm_type": "RSA", + "date": "1/27/2017" + }, + { + "_type": "sec_certs.sample.fips_algorithm.FIPSAlgorithm", + "cert_id": "3426", + "vendor": "Apple Inc.", + "implementation": "Apple iOS CoreCrypto Module (Generic)", + "algorithm_type": "SHS", + "date": "12/2/2016" + }, + { + "_type": "sec_certs.sample.fips_algorithm.FIPSAlgorithm", + "cert_id": "2702", + "vendor": "OpenSSL Validation Services, Inc.", + "implementation": "OpenSSL FIPS Object Module", + "algorithm_type": "SHS", + "date": "3/13/2015" + }, + { + "_type": "sec_certs.sample.fips_algorithm.FIPSAlgorithm", + "cert_id": "2601", + "vendor": "Canon Inc.", + "implementation": "SHA256 Library on Canon MFP Security Chip", + "algorithm_type": "SHS", + "date": "12/5/2014" + }, + { + "_type": "sec_certs.sample.fips_algorithm.FIPSAlgorithm", + "cert_id": "2701", + "vendor": "VMware, Inc.", + "implementation": "VMware Cryptographic Module", + "algorithm_type": "AES", + "date": "11/29/2013" + }, + { + "_type": "sec_certs.sample.fips_algorithm.FIPSAlgorithm", + "cert_id": "2352", + "vendor": "Juniper Networks, Inc.", + "implementation": "Junos FIPS Version Junos 15.1 X49 - Dataplane_CN7130", + "algorithm_type": "TDES", + "date": "1/19/2017" + }, + { + "_type": "sec_certs.sample.fips_algorithm.FIPSAlgorithm", + "cert_id": "2351", + "vendor": "Juniper Networks, Inc.", + "implementation": "Junos FIPS Version Junos 15.1 X49 - Dataplane_CN7020", + "algorithm_type": "TDES", + "date": "1/19/2017" + }, + { + "_type": "sec_certs.sample.fips_algorithm.FIPSAlgorithm", + "cert_id": "2601", + "vendor": "IBM Corporation", + "implementation": "IBM z/OS(R) Cryptographic Services System SSL - 64bit", + "algorithm_type": "RSA", + "date": "9/1/2017" + }, + { + "_type": "sec_certs.sample.fips_algorithm.FIPSAlgorithm", + "cert_id": "2602", + "vendor": "Legion of the Bouncy Castle Inc.", + "implementation": "Bouncy Castle FIPS Java API", + "algorithm_type": "RSA", + "date": "9/1/2017" + }, + { + "_type": "sec_certs.sample.fips_algorithm.FIPSAlgorithm", + "cert_id": "2351", + "vendor": "Samsung Electronics Co., Ltd", + "implementation": "Samsung OpenSSL Cryptographic Module", + "algorithm_type": "AES", + "date": "3/8/2013" + }, + { + "_type": "sec_certs.sample.fips_algorithm.FIPSAlgorithm", + "cert_id": "3464", + "vendor": "Apple Inc.", + "implementation": "Apple OSX CoreCrypto Module (Generic)", + "algorithm_type": "SHS", + "date": "12/9/2016" + }, + { + "_type": "sec_certs.sample.fips_algorithm.FIPSAlgorithm", + "cert_id": "3451", + "vendor": "Red Hat, Inc.", + "implementation": "OpenSSL (no AVX2/AVX/AESNI, x86_64, 64-bit library)", + "algorithm_type": "HMAC", + "date": "2/9/2018" + }, + { + "_type": "sec_certs.sample.fips_algorithm.FIPSAlgorithm", + "cert_id": "3464", + "vendor": "Certicom Corp.", + "implementation": "Security Builder Linux Kernel Crypto Core", + "algorithm_type": "AES", + "date": "7/10/2015" + }, + { + "_type": "sec_certs.sample.fips_algorithm.FIPSAlgorithm", + "cert_id": "3415", + "vendor": "Motorola Solutions Inc", + "implementation": "Motorola Solutions Subscriber µMace AES256", + "algorithm_type": "AES", + "date": "6/5/2015" + } + ] }
\ No newline at end of file diff --git a/tests/test_fips_oop.py b/tests/test_fips_oop.py index d8932d91..e07eb572 100644 --- a/tests/test_fips_oop.py +++ b/tests/test_fips_oop.py @@ -4,6 +4,8 @@ from tempfile import TemporaryDirectory from typing import Dict, Final, List from unittest import TestCase +import pytest + import tests.data.test_fips_oop from sec_certs.config.configuration import config from sec_certs.dataset import FIPSAlgorithmDataset, FIPSDataset @@ -14,7 +16,7 @@ from tests.fips_test_utils import generate_html def _set_up_dataset(td, certs): dataset = FIPSDataset({}, Path(td), "test_dataset", "fips_test_dataset") generate_html(certs, td + "/test_search.html") - dataset.get_certs_from_web(test=td + "/test_search.html", no_download_algorithms=True) + dataset.get_certs_from_web(test=td + "/test_search.html") return dataset @@ -114,6 +116,11 @@ class TestFipsOOP(TestCase): dataset = _set_up_dataset(tmp_dir, certs) self.assertEqual(len(dataset.certs), len(certs), "Wrong number of parsed certs") + def test_metadata_extraction(self): + with TemporaryDirectory() as tmp_dir: + dst = _set_up_dataset_for_full(tmp_dir, ["3493"], self.cpe_dset_path, self.cve_dset_path) + self.assertIsNotNone(dst.certs[fips_dgst("3493")].pdf_data.st_metadata) + def test_connections_microsoft(self): certs = self.certs_to_parse["microsoft"] with TemporaryDirectory() as tmp_dir: @@ -335,3 +342,13 @@ class TestFipsOOP(TestCase): self.assertEqual( set(dataset.certs[fips_dgst("3158")].heuristics.web_references.directly_referencing), {"2398"} ) + + +class TestFIPSAlgo(TestCase): + @pytest.mark.slow + def test_get_certs_from_web(self): + with TemporaryDirectory() as tmp_dir: + web_path = Path(tmp_dir) / "web" + web_path.mkdir() + aset = FIPSAlgorithmDataset({}, web_path / "algorithms", "algorithms", "sample algs") + aset.get_certs_from_web() |
