def parse_command_line(self): """Parses the command line used to launch SSLyze. """ (args_command_list, args_target_list) = self._parser.parse_args() # Handle the --targets_in command line and fill args_target_list if args_command_list.targets_in: if args_target_list: raise CommandLineParsingError("Cannot use --targets_list and specify targets within the command line.") 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("Can't read targets from input file '{}.".format( args_command_list.targets_in)) if not args_target_list: raise CommandLineParsingError('No targets to scan.') # Handle the --regular command line parameter as a shortcut if self._parser.has_option('--regular'): if getattr(args_command_list, 'regular'): setattr(args_command_list, 'regular', False) for cmd in self.REGULAR_CMD: setattr(args_command_list, cmd, True) # Sanity checks on the command line options # Prevent --quiet and --xml_out - if args_command_list.xml_file and args_command_list.xml_file == '-' and args_command_list.quiet: raise CommandLineParsingError('Cannot use --quiet with --xml_out -.') # Prevent --quiet and --json_out - if args_command_list.json_file and args_command_list.json_file == '-' and args_command_list.quiet: raise CommandLineParsingError('Cannot use --quiet with --json_out -.') # Prevent --xml_out - and --json_out - if args_command_list.json_file and args_command_list.json_file == '-' \ and args_command_list.xml_file and args_command_list.xml_file == '-': raise CommandLineParsingError('Cannot use --xml_out - with --json_out -.') # 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 = SSL_FILETYPE_ASN1 elif args_command_list.keyform == 'PEM': key_type = SSL_FILETYPE_PEM else: raise CommandLineParsingError('--keyform should be DER or PEM.') # Let's try to open the cert and key files try: client_auth_creds = ClientAuthenticationCredentials(args_command_list.cert, args_command_list.key, key_type, args_command_list.keypass) except ValueError as e: raise CommandLineParsingError('Invalid client authentication settings: {}.'.format(e[0])) # HTTP CONNECT proxy http_tunneling_settings = None if args_command_list.https_tunnel: try: http_tunneling_settings = HttpConnectTunnelingSettings.from_url(args_command_list.https_tunnel) except ValueError as e: raise CommandLineParsingError('Invalid proxy URL for --https_tunnel: {}.'.format(e[0])) # STARTTLS tls_wrapped_protocol = TlsWrappedProtocolEnum.PLAIN_TLS if args_command_list.starttls: if args_command_list.starttls not in self.START_TLS_PROTOCOLS: raise CommandLineParsingError(self.START_TLS_USAGE) else: # StartTLS was specified if args_command_list.starttls in self.STARTTLS_PROTOCOL_DICT.keys(): # Protocol was given in the command line tls_wrapped_protocol = self.STARTTLS_PROTOCOL_DICT[args_command_list.starttls] # Number of connection retries if args_command_list.nb_retries < 1: raise CommandLineParsingError('Cannot have a number smaller than 1 for --nb_retries.') # Create the server connectivity info for each specifed servers # A limitation when using the command line is that only one client_auth_credentials and http_tunneling_settings # can be specified, for all the servers to scan good_server_list = [] bad_server_list = [] for server_string in args_target_list: # Support unicode domains server_string = unicode(server_string, 'utf-8') try: hostname, ip_address, port = CommandLineServerStringParser.parse_server_string(server_string) server_info = ServerConnectivityInfo( hostname=hostname, port=port, ip_address=ip_address, tls_wrapped_protocol=tls_wrapped_protocol, tls_server_name_indication=args_command_list.sni, xmpp_to_hostname=args_command_list.xmpp_to, client_auth_credentials=client_auth_creds, http_tunneling_settings=http_tunneling_settings ) # Keep the original server string to display it in the CLI output if there was a connection error server_info.server_string = server_string good_server_list.append(server_info) except ServerConnectivityError as e: # Will happen for example if the DNS lookup failed or the server string is malformed bad_server_list.append(FailedServerScan(server_string, e)) except ValueError as e: # Will happen for example if xmpp_to is specified for a non-XMPP connection raise CommandLineParsingError(e[0]) # Command line hacks # Handle --starttls=auto now that we parsed the server strings if args_command_list.starttls == 'auto': for server_info in good_server_list: # We use the port number to deduce the protocol if server_info.port in self.STARTTLS_PROTOCOL_DICT.keys(): server_info.tls_wrapped_protocol = self.STARTTLS_PROTOCOL_DICT[server_info.port] # Handle --http_get now that we parsed the server strings # Doing it here is hacky as the option is defined within PluginOpenSSLCipherSuites if args_command_list.http_get: for server_info in good_server_list: if server_info.port == 443: server_info.tls_wrapped_protocol = TlsWrappedProtocolEnum.HTTPS return good_server_list, bad_server_list, args_command_list
def parse_command_line(self): """Parses the command line used to launch SSLyze. """ (args_command_list, args_target_list) = self._parser.parse_args() # Handle the --targets_in command line and fill args_target_list if args_command_list.targets_in: if args_target_list: raise CommandLineParsingError( u'Cannot use --targets_list and specify targets within the command line.' ) 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( u'#'): # Ignore comment lines args_target_list.append(target.strip()) except IOError: raise CommandLineParsingError( u'Can\'t read targets from input file \'{}.'.format( args_command_list.targets_in)) if not args_target_list: raise CommandLineParsingError(u'No targets to scan.') # Handle the --regular command line parameter as a shortcut if self._parser.has_option(u'--regular'): if getattr(args_command_list, u'regular'): setattr(args_command_list, u'regular', False) for cmd in self.REGULAR_CMD: setattr(args_command_list, cmd, True) # Sanity checks on the command line options # Prevent --quiet and --xml_out - if args_command_list.xml_file and args_command_list.xml_file == '-' and args_command_list.quiet: raise CommandLineParsingError( u'Cannot use --quiet with --xml_out -.') # Prevent --quiet and --json_out - if args_command_list.json_file and args_command_list.json_file == '-' and args_command_list.quiet: raise CommandLineParsingError( u'Cannot use --quiet with --json_out -.') # Prevent --xml_out - and --json_out - if args_command_list.json_file and args_command_list.json_file == '-' \ and args_command_list.xml_file and args_command_list.xml_file == '-': raise CommandLineParsingError( u'Cannot use --xml_out - with --json_out -.') # Sanity checks on the client cert options client_auth_creds = None if bool(args_command_list.cert) ^ bool(args_command_list.key): raise CommandLineParsingError( u'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 == u'DER': key_type = OpenSslFileTypeEnum.ASN1 elif args_command_list.keyform == u'PEM': key_type = OpenSslFileTypeEnum.PEM else: raise CommandLineParsingError( u'--keyform should be DER or PEM.') # Let's try to open the cert and key files try: client_auth_creds = ClientAuthenticationCredentials( args_command_list.cert, args_command_list.key, key_type, args_command_list.keypass) except ValueError as e: raise CommandLineParsingError( u'Invalid client authentication settings: {}.'.format( e[0])) # HTTP CONNECT proxy http_tunneling_settings = None if args_command_list.https_tunnel: try: http_tunneling_settings = HttpConnectTunnelingSettings.from_url( args_command_list.https_tunnel) except ValueError as e: raise CommandLineParsingError( u'Invalid proxy URL for --https_tunnel: {}.'.format(e[0])) # STARTTLS tls_wrapped_protocol = TlsWrappedProtocolEnum.PLAIN_TLS if args_command_list.starttls: if args_command_list.starttls not in self.START_TLS_PROTOCOLS: raise CommandLineParsingError(self.START_TLS_USAGE) else: # StartTLS was specified if args_command_list.starttls in self.STARTTLS_PROTOCOL_DICT.keys( ): # Protocol was given in the command line tls_wrapped_protocol = self.STARTTLS_PROTOCOL_DICT[ args_command_list.starttls] # Number of connection retries if args_command_list.nb_retries < 1: raise CommandLineParsingError( u'Cannot have a number smaller than 1 for --nb_retries.') # Create the server connectivity info for each specifed servers # A limitation when using the command line is that only one client_auth_credentials and http_tunneling_settings # can be specified, for all the servers to scan good_server_list = [] bad_server_list = [] for server_string in args_target_list: # Support unicode domains server_string = server_string.decode('utf-8') try: hostname, ip_address, port = CommandLineServerStringParser.parse_server_string( server_string) server_info = ServerConnectivityInfo( hostname=hostname, port=port, ip_address=ip_address, tls_wrapped_protocol=tls_wrapped_protocol, tls_server_name_indication=args_command_list.sni, xmpp_to_hostname=args_command_list.xmpp_to, client_auth_credentials=client_auth_creds, http_tunneling_settings=http_tunneling_settings) # Keep the original server string to display it in the CLI output if there was a connection error server_info.server_string = server_string good_server_list.append(server_info) except ServerConnectivityError as e: # Will happen for example if the DNS lookup failed or the server string is malformed bad_server_list.append(FailedServerScan(server_string, e)) except ValueError as e: # Will happen for example if xmpp_to is specified for a non-XMPP connection raise CommandLineParsingError(e[0]) # Command line hacks # Handle --starttls=auto now that we parsed the server strings if args_command_list.starttls == u'auto': for server_info in good_server_list: # We use the port number to deduce the protocol if server_info.port in self.STARTTLS_PROTOCOL_DICT.keys(): server_info.tls_wrapped_protocol = self.STARTTLS_PROTOCOL_DICT[ server_info.port] # Handle --http_get now that we parsed the server strings # Doing it here is hacky as the option is defined within PluginOpenSSLCipherSuites if args_command_list.http_get: for server_info in good_server_list: if server_info.port == 443: server_info.tls_wrapped_protocol = TlsWrappedProtocolEnum.HTTPS return good_server_list, bad_server_list, args_command_list