Example #1
0
    def get_all_cipher_suites(cls,
                              tls_version: TlsVersionEnum) -> Set[CipherSuite]:
        """Get the list of cipher suites supported by OpenSSL for the given SSL/TLS version.
        """
        if tls_version in [
                TlsVersionEnum.SSL_2_0,
                TlsVersionEnum.SSL_3_0,
                TlsVersionEnum.TLS_1_0,
                TlsVersionEnum.TLS_1_1,
        ]:
            openssl_cipher_strings = cls._get_all_cipher_suites_with_legacy_openssl(
                tls_version)

        elif tls_version == TlsVersionEnum.TLS_1_2:
            # For TLS 1.2, we have to use both the legacy and modern OpenSSL to cover all cipher suites
            cipher_suites_from_legacy_openssl = cls._get_all_cipher_suites_with_legacy_openssl(
                tls_version)

            ssl_client_modern = SslClient(
                ssl_version=OpenSslVersionEnum(tls_version.value))
            ssl_client_modern.set_cipher_list("ALL:COMPLEMENTOFALL:-PSK:-SRP")
            ssl_client_modern.set_ciphersuites(
                "")  # Disable TLS 1.3 cipher suites
            cipher_suites_from_modern_openssl = set(
                ssl_client_modern.get_cipher_list())

            # Combine the two sets of cipher suites
            openssl_cipher_strings = cipher_suites_from_legacy_openssl.union(
                cipher_suites_from_modern_openssl)

        elif tls_version == TlsVersionEnum.TLS_1_3:
            ssl_client_modern = SslClient(
                ssl_version=OpenSslVersionEnum(tls_version.value))
            ssl_client_modern.set_cipher_list(
                "")  # Disable NON-TLS-1.3 cipher suites
            ssl_client_modern.set_ciphersuites(
                "TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:"
                "TLS_AES_128_CCM_SHA256:TLS_AES_128_CCM_8_SHA256"
            )  # Enable all TLS 1.3 cipher suites
            openssl_cipher_strings = set(ssl_client_modern.get_cipher_list())

        else:
            raise ValueError("Should never happen")

        return {
            CipherSuite.from_openssl(cipher_str, tls_version)
            for cipher_str in openssl_cipher_strings
        }
Example #2
0
    def process_task(self, server_info, scan_command):
        # type: (ServerConnectivityInfo, FallbackScsvScanCommand) -> FallbackScsvScanResult
        if server_info.highest_ssl_version_supported.value <= OpenSslVersionEnum.SSLV3.value:
            raise ValueError('Server only supports SSLv3; no downgrade attacks are possible')

        # Try to connect using a lower TLS version with the fallback cipher suite enabled
        ssl_version_downgrade = OpenSslVersionEnum(server_info.highest_ssl_version_supported.value - 1)
        ssl_connection = server_info.get_preconfigured_ssl_connection(override_ssl_version=ssl_version_downgrade)
        ssl_connection.ssl_client.enable_fallback_scsv()

        supports_fallback_scsv = False
        try:
            # Perform the SSL handshake
            ssl_connection.connect()

        except _nassl.OpenSSLError as e:
            # This is the right, specific alert the server should return
            if 'tlsv1 alert inappropriate fallback' in str(e.args):
                supports_fallback_scsv = True
            else:
                raise

        except SSLHandshakeRejected:
            # If the handshake is rejected, we assume downgrade attacks are prevented (this is how F5 balancers do it)
            # although it could also be because the server does not support this version of TLS
            # https://github.com/nabla-c0d3/sslyze/issues/119
            supports_fallback_scsv = True

        finally:
            ssl_connection.close()

        return FallbackScsvScanResult(server_info, scan_command, supports_fallback_scsv)
Example #3
0
def _parse_all_cipher_suites_with_legacy_openssl(
        tls_version: TlsVersionEnum) -> Set[str]:
    ssl_client = LegacySslClient(
        ssl_version=OpenSslVersionEnum(tls_version.value))
    # Disable SRP and PSK cipher suites as they need a special setup in the client and are never used
    ssl_client.set_cipher_list("ALL:COMPLEMENTOFALL:-PSK:-SRP")
    return set(ssl_client.get_cipher_list())
Example #4
0
def _parse_all_cipher_suites() -> Dict[TlsVersionEnum, Set[CipherSuite]]:
    tls_version_to_cipher_suites: Dict[TlsVersionEnum, Set[CipherSuite]] = {}

    for tls_version in [
        TlsVersionEnum.SSL_2_0,
        TlsVersionEnum.SSL_3_0,
        TlsVersionEnum.TLS_1_0,
        TlsVersionEnum.TLS_1_1,
    ]:
        openssl_cipher_strings = _parse_all_cipher_suites_with_legacy_openssl(tls_version)
        tls_version_to_cipher_suites[tls_version] = set()
        for cipher_suite_openssl_name in openssl_cipher_strings:
            cipher_suite_rfc_name = _OPENSSL_TO_RFC_NAMES_MAPPING[tls_version][cipher_suite_openssl_name]
            tls_version_to_cipher_suites[tls_version].add(
                CipherSuite(
                    name=cipher_suite_rfc_name,
                    openssl_name=cipher_suite_openssl_name,
                    is_anonymous=True if "anon" in cipher_suite_rfc_name else False,
                    key_size=_RFC_NAME_TO_KEY_SIZE_MAPPING[cipher_suite_rfc_name],
                )
            )

    # For TLS 1.2, we have to use both the legacy and modern OpenSSL to cover all cipher suites
    cipher_suites_from_legacy_openssl = _parse_all_cipher_suites_with_legacy_openssl(TlsVersionEnum.TLS_1_2)

    ssl_client_modern = SslClient(ssl_version=OpenSslVersionEnum(TlsVersionEnum.TLS_1_2.value))
    ssl_client_modern.set_cipher_list("ALL:COMPLEMENTOFALL:-PSK:-SRP")
    cipher_suites_from_modern_openssl = set(ssl_client_modern.get_cipher_list())

    # Combine the two sets of cipher suites
    openssl_cipher_strings = cipher_suites_from_legacy_openssl.union(cipher_suites_from_modern_openssl)
    tls_version_to_cipher_suites[TlsVersionEnum.TLS_1_2] = set()
    for cipher_suite_openssl_name in openssl_cipher_strings:
        # Ignore TLS 1.3 cipher suites
        if cipher_suite_openssl_name in _TLS_1_3_CIPHER_SUITES:
            continue

        cipher_suite_rfc_name = _OPENSSL_TO_RFC_NAMES_MAPPING[TlsVersionEnum.TLS_1_2][cipher_suite_openssl_name]
        tls_version_to_cipher_suites[TlsVersionEnum.TLS_1_2].add(
            CipherSuite(
                name=cipher_suite_rfc_name,
                openssl_name=cipher_suite_openssl_name,
                is_anonymous=True if "anon" in cipher_suite_rfc_name else False,
                key_size=_RFC_NAME_TO_KEY_SIZE_MAPPING[cipher_suite_rfc_name],
            )
        )

    # TLS 1.3 - the list is just hardcoded
    tls_version_to_cipher_suites[TlsVersionEnum.TLS_1_3] = {
        CipherSuite(
            # For TLS 1.3 OpenSSL started using the official names
            name=cipher_suite_name,
            openssl_name=cipher_suite_name,
            is_anonymous=False,
            key_size=_RFC_NAME_TO_KEY_SIZE_MAPPING[cipher_suite_name],
        )
        for cipher_suite_name in _TLS_1_3_CIPHER_SUITES
    }

    return tls_version_to_cipher_suites
Example #5
0
    def __init__(
        self,
        server_location: ServerNetworkLocation,
        network_configuration: ServerNetworkConfiguration,
        tls_version: "TlsVersionEnum",
        should_ignore_client_auth: bool,
        should_use_legacy_openssl: Optional[bool] = None,
        ca_certificates_path: Optional[Path] = None,
    ) -> None:
        self._server_location = server_location
        self._network_configuration = network_configuration

        # Create the SSL client
        nassl_tls_version = OpenSslVersionEnum(tls_version.value)
        self.ssl_client: BaseSslClient
        # For older versions of TLS/SSL, we have to use a legacy OpenSSL
        if should_use_legacy_openssl is None:
            # For older versions of TLS/SSL, we have to use a legacy OpenSSL
            final_should_use_legacy_openssl = (
                False if nassl_tls_version in [OpenSslVersionEnum.TLSV1_2, OpenSslVersionEnum.TLSV1_3] else True
            )
        else:
            final_should_use_legacy_openssl = should_use_legacy_openssl
        ssl_client_cls = LegacySslClient if final_should_use_legacy_openssl else SslClient

        if network_configuration.tls_client_auth_credentials:
            # A client certificate and private key were provided
            self.ssl_client = ssl_client_cls(
                ssl_version=nassl_tls_version,
                ssl_verify=OpenSslVerifyEnum.NONE,
                ssl_verify_locations=ca_certificates_path,
                client_certificate_chain=network_configuration.tls_client_auth_credentials.certificate_chain_path,
                client_key=network_configuration.tls_client_auth_credentials.key_path,
                client_key_type=network_configuration.tls_client_auth_credentials.key_type,
                client_key_password=network_configuration.tls_client_auth_credentials.key_password,
                ignore_client_authentication_requests=False,
            )
        else:
            # No client cert and key
            self.ssl_client = ssl_client_cls(
                ssl_version=nassl_tls_version,
                ssl_verify=OpenSslVerifyEnum.NONE,
                ssl_verify_locations=ca_certificates_path,
                ignore_client_authentication_requests=should_ignore_client_auth,
            )

        # Add Server Name Indication
        if nassl_tls_version != OpenSslVersionEnum.SSLV2:
            self.ssl_client.set_tlsext_host_name(network_configuration.tls_server_name_indication)

        # And a default cipher list to make the client hello smaller so we don't run into
        # https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=665452
        if nassl_tls_version != OpenSslVersionEnum.TLSV1_3:
            self.ssl_client.set_cipher_list("HIGH:MEDIUM:-aNULL:-eNULL:-3DES:-SRP:-PSK:-CAMELLIA")
def _test_scsv(server_info: ServerConnectivityInfo) -> bool:
    # Try with TLS 1.2 even if the server supports TLS 1.3 or higher as there is no downgrade possible with TLS 1.3
    if server_info.tls_probing_result.highest_tls_version_supported >= OpenSslVersionEnum.TLSV1_3:
        ssl_version_to_use = OpenSslVersionEnum.TLSV1_2
    else:
        ssl_version_to_use = server_info.tls_probing_result.highest_tls_version_supported

    # Try to connect using a lower TLS version with the fallback cipher suite enabled
    ssl_version_downgrade = OpenSslVersionEnum(ssl_version_to_use.value -
                                               1)  # type: ignore
    ssl_connection = server_info.get_preconfigured_tls_connection(
        override_tls_version=ssl_version_downgrade,
        # Only the legacy client has enable_fallback_scsv()
        should_use_legacy_openssl=True,
    )
    if not isinstance(ssl_connection.ssl_client, LegacySslClient):
        raise RuntimeError("Should never happen")

    ssl_connection.ssl_client.enable_fallback_scsv()

    supports_fallback_scsv = False
    try:
        # Perform the SSL handshake
        ssl_connection.connect()

    except _nassl.OpenSSLError as e:
        # This is the right, specific alert the server should return
        if "tlsv1 alert inappropriate fallback" in str(e.args):
            supports_fallback_scsv = True
        else:
            raise

    except ServerRejectedTlsHandshake:
        # If the handshake is rejected, we assume downgrade attacks are prevented (this is how F5 balancers do it)
        # although it could also be because the server does not support this version of TLS
        # https://github.com/nabla-c0d3/sslyze/issues/119
        supports_fallback_scsv = True

    finally:
        ssl_connection.close()

    return supports_fallback_scsv
Example #7
0
def _parse_all_cipher_suites() -> Dict[TlsVersionEnum, Set[CipherSuite]]:
    tls_version_to_cipher_suites: Dict[TlsVersionEnum, Set[CipherSuite]] = {}

    for tls_version in [
        TlsVersionEnum.SSL_2_0,
        TlsVersionEnum.SSL_3_0,
        TlsVersionEnum.TLS_1_0,
        TlsVersionEnum.TLS_1_1,
    ]:
        openssl_cipher_strings = _parse_all_cipher_suites_with_legacy_openssl(tls_version)
        tls_version_to_cipher_suites[tls_version] = set()
        for cipher_suite_openssl_name in openssl_cipher_strings:
            cipher_suite_rfc_name = _OPENSSL_TO_RFC_NAMES_MAPPING[tls_version][cipher_suite_openssl_name]
            tls_version_to_cipher_suites[tls_version].add(
                CipherSuite(
                    name=cipher_suite_rfc_name,
                    openssl_name=cipher_suite_openssl_name,
                    is_anonymous=True if "anon" in cipher_suite_rfc_name else False,
                    key_size=_RFC_NAME_TO_KEY_SIZE_MAPPING[cipher_suite_rfc_name],
                )
            )

        # For TLS 1.2, we have to use both the legacy and modern OpenSSL to cover all cipher suites
        cipher_suites_from_legacy_openssl = _parse_all_cipher_suites_with_legacy_openssl(TlsVersionEnum.TLS_1_2)

        ssl_client_modern = SslClient(ssl_version=OpenSslVersionEnum(TlsVersionEnum.TLS_1_2.value))
        ssl_client_modern.set_cipher_list("ALL:COMPLEMENTOFALL:-PSK:-SRP")
        ssl_client_modern.set_ciphersuites("")  # Disable TLS 1.3 cipher suites
        cipher_suites_from_modern_openssl = set(ssl_client_modern.get_cipher_list())

        # Combine the two sets of cipher suites
        openssl_cipher_strings = cipher_suites_from_legacy_openssl.union(cipher_suites_from_modern_openssl)
        tls_version_to_cipher_suites[TlsVersionEnum.TLS_1_2] = set()
        for cipher_suite_openssl_name in openssl_cipher_strings:
            cipher_suite_rfc_name = _OPENSSL_TO_RFC_NAMES_MAPPING[TlsVersionEnum.TLS_1_2][cipher_suite_openssl_name]
            tls_version_to_cipher_suites[TlsVersionEnum.TLS_1_2].add(
                CipherSuite(
                    name=cipher_suite_rfc_name,
                    openssl_name=cipher_suite_openssl_name,
                    is_anonymous=True if "anon" in cipher_suite_rfc_name else False,
                    key_size=_RFC_NAME_TO_KEY_SIZE_MAPPING[cipher_suite_rfc_name],
                )
            )

        # TLS 1.3
        ssl_client_modern = SslClient(ssl_version=OpenSslVersionEnum(TlsVersionEnum.TLS_1_3.value))
        ssl_client_modern.set_cipher_list("")  # Disable NON-TLS-1.3 cipher suites
        ssl_client_modern.set_ciphersuites(
            "TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:"
            "TLS_AES_128_CCM_SHA256:TLS_AES_128_CCM_8_SHA256"
        )  # Enable all TLS 1.3 cipher suites
        openssl_cipher_strings = set(ssl_client_modern.get_cipher_list())

        tls_version_to_cipher_suites[TlsVersionEnum.TLS_1_3] = {
            CipherSuite(
                # For TLS 1.3 OpenSSL started using the official names
                name=cipher_suite_openssl_name,
                openssl_name=cipher_suite_openssl_name,
                is_anonymous=False,
                key_size=_RFC_NAME_TO_KEY_SIZE_MAPPING[cipher_suite_openssl_name],
            )
            for cipher_suite_openssl_name in openssl_cipher_strings
        }

    return tls_version_to_cipher_suites