Beispiel #1
0
class ClientAuthenticationTestCase(unittest.TestCase):
    @unittest.skipIf(not ModernOpenSslServer.is_platform_supported(),
                     'Not on Linux 64')
    def test_optional_client_auth(self):
        # Given a server that supports optional client authentication
        with ModernOpenSslServer(
                client_auth_config=ClientAuthConfigEnum.OPTIONAL) as server:
            server_test = ServerConnectivityTester(
                hostname=server.hostname,
                ip_address=server.ip_address,
                port=server.port)
            server_info = server_test.perform()

        # SSLyze correctly detects that client auth is optional
        self.assertEqual(server_info.client_auth_requirement,
                         ClientAuthenticationServerConfigurationEnum.OPTIONAL)

    @unittest.skipIf(not ModernOpenSslServer.is_platform_supported(),
                     'Not on Linux 64')
    def test_required_client_auth(self):
        # Given a server that requires client authentication
        with ModernOpenSslServer(
                client_auth_config=ClientAuthConfigEnum.REQUIRED) as server:
            server_test = ServerConnectivityTester(
                hostname=server.hostname,
                ip_address=server.ip_address,
                port=server.port)
            server_info = server_test.perform()

        # SSLyze correctly detects that client auth is required
        self.assertEqual(server_info.client_auth_requirement,
                         ClientAuthenticationServerConfigurationEnum.REQUIRED)
    def test_works_when_client_auth_succeeded(self):
        # Given a server that requires client authentication
        with ModernOpenSslServer(
                client_auth_config=ClientAuthConfigEnum.REQUIRED) as server:
            # And the client provides a client certificate
            client_creds = ClientAuthenticationCredentials(
                client_certificate_chain_path=server.
                get_client_certificate_path(),
                client_key_path=server.get_client_key_path(),
            )

            server_test = ServerConnectivityTester(
                hostname=server.hostname,
                ip_address=server.ip_address,
                port=server.port,
                client_auth_credentials=client_creds,
            )
            server_info = server_test.perform()

            # The plugin works fine
            plugin = HttpHeadersPlugin()
            plugin_result = plugin.process_task(server_info,
                                                HttpHeadersScanCommand())

        self.assertIsNone(plugin_result.expect_ct_header)
        self.assertTrue(plugin_result.as_text())
        self.assertTrue(plugin_result.as_xml())
Beispiel #3
0
    def test_tls_1_3_write_early_data_fail_when_trying_to_send_more_than_max_early_data(self):
        # Given a server that supports TLS 1.3 and early data
        with ModernOpenSslServer(max_early_data=1) as server:
            # That has a previous TLS 1.3 session with the server
            session = self._create_tls_1_3_session(server.hostname, server.port)
            assert session

            # And the server only accepts 1 byte of early data
            max_early = session.get_max_early_data()
            assert 1 == max_early

            # When creating a new connection
            sock_early_data = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            sock_early_data.settimeout(5)
            sock_early_data.connect((server.hostname, server.port))

            ssl_client_early_data = SslClient(
                ssl_version=OpenSslVersionEnum.TLSV1_3,
                underlying_socket=sock_early_data,
                ssl_verify=OpenSslVerifyEnum.NONE
            )

            # That re-uses the previous TLS 1.3 session
            ssl_client_early_data.set_session(session)
            assert OpenSslEarlyDataStatusEnum.NOT_SENT == ssl_client_early_data.get_early_data_status()

            # When sending too much early data
            # It fails
            with pytest.raises(OpenSSLError, match='too much early data'):
                ssl_client_early_data.write_early_data(
                    'GET / HTTP/1.1\r\nData: {}\r\n\r\n'.format('*' * max_early).encode('ascii')
                )

            ssl_client_early_data.shutdown()
Beispiel #4
0
    def test_get_dh_info_ecdh_p256(self):
        with ModernOpenSslServer(cipher="ECDHE-RSA-AES256-SHA",
                                 groups="P-256") as server:
            sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            sock.settimeout(5)
            sock.connect((server.hostname, server.port))

            ssl_client = SslClient(ssl_version=OpenSslVersionEnum.TLSV1_2,
                                   underlying_socket=sock,
                                   ssl_verify=OpenSslVerifyEnum.NONE)

            try:
                ssl_client.do_handshake()
            finally:
                ssl_client.shutdown()

            dh_info = ssl_client.get_dh_info()

            assert isinstance(dh_info, NistEcDhKeyExchangeInfo)
            assert dh_info.key_type == OpenSslEvpPkeyEnum.EC
            assert dh_info.key_size == 256
            assert dh_info.curve == OpenSslEcNidEnum.PRIME256V1
            assert len(dh_info.public_key) == 65
            assert len(dh_info.x) == 32
            assert len(dh_info.y) == 32
    def test_works_when_client_auth_succeeded(self):
        # Given a server that requires client authentication
        with ModernOpenSslServer(
                client_auth_config=ClientAuthConfigEnum.REQUIRED) as server:
            # And the client provides a client certificate
            client_creds = ClientAuthenticationCredentials(
                client_certificate_chain_path=server.
                get_client_certificate_path(),
                client_key_path=server.get_client_key_path(),
            )

            server_test = ServerConnectivityTester(
                hostname=server.hostname,
                ip_address=server.ip_address,
                port=server.port,
                client_auth_credentials=client_creds,
            )
            server_info = server_test.perform()

            # SessionResumptionPlugin works fine
            plugin = SessionResumptionPlugin()
            plugin_result = plugin.process_task(
                server_info, SessionResumptionSupportScanCommand())

        assert plugin_result.successful_resumptions_nb == 5
        assert plugin_result.as_text()
        assert plugin_result.as_xml()
    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
Beispiel #7
0
    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
Beispiel #8
0
    def test_server_cipher_ordering(self):
        configured_ciphers = [
            'ECDHE-RSA-CHACHA20-POLY1305', 'ECDHE-RSA-AES128-GCM-SHA256',
            'ECDHE-RSA-AES256-GCM-SHA384', 'ECDHE-RSA-AES128-SHA256',
            'ECDHE-RSA-AES256-SHA384', 'ECDHE-RSA-AES128-SHA',
            'ECDHE-RSA-AES256-SHA', 'AES128-GCM-SHA256', 'AES256-GCM-SHA384',
            'AES128-SHA256', 'AES256-SHA256', 'AES128-SHA', 'AES256-SHA'
        ]
        random.shuffle(configured_ciphers)
        cipher_string = ":".join(configured_ciphers)

        with ModernOpenSslServer(cipher=cipher_string,
                                 prefer_server_order=True) as server:
            # And the client does NOT provide a client certificate
            server_test = ServerConnectivityTester(
                hostname=server.hostname,
                ip_address=server.ip_address,
                port=server.port)
            server_info = server_test.perform()

            # OpenSslCipherSuitesPlugin works even when a client cert was not supplied
            plugin = OpenSslCipherSuitesPlugin()
            plugin_result = plugin.process_task(server_info,
                                                Tlsv12ScanCommand())

            detected_ciphers = [
                c.openssl_name for c in plugin_result.accepted_cipher_list
            ]

        assert configured_ciphers == detected_ciphers
Beispiel #9
0
    def test_cipher_suite_preferred_by_server(self):
        # Given an ordered list of cipher suites
        configured_cipher_suites = [
            "ECDHE-RSA-CHACHA20-POLY1305",
            "ECDHE-RSA-AES128-GCM-SHA256",
            "ECDHE-RSA-AES256-GCM-SHA384",
            "ECDHE-RSA-AES128-SHA256",
            "ECDHE-RSA-AES256-SHA384",
            "ECDHE-RSA-AES128-SHA",
            "ECDHE-RSA-AES256-SHA",
            "AES128-GCM-SHA256",
            "AES256-GCM-SHA384",
            "AES128-SHA256",
            "AES256-SHA256",
            "AES128-SHA",
            "AES256-SHA",
        ]
        random.shuffle(configured_cipher_suites)
        cipher_string = ":".join(configured_cipher_suites)

        # And a server that is configured with this list as its prefered cipher suites
        with ModernOpenSslServer(
            openssl_cipher_string=cipher_string, should_enable_server_cipher_preference=True
        ) as server:
            server_location = ServerNetworkLocationViaDirectConnection(
                hostname=server.hostname, ip_address=server.ip_address, port=server.port
            )
            server_info = ServerConnectivityTester().perform(server_location)

            # When scanning for cipher suites, it succeeds
            result: CipherSuitesScanResult = Tlsv12ScanImplementation.scan_server(server_info)

        # And the server's cipher suite preference was detected
        assert result.cipher_suite_preferred_by_server
        assert configured_cipher_suites[0] == result.cipher_suite_preferred_by_server.cipher_suite.openssl_name
Beispiel #10
0
    def test_get_dh_info_ecdh_x25519(self):
        with ModernOpenSslServer(cipher="ECDHE-RSA-AES256-SHA",
                                 groups="X25519") as server:
            sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            sock.settimeout(5)
            sock.connect((server.hostname, server.port))

            ssl_client = SslClient(
                ssl_version=OpenSslVersionEnum.TLSV1_2,
                underlying_socket=sock,
                ssl_verify=OpenSslVerifyEnum.NONE,
            )

            try:
                ssl_client.do_handshake()
            finally:
                ssl_client.shutdown()

            dh_info = ssl_client.get_ephemeral_key()

            assert isinstance(dh_info, EcDhEphemeralKeyInfo)
            assert dh_info.type == OpenSslEvpPkeyEnum.X25519
            assert dh_info.size == 253
            assert dh_info.curve == OpenSslEcNidEnum.X25519
            assert len(dh_info.public_bytes) == 32
Beispiel #11
0
    def test_set_groups_curve_x448(self):
        # Given a server that supports a bunch of curves
        with ModernOpenSslServer(
                cipher="ECDHE-RSA-AES256-SHA",
                groups="X25519:prime256v1:X448:secp384r1:secp192k1") as server:
            sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            sock.settimeout(5)
            sock.connect((server.hostname, server.port))

            # And a client that only supports a specific curve: X448
            ssl_client = SslClient(
                ssl_version=OpenSslVersionEnum.TLSV1_2,
                underlying_socket=sock,
                ssl_verify=OpenSslVerifyEnum.NONE,
            )
            configured_curve = OpenSslEcNidEnum.X448
            ssl_client.set_groups([configured_curve])

            # When the client connects to the server
            try:
                ssl_client.do_handshake()
            finally:
                ssl_client.shutdown()

            # The curve enabled in the client is the one that was used
            dh_info = ssl_client.get_ephemeral_key()
            assert isinstance(dh_info, EcDhEphemeralKeyInfo)
            assert dh_info.curve == configured_curve
            assert dh_info.type == OpenSslEvpPkeyEnum.X448
            assert dh_info.size == 448
            assert len(dh_info.public_bytes) == 56
    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_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
Beispiel #14
0
    def test_optional_client_auth(self):
        # Given a server that supports optional client authentication
        with ModernOpenSslServer(
                client_auth_config=ClientAuthConfigEnum.OPTIONAL) as server:
            server_location = ServerNetworkLocationViaDirectConnection(
                hostname=server.hostname,
                port=server.port,
                ip_address=server.ip_address)
            server_info = ServerConnectivityTester().perform(server_location)

        # SSLyze correctly detects that client auth is optional
        assert server_info.tls_probing_result.client_auth_requirement == ClientAuthRequirementEnum.OPTIONAL
Beispiel #15
0
    def test_optional_client_auth(self):
        # Given a server that supports optional client authentication
        with ModernOpenSslServer(client_auth_config=ClientAuthConfigEnum.OPTIONAL) as server:
            server_test = ServerConnectivityTester(
                hostname=server.hostname,
                ip_address=server.ip_address,
                port=server.port
            )
            server_info = server_test.perform()

        # SSLyze correctly detects that client auth is optional
        assert server_info.client_auth_requirement == ClientAuthenticationServerConfigurationEnum.OPTIONAL
Beispiel #16
0
    def test_required_client_auth_tls_1_3(self):
        # Given a TLS 1.3 server that requires client authentication
        with ModernOpenSslServer(client_auth_config=ClientAuthConfigEnum.REQUIRED) as server:
            server_test = ServerConnectivityTester(
                hostname=server.hostname,
                ip_address=server.ip_address,
                port=server.port
            )
            server_info = server_test.perform()

        # SSLyze correctly detects that client auth is required
        # TODO(AD): Fix this bug; it should be REQUIRED
        assert server_info.client_auth_requirement == ClientAuthenticationServerConfigurationEnum.OPTIONAL
Beispiel #17
0
    def test_required_client_auth_tls_1_3(self):
        # Given a TLS 1.3 server that requires client authentication
        with ModernOpenSslServer(
                client_auth_config=ClientAuthConfigEnum.REQUIRED) as server:
            server_location = ServerNetworkLocationViaDirectConnection(
                hostname=server.hostname,
                port=server.port,
                ip_address=server.ip_address)

            server_info = ServerConnectivityTester().perform(server_location)

        # SSLyze correctly detects that client auth is required
        assert server_info.tls_probing_result.client_auth_requirement == ClientAuthRequirementEnum.REQUIRED
Beispiel #18
0
    def test_succeeds_when_client_auth_failed_tls_1_3(self):
        # Given a TLS 1.3 server that requires client authentication
        with ModernOpenSslServer(client_auth_config=ClientAuthConfigEnum.REQUIRED) as server:
            # And SSLyze does NOT provide a client certificate
            server_location = ServerNetworkLocationViaDirectConnection(
                hostname=server.hostname, ip_address=server.ip_address, port=server.port
            )
            server_info = ServerConnectivityTester().perform(server_location)

            # When scanning for cipher suites, it succeeds
            result: CipherSuitesScanResult = Tlsv13ScanImplementation.scan_server(server_info)

        assert result.accepted_cipher_suites
Beispiel #19
0
    def test_required_client_auth(self):
        # Given a server that requires client authentication
        with ModernOpenSslServer(
                client_auth_config=ClientAuthConfigEnum.REQUIRED) as server:
            server_test = ServerConnectivityTester(
                hostname=server.hostname,
                ip_address=server.ip_address,
                port=server.port)
            server_info = server_test.perform()

        # SSLyze correctly detects that client auth is required
        self.assertEqual(server_info.client_auth_requirement,
                         ClientAuthenticationServerConfigurationEnum.REQUIRED)
Beispiel #20
0
    def test_fails_when_client_auth_failed_session(self):
        # Given a server that requires client authentication
        with ModernOpenSslServer(
                client_auth_config=ClientAuthConfigEnum.REQUIRED) as server:
            # And sslyze does NOT provide a client certificate
            server_location = ServerNetworkLocationViaDirectConnection(
                hostname=server.hostname,
                ip_address=server.ip_address,
                port=server.port)
            server_info = ServerConnectivityTester().perform(server_location)

            # When testing for resumption, it fails
            with pytest.raises(ClientCertificateRequested):
                SessionResumptionSupportImplementation.perform(server_info)
Beispiel #21
0
    def test_tls_1_3(self):
        # Given a server that supports TLS 1.3
        with ModernOpenSslServer() as server:
            sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            sock.settimeout(5)
            sock.connect((server.hostname, server.port))

            ssl_client = SslClient(ssl_version=OpenSslVersionEnum.TLSV1_3,
                                   underlying_socket=sock,
                                   ssl_verify=OpenSslVerifyEnum.NONE)
            # When doing the TLS 1.3 handshake, it succeeds
            try:
                ssl_client.do_handshake()
            finally:
                ssl_client.shutdown()
    def test_fails_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_test = ServerConnectivityTester(
                hostname=server.hostname,
                ip_address=server.ip_address,
                port=server.port)
            server_info = server_test.perform()

            # The plugin fails when a client cert was not supplied
            plugin = HttpHeadersPlugin()
            with self.assertRaises(ClientCertificateRequested):
                plugin.process_task(server_info, HttpHeadersScanCommand())
    def test_early_data_enabled(self):
        # Given a server to scan that supports early data
        with ModernOpenSslServer(max_early_data=256) as server:
            server_location = ServerNetworkLocationViaDirectConnection(
                hostname=server.hostname,
                ip_address=server.ip_address,
                port=server.port)
            server_info = ServerConnectivityTester().perform(server_location)

            # When testing for early data support, it succeeds
            result: EarlyDataScanResult = EarlyDataImplementation.perform(
                server_info)

        # And the right result is returned
        assert result.supports_early_data
Beispiel #24
0
    def test_optional_client_auth(self):
        # Given a server that supports optional client authentication
        with ModernOpenSslServer(
                client_auth_config=ClientAuthConfigEnum.OPTIONAL) as server:
            server_location = ServerNetworkLocation(
                hostname=server.hostname,
                port=server.port,
                ip_address=server.ip_address)
            tls_probing_result = check_connectivity_to_server(
                server_location=server_location,
                network_configuration=ServerNetworkConfiguration.
                default_for_server_location(server_location),
            )

        # SSLyze correctly detects that client auth is optional
        assert tls_probing_result.client_auth_requirement == ClientAuthRequirementEnum.OPTIONAL
Beispiel #25
0
    def test_client_authentication_tls_1_3(self):
        # Given a server that requires client authentication
        with ModernOpenSslServer(
                client_auth_config=ClientAuthConfigEnum.REQUIRED) as server:
            # And the client provides an invalid client certificate (actually the server cert)
            sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            sock.settimeout(5)
            sock.connect((server.hostname, server.port))

            ssl_client = SslClient(ssl_version=OpenSslVersionEnum.TLSV1_3,
                                   underlying_socket=sock,
                                   ssl_verify=OpenSslVerifyEnum.NONE)

            # When doing the handshake the right error is returned
            with pytest.raises(ClientCertificateRequested):
                ssl_client.do_handshake()
Beispiel #26
0
    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
Beispiel #27
0
    def test_required_client_auth_tls_1_3(self):
        # Given a TLS 1.3 server that requires client authentication
        with ModernOpenSslServer(
                client_auth_config=ClientAuthConfigEnum.REQUIRED) as server:
            server_location = ServerNetworkLocation(
                hostname=server.hostname,
                port=server.port,
                ip_address=server.ip_address)

            tls_probing_result = check_connectivity_to_server(
                server_location=server_location,
                network_configuration=ServerNetworkConfiguration.
                default_for_server_location(server_location),
            )

        # SSLyze correctly detects that client auth is required
        assert tls_probing_result.client_auth_requirement == ClientAuthRequirementEnum.REQUIRED
    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_test = ServerConnectivityTester(
                hostname=server.hostname,
                ip_address=server.ip_address,
                port=server.port
            )
            server_info = server_test.perform()

            # CertificateInfoPlugin works even when a client cert was not supplied
            plugin = CertificateInfoPlugin()
            plugin_result = plugin.process_task(server_info, CertificateInfoScanCommand())

        assert plugin_result.received_certificate_chain
        assert plugin_result.as_text()
        assert plugin_result.as_xml()
Beispiel #29
0
    def test_client_authentication_no_certificate_supplied(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
            sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            sock.settimeout(5)
            sock.connect((server.hostname, server.port))

            ssl_client = self._SSL_CLIENT_CLS(
                ssl_version=OpenSslVersionEnum.SSLV23,
                underlying_socket=sock,
                ssl_verify=OpenSslVerifyEnum.NONE,
            )
            # When doing the handshake the right error is returned
            self.assertRaisesRegex(ClientCertificateRequested,
                                   'Server requested a client certificate',
                                   ssl_client.do_handshake)
Beispiel #30
0
class RobotPluginPluginTestCase(unittest.TestCase):
    def test_robot_attack_good(self):
        # Validate the bug fix for https://github.com/nabla-c0d3/sslyze/issues/282
        server_test = ServerConnectivityTester(hostname='guide.duo.com')
        server_info = server_test.perform()

        plugin = RobotPlugin()
        plugin_result = plugin.process_task(server_info, RobotScanCommand())

        # On Travis CI we sometimes get inconsistent results
        if IS_RUNNING_ON_TRAVIS:
            self.assertIn(plugin_result.robot_result_enum, [
                RobotScanResultEnum.NOT_VULNERABLE_NO_ORACLE,
                RobotScanResultEnum.UNKNOWN_INCONSISTENT_RESULTS
            ])
        else:
            self.assertEqual(plugin_result.robot_result_enum,
                             RobotScanResultEnum.NOT_VULNERABLE_NO_ORACLE)

        self.assertTrue(plugin_result.as_text())
        self.assertTrue(plugin_result.as_xml())

    @unittest.skip('Not implemented')
    def test_robot_attack_bad(self):
        # TODO(AD): Find a vulnerable server?
        pass

    @unittest.skipIf(not ModernOpenSslServer.is_platform_supported(),
                     'Not on Linux 64')
    def test_fails_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_test = ServerConnectivityTester(
                hostname=server.hostname,
                ip_address=server.ip_address,
                port=server.port)
            server_info = server_test.perform()

            # The plugin fails when a client cert was not supplied
            plugin = RobotPlugin()
            with self.assertRaises(ClientCertificateRequested):
                plugin.process_task(server_info, RobotScanCommand())