class TrustStoresRepository(object): """Retrieve the trust stores available for certificate validation. """ _TRUST_STORES_PATH = join(_get_script_dir(), 'pem_files') _MAIN_STORE = TrustStore(join(_TRUST_STORES_PATH, 'mozilla.pem'), 'Mozilla', '12/2017', _MOZILLA_EV_OIDS) _ALL_STORES = [ _MAIN_STORE, TrustStore(join(_TRUST_STORES_PATH, 'microsoft.pem'), 'Microsoft', '12/2017'), TrustStore(join(_TRUST_STORES_PATH, 'apple.pem'), 'Apple', 'macOS 10.13.1'), TrustStore(join(_TRUST_STORES_PATH, 'java.pem'), 'Java 8', 'Update 121'), TrustStore(join(_TRUST_STORES_PATH, 'aosp.pem'), 'AOSP', '8.0.0 r36'), ] @classmethod def get_all(cls): # type: () -> List[TrustStore] """Return all available trust stores. """ return cls._ALL_STORES @classmethod def get_main(cls): # type: () -> TrustStore """Return the main trust store we use for certificate validation - for now we use Mozilla's. It is used for additional things including OCSP and EV validation. """ return cls._MAIN_STORE
def process_task( self, server_info: ServerConnectivityInfo, scan_command: PluginScanCommand ) -> 'CertificateInfoScanResult': if not isinstance(scan_command, CertificateInfoScanCommand): raise ValueError('Unexpected scan command') final_trust_store_list = TrustStoresRepository.get_default().get_all_stores() if scan_command.custom_ca_file: if not os.path.isfile(scan_command.custom_ca_file): raise ValueError('Could not open supplied CA file at "{}"'.format(scan_command.custom_ca_file)) final_trust_store_list.append(TrustStore(scan_command.custom_ca_file, 'Custom --ca_file', 'N/A')) # Workaround for https://github.com/pyca/cryptography/issues/3495 default_backend() thread_pool = ThreadPool() for trust_store in final_trust_store_list: # Try to connect with each trust store thread_pool.add_job((self._get_and_verify_certificate_chain, [server_info, trust_store])) # Start processing the jobs; one thread per trust thread_pool.start(len(final_trust_store_list)) # Store the results as they come certificate_chain: List[Certificate] = [] path_validation_result_list = [] path_validation_error_list = [] ocsp_response = None for (job, result) in thread_pool.get_result(): (_, (_, trust_store)) = job certificate_chain, validation_result, _ocsp_response = result # Keep the OCSP response if the validation was succesful and a response was returned if _ocsp_response: ocsp_response = _ocsp_response # Store the returned verify string for each trust store path_validation_result_list.append(PathValidationResult(trust_store, validation_result)) # Store thread pool errors last_exception = None for (job, exception) in thread_pool.get_error(): (_, (_, trust_store)) = job path_validation_error_list.append(PathValidationError(trust_store, exception)) last_exception = exception thread_pool.join() if len(path_validation_error_list) == len(final_trust_store_list): # All connections failed unexpectedly; raise an exception instead of returning a result raise last_exception # type: ignore # All done return CertificateInfoScanResult(server_info, scan_command, certificate_chain, path_validation_result_list, path_validation_error_list, ocsp_response)
def __init__(self, repository_path: str) -> None: available_stores = {} for store_name, store_version, store_pem_path in self._parse_trust_stores_in_folder( repository_path): store_pretty_name = self._STORE_PRETTY_NAMES.get( store_name, store_name) ev_oids = None if store_name == self._MOZILLA_STORE_NAME: ev_oids = _MOZILLA_EV_OIDS store = TrustStore(store_pem_path, store_pretty_name, store_version, ev_oids) available_stores[store_name] = store self._available_stores = available_stores
def process_task(self, server_info, scan_command): # type: (ServerConnectivityInfo, CertificateInfoScanCommand) -> CertificateInfoScanResult final_trust_store_list = list(TrustStoresRepository.get_all()) if scan_command.custom_ca_file: if not os.path.isfile(scan_command.custom_ca_file): raise ValueError(u'Could not open supplied CA file at "{}"'.format(scan_command.custom_ca_file)) final_trust_store_list.append(TrustStore(scan_command.custom_ca_file, u'Custom --ca_file', u'N/A')) thread_pool = ThreadPool() for trust_store in final_trust_store_list: # Try to connect with each trust store thread_pool.add_job((self._get_and_verify_certificate_chain, (server_info, trust_store))) # Start processing the jobs; one thread per trust thread_pool.start(len(final_trust_store_list)) # Store the results as they come certificate_chain = [] path_validation_result_list = [] path_validation_error_list = [] ocsp_response = None for (job, result) in thread_pool.get_result(): (_, (_, trust_store)) = job certificate_chain, validation_result, ocsp_response = result # Store the returned verify string for each trust store path_validation_result_list.append(PathValidationResult(trust_store, validation_result)) # Store thread pool errors last_exception = None for (job, exception) in thread_pool.get_error(): (_, (_, trust_store)) = job path_validation_error_list.append(PathValidationError(trust_store, exception)) last_exception = exception thread_pool.join() if len(path_validation_error_list) == len(final_trust_store_list): # All connections failed unexpectedly; raise an exception instead of returning a result raise RuntimeError(u'Could not connect to the server; last error: {}'.format(last_exception)) # All done return CertificateInfoScanResult(server_info, scan_command, certificate_chain, path_validation_result_list, path_validation_error_list, ocsp_response)
def __init__(self, repository_path: Path) -> None: available_stores = {} # Validate and parse the content of the trust stores folder for store_enum in TrustStoreEnum: # Parse the YAML file to extract the version store_yaml_path = repository_path / f"{store_enum.name.lower()}.yaml" store_yaml = store_yaml_path.read_text() if store_enum in [ TrustStoreEnum.MICROSOFT_WINDOWS, TrustStoreEnum.MOZILLA_NSS ]: # Use the date_fetched instead as the version store_version = store_yaml.split("date_fetched: ", 1)[1].split("\n", 1)[0].strip() else: store_version = store_yaml.split("version: ", 1)[1].split("\n", 1)[0].strip(" '") # Ensure the corresponding PEM file is there store_pem_path = repository_path / f"{store_enum.name.lower()}.pem" if not store_pem_path.exists(): raise ValueError( f"Could not find trust store at {store_pem_path}") # Store the result available_stores[store_enum] = TrustStore( path=store_pem_path, name=self._STORE_PRETTY_NAMES[store_enum], version=store_version, ev_oids=_MOZILLA_EV_OIDS if store_enum == TrustStoreEnum.MOZILLA_NSS else None, ) self._available_stores = available_stores