def test_null_cipher_suites(self): # Given a server to scan that supports NULL cipher suites server_location = ServerNetworkLocation("null.badssl.com", 443) server_info = check_connectivity_to_server_and_return_info( server_location) # When scanning for cipher suites, it succeeds result: CipherSuitesScanResult = Tlsv12ScanImplementation.scan_server( server_info) # And the NULL/Anon cipher suites were detected expected_ciphers = { "TLS_ECDH_anon_WITH_AES_256_CBC_SHA", "TLS_DH_anon_WITH_AES_256_CBC_SHA256", "TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA", "TLS_DH_anon_WITH_AES_256_GCM_SHA384", "TLS_DH_anon_WITH_AES_256_CBC_SHA", "TLS_ECDH_anon_WITH_AES_128_CBC_SHA", "TLS_DH_anon_WITH_AES_128_CBC_SHA256", "TLS_DH_anon_WITH_AES_128_CBC_SHA", "TLS_DH_anon_WITH_AES_128_GCM_SHA256", "TLS_DH_anon_WITH_SEED_CBC_SHA", "TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA", "TLS_ECDHE_RSA_WITH_NULL_SHA", "TLS_ECDH_anon_WITH_NULL_SHA", "TLS_RSA_WITH_NULL_SHA256", "TLS_RSA_WITH_NULL_SHA", } assert expected_ciphers == { accepted_cipher.cipher_suite.name for accepted_cipher in result.accepted_cipher_suites }
def test_works_when_client_auth_succeeded(self): # Given a server that requires client authentication with LegacyOpenSslServer( client_auth_config=ClientAuthConfigEnum.REQUIRED) as server: server_location = ServerNetworkLocation( hostname=server.hostname, ip_address=server.ip_address, port=server.port) # And sslyze provides a client certificate network_config = ServerNetworkConfiguration( tls_server_name_indication=server.hostname, tls_client_auth_credentials=ClientAuthenticationCredentials( certificate_chain_path=server.get_client_certificate_path( ), key_path=server.get_client_key_path()), ) server_info = check_connectivity_to_server_and_return_info( server_location, network_config) # When scanning for HTTP headers, it succeeds result: HttpHeadersScanResult = HttpHeadersImplementation.scan_server( server_info) assert not result.strict_transport_security_header assert not result.expect_ct_header
def test_works_when_client_auth_succeeded(self): # Given a server that requires client authentication with ModernOpenSslServer( client_auth_config=ClientAuthConfigEnum.REQUIRED) as server: server_location = ServerNetworkLocation( hostname=server.hostname, ip_address=server.ip_address, port=server.port) # And sslyze provides a client certificate network_config = ServerNetworkConfiguration( tls_server_name_indication=server.hostname, tls_client_auth_credentials=ClientAuthenticationCredentials( certificate_chain_path=server.get_client_certificate_path( ), key_path=server.get_client_key_path()), ) server_info = check_connectivity_to_server_and_return_info( server_location, network_config) # When testing for resumption, it succeeds result: SessionResumptionSupportScanResult = SessionResumptionSupportImplementation.scan_server( server_info) assert result.session_id_successful_resumptions_count assert result.session_id_resumption_result == TlsResumptionSupportEnum.FULLY_SUPPORTED
def test_via_http_proxy(self): # Given an HTTP proxy proxy_port = 8123 proxy_server = ThreadingHTTPServer(("", proxy_port), ProxyHandler) proxy_server_thread = threading.Thread( target=proxy_server.serve_forever) proxy_server_thread.start() # And a server location server_location = ServerNetworkLocation( hostname="www.google.com", port=443, # Configured with this proxy http_proxy_settings=HttpProxySettings("localhost", proxy_port), ) # When testing connectivity try: tls_probing_result = check_connectivity_to_server( server_location=server_location, network_configuration=ServerNetworkConfiguration. default_for_server_location(server_location), ) finally: proxy_server.shutdown() # It succeeds assert tls_probing_result.cipher_suite_supported assert tls_probing_result.highest_tls_version_supported assert tls_probing_result.client_auth_requirement # And the result can be converted to JSON tls_probing_result_as_json = _ServerTlsProbingResultAsJson.from_orm( tls_probing_result) assert tls_probing_result_as_json.json()
def test_tlsv1_2_enabled(self): # Given a server to scan that supports TLS 1.2 server_location = ServerNetworkLocation("www.google.com", 443) server_info = check_connectivity_to_server_and_return_info( server_location) # When scanning for cipher suites, it succeeds result: CipherSuitesScanResult = Tlsv12ScanImplementation.scan_server( server_info) # And the result confirms that TLS 1.2 is supported expected_ciphers = { "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", "TLS_RSA_WITH_AES_256_GCM_SHA384", "TLS_RSA_WITH_AES_256_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", "TLS_RSA_WITH_AES_128_GCM_SHA256", "TLS_RSA_WITH_AES_128_CBC_SHA", "TLS_RSA_WITH_3DES_EDE_CBC_SHA", "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256", "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256", } assert expected_ciphers == { accepted_cipher.cipher_suite.name for accepted_cipher in result.accepted_cipher_suites }
def test_works_when_client_auth_succeeded(self): # Given a server that does NOT support SCSV and that requires client authentication with LegacyOpenSslServer( client_auth_config=ClientAuthConfigEnum.REQUIRED) as server: server_location = ServerNetworkLocation( hostname=server.hostname, ip_address=server.ip_address, port=server.port) # And sslyze provides a client certificate network_config = ServerNetworkConfiguration( tls_server_name_indication=server.hostname, tls_client_auth_credentials=ClientAuthenticationCredentials( certificate_chain_path=server.get_client_certificate_path( ), key_path=server.get_client_key_path()), ) server_info = check_connectivity_to_server_and_return_info( server_location, network_config) # When testing for SCSV, it succeeds result: FallbackScsvScanResult = FallbackScsvImplementation.scan_server( server_info) # And the server is reported as NOT supporting SCSV assert not result.supports_fallback_scsv
def test_http_error(self): # Given a server to scan with ModernOpenSslServer( # And the server will trigger an error when receiving an HTTP request should_reply_to_http_requests=False) as server: server_location = ServerNetworkLocation( hostname=server.hostname, ip_address=server.ip_address, port=server.port) server_info = check_connectivity_to_server_and_return_info( server_location) # When scanning for HTTP headers, it succeeds result: HttpHeadersScanResult = HttpHeadersImplementation.scan_server( server_info) # And the result mention the error returned by the server when sending an HTTP request assert result.http_error_trace assert result.http_request_sent # And the other result fields are not set assert not result.http_path_redirected_to assert not result.expect_ct_header # And a CLI output can be generated assert HttpHeadersImplementation.cli_connector_cls.result_to_console_output( result) # And the result can be converted to JSON result_as_json = HttpHeadersScanResultAsJson.from_orm(result).json() assert result_as_json
def test_works_when_client_auth_succeeded(self): # Given a server that is vulnerable and that requires client authentication with LegacyOpenSslServer( client_auth_config=ClientAuthConfigEnum.REQUIRED) as server: server_location = ServerNetworkLocation( hostname=server.hostname, ip_address=server.ip_address, port=server.port) # And sslyze provides a client certificate network_config = ServerNetworkConfiguration( tls_server_name_indication=server.hostname, tls_client_auth_credentials=ClientAuthenticationCredentials( certificate_chain_path=server.get_client_certificate_path( ), key_path=server.get_client_key_path()), ) server_info = check_connectivity_to_server_and_return_info( server_location, network_config) # When testing for insecure reneg, it succeeds result: SessionRenegotiationScanResult = SessionRenegotiationImplementation.scan_server( server_info) # And the results are correct assert result.supports_secure_renegotiation assert result.is_vulnerable_to_client_renegotiation_dos
def test_vulnerable_and_server_has_sni_bug(self): # Test for https://github.com/nabla-c0d3/sslyze/issues/202 # Given a server that is vulnerable to Heartbleed and that requires the right SNI to be sent server_name_indication = "server.com" with LegacyOpenSslServer( require_server_name_indication_value=server_name_indication ) as server: server_location = ServerNetworkLocation( hostname=server_name_indication, ip_address=server.ip_address, port=server.port) server_info = check_connectivity_to_server_and_return_info( server_location) # But the server is buggy and returns a TLS alert when SNI is sent during the Hearbtleed check # We replicate this behavior by having SSLyze send a wrong value for SNI, instead of complicated server code # Use __setattr__ to bypass the dataclass' frozen=True setting object.__setattr__(server_info.network_configuration, "tls_server_name_indication", "wrongvalue.com") # When testing for Heartbleed, it succeeds result = HeartbleedImplementation.scan_server(server_info) # And the server is reported as vulnerable even though it has the SNI bug assert result.is_vulnerable_to_heartbleed
def create() -> ServerNetworkLocation: return ServerNetworkLocation( hostname="ûnicôdé." + fake.hostname(), port=123, http_proxy_settings=HttpProxySettings(hostname="prôxy." + fake.hostname(), port=456), )
def test(self): # Given a completed scan for a CERTIFICATE_INFO scan command server_location = ServerNetworkLocation("www.facebook.com", 443) server_info = check_connectivity_to_server_and_return_info( server_location) plugin_result = CertificateInfoImplementation.scan_server(server_info) # When generating the CLI output for this result, it succeeds result_as_txt = CertificateInfoImplementation.cli_connector_cls.result_to_console_output( plugin_result) assert result_as_txt
def test(self): # Given a completed scan for a cipher suites scan command server_location = ServerNetworkLocation("www.google.com", 443) server_info = check_connectivity_to_server_and_return_info( server_location) plugin_result = Tlsv12ScanImplementation.scan_server(server_info) # When generating the CLI output for this result, it succeeds result_as_txt = Tlsv12ScanImplementation.cli_connector_cls.result_to_console_output( plugin_result) assert result_as_txt
def test_via_direct_connection_but_server_rejected_connection(self): # Given a server location for a server that's offline server_location = ServerNetworkLocation(hostname="localhost", port=1234) # When testing connectivity, it fails with the right error with pytest.raises(ServerRejectedConnection): check_connectivity_to_server( server_location=server_location, network_configuration=ServerNetworkConfiguration. default_for_server_location(server_location), )
def test_follows_client_cipher_suite_preference(self): # Given a server to scan that follows client cipher suite preference server_location = ServerNetworkLocation("www.hotmail.com", 443) server_info = check_connectivity_to_server_and_return_info( server_location) # When scanning for cipher suites, it succeeds result: CipherSuitesScanResult = Tlsv12ScanImplementation.scan_server( server_info) # And the server is detected as following the client's preference assert result.cipher_suite_preferred_by_server
def test_via_direct_connection_but_server_tls_config_not_supported(self): # Given a server location for a server that only supports DH settings that SSLyze can't use server_location = ServerNetworkLocation(hostname="dh480.badssl.com", port=443) # When testing connectivity, it fails with the right error with pytest.raises(ServerTlsConfigurationNotSupported): check_connectivity_to_server( server_location=server_location, network_configuration=ServerNetworkConfiguration. default_for_server_location(server_location), )
def test_robot_attack_good(self): # Validate the bug fix for https://github.com/nabla-c0d3/sslyze/issues/282 # Given a server to scan that is not vulnerable to ROBOT server_location = ServerNetworkLocation("guide.duo.com", 443) server_info = check_connectivity_to_server_and_return_info( server_location) result: RobotScanResult = RobotImplementation.scan_server(server_info) assert result.robot_result == RobotScanResultEnum.NOT_VULNERABLE_NO_ORACLE # And a CLI output can be generated assert RobotImplementation.cli_connector_cls.result_to_console_output( result)
def test_sslv3_disabled(self): # Given a server to scan that does not support SSL 3.0 server_location = ServerNetworkLocation("www.google.com", 443) server_info = check_connectivity_to_server_and_return_info( server_location) # When scanning for cipher suites, it succeeds result: CipherSuitesScanResult = Sslv30ScanImplementation.scan_server( server_info) # And the result confirms that SSL 3.0 is not supported assert not result.accepted_cipher_suites assert result.rejected_cipher_suites
def test_tlsv1_0_disabled(self): # Given a server to scan that does NOT support TLS 1.0 server_location = ServerNetworkLocation("success.trendmicro.com", 443) server_info = check_connectivity_to_server_and_return_info( server_location) # When scanning for cipher suites, it succeeds result: CipherSuitesScanResult = Tlsv10ScanImplementation.scan_server( server_info) # And the result confirms that TLS 1.0 is not supported assert not result.accepted_cipher_suites assert result.rejected_cipher_suites
def test_not_vulnerable_and_server_has_cloudfront_bug(self): # Test for https://github.com/nabla-c0d3/sslyze/issues/437 # Given a server that is NOT vulnerable to CCS injection and that is hosted on Cloudfront with the SNI bug server_location = ServerNetworkLocation(hostname="amazon.com", port=443, ip_address="13.35.126.17") server_info = check_connectivity_to_server_and_return_info( server_location) # When testing for CCS injection, it succeeds result = HeartbleedImplementation.scan_server(server_info) # And the server is reported as not vulnerable assert not result.is_vulnerable_to_heartbleed
def test_smtp(self): # Given an SMTP server to scan hostname = "smtp.gmail.com" server_location = ServerNetworkLocation(hostname, 587) network_configuration = ServerNetworkConfiguration( tls_server_name_indication=hostname, tls_opportunistic_encryption=ProtocolWithOpportunisticTlsEnum.SMTP) server_info = check_connectivity_to_server_and_return_info( server_location, network_configuration) # When scanning for cipher suites, it succeeds result: CipherSuitesScanResult = Tlsv12ScanImplementation.scan_server( server_info) assert result.accepted_cipher_suites
def test_via_direct_connection_but_server_timed_out(self): # Given a server location for a server that's offline server_location = ServerNetworkLocation( hostname="notarealdomain.not.real.notreal.not", port=1234, ip_address="123.123.123.123") # When testing connectivity, it fails with the right error with pytest.raises(ConnectionToServerTimedOut): check_connectivity_to_server( server_location=server_location, network_configuration=ServerNetworkConfiguration. default_for_server_location(server_location), )
def test_fails_when_client_auth_failed(self): # Given a server that does NOT support SCSV and that requires client authentication with LegacyOpenSslServer( client_auth_config=ClientAuthConfigEnum.REQUIRED) as server: # And sslyze does NOT provide a client certificate server_location = ServerNetworkLocation( hostname=server.hostname, ip_address=server.ip_address, port=server.port) server_info = check_connectivity_to_server_and_return_info( server_location) # When testing for SCSV, it fails as a client cert was not supplied with pytest.raises(ClientCertificateRequested): FallbackScsvImplementation.scan_server(server_info)
def test_not_vulnerable(self): # Given a server that is NOT vulnerable to Heartbleed server_location = ServerNetworkLocation("www.google.com", 443) server_info = check_connectivity_to_server_and_return_info( server_location) # When testing for Heartbleed, it succeeds result = HeartbleedImplementation.scan_server(server_info) # And the server is reported as not vulnerable assert not result.is_vulnerable_to_heartbleed # And a CLI output can be generated assert HeartbleedImplementation.cli_connector_cls.result_to_console_output( result)
def test_fails_when_client_auth_failed(self): # Given a server that requires client authentication with LegacyOpenSslServer( client_auth_config=ClientAuthConfigEnum.REQUIRED) as server: # And sslyze does NOT provide a client certificate server_location = ServerNetworkLocation( hostname=server.hostname, ip_address=server.ip_address, port=server.port) server_info = check_connectivity_to_server_and_return_info( server_location) # When scanning for HTTP headers, it fails with pytest.raises(ClientCertificateRequested): HttpHeadersImplementation.scan_server(server_info)
def test_via_http_proxy_but_proxy_timed_out(self): # Given a server location server_location = ServerNetworkLocation( hostname="www.google.com", port=443, # Configured with a proxy that will time out http_proxy_settings=HttpProxySettings("1.2.3.4", 80), ) # When testing connectivity, it fails with the right error with pytest.raises(ConnectionToHttpProxyTimedOut): check_connectivity_to_server( server_location=server_location, network_configuration=ServerNetworkConfiguration. default_for_server_location(server_location), )
def test_fallback_good(self): # Given a server that supports SCSV server_location = ServerNetworkLocation("www.google.com", 443) server_info = check_connectivity_to_server_and_return_info( server_location) # When testing for SCSV, it succeeds result: FallbackScsvScanResult = FallbackScsvImplementation.scan_server( server_info) # And the server is reported as supporting SCSV assert result.supports_fallback_scsv # And a CLI output can be generated assert FallbackScsvImplementation.cli_connector_cls.result_to_console_output( result)
def test_fallback_bad(self): # Given a server that does NOT support SCSV with LegacyOpenSslServer() as server: server_location = ServerNetworkLocation( hostname=server.hostname, ip_address=server.ip_address, port=server.port) server_info = check_connectivity_to_server_and_return_info( server_location) # When testing for SCSV, it succeeds result: FallbackScsvScanResult = FallbackScsvImplementation.scan_server( server_info) # And the server is reported as NOT supporting SCSV assert not result.supports_fallback_scsv
def test_via_http_proxy_but_proxy_rejected_http_connect(self): # Given a server location server_location = ServerNetworkLocation( hostname="www.google.com", port=443, # Configured with a proxy that is going to reject the HTTP CONNECT request http_proxy_settings=HttpProxySettings("www.hotmail.com", 443), ) # When testing connectivity, it fails with the right error with pytest.raises(HttpProxyRejectedConnection): check_connectivity_to_server( server_location=server_location, network_configuration=ServerNetworkConfiguration. default_for_server_location(server_location), )
def test_via_http_proxy_but_proxy_rejected_connection(self): # Given a server location server_location = ServerNetworkLocation( hostname="www.google.com", port=443, # Configured with a proxy that's offline http_proxy_settings=HttpProxySettings("localhost", 1234), ) # When testing connectivity, it fails with the right error with pytest.raises(HttpProxyRejectedConnection): check_connectivity_to_server( server_location=server_location, network_configuration=ServerNetworkConfiguration. default_for_server_location(server_location), )
def test_early_data_disabled(self): # Given a server to scan that does NOT support early data because it it is disabled with ModernOpenSslServer(max_early_data=None) as server: server_location = ServerNetworkLocation( hostname=server.hostname, ip_address=server.ip_address, port=server.port) server_info = check_connectivity_to_server_and_return_info( server_location) # When testing for early data support, it succeeds result: EarlyDataScanResult = EarlyDataImplementation.scan_server( server_info) # And the right result is returned assert not result.supports_early_data