示例#1
0
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
示例#2
0
    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)
示例#3
0
    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
示例#4
0
    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)
示例#5
0
    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