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
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, )