Ejemplo n.º 1
0
    def test_server_scan_completed_with_proxy(self):
        # Given a completed scan for a server when the compression scan command was run
        compression_attempt = CompressionScanAttempt(
            status=ScanCommandAttemptStatusEnum.COMPLETED,
            error_reason=None,
            error_trace=None,
            result=CompressionScanResult(supports_compression=True),
        )
        scan_result = ServerScanResultFactory.create(
            # And sslyze connected to the server via an HTTP proxy
            server_location=ServerNetworkLocationViaHttpProxyFactory.create(),
            scan_result=AllScanCommandsAttemptsFactory.create(
                {"tls_compression": compression_attempt}),
        )

        # When generating the console output for this server scan
        with StringIO() as file_out:
            console_gen = ObserverToGenerateConsoleOutput(file_to=file_out)
            console_gen.server_scan_completed(scan_result)
            final_output = file_out.getvalue()

        # It succeeds and mentions the HTTP proxy
        assert final_output
        assert "HTTP PROXY" in final_output
        assert "Compression" in final_output
Ejemplo n.º 2
0
    def test_server_connectivity_test_error(self):
        # Given a server to scan to which sslyze could not connect
        scan_request = ServerScanRequestFactory.create()
        error = ConnectionToServerFailedFactory.create()

        # When generating the console output for this
        with StringIO() as file_out:
            console_gen = ObserverToGenerateConsoleOutput(file_to=file_out)
            console_gen.server_connectivity_test_error(scan_request, error)
            final_output = file_out.getvalue()

        # It succeeds and the connectivity error was displayed
        assert final_output
        assert error.error_message in final_output
Ejemplo n.º 3
0
    def test_server_connectivity_test_completed(self):
        # Given a server to scan to which sslyze was able to connect
        scan_request = ServerScanRequestFactory.create()
        connectivity_result = ServerTlsProbingResultFactory.create()

        # When generating the console output for this
        with StringIO() as file_out:
            console_gen = ObserverToGenerateConsoleOutput(file_to=file_out)
            console_gen.server_connectivity_test_completed(
                scan_request, connectivity_result)
            final_output = file_out.getvalue()

        # It succeeds and the server is displayed
        assert final_output
        assert scan_request.server_location.hostname in final_output
Ejemplo n.º 4
0
    def test_server_connectivity_test_completed_with_http_tunneling(self):
        # Given a server to scan to which sslyze was able to connect
        scan_request = ServerScanRequestFactory.create(
            # And sslyze connected to it via an HTTP proxy
            server_location=ServerNetworkLocationViaHttpProxyFactory.create())
        connectivity_result = ServerTlsProbingResultFactory.create()

        # When generating the console output for this
        with StringIO() as file_out:
            console_gen = ObserverToGenerateConsoleOutput(file_to=file_out)
            console_gen.server_connectivity_test_completed(
                scan_request, connectivity_result)
            final_output = file_out.getvalue()

        # It succeeds and the fact that an HTTP proxy was used was displayed
        assert final_output
        assert "proxy" in final_output
Ejemplo n.º 5
0
    def test_server_connectivity_test_completed_with_required_client_auth(
            self):
        # Given a server to scan to which sslyze was able to connect
        scan_request = ServerScanRequestFactory.create()
        connectivity_result = ServerTlsProbingResultFactory.create(
            # And the server requires client authentication
            client_auth_requirement=ClientAuthRequirementEnum.REQUIRED, )

        # When generating the console output for this
        with StringIO() as file_out:
            console_gen = ObserverToGenerateConsoleOutput(file_to=file_out)
            console_gen.server_connectivity_test_completed(
                scan_request, connectivity_result)
            final_output = file_out.getvalue()

        # It succeeds and the fact that the server requires client auth was displayed
        assert final_output
        assert "Server REQUIRED client authentication" in final_output
Ejemplo n.º 6
0
    def test_command_line_parsed(self):
        # Given a command line used to run sslyze
        parsed_cmd_line = ParsedCommandLineFactory.create()

        # Which contained some valid, and some invalid servers
        assert parsed_cmd_line.invalid_servers
        assert parsed_cmd_line.servers_to_scans

        # When generating the console output for this
        with StringIO() as file_out:
            console_gen = ObserverToGenerateConsoleOutput(file_to=file_out)
            console_gen.command_line_parsed(parsed_cmd_line)
            final_output = file_out.getvalue()

        # It succeeds and the invalid servers were displayed
        assert final_output
        for bad_server in parsed_cmd_line.invalid_servers:
            assert bad_server.server_string in final_output
            assert bad_server.error_message in final_output
Ejemplo n.º 7
0
    def test_server_scan_completed(self):
        # Given a completed scan for a server when the compression scan command was run
        compression_attempt = CompressionScanAttempt(
            status=ScanCommandAttemptStatusEnum.COMPLETED,
            error_reason=None,
            error_trace=None,
            result=CompressionScanResult(supports_compression=True),
        )
        scan_result = ServerScanResultFactory.create(
            scan_result=AllScanCommandsAttemptsFactory.create(
                {"tls_compression": compression_attempt}))

        # When generating the console output for this server scan
        with StringIO() as file_out:
            console_gen = ObserverToGenerateConsoleOutput(file_to=file_out)
            console_gen.server_scan_completed(scan_result)
            final_output = file_out.getvalue()

        # It succeeds
        assert final_output
        assert "Compression" in final_output
Ejemplo n.º 8
0
    def test_server_scan_completed_with_error(self):
        # Given a completed scan for a server that triggered an error
        error_trace = TracebackExceptionFactory.create()
        compression_attempt = CompressionScanAttempt(
            status=ScanCommandAttemptStatusEnum.ERROR,
            error_reason=ScanCommandErrorReasonEnum.BUG_IN_SSLYZE,
            error_trace=error_trace,
            result=None,
        )
        scan_result = ServerScanResultFactory.create(
            scan_result=AllScanCommandsAttemptsFactory.create(
                {"tls_compression": compression_attempt}))

        # When generating the console output for this server scan
        with StringIO() as file_out:
            console_gen = ObserverToGenerateConsoleOutput(file_to=file_out)
            console_gen.server_scan_completed(scan_result)
            final_output = file_out.getvalue()

        # It succeeds and displays the error
        assert final_output
        assert error_trace.stack.format()[0] in final_output
Ejemplo n.º 9
0
def main() -> None:
    # Parse the supplied command line
    date_scans_started = datetime.utcnow()
    sslyze_parser = CommandLineParser(__version__)
    try:
        parsed_command_line = sslyze_parser.parse_command_line()
    except CommandLineParsingError as e:
        print(e.get_error_msg())
        return

    # Setup the observer to print to the console, if needed
    scanner_observers = []
    if not parsed_command_line.should_disable_console_output:
        observer_for_console_output = ObserverToGenerateConsoleOutput(
            file_to=sys.stdout, json_path_out=parsed_command_line.json_path_out
        )
        observer_for_console_output.command_line_parsed(parsed_command_line=parsed_command_line)

        scanner_observers.append(observer_for_console_output)

    # Setup the scanner
    sslyze_scanner = Scanner(
        per_server_concurrent_connections_limit=parsed_command_line.per_server_concurrent_connections_limit,
        concurrent_server_scans_limit=parsed_command_line.concurrent_server_scans_limit,
        observers=scanner_observers,
    )

    # Queue the scans
    all_server_scan_requests = []
    for server_location, network_config in parsed_command_line.servers_to_scans:
        scan_request = ServerScanRequest(
            server_location=server_location,
            network_configuration=network_config,
            scan_commands=parsed_command_line.scan_commands,
            scan_commands_extra_arguments=parsed_command_line.scan_commands_extra_arguments,
        )
        all_server_scan_requests.append(scan_request)

    # If there are servers that we were able to resolve, scan them
    all_server_scan_results = []
    if all_server_scan_requests:
        sslyze_scanner.queue_scans(all_server_scan_requests)
        for result in sslyze_scanner.get_results():
            # Results are actually displayed by the observer; here we just store them
            all_server_scan_results.append(result)

    # Write results to a JSON file if needed
    json_file_out: Optional[TextIO] = None
    if parsed_command_line.should_print_json_to_console:
        json_file_out = sys.stdout
    elif parsed_command_line.json_path_out:
        json_file_out = parsed_command_line.json_path_out.open("wt", encoding="utf-8")

    if json_file_out:
        json_output = SslyzeOutputAsJson(
            server_scan_results=[ServerScanResultAsJson.from_orm(result) for result in all_server_scan_results],
            invalid_server_strings=[
                InvalidServerStringAsJson.from_orm(bad_server) for bad_server in parsed_command_line.invalid_servers
            ],
            date_scans_started=date_scans_started,
            date_scans_completed=datetime.utcnow(),
        )
        json_output_as_str = json_output.json(sort_keys=True, indent=4, ensure_ascii=True)
        json_file_out.write(json_output_as_str)

    # If we printed the JSON results to the console, don't run the Mozilla compliance check so we return valid JSON
    if parsed_command_line.should_print_json_to_console:
        sys.exit(0)

    if not all_server_scan_results:
        # There are no results to present: all supplied server strings were invalid?
        sys.exit(0)

    # Check the results against the Mozilla config if needed
    are_all_servers_compliant = True
    # TODO(AD): Expose format_title method
    title = ObserverToGenerateConsoleOutput._format_title("Compliance against Mozilla TLS configuration")
    print()
    print(title)
    if not parsed_command_line.check_against_mozilla_config:
        print("    Disabled; use --mozilla_config={old, intermediate, modern}.\n")
    else:

        print(
            f'    Checking results against Mozilla\'s "{parsed_command_line.check_against_mozilla_config}"'
            f" configuration. See https://ssl-config.mozilla.org/ for more details.\n"
        )
        mozilla_checker = MozillaTlsConfigurationChecker.get_default()
        for server_scan_result in all_server_scan_results:
            try:
                mozilla_checker.check_server(
                    against_config=parsed_command_line.check_against_mozilla_config,
                    server_scan_result=server_scan_result,
                )
                print(f"    {server_scan_result.server_location.display_string}: OK - Compliant.\n")

            except ServerNotCompliantWithMozillaTlsConfiguration as e:
                are_all_servers_compliant = False
                print(f"    {server_scan_result.server_location.display_string}: FAILED - Not compliant.")
                for criteria, error_description in e.issues.items():
                    print(f"        * {criteria}: {error_description}")
                print()

            except ServerScanResultIncomplete:
                are_all_servers_compliant = False
                print(
                    f"    {server_scan_result.server_location.display_string}: ERROR - Scan did not run successfully;"
                    f" review the scan logs above."
                )

    if not are_all_servers_compliant:
        # Return a non-zero error code to signal failure (for example to fail a CI/CD pipeline)
        sys.exit(1)
Ejemplo n.º 10
0
 def test_scans_completed(self):
     # When generating the console output for when all scans got completed, it succeeds
     with StringIO() as file_out:
         console_gen = ObserverToGenerateConsoleOutput(file_to=file_out)
         console_gen.all_server_scans_completed()