def test_ipv6_as_hint_with_port(self):
     server_string = "www.google.com:443{[2604:5500:c370:e100:15ba:f57b:e10e:50c1]}"
     hostname, ip_address, port = CommandLineServerStringParser.parse_server_string(
         server_string)
     assert "www.google.com" == hostname
     assert 443 == port
     assert "2604:5500:c370:e100:15ba:f57b:e10e:50c1" == ip_address
 def test_ipv6_with_port(self):
     server_string = "[2604:5500:c370:e100:15ba:f57b:e10e:50c1]:443"
     hostname, ip_address, port = CommandLineServerStringParser.parse_server_string(
         server_string)
     assert "2604:5500:c370:e100:15ba:f57b:e10e:50c1" == hostname
     assert 443 == port
     assert not ip_address
 def test_ipv4_as_hint_with_port(self):
     server_string = "www.google.com:443{192.168.2.1}"
     hostname, ip_address, port = CommandLineServerStringParser.parse_server_string(
         server_string)
     assert "www.google.com" == hostname
     assert 443 == port
     assert "192.168.2.1" == ip_address
 def test(self):
     server_string = "www.google.com"
     hostname, ip_address, port = CommandLineServerStringParser.parse_server_string(
         server_string)
     assert "www.google.com" == hostname
     assert not port
     assert not ip_address
예제 #5
0
    def parse_command_line(self) -> ParsedCommandLine:
        """Parses the command line used to launch SSLyze."""
        args_command_list = self.aparser.parse_args()
        args_target_list = []

        if args_command_list.update_trust_stores:
            # Just update the trust stores and do nothing
            TrustStoresRepository.update_default()
            raise TrustStoresUpdateCompleted()

        # Handle the --targets_in command line and fill args_target_list
        if args_command_list.targets_in:
            try:  # Read targets from a file
                with open(args_command_list.targets_in) as f:
                    for target in f.readlines():
                        if target.strip():  # Ignore empty lines
                            if not target.startswith(
                                    "#"):  # Ignore comment lines
                                args_target_list.append(target.strip())
            except IOError:
                raise CommandLineParsingError(
                    f"Can't read targets from input file '{args_command_list.targets_in}'"
                )

        for target in args_command_list.target:
            args_target_list.append(target)

        if not args_target_list:
            raise CommandLineParsingError("No targets to scan.")

        # Handle the case when no scan commands have been specified: run --mozilla-config=intermediate by default
        if not args_command_list.mozilla_config:
            did_user_enable_some_scan_commands = [
                getattr(args_command_list, option.option)
                for option in self._get_plugin_scan_commands()
                if getattr(args_command_list, option.option)
            ]
            if not did_user_enable_some_scan_commands:
                setattr(args_command_list, "mozilla_config",
                        MozillaTlsConfigurationEnum.INTERMEDIATE.value)

        # Enable the commands needed by --mozilla-config
        check_against_mozilla_config: Optional[
            MozillaTlsConfigurationEnum] = None
        if args_command_list.mozilla_config:
            if args_command_list.mozilla_config == "disable":
                check_against_mozilla_config = None
            else:
                check_against_mozilla_config = MozillaTlsConfigurationEnum(
                    args_command_list.mozilla_config)

            for scan_cmd in SCAN_COMMANDS_NEEDED_BY_MOZILLA_CHECKER:
                cli_connector_cls = ScanCommandsRepository.get_implementation_cls(
                    scan_cmd).cli_connector_cls
                setattr(args_command_list, cli_connector_cls._cli_option, True)

        # Handle JSON settings
        should_print_json_to_console = False
        json_path_out: Optional[Path] = None
        if args_command_list.json_file:
            if args_command_list.json_file == "-":
                if args_command_list.quiet:
                    raise CommandLineParsingError(
                        "Cannot use --quiet with --json_out -.")
                should_print_json_to_console = True
            else:
                json_path_out = Path(args_command_list.json_file).absolute()

        # Sanity checks on the client cert options
        client_auth_creds = None
        if bool(args_command_list.cert) ^ bool(args_command_list.key):
            raise CommandLineParsingError(
                "No private key or certificate file were given. See --cert and --key."
            )

        elif args_command_list.cert:
            # Private key formats
            if args_command_list.keyform == "DER":
                key_type = OpenSslFileTypeEnum.ASN1
            elif args_command_list.keyform == "PEM":
                key_type = OpenSslFileTypeEnum.PEM

            # Let's try to open the cert and key files
            try:
                client_auth_creds = ClientAuthenticationCredentials(
                    certificate_chain_path=Path(args_command_list.cert),
                    key_path=Path(args_command_list.key),
                    key_password=args_command_list.keypass,
                    key_type=key_type,
                )
            except ValueError as e:
                raise CommandLineParsingError(
                    "Invalid client authentication settings: {}.".format(
                        e.args[0]))

        # HTTP CONNECT proxy
        http_proxy_settings = None
        if args_command_list.https_tunnel:
            try:
                http_proxy_settings = HttpProxySettings.from_url(
                    args_command_list.https_tunnel)
            except ValueError as e:
                raise CommandLineParsingError(
                    "Invalid proxy URL for --https_tunnel: {}.".format(
                        e.args[0]))

        # Create the server location objects for each specified servers
        good_servers: List[Tuple[ServerNetworkLocation,
                                 ServerNetworkConfiguration]] = []
        invalid_server_strings: List[InvalidServerStringError] = []
        for server_string in args_target_list:
            try:
                # Parse the string supplied via the CLI for this server
                (
                    hostname,
                    ip_address,
                    port,
                ) = CommandLineServerStringParser.parse_server_string(
                    server_string)
            except InvalidServerStringError as e:
                # The server string is malformed
                invalid_server_strings.append(e)
                continue

            # If not port number was supplied, assume 443
            final_port = port if port else 443

            # Figure out how we're going to connect to the server
            server_location: ServerNetworkLocation
            if http_proxy_settings:
                # Connect to the server via an HTTP proxy
                # A limitation when using the CLI is that only one http_proxy_settings can be specified for all servers
                server_location = ServerNetworkLocation(
                    hostname=hostname,
                    port=final_port,
                    http_proxy_settings=http_proxy_settings,
                )
            else:
                # Connect to the server directly
                if ip_address:
                    server_location = ServerNetworkLocation(
                        hostname=hostname,
                        port=final_port,
                        ip_address=ip_address,
                    )
                else:
                    # No IP address supplied - do a DNS lookup
                    try:
                        server_location = ServerNetworkLocation(
                            hostname=hostname,
                            port=final_port,
                        )
                    except ServerHostnameCouldNotBeResolved:
                        invalid_server_strings.append(
                            InvalidServerStringError(
                                server_string=f"{hostname}:{final_port}",
                                error_message=
                                f"Could not resolve hostname {hostname}",
                            ))
                        continue

            # Figure out extra network config for this server
            # Opportunistic TLS
            opportunistic_tls: Optional[
                ProtocolWithOpportunisticTlsEnum] = None
            if args_command_list.starttls:
                if args_command_list.starttls == "auto":
                    # Special value to auto-derive the protocol from the port number
                    opportunistic_tls = ProtocolWithOpportunisticTlsEnum.from_default_port(
                        final_port)
                elif args_command_list.starttls in _STARTTLS_PROTOCOL_DICT:
                    opportunistic_tls = _STARTTLS_PROTOCOL_DICT[
                        args_command_list.starttls]
                else:
                    raise CommandLineParsingError(
                        f"StartTLS should be one of: auto, {', '.join(_STARTTLS_PROTOCOL_DICT.keys())}."
                    )

            try:
                sni_hostname = args_command_list.sni if args_command_list.sni else hostname
                network_config = ServerNetworkConfiguration(
                    tls_opportunistic_encryption=opportunistic_tls,
                    tls_server_name_indication=sni_hostname,
                    tls_client_auth_credentials=client_auth_creds,
                    xmpp_to_hostname=args_command_list.xmpp_to,
                )
                good_servers.append((server_location, network_config))
            except InvalidServerNetworkConfigurationError as e:
                raise CommandLineParsingError(e.args[0])

        # Figure out global network settings
        concurrent_server_scans_limit = None
        per_server_concurrent_connections_limit = None
        if args_command_list.https_tunnel:
            # All the connections will go through a single proxy; only scan one server at a time to not DOS the proxy
            concurrent_server_scans_limit = 1
        if args_command_list.slow_connection:
            # Go easy on the servers; only open 2 concurrent connections against each server
            per_server_concurrent_connections_limit = 2

        # Figure out the scan commands that are enabled
        scan_commands: Set[ScanCommand] = set()
        scan_commands_extra_arguments_dict: Dict[
            ScanCommand, plugin_base.ScanCommandExtraArgument] = {}
        for scan_command in ScanCommandsRepository.get_all_scan_commands():
            cli_connector_cls = ScanCommandsRepository.get_implementation_cls(
                scan_command).cli_connector_cls
            (
                is_scan_cmd_enabled,
                extra_args,
            ) = cli_connector_cls.find_cli_options_in_command_line(
                args_command_list.__dict__)
            if is_scan_cmd_enabled:
                scan_commands.add(scan_command)
                if extra_args:
                    scan_commands_extra_arguments_dict[
                        scan_command] = extra_args
        scan_commands_extra_arguments = ScanCommandsExtraArguments(
            **scan_commands_extra_arguments_dict)  # type: ignore

        return ParsedCommandLine(
            invalid_servers=invalid_server_strings,
            servers_to_scans=good_servers,
            scan_commands=scan_commands,
            scan_commands_extra_arguments=scan_commands_extra_arguments,
            should_print_json_to_console=should_print_json_to_console,
            json_path_out=json_path_out,
            should_disable_console_output=args_command_list.quiet
            or args_command_list.json_file == "-",
            concurrent_server_scans_limit=concurrent_server_scans_limit,
            per_server_concurrent_connections_limit=
            per_server_concurrent_connections_limit,
            check_against_mozilla_config=check_against_mozilla_config,
        )