From 42de4e696a6a9a595142fb9139adbc0f916ccbbe Mon Sep 17 00:00:00 2001 From: Stanislav Boboň Date: Sat, 24 Oct 2020 15:24:06 +0200 Subject: Fips - bs4, added parsing (#9) * fixed KeyErrors and added simplier table finding * remove duplicities in json * use bs4 to parse web files * search for broken pdfs, saner pdf opening * better html parsing * more exceptions handled * more fields to parse * added more rules * type hinting added * common dict + Path functions Co-authored-by: Stanislav Boboň --- requirements.txt | 8 +- sec_certs/cert_rules.py | 48 +++--- sec_certs/extract_certificates.py | 4 +- sec_certs/fips_certificates.py | 325 ++++++++++++++++++++------------------ 4 files changed, 213 insertions(+), 172 deletions(-) diff --git a/requirements.txt b/requirements.txt index cb1e0c9b..8b817605 100644 --- a/requirements.txt +++ b/requirements.txt @@ -11,4 +11,10 @@ python-dateutil==2.8.1 six==1.15.0 tabulate==0.8.7 pikepdf~=1.19.3 -tqdm==4.50.2 \ No newline at end of file +tqdm==4.50.2 +setuptools~=50.3.2 +requests~=2.24.0 +click~=7.1.2 +bs4~=0.0.1 +beautifulsoup4~=4.9.3 +tabula-py~=2.2.0 \ No newline at end of file diff --git a/sec_certs/cert_rules.py b/sec_certs/cert_rules.py index 78257525..2100a60b 100644 --- a/sec_certs/cert_rules.py +++ b/sec_certs/cert_rules.py @@ -323,6 +323,33 @@ rules_fips_htmls = [ r"Vendor<\/h4>[\s\S]*?href=\".*?\">(?P.*?)<\/a>" ] + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Common rules +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +common_rules = {} +common_rules['rules_os'] = rules_os +common_rules['rules_standard_id'] = rules_standard_id +common_rules['rules_security_level'] = rules_security_level +common_rules['rules_security_assurance_components'] = rules_security_assurance_components +common_rules['rules_security_functional_components'] = rules_security_functional_components +common_rules['rules_javacard'] = rules_javacard +common_rules['rules_crypto_algs'] = rules_crypto_algs +common_rules['rules_block_cipher_modes'] = rules_block_cipher_modes +common_rules['rules_ecc_curves'] = rules_ecc_curves +common_rules['rules_cplc'] = rules_cplc +common_rules['rules_crypto_engines'] = rules_crypto_engines +common_rules['rules_crypto_libs'] = rules_crypto_libs +common_rules['rules_IC_data_groups'] = rules_IC_data_groups +common_rules['rules_defenses'] = rules_defenses +common_rules['rules_certification_process'] = rules_certification_process +common_rules['rules_vulnerabilities'] = rules_vulnerabilities +common_rules['rules_other'] = rules_other + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# For CC +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # rules_security_target_class rules = {} rules['rules_vendor'] = rules_vendor @@ -330,28 +357,13 @@ rules['rules_cert_id'] = rules_cert_id rules['rules_protection_profiles'] = rules_protection_profiles rules['rules_technical_reports'] = rules_technical_reports rules['rules_device_id'] = rules_device_id -rules['rules_os'] = rules_os -rules['rules_standard_id'] = rules_standard_id -rules['rules_security_level'] = rules_security_level -rules['rules_security_assurance_components'] = rules_security_assurance_components -rules['rules_security_functional_components'] = rules_security_functional_components -rules['rules_javacard'] = rules_javacard -rules['rules_crypto_algs'] = rules_crypto_algs -rules['rules_block_cipher_modes'] = rules_block_cipher_modes -rules['rules_ecc_curves'] = rules_ecc_curves -rules['rules_cplc'] = rules_cplc -rules['rules_crypto_engines'] = rules_crypto_engines -rules['rules_crypto_libs'] = rules_crypto_libs -rules['rules_IC_data_groups'] = rules_IC_data_groups -rules['rules_defenses'] = rules_defenses -rules['rules_certification_process'] = rules_certification_process -rules['rules_vulnerabilities'] = rules_vulnerabilities -rules['rules_other'] = rules_other +rules.update(common_rules) # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -# For FIPS +# For FIPS # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ fips_rules = {} fips_rules['rules_fips_algorithms'] = rules_fips_remove_algorithm_ids fips_rules['rules_security_level'] = rules_fips_security_level fips_rules['rules_cert_id'] = rules_fips_cert +fips_rules.update(common_rules) \ No newline at end of file diff --git a/sec_certs/extract_certificates.py b/sec_certs/extract_certificates.py index a857a5c4..a86957c0 100644 --- a/sec_certs/extract_certificates.py +++ b/sec_certs/extract_certificates.py @@ -1077,10 +1077,10 @@ def extract_certificates_keywords(walk_dir: Path, fragments_dir: Path, file_pref # print('*** {} ***'.format(file_name)) - file_cert_name = os.path.splitext( + fips_cert_name = os.path.splitext( os.path.splitext(os.path.basename(file_name))[0])[0] # parse certificate, return all matches - all_items_found[file_name], modified_cert_file = parse_cert_file( + all_items_found[fips_cert_name if fips_items else file_name], modified_cert_file = parse_cert_file( file_name, fips_rules if fips_items else rules, -1, should_censure_right_away=should_censure_right_away, fips_items=fips_items) diff --git a/sec_certs/fips_certificates.py b/sec_certs/fips_certificates.py index 55c6a33b..a6a73bf0 100755 --- a/sec_certs/fips_certificates.py +++ b/sec_certs/fips_certificates.py @@ -4,24 +4,33 @@ import os import re import time from pathlib import Path -from typing import Set, Optional +from typing import Set, Optional, List, Dict +from bs4 import BeautifulSoup from graphviz import Digraph import click import pikepdf -# from camelot import read_pdf from tabula import read_pdf from .download import download_fips_web, download_fips from . import extract_certificates from .files import load_json_files, FILE_ERRORS_STRATEGY, search_files -from .cert_rules import rules_fips_htmls as RE_FIPS_HTMLS - FIPS_BASE_URL = 'https://csrc.nist.gov' FIPS_MODULE_URL = 'https://csrc.nist.gov/projects/cryptographic-module-validation-program/certificate/' +def find_empty_pdfs(base_dir: Path) -> (List, List): + missing = [] + not_available = [] + for i in range(1, 3725): + if not (base_dir / f'{i}.pdf').exists(): + missing.append(i) + elif os.path.getsize(base_dir / f'{i}.pdf') < 10000: + not_available.append(i) + return missing, not_available + + def extract_filename(file: str) -> str: """ Extracts filename from path @@ -31,147 +40,144 @@ def extract_filename(file: str) -> str: return os.path.splitext(os.path.basename(file))[0] -def parse_ul(text): - """ - Parses content between