def test_ca_file_bad_file(self): # Given a server to scan server_location = ServerNetworkLocationViaDirectConnection.with_ip_address_lookup( "www.hotmail.com", 443) server_info = ServerConnectivityTester().perform(server_location) # When trying to enable a custom CA file but the path is wrong, it fails with pytest.raises(ValueError): CertificateInfoImplementation.scan_server( server_info, CertificateInfoExtraArguments( custom_ca_file=Path("doesntexist")))
def test_invalid_certificate_bad_name(self, certificate_name_field): # Given a server to scan server_location = ServerNetworkLocationViaDirectConnection.with_ip_address_lookup( "www.cloudflare.com", 443) server_info = ServerConnectivityTester().perform(server_location) # And the server has a certificate with an invalid Subject field with mock.patch.object( hazmat.backends.openssl.x509._Certificate, certificate_name_field, new_callable=PropertyMock) as mock_certificate_name: # https://github.com/nabla-c0d3/sslyze/issues/495 mock_certificate_name.side_effect = ValueError( "Country name must be a 2 character country code") # When running the scan, it succeeds scan_result = CertificateInfoImplementation.scan_server( server_info) # And the result can be converted to console output result_as_txt = CertificateInfoImplementation.cli_connector_cls.result_to_console_output( scan_result) assert result_as_txt # And the result can be converted to JSON result_as_json = json.dumps(asdict(scan_result), cls=JsonEncoder) assert result_as_json
def test_ed25519_certificate(self): # Given a server that is configured with an ED25519 certificate with ModernOpenSslServer( server_certificate_path=Path(__file__).parent.absolute() / "server-ed25519-cert.pem", server_key_path=Path(__file__).parent.absolute() / "server-ed25519-key.pem", ) as server: server_location = ServerNetworkLocation( hostname=server.hostname, port=server.port, ip_address=server.ip_address) server_info = check_connectivity_to_server_and_return_info( server_location) # When running the scan, it succeeds scan_result = CertificateInfoImplementation.scan_server( server_info) assert scan_result.certificate_deployments[ 0].received_certificate_chain # And the result can be converted to JSON result_as_json = CertificateInfoScanResultAsJson.from_orm( scan_result).json() assert result_as_json # And the result can be converted to console output result_as_txt = CertificateInfoImplementation.cli_connector_cls.result_to_console_output( scan_result) assert result_as_txt
def test_invalid_chain(self): # Given a server to scan that has a self-signed certificate server_location = ServerNetworkLocationViaDirectConnection.with_ip_address_lookup( "self-signed.badssl.com", 443) server_info = ServerConnectivityTester().perform(server_location) # When running the scan plugin_result = CertificateInfoImplementation.scan_server(server_info) # A verified chain cannot be built assert not plugin_result.certificate_deployments[ 0].verified_certificate_chain assert plugin_result.certificate_deployments[ 0].verified_chain_has_sha1_signature is None # And the result has other details about the certificate chain assert plugin_result.certificate_deployments[0].ocsp_response is None assert len(plugin_result.certificate_deployments[0]. received_certificate_chain) == 1 assert len(plugin_result.certificate_deployments[0]. path_validation_results) >= 5 for path_validation_result in plugin_result.certificate_deployments[ 0].path_validation_results: assert not path_validation_result.was_validation_successful assert plugin_result.certificate_deployments[ 0].leaf_certificate_signed_certificate_timestamps_count == 0 assert plugin_result.certificate_deployments[ 0].leaf_certificate_subject_matches_hostname assert plugin_result.certificate_deployments[ 0].received_chain_has_valid_order assert plugin_result.certificate_deployments[ 0].received_chain_contains_anchor_certificate is None
def test_json_serializer_functions(self): # Given a completed scan for a server with the CERTIFICATE_INFO scan command server_location = ServerNetworkLocationViaDirectConnection.with_ip_address_lookup( "www.hotmail.com", 443) server_info = ServerConnectivityTester().perform(server_location) plugin_result = CertificateInfoImplementation.perform(server_info) scan_results = {ScanCommandEnum.CERTIFICATE_INFO: plugin_result} scan_result = ServerScanResultFactory.create( scan_commands_results=scan_results) # When generating the JSON output for this server scan with StringIO() as file_out: json_generator = JsonOutputGenerator(file_to=file_out) json_generator.server_scan_completed(scan_result) # We call scans_completed() because this is when the output actually gets written to the file json_generator.scans_completed(0.2) final_output = file_out.getvalue() # It succeeds assert final_output # And complex object like certificates were properly serialized assert "notBefore" in final_output assert "issuer" in final_output assert "subject" in final_output
def test_valid_chain_with_ev_cert(self): # Given a server to scan that has an EV certificate server_location = ServerNetworkLocationViaDirectConnection.with_ip_address_lookup( "www.digicert.com", 443) server_info = ServerConnectivityTester().perform(server_location) # When running the scan plugin_result = CertificateInfoImplementation.scan_server(server_info) # The result returns that the certificate is EV assert plugin_result.certificate_deployments[0].leaf_certificate_is_ev # And the result has other details about the certificate chain assert len(plugin_result.certificate_deployments[0]. received_certificate_chain) assert len(plugin_result.certificate_deployments[0]. verified_certificate_chain) assert not plugin_result.certificate_deployments[ 0].received_chain_contains_anchor_certificate assert len(plugin_result.certificate_deployments[0]. path_validation_results) == 5 for path_validation_result in plugin_result.certificate_deployments[ 0].path_validation_results: assert path_validation_result.was_validation_successful assert plugin_result.certificate_deployments[ 0].leaf_certificate_subject_matches_hostname assert plugin_result.certificate_deployments[ 0].received_chain_has_valid_order
def test_ca_file(self): # Given a server to scan server_location = ServerNetworkLocationViaDirectConnection.with_ip_address_lookup( "www.hotmail.com", 443) server_info = ServerConnectivityTester().perform(server_location) # And a valid path to a custom CA file ca_file_path = Path( __file__ ).parent / ".." / ".." / "certificates" / "wildcard-self-signed.pem" # When running the scan with the custom CA file enabled plugin_result = CertificateInfoImplementation.scan_server( server_info, CertificateInfoExtraArguments(custom_ca_file=ca_file_path)) # It succeeds assert len(plugin_result.certificate_deployments[0]. path_validation_results) >= 6 for path_validation_result in plugin_result.certificate_deployments[ 0].path_validation_results: if path_validation_result.trust_store.path == ca_file_path: assert not path_validation_result.was_validation_successful else: assert path_validation_result.was_validation_successful
def test_invalid_certificate_bad_name(self, certificate_name_field): # Given a server to scan server_location = ServerNetworkLocation("www.cloudflare.com", 443) server_info = check_connectivity_to_server_and_return_info( server_location) # And the server has a certificate with an invalid Subject field with mock.patch.object( cryptography.x509.Certificate, certificate_name_field, new_callable=PropertyMock) as mock_certificate_name: # https://github.com/nabla-c0d3/sslyze/issues/495 mock_certificate_name.side_effect = ValueError( "Country name must be a 2 character country code") # When running the scan, it succeeds scan_result = CertificateInfoImplementation.scan_server( server_info) # And the result can be converted to console output result_as_txt = CertificateInfoImplementation.cli_connector_cls.result_to_console_output( scan_result) assert result_as_txt # And the result can be converted to JSON result_as_json = CertificateInfoScanResultAsJson.from_orm( scan_result).json() assert result_as_json
def test_certificate_with_no_subject(self): # Given a server to scan that has a certificate with no Subject server_location = ServerNetworkLocationViaDirectConnection.with_ip_address_lookup("no-subject.badssl.com", 443) server_info = ServerConnectivityTester().perform(server_location) # When running the scan, it succeeds plugin_result = CertificateInfoImplementation.scan_server(server_info) assert plugin_result.certificate_deployments[0].verified_certificate_chain
def test_multiple_certificates(self): # Given a server to scan that exposes multiple certificates for maximum compatibility server_location = ServerNetworkLocationViaDirectConnection.with_ip_address_lookup("www.facebook.com", 443) server_info = ServerConnectivityTester().perform(server_location) # When running the scan, it succeeds plugin_result = CertificateInfoImplementation.scan_server(server_info) # And multiple certificates were detected assert len(plugin_result.certificate_deployments) > 1
def test_certificate_with_scts(self): # Given a server to scan that has a certificate with SCTS server_location = ServerNetworkLocationViaDirectConnection.with_ip_address_lookup("www.apple.com", 443) server_info = ServerConnectivityTester().perform(server_location) # When running the scan, it succeeds plugin_result = CertificateInfoImplementation.scan_server(server_info) # And the SCTS were detected assert plugin_result.certificate_deployments[0].leaf_certificate_signed_certificate_timestamps_count > 1
def test_chain_with_anchor(self): # Given a server to scan that has its anchor certificate returned in its chain server_location = ServerNetworkLocationViaDirectConnection.with_ip_address_lookup("www.verizon.com", 443) server_info = ServerConnectivityTester().perform(server_location) # When running the scan, it succeeds plugin_result = CertificateInfoImplementation.scan_server(server_info) # And the anchor certificate was detected assert plugin_result.certificate_deployments[0].received_chain_contains_anchor_certificate
def test_sha256_chain(self): # Given a server to scan that has a SHA256-signed certificate server_location = ServerNetworkLocationViaDirectConnection.with_ip_address_lookup("sha256.badssl.com", 443) server_info = ServerConnectivityTester().perform(server_location) # When running the scan plugin_result = CertificateInfoImplementation.scan_server(server_info) # No SHA1 signature is detected assert not plugin_result.certificate_deployments[0].verified_chain_has_sha1_signature
def test(self): # Given a completed scan for a CERTIFICATE_INFO scan command server_location = ServerNetworkLocationViaDirectConnection.with_ip_address_lookup( "www.facebook.com", 443) server_info = ServerConnectivityTester().perform(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 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_succeeds_when_client_auth_failed(self): # Given a server that requires client authentication with ModernOpenSslServer(client_auth_config=ClientAuthConfigEnum.REQUIRED) as server: # And the client does NOT provide a client certificate server_location = ServerNetworkLocationViaDirectConnection( hostname=server.hostname, port=server.port, ip_address=server.ip_address ) server_info = ServerConnectivityTester().perform(server_location) # When running the scan, it succeeds plugin_result = CertificateInfoImplementation.scan_server(server_info) assert plugin_result.certificate_deployments[0].received_certificate_chain
def test_valid_chain_with_ocsp_stapling(self): # Given a server to scan that supports OCSP stapling server_location = ServerNetworkLocationViaDirectConnection.with_ip_address_lookup("www.apple.com", 443) server_info = ServerConnectivityTester().perform(server_location) # When running the scan plugin_result = CertificateInfoImplementation.scan_server(server_info) # The result contains details about the server's OCSP config assert plugin_result.certificate_deployments[0].ocsp_response assert plugin_result.certificate_deployments[0].ocsp_response.status == OcspResponseStatusEnum.SUCCESSFUL assert plugin_result.certificate_deployments[0].ocsp_response_is_trusted assert not plugin_result.certificate_deployments[0].leaf_certificate_has_must_staple_extension
def test_ecdsa_certificate(self): # Given a server to scan that has an ECDSA certificate server_location = ServerNetworkLocationViaDirectConnection.with_ip_address_lookup( "www.cloudflare.com", 443) server_info = ServerConnectivityTester().perform(server_location) # When running the scan, it succeeds scan_result = CertificateInfoImplementation.scan_server(server_info) # And the result can be converted to JSON result_as_json = json.dumps(asdict(scan_result), cls=JsonEncoder) assert result_as_json # And the result can be converted to console output result_as_txt = CertificateInfoImplementation.cli_connector_cls.result_to_console_output( scan_result) assert result_as_txt
def test(self): # Given a completed scan for a server with the 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 converting it to JSON result_as_json = CertificateInfoScanResultAsJson.from_orm( plugin_result).json() # It succeeds assert result_as_json # And complex object like certificates were properly serialized assert "issuer" in result_as_json assert "subject" in result_as_json
def test_not_trusted_by_mozilla_but_trusted_by_microsoft(self): # Given a server to scan that has a certificate chain valid for the Microsoft but not the Mozilla trust stores server_location = ServerNetworkLocationViaDirectConnection.with_ip_address_lookup( "webmail.russia.nasa.gov", 443) server_info = ServerConnectivityTester().perform(server_location) # When running the scan, it succeeds plugin_result = CertificateInfoImplementation.scan_server(server_info) # And the chain was correctly identified as valid with the Microsoft store found_microsoft_store = False for validation_result in plugin_result.certificate_deployments[ 0].path_validation_results: if validation_result.trust_store.name == "Windows": found_microsoft_store = True assert validation_result.was_validation_successful break assert found_microsoft_store
def test_ecdsa_certificate(self): # Given a server to scan that has an ECDSA certificate server_location = ServerNetworkLocation("www.cloudflare.com", 443) server_info = check_connectivity_to_server_and_return_info( server_location) # When running the scan, it succeeds scan_result = CertificateInfoImplementation.scan_server(server_info) # And the result can be converted to JSON result_as_json = CertificateInfoScanResultAsJson.from_orm( scan_result).json() assert result_as_json # And the result can be converted to console output result_as_txt = CertificateInfoImplementation.cli_connector_cls.result_to_console_output( scan_result) assert result_as_txt
def test(self): # Given a completed scan for a server with the CERTIFICATE_INFO scan command server_location = ServerNetworkLocationViaDirectConnection.with_ip_address_lookup( "www.facebook.com", 443) server_info = ServerConnectivityTester().perform(server_location) plugin_result = CertificateInfoImplementation.scan_server(server_info) scan_results = {ScanCommand.CERTIFICATE_INFO: plugin_result} scan_result = ServerScanResultFactory.create( scan_commands_results=scan_results) # When converting it into to JSON result_as_json = json.dumps(asdict(scan_result), cls=sslyze.JsonEncoder) # It succeeds assert result_as_json # And complex object like certificates were properly serialized assert "issuer" in result_as_json assert "subject" in result_as_json
def test_rsa_certificate(self): # Given a server that is configured with an RSA certificate with ModernOpenSslServer() as server: server_location = ServerNetworkLocationViaDirectConnection( hostname=server.hostname, port=server.port, ip_address=server.ip_address) server_info = ServerConnectivityTester().perform(server_location) # When running the scan, it succeeds scan_result = CertificateInfoImplementation.scan_server( server_info) assert scan_result.certificate_deployments[ 0].received_certificate_chain # And the result can be converted to JSON result_as_json = json.dumps(asdict(scan_result), cls=JsonEncoder) assert result_as_json # And the result can be converted to console output result_as_txt = CertificateInfoImplementation.cli_connector_cls.result_to_console_output( scan_result) assert result_as_txt