Example #1
0
    def test_error_server_connectivity_issue_handshake_timeout(self, mock_scan_commands):
        # Given a server to scan with some commands
        server_scan = ServerScanRequest(
            server_info=ServerConnectivityInfoFactory.create(),
            scan_commands={ScanCommandForTests.MOCK_COMMAND_1, ScanCommandForTests.MOCK_COMMAND_2},
        )

        # And the first scan command will trigger a handshake timeout with the server
        with mock.patch.object(
            MockPlugin1Implementation,
            "_scan_job_work_function",
            side_effect=TlsHandshakeTimedOut(
                server_location=server_scan.server_info.server_location,
                network_configuration=server_scan.server_info.network_configuration,
                error_message="error",
            ),
        ):
            # When queuing the scan
            scanner = Scanner()
            scanner.queue_scan(server_scan)

        # It succeeds
        for result in scanner.get_results():
            # And the error was properly caught and returned
            assert len(result.scan_commands_errors) == 1
            error = result.scan_commands_errors[ScanCommandForTests.MOCK_COMMAND_1]
            assert ScanCommandErrorReasonEnum.CONNECTIVITY_ISSUE == error.reason
            assert error.exception_trace
Example #2
0
 def _scan_job_work_function(arg1: str) -> str:
     raise TlsHandshakeTimedOut(
         server_location=server_scan_request.server_location,
         network_configuration=server_scan_request.
         network_configuration,
         error_message="error",
     )
Example #3
0
    def connect(self, should_retry_connection: bool = True) -> None:
        max_attempts_nb = self._network_configuration.network_max_retries if should_retry_connection else 1
        connection_attempts_nb = 0
        delay_for_next_attempt = 0

        # First try to connect to the server, and do retries if there are timeouts
        while True:
            # Sleep if it's a retry attempt
            time.sleep(delay_for_next_attempt)
            try:
                self._do_pre_handshake()
            except socket.timeout:
                # Attempt to retry connection if a network error occurred during connection or the handshake
                connection_attempts_nb += 1
                if connection_attempts_nb >= max_attempts_nb:
                    # Exhausted the number of retry attempts, give up
                    raise ConnectionToServerTimedOut(
                        server_location=self._server_location,
                        network_configuration=self._network_configuration,
                        error_message="Connection to the server timed out",
                    )
                elif connection_attempts_nb == 1:
                    # Start with a 1 second delay
                    delay_for_next_attempt = 1
                else:
                    # Exponential back off; cap maximum delay at 6 seconds
                    delay_for_next_attempt = min(6, 2 * delay_for_next_attempt)
            except ConnectionError:
                raise ServerRejectedConnection(
                    server_location=self._server_location,
                    network_configuration=self._network_configuration,
                    error_message="Server rejected the connection",
                )
            except OSError:
                # OSError is the parent class of all socket (ie. non-TLS) connection errors such as socket.timeout or
                # ConnectionError; hence this is the most generic error handler and should always be defined last
                raise ConnectionToServerFailed(
                    server_location=self._server_location,
                    network_configuration=self._network_configuration,
                    error_message="Connection to the server failed",
                )

            else:
                # No network error occurred
                break

        # After successfully connecting to the server, perform the TLS handshake
        try:
            self.ssl_client.do_handshake()

        except ClientCertificateRequested:
            # Server expected a client certificate and we didn't provide one
            raise
        except socket.timeout:
            # Network timeout, propagate the error
            raise TlsHandshakeTimedOut(
                server_location=self._server_location,
                network_configuration=self._network_configuration,
                error_message=
                "Connection to server timed out during the TLS handshake",
            )
        except ConnectionError:
            raise ServerRejectedTlsHandshake(
                server_location=self._server_location,
                network_configuration=self._network_configuration,
                error_message="Server rejected the connection",
            )
        except OSError as e:
            # OSError is the parent of all (non-TLS) socket/connection errors so it should be last
            if "Nassl SSL handshake failed" in e.args[0]:
                # Special error returned by nassl
                raise ServerRejectedTlsHandshake(
                    server_location=self._server_location,
                    network_configuration=self._network_configuration,
                    error_message="Server rejected the connection",
                )
            # Unknown connection error
            raise
        except _nassl.OpenSSLError as e:
            openssl_error_message = e.args[0]
            if "dh key too small" in openssl_error_message:
                # This is when SSLyze's OpenSSL rejects DH parameters (to protect against Logjam); this actually
                # means the server supports whatever cipher suite was used
                raise ServerTlsConfigurationNotSupported(
                    server_location=self._server_location,
                    network_configuration=self._network_configuration,
                    error_message="DH key too small",
                )

            if "no ciphers available" in openssl_error_message:
                # This one is returned by OpenSSL when a cipher set via set_cipher_list() is not actually supported
                # Should never happen (SSLyze bugs)
                raise NoCiphersAvailableBugInSSlyze(
                    f"Set a cipher that is not supported by nassl: {self.ssl_client.get_cipher_list()}"
                )

            for error_msg in _HANDSHAKE_REJECTED_TLS_ERRORS.keys():
                if error_msg in openssl_error_message:
                    raise ServerRejectedTlsHandshake(
                        server_location=self._server_location,
                        network_configuration=self._network_configuration,
                        error_message=_HANDSHAKE_REJECTED_TLS_ERRORS[
                            error_msg],
                    )

            # Unknown SSL error if we get there
            raise