def _test_cipher_suite(server_connectivity_info, ssl_version, openssl_cipher_name):
        # type: (ServerConnectivityInfo, OpenSslVersionEnum, Text) -> CipherSuite
        """Initiates a SSL handshake with the server using the SSL version and the cipher suite specified.
        """
        requires_legacy_openssl = None
        if ssl_version == OpenSslVersionEnum.TLSV1_2:
            # For TLS 1.2, we need to pick the right version of OpenSSL depending on which cipher suite
            requires_legacy_openssl = WorkaroundForTls12ForCipherSuites.requires_legacy_openssl(openssl_cipher_name)

        ssl_connection = server_connectivity_info.get_preconfigured_ssl_connection(
            override_ssl_version=ssl_version,
            should_use_legacy_openssl=requires_legacy_openssl
        )
        ssl_connection.ssl_client.set_cipher_list(openssl_cipher_name)
        if len(ssl_connection.ssl_client.get_cipher_list()) != 1:
            raise ValueError('Passed an OpenSSL string for multiple cipher suites: "{}"'.format(openssl_cipher_name))

        try:
            # Perform the SSL handshake
            ssl_connection.connect()
            cipher_result = AcceptedCipherSuite.from_ongoing_ssl_connection(ssl_connection, ssl_version)

        except SSLHandshakeRejected as e:
            cipher_result = RejectedCipherSuite(openssl_cipher_name, ssl_version, str(e))

        except ClientCertificateRequested:
            cipher_result = AcceptedCipherSuite.from_ongoing_ssl_connection(ssl_connection, ssl_version)

        except Exception as e:
            cipher_result = ErroredCipherSuite(openssl_cipher_name, ssl_version, e)
            
        finally:
            ssl_connection.close()

        return cipher_result
Exemple #2
0
    def _get_preferred_cipher_suite(
        cls,
        server_connectivity_info: ServerConnectivityInfo,
        ssl_version: OpenSslVersionEnum,
        accepted_cipher_list: List["AcceptedCipherSuite"],
    ) -> Optional["AcceptedCipherSuite"]:
        """Try to detect the server's preferred cipher suite among all cipher suites supported by SSLyze.
        """
        if len(accepted_cipher_list) < 2:
            return None

        accepted_cipher_names = [
            cipher.openssl_name for cipher in accepted_cipher_list
        ]
        should_use_legacy_openssl = None

        # For TLS 1.2, we need to figure whether the modern or legacy OpenSSL should be used to connect
        if ssl_version == OpenSslVersionEnum.TLSV1_2:
            should_use_legacy_openssl = True
            # If there are more than two modern-supported cipher suites, use the modern OpenSSL
            for cipher_name in accepted_cipher_names:
                modern_supported_cipher_count = 0
                if not WorkaroundForTls12ForCipherSuites.requires_legacy_openssl(
                        cipher_name):
                    modern_supported_cipher_count += 1

                if modern_supported_cipher_count > 1:
                    should_use_legacy_openssl = False
                    break

        first_cipher_str = ", ".join(accepted_cipher_names)
        # Swap the first two ciphers in the list to see if the server always picks the client's first cipher
        second_cipher_str = ", ".join(
            [accepted_cipher_names[1], accepted_cipher_names[0]] +
            accepted_cipher_names[2:])

        try:
            first_cipher = cls._get_selected_cipher_suite(
                server_connectivity_info, ssl_version, first_cipher_str,
                should_use_legacy_openssl)
            second_cipher = cls._get_selected_cipher_suite(
                server_connectivity_info, ssl_version, second_cipher_str,
                should_use_legacy_openssl)
        except (SslHandshakeRejected, ConnectionError):
            # Could not complete a handshake
            return None

        if first_cipher.name == second_cipher.name:
            # The server has its own preference for picking a cipher suite
            return first_cipher
        else:
            # The server has no preferred cipher suite as it follows the client's preference for picking a cipher suite
            return None
    def _get_preferred_cipher_suite(
            cls,
            server_connectivity_info: ServerConnectivityInfo,
            ssl_version: OpenSslVersionEnum,
            accepted_cipher_list: List['AcceptedCipherSuite']
    ) -> Optional['AcceptedCipherSuite']:
        """Try to detect the server's preferred cipher suite among all cipher suites supported by SSLyze.
        """
        if len(accepted_cipher_list) < 2:
            return None

        accepted_cipher_names = [cipher.openssl_name for cipher in accepted_cipher_list]
        should_use_legacy_openssl = None

        # For TLS 1.2, we need to figure whether the modern or legacy OpenSSL should be used to connect
        if ssl_version == OpenSslVersionEnum.TLSV1_2:
            should_use_legacy_openssl = True
            # If there are more than two modern-supported cipher suites, use the modern OpenSSL
            for cipher_name in accepted_cipher_names:
                modern_supported_cipher_count = 0
                if not WorkaroundForTls12ForCipherSuites.requires_legacy_openssl(cipher_name):
                    modern_supported_cipher_count += 1

                if modern_supported_cipher_count > 1:
                    should_use_legacy_openssl = False
                    break

        first_cipher_str = ', '.join(accepted_cipher_names)
        # Swap the first two ciphers in the list to see if the server always picks the client's first cipher
        second_cipher_str = ', '.join([accepted_cipher_names[1], accepted_cipher_names[0]] + accepted_cipher_names[2:])

        try:
            first_cipher = cls._get_selected_cipher_suite(
                server_connectivity_info, ssl_version, first_cipher_str, should_use_legacy_openssl
            )
            second_cipher = cls._get_selected_cipher_suite(
                server_connectivity_info, ssl_version, second_cipher_str, should_use_legacy_openssl
            )
        except (SslHandshakeRejected, ConnectionError):
            # Could not complete a handshake
            return None

        if first_cipher.name == second_cipher.name:
            # The server has its own preference for picking a cipher suite
            return first_cipher
        else:
            # The server has no preferred cipher suite as it follows the client's preference for picking a cipher suite
            return None
    def _should_use_legacy_openssl(self, ssl_version, accepted_ciphers):
        # For TLS 1.2, we need to figure whether the modern or legacy OpenSSL should be used to connect

        should_use_legacy_openssl = None
        if ssl_version == OpenSslVersionEnum.TLSV1_2:
            should_use_legacy_openssl = True
            # If there are more than two modern-supported cipher suites, use the modern OpenSSL
            for cipher in accepted_ciphers:
                modern_supported_cipher_count = 0
                if not WorkaroundForTls12ForCipherSuites.requires_legacy_openssl(cipher.openssl_name):
                    modern_supported_cipher_count += 1

                if modern_supported_cipher_count > 1:
                    should_use_legacy_openssl = False
                    break

        return should_use_legacy_openssl
Exemple #5
0
    def _test_cipher_suite(server_connectivity_info, ssl_version,
                           openssl_cipher_name):
        # type: (ServerConnectivityInfo, OpenSslVersionEnum, Text) -> CipherSuite
        """Initiates a SSL handshake with the server using the SSL version and the cipher suite specified.
        """
        requires_legacy_openssl = None
        if ssl_version == OpenSslVersionEnum.TLSV1_2:
            # For TLS 1.2, we need to pick the right version of OpenSSL depending on which cipher suite
            requires_legacy_openssl = WorkaroundForTls12ForCipherSuites.requires_legacy_openssl(
                openssl_cipher_name)

        ssl_connection = server_connectivity_info.get_preconfigured_ssl_connection(
            override_ssl_version=ssl_version,
            should_use_legacy_openssl=requires_legacy_openssl)
        ssl_connection.ssl_client.set_cipher_list(openssl_cipher_name)
        if len(ssl_connection.ssl_client.get_cipher_list()) != 1:
            raise ValueError(
                'Passed an OpenSSL string for multiple cipher suites: "{}"'.
                format(openssl_cipher_name))

        try:
            # Perform the SSL handshake
            ssl_connection.connect()
            cipher_result = AcceptedCipherSuite.from_ongoing_ssl_connection(
                ssl_connection, ssl_version)  # type: CipherSuite

        except SSLHandshakeRejected as e:
            cipher_result = RejectedCipherSuite(openssl_cipher_name,
                                                ssl_version, str(e))

        except ClientCertificateRequested:
            cipher_result = AcceptedCipherSuite.from_ongoing_ssl_connection(
                ssl_connection, ssl_version)

        except Exception as e:
            cipher_result = ErroredCipherSuite(openssl_cipher_name,
                                               ssl_version, e)

        finally:
            ssl_connection.close()

        return cipher_result
    def _test_cipher_suite(server_connectivity_info: ServerConnectivityInfo,
                           ssl_version: OpenSslVersionEnum,
                           openssl_cipher_name: str) -> 'CipherSuite':
        """Initiates a SSL handshake with the server using the SSL version and the cipher suite specified.
        """
        requires_legacy_openssl = True
        if ssl_version == OpenSslVersionEnum.TLSV1_2:
            # For TLS 1.2, we need to pick the right version of OpenSSL depending on which cipher suite
            requires_legacy_openssl = WorkaroundForTls12ForCipherSuites.requires_legacy_openssl(
                openssl_cipher_name)
        elif ssl_version == OpenSslVersionEnum.TLSV1_3:
            requires_legacy_openssl = False

        ssl_connection = server_connectivity_info.get_preconfigured_ssl_connection(
            override_ssl_version=ssl_version,
            should_use_legacy_openssl=requires_legacy_openssl)

        # Only enable the cipher suite to test; not trivial anymore since OpenSSL 1.1.1 and TLS 1.3
        if ssl_version == OpenSslVersionEnum.TLSV1_3:
            # The function to control cipher suites is different for TLS 1.3
            # Disable the default, non-TLS 1.3 cipher suites
            ssl_connection.ssl_client.set_cipher_list('')
            # Enable the one TLS 1.3 cipher suite we want to test
            ssl_connection.ssl_client.set_ciphersuites(openssl_cipher_name)
        else:
            if not requires_legacy_openssl:
                # Disable the TLS 1.3 cipher suites if we are using the modern client
                ssl_connection.ssl_client.set_ciphersuites('')

            ssl_connection.ssl_client.set_cipher_list(openssl_cipher_name)

        if len(ssl_connection.ssl_client.get_cipher_list()) != 1:
            raise ValueError(
                f'Passed an OpenSSL string for multiple cipher suites: "{openssl_cipher_name}": '
                f'{str(ssl_connection.ssl_client.get_cipher_list())}')

        try:
            # Perform the SSL handshake
            ssl_connection.connect()
            cipher_result: CipherSuite = AcceptedCipherSuite.from_ongoing_ssl_connection(
                ssl_connection, ssl_version)

        except SslHandshakeRejected as e:
            cipher_result = RejectedCipherSuite(openssl_cipher_name,
                                                ssl_version, str(e))

        except ClientCertificateRequested:
            # TODO(AD): Sometimes get_current_cipher_name() called in from_ongoing_ssl_connection() will return None
            # When the handshake failed due to ClientCertificateRequested
            # We need to rewrite this logic to not use OpenSSL for looking up key size and RFC names as it is
            # too complicated
            # cipher_result = AcceptedCipherSuite.from_ongoing_ssl_connection(ssl_connection, ssl_version)
            # The ClientCertificateRequested exception already proves that the cipher suite was accepted
            # Workaround here:
            cipher_result = AcceptedCipherSuite(openssl_cipher_name,
                                                ssl_version, None, None)

        except Exception as e:
            cipher_result = ErroredCipherSuite(openssl_cipher_name,
                                               ssl_version, e)

        finally:
            ssl_connection.close()

        return cipher_result
    def _test_cipher_suite(
            server_connectivity_info: ServerConnectivityInfo,
            ssl_version: OpenSslVersionEnum,
            openssl_cipher_name: str
    ) -> 'CipherSuite':
        """Initiates a SSL handshake with the server using the SSL version and the cipher suite specified.
        """
        requires_legacy_openssl = True
        if ssl_version == OpenSslVersionEnum.TLSV1_2:
            # For TLS 1.2, we need to pick the right version of OpenSSL depending on which cipher suite
            requires_legacy_openssl = WorkaroundForTls12ForCipherSuites.requires_legacy_openssl(openssl_cipher_name)
        elif ssl_version == OpenSslVersionEnum.TLSV1_3:
            requires_legacy_openssl = False

        ssl_connection = server_connectivity_info.get_preconfigured_ssl_connection(
            override_ssl_version=ssl_version,
            should_use_legacy_openssl=requires_legacy_openssl
        )

        # Only enable the cipher suite to test; not trivial anymore since OpenSSL 1.1.1 and TLS 1.3
        if ssl_version == OpenSslVersionEnum.TLSV1_3:
            # The function to control cipher suites is different for TLS 1.3
            # Disable the default, non-TLS 1.3 cipher suites
            ssl_connection.ssl_client.set_cipher_list('')
            # Enable the one TLS 1.3 cipher suite we want to test
            ssl_connection.ssl_client.set_ciphersuites(openssl_cipher_name)
        else:
            if not requires_legacy_openssl:
                # Disable the TLS 1.3 cipher suites if we are using the modern client
                ssl_connection.ssl_client.set_ciphersuites('')

            ssl_connection.ssl_client.set_cipher_list(openssl_cipher_name)

        if len(ssl_connection.ssl_client.get_cipher_list()) != 1:
            raise ValueError(f'Passed an OpenSSL string for multiple cipher suites: "{openssl_cipher_name}": '
                             f'{str(ssl_connection.ssl_client.get_cipher_list())}')

        try:
            # Perform the SSL handshake
            ssl_connection.connect()
            cipher_result: CipherSuite = AcceptedCipherSuite.from_ongoing_ssl_connection(ssl_connection, ssl_version)

        except SslHandshakeRejected as e:
            cipher_result = RejectedCipherSuite(openssl_cipher_name, ssl_version, str(e))

        except ClientCertificateRequested:
            # TODO(AD): Sometimes get_current_cipher_name() called in from_ongoing_ssl_connection() will return None
            # When the handshake failed due to ClientCertificateRequested
            # We need to rewrite this logic to not use OpenSSL for looking up key size and RFC names as it is
            # too complicated
            # cipher_result = AcceptedCipherSuite.from_ongoing_ssl_connection(ssl_connection, ssl_version)
            # The ClientCertificateRequested exception already proves that the cipher suite was accepted
            # Workaround here:
            cipher_result = AcceptedCipherSuite(openssl_cipher_name, ssl_version, None, None)

        except Exception as e:
            cipher_result = ErroredCipherSuite(openssl_cipher_name, ssl_version, e)

        finally:
            ssl_connection.close()

        return cipher_result