diff --git a/frameworks/kafka/src/main/dist/server.properties.mustache b/frameworks/kafka/src/main/dist/server.properties.mustache index b2293fd2413..291fe77c067 100644 --- a/frameworks/kafka/src/main/dist/server.properties.mustache +++ b/frameworks/kafka/src/main/dist/server.properties.mustache @@ -53,6 +53,10 @@ ssl.truststore.password=notsecure ssl.enabled.protocols=TLSv1.2 +{{#SECURITY_TRANSPORT_ENCRYPTION_CIPHERS}} +ssl.cipher.suites={{SECURITY_TRANSPORT_ENCRYPTION_CIPHERS}} +{{/SECURITY_TRANSPORT_ENCRYPTION_CIPHERS}} + # If Kerberos is NOT enabled, then SSL authentication can be turned on. {{^SECURITY_KERBEROS_ENABLED}} {{#SECURITY_SSL_AUTHENTICATION_ENABLED}} diff --git a/frameworks/kafka/tests/test_tls.py b/frameworks/kafka/tests/test_tls.py index d6f44f3c45c..a4464edcb97 100644 --- a/frameworks/kafka/tests/test_tls.py +++ b/frameworks/kafka/tests/test_tls.py @@ -4,9 +4,10 @@ import sdk_install import sdk_networks import sdk_plan +import sdk_security import sdk_utils -from security import transport_encryption +from security import transport_encryption, cipher_suites from tests import config @@ -96,3 +97,44 @@ def test_producer_over_tls(kafka_service_tls): json=True) assert len(write_info) == 1 assert write_info['message'].startswith('Output: {} records sent'.format(num_messages)) + + +@pytest.mark.tls +@pytest.mark.smoke +@pytest.mark.sanity +@sdk_utils.dcos_ee_only +@pytest.mark.dcos_min_version('1.10') +def test_tls_ciphers(kafka_service_tls): + task_name = 'kafka-0-broker' + endpoint = sdk_cmd.svc_cli( + config.PACKAGE_NAME, + config.SERVICE_NAME, + 'endpoints {}'.format(BROKER_TLS_ENDPOINT), + json=True)['dns'][0] + ciphers_config_path = ['service', 'security', 'transport_encryption', 'ciphers'] + expected_ciphers = set(sdk_utils.get_in(ciphers_config_path, sdk_cmd.svc_cli( + config.PACKAGE_NAME, + config.SERVICE_NAME, + 'describe', + json=True), '').rstrip().split(',')) + possible_ciphers = set(map(cipher_suites.rfc_name, sdk_security.openssl_ciphers())) + enabled_ciphers = set() + + assert expected_ciphers, 'Expected ciphers should be non-empty' + assert possible_ciphers, 'Possible ciphers should be non-empty' + + sdk_cmd.service_task_exec(config.SERVICE_NAME, task_name, 'openssl version') # Output OpenSSL version. + print("\nExpected ciphers:") + print("\n".join(sdk_utils.sort(list(expected_ciphers)))) + print("\n{} ciphers will be checked:".format(len(possible_ciphers))) + print("\n".join(sdk_utils.sort(list(possible_ciphers)))) + + for cipher in possible_ciphers: + openssl_cipher = cipher_suites.openssl_name(cipher) + if sdk_security.is_cipher_enabled(config.SERVICE_NAME, task_name, openssl_cipher, endpoint): + enabled_ciphers.add(cipher) + + print('{} ciphers enabled out of {}:'.format(len(enabled_ciphers), len(possible_ciphers))) + print("\n".join(sdk_utils.sort(list(enabled_ciphers)))) + + assert expected_ciphers == enabled_ciphers, "Enabled ciphers should match expected ciphers" diff --git a/frameworks/kafka/universe/config.json b/frameworks/kafka/universe/config.json index dd97c53c522..9f2f713511a 100644 --- a/frameworks/kafka/universe/config.json +++ b/frameworks/kafka/universe/config.json @@ -193,6 +193,11 @@ "description": "Allow plaintext alongside encrypted traffic", "type": "boolean", "default": false + }, + "ciphers": { + "description": "Comma-separated list of JSSE Cipher Suite Names", + "type": "string", + "default": "TLS_RSA_WITH_AES_128_GCM_SHA256,TLS_RSA_WITH_AES_128_CBC_SHA256,TLS_RSA_WITH_AES_256_GCM_SHA384,TLS_RSA_WITH_AES_256_CBC_SHA256,TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,TLS_DHE_RSA_WITH_AES_256_GCM_SHA384,TLS_DHE_RSA_WITH_AES_256_CBC_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384" } } }, diff --git a/frameworks/kafka/universe/marathon.json.mustache b/frameworks/kafka/universe/marathon.json.mustache index 4fa0e799b6a..52385c30bab 100644 --- a/frameworks/kafka/universe/marathon.json.mustache +++ b/frameworks/kafka/universe/marathon.json.mustache @@ -92,6 +92,10 @@ "TASKCFG_ALL_SECURITY_TRANSPORT_ENCRYPTION_ALLOW_PLAINTEXT": "{{service.security.transport_encryption.allow_plaintext}}", {{/service.security.transport_encryption.allow_plaintext}} + {{#service.security.transport_encryption.ciphers}} + "TASKCFG_ALL_SECURITY_TRANSPORT_ENCRYPTION_CIPHERS": "{{service.security.transport_encryption.ciphers}}", + {{/service.security.transport_encryption.ciphers}} + {{#service.security.ssl_authentication.enabled}} "TASKCFG_ALL_SECURITY_SSL_AUTHENTICATION_ENABLED": "{{service.security.ssl_authentication.enabled}}", {{/service.security.ssl_authentication.enabled}} diff --git a/testing/sdk_security.py b/testing/sdk_security.py index 48feafde991..002a92b44ef 100644 --- a/testing/sdk_security.py +++ b/testing/sdk_security.py @@ -6,6 +6,7 @@ ''' import logging import os +from subprocess import check_output from typing import List import retrying @@ -272,3 +273,31 @@ def configure_security(configure_universe): finally: if is_strict: cleanup_security(framework_name) + + +def openssl_ciphers(): + return set( + check_output(['openssl', 'ciphers', + 'ALL:eNULL']).decode('utf-8').rstrip().split(':')) + + +def is_cipher_enabled(service_name: str, + task_name: str, + cipher: str, + endpoint: str, + openssl_timeout: str = '1') -> bool: + @retrying.retry(stop_max_attempt_number=3, + wait_fixed=2000, + retry_on_result=lambda result: 'Failed to enter mount namespace' in result) + def run_openssl_command() -> str: + command = ' '.join([ + 'timeout', openssl_timeout, + 'openssl', 's_client', '-cipher', cipher, '-connect', endpoint + ]) + + _, output = sdk_cmd.service_task_exec(service_name, task_name, command, True) + return output + + output = run_openssl_command() + + return "Cipher is {}".format(cipher) in output diff --git a/testing/sdk_utils.py b/testing/sdk_utils.py index 3208922954e..1eb872424ad 100644 --- a/testing/sdk_utils.py +++ b/testing/sdk_utils.py @@ -159,3 +159,14 @@ def get_in(keys, coll, default=None): return functools.reduce(operator.getitem, keys, coll) except (KeyError, IndexError, TypeError): return default + + +def sort(coll): + """ Sorts a collection and returns it. """ + coll.sort() + return coll + + +def invert_dict(d: dict) -> dict: + """ Returns a dictionary with its values being its keys and vice-versa. """ + return dict((v, k) for k, v in d.items()) diff --git a/testing/security/cipher_suites.py b/testing/security/cipher_suites.py new file mode 100644 index 00000000000..f6f8fc389b8 --- /dev/null +++ b/testing/security/cipher_suites.py @@ -0,0 +1,184 @@ +import sdk_utils + +OPENSSL_TO_RFC_NAMES = { + 'ADH-AES128-GCM-SHA256': 'TLS_DH_anon_WITH_AES_128_GCM_SHA256', + 'ADH-AES128-SHA': 'TLS_DH_anon_WITH_AES_128_CBC_SHA', + 'ADH-AES128-SHA256': 'TLS_DH_anon_WITH_AES_128_CBC_SHA256', + 'ADH-AES256-GCM-SHA384': 'TLS_DH_anon_WITH_AES_256_GCM_SHA384', + 'ADH-AES256-SHA': 'TLS_DH_anon_WITH_AES_256_CBC_SHA', + 'ADH-AES256-SHA256': 'TLS_DH_anon_WITH_AES_256_CBC_SHA256', + 'ADH-CAMELLIA128-SHA': 'TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA', + 'ADH-CAMELLIA256-SHA': 'TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA', + 'ADH-DES-CBC-SHA': 'TLS_DH_anon_WITH_DES_CBC_SHA', + 'ADH-DES-CBC3-SHA': 'TLS_DH_anon_WITH_3DES_EDE_CBC_SHA', + 'ADH-RC4-MD5': 'TLS_DH_anon_WITH_RC4_128_MD5', + 'ADH-SEED-SHA': 'TLS_DH_anon_WITH_SEED_CBC_SHA', + 'AECDH-AES128-SHA': 'TLS_ECDH_anon_WITH_AES_128_CBC_SHA', + 'AECDH-AES256-SHA': 'TLS_ECDH_anon_WITH_AES_256_CBC_SHA', + 'AECDH-DES-CBC3-SHA': 'TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA', + 'AECDH-NULL-SHA': 'TLS_ECDH_anon_WITH_NULL_SHA', + 'AECDH-RC4-SHA': 'TLS_ECDH_anon_WITH_RC4_128_SHA', + 'AES128-GCM-SHA256': 'TLS_RSA_WITH_AES_128_GCM_SHA256', + 'AES128-SHA': 'TLS_RSA_WITH_AES_128_CBC_SHA', + 'AES128-SHA256': 'TLS_RSA_WITH_AES_128_CBC_SHA256', + 'AES256-GCM-SHA384': 'TLS_RSA_WITH_AES_256_GCM_SHA384', + 'AES256-SHA': 'TLS_RSA_WITH_AES_256_CBC_SHA', + 'AES256-SHA256': 'TLS_RSA_WITH_AES_256_CBC_SHA256', + 'CAMELLIA128-SHA': 'TLS_RSA_WITH_CAMELLIA_128_CBC_SHA', + 'CAMELLIA256-SHA': 'TLS_RSA_WITH_CAMELLIA_256_CBC_SHA', + 'DES-CBC-MD5': 'SSL_CK_DES_64_CBC_WITH_MD5', + 'DES-CBC-SHA': 'TLS_RSA_WITH_DES_CBC_SHA', + 'DES-CBC3-MD5': 'SSL_CK_DES_192_EDE3_CBC_WITH_MD5', + 'DES-CBC3-SHA': 'TLS_RSA_WITH_3DES_EDE_CBC_SHA', + 'DH-DSS-AES128-GCM-SHA256': 'TLS_DH_DSS_WITH_AES_128_GCM_SHA256', + 'DH-DSS-AES128-SHA': 'TLS_DH_DSS_WITH_AES_128_CBC_SHA', + 'DH-DSS-AES128-SHA256': 'TLS_DH_DSS_WITH_AES_128_CBC_SHA256', + 'DH-DSS-AES256-GCM-SHA384': 'TLS_DH_DSS_WITH_AES_256_GCM_SHA384', + 'DH-DSS-AES256-SHA': 'TLS_DH_DSS_WITH_AES_256_CBC_SHA', + 'DH-DSS-AES256-SHA256': 'TLS_DH_DSS_WITH_AES_256_CBC_SHA256', + 'DH-DSS-CAMELLIA128-SHA': 'TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA', + 'DH-DSS-CAMELLIA256-SHA': 'TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA', + 'DH-DSS-DES-CBC-SHA': 'TLS_DH_DSS_WITH_DES_CBC_SHA', + 'DH-DSS-DES-CBC3-SHA': 'TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA', + 'DH-DSS-SEED-SHA': 'TLS_DH_DSS_WITH_SEED_CBC_SHA', + 'DH-RSA-AES128-GCM-SHA256': 'TLS_DH_RSA_WITH_AES_128_GCM_SHA256', + 'DH-RSA-AES128-SHA': 'TLS_DH_RSA_WITH_AES_128_CBC_SHA', + 'DH-RSA-AES128-SHA256': 'TLS_DH_RSA_WITH_AES_128_CBC_SHA256', + 'DH-RSA-AES256-GCM-SHA384': 'TLS_DH_RSA_WITH_AES_256_GCM_SHA384', + 'DH-RSA-AES256-SHA': 'TLS_DH_RSA_WITH_AES_256_CBC_SHA', + 'DH-RSA-AES256-SHA256': 'TLS_DH_RSA_WITH_AES_256_CBC_SHA256', + 'DH-RSA-CAMELLIA128-SHA': 'TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA', + 'DH-RSA-CAMELLIA256-SHA': 'TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA', + 'DH-RSA-DES-CBC-SHA': 'TLS_DH_RSA_WITH_DES_CBC_SHA', + 'DH-RSA-DES-CBC3-SHA': 'TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA', + 'DH-RSA-SEED-SHA': 'TLS_DH_RSA_WITH_SEED_CBC_SHA', + 'DHE-DSS-AES128-GCM-SHA256': 'TLS_DHE_DSS_WITH_AES_128_GCM_SHA256', + 'DHE-DSS-AES128-SHA': 'TLS_DHE_DSS_WITH_AES_128_CBC_SHA', + 'DHE-DSS-AES128-SHA256': 'TLS_DHE_DSS_WITH_AES_128_CBC_SHA256', + 'DHE-DSS-AES256-GCM-SHA384': 'TLS_DHE_DSS_WITH_AES_256_GCM_SHA384', + 'DHE-DSS-AES256-SHA': 'TLS_DHE_DSS_WITH_AES_256_CBC_SHA', + 'DHE-DSS-AES256-SHA256': 'TLS_DHE_DSS_WITH_AES_256_CBC_SHA256', + 'DHE-DSS-CAMELLIA128-SHA': 'TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA', + 'DHE-DSS-CAMELLIA256-SHA': 'TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA', + 'DHE-DSS-RC4-SHA': 'TLS_DHE_DSS_WITH_RC4_128_SHA', + 'DHE-DSS-SEED-SHA': 'TLS_DHE_DSS_WITH_SEED_CBC_SHA', + 'DHE-RSA-AES128-GCM-SHA256': 'TLS_DHE_RSA_WITH_AES_128_GCM_SHA256', + 'DHE-RSA-AES128-SHA': 'TLS_DHE_RSA_WITH_AES_128_CBC_SHA', + 'DHE-RSA-AES128-SHA256': 'TLS_DHE_RSA_WITH_AES_128_CBC_SHA256', + 'DHE-RSA-AES256-GCM-SHA384': 'TLS_DHE_RSA_WITH_AES_256_GCM_SHA384', + 'DHE-RSA-AES256-SHA': 'TLS_DHE_RSA_WITH_AES_256_CBC_SHA', + 'DHE-RSA-AES256-SHA256': 'TLS_DHE_RSA_WITH_AES_256_CBC_SHA256', + 'DHE-RSA-CAMELLIA128-SHA': 'TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA', + 'DHE-RSA-CAMELLIA256-SHA': 'TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA', + 'DHE-RSA-CHACHA20-POLY1305': 'TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256', + 'DHE-RSA-SEED-SHA': 'TLS_DHE_RSA_WITH_SEED_CBC_SHA', + 'ECDH-ECDSA-AES128-GCM-SHA256': 'TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256', + 'ECDH-ECDSA-AES128-SHA': 'TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA', + 'ECDH-ECDSA-AES128-SHA256': 'TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256', + 'ECDH-ECDSA-AES256-GCM-SHA384': 'TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384', + 'ECDH-ECDSA-AES256-SHA': 'TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA', + 'ECDH-ECDSA-AES256-SHA384': 'TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384', + 'ECDH-ECDSA-DES-CBC3-SHA': 'TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA', + 'ECDH-ECDSA-NULL-SHA': 'TLS_ECDH_ECDSA_WITH_NULL_SHA', + 'ECDH-ECDSA-RC4-SHA': 'TLS_ECDH_ECDSA_WITH_RC4_128_SHA', + 'ECDH-RSA-AES128-GCM-SHA256': 'TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256', + 'ECDH-RSA-AES128-SHA': 'TLS_ECDH_RSA_WITH_AES_128_CBC_SHA', + 'ECDH-RSA-AES128-SHA256': 'TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256', + 'ECDH-RSA-AES256-GCM-SHA384': 'TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384', + 'ECDH-RSA-AES256-SHA': 'TLS_ECDH_RSA_WITH_AES_256_CBC_SHA', + 'ECDH-RSA-AES256-SHA384': 'TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384', + 'ECDH-RSA-DES-CBC3-SHA': 'TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA', + 'ECDH-RSA-NULL-SHA': 'TLS_ECDH_RSA_WITH_NULL_SHA', + 'ECDH-RSA-RC4-SHA': 'TLS_ECDH_RSA_WITH_RC4_128_SHA', + 'ECDHE-ECDSA-AES128-GCM-SHA256': 'TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256', + 'ECDHE-ECDSA-AES128-SHA': 'TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA', + 'ECDHE-ECDSA-AES128-SHA256': 'TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256', + 'ECDHE-ECDSA-AES256-GCM-SHA384': 'TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384', + 'ECDHE-ECDSA-AES256-SHA': 'TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA', + 'ECDHE-ECDSA-AES256-SHA384': 'TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384', + 'ECDHE-ECDSA-CHACHA20-POLY1305': 'TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256', + 'ECDHE-ECDSA-DES-CBC3-SHA': 'TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA', + 'ECDHE-ECDSA-NULL-SHA': 'TLS_ECDHE_ECDSA_WITH_NULL_SHA', + 'ECDHE-ECDSA-RC4-SHA': 'TLS_ECDHE_ECDSA_WITH_RC4_128_SHA', + 'ECDHE-RSA-AES128-GCM-SHA256': 'TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256', + 'ECDHE-RSA-AES128-SHA': 'TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA', + 'ECDHE-RSA-AES128-SHA256': 'TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256', + 'ECDHE-RSA-AES256-GCM-SHA384': 'TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384', + 'ECDHE-RSA-AES256-SHA': 'TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA', + 'ECDHE-RSA-AES256-SHA384': 'TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384', + 'ECDHE-RSA-CHACHA20-POLY1305': 'TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256', + 'ECDHE-RSA-DES-CBC3-SHA': 'TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA', + 'ECDHE-RSA-NULL-SHA': 'TLS_ECDHE_RSA_WITH_NULL_SHA', + 'ECDHE-RSA-RC4-SHA': 'TLS_ECDHE_RSA_WITH_RC4_128_SHA', + 'EDH-DSS-DES-CBC-SHA': 'TLS_DHE_DSS_WITH_DES_CBC_SHA', + 'EDH-DSS-DES-CBC3-SHA': 'TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA', + 'EDH-RSA-DES-CBC-SHA': 'TLS_DHE_RSA_WITH_DES_CBC_SHA', + 'EDH-RSA-DES-CBC3-SHA': 'TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA', + 'EXP-ADH-DES-CBC-SHA': 'TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA', + 'EXP-ADH-RC4-MD5': 'TLS_DH_anon_EXPORT_WITH_RC4_40_MD5', + 'EXP-DES-CBC-SHA': 'TLS_RSA_EXPORT_WITH_DES40_CBC_SHA', + 'EXP-DH-DSS-DES-CBC-SHA': 'TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA', + 'EXP-DH-RSA-DES-CBC-SHA': 'TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA', + 'EXP-EDH-DSS-DES-CBC-SHA': 'TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA', + 'EXP-EDH-RSA-DES-CBC-SHA': 'TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA', + 'EXP-KRB5-DES-CBC-MD5': 'TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5', + 'EXP-KRB5-DES-CBC-SHA': 'TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA', + 'EXP-KRB5-RC2-CBC-MD5': 'TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5', + 'EXP-KRB5-RC2-CBC-SHA': 'TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA', + 'EXP-KRB5-RC4-MD5': 'TLS_KRB5_EXPORT_WITH_RC4_40_MD5', + 'EXP-KRB5-RC4-SHA': 'TLS_KRB5_EXPORT_WITH_RC4_40_SHA', + 'EXP-RC2-CBC-MD5': 'SSL_CK_RC2_128_CBC_EXPORT40_WITH_MD5', + 'EXP-RC2-CBC-MD5': 'TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5', + 'EXP-RC4-MD5': 'SSL_CK_RC4_128_EXPORT40_WITH_MD5', + 'EXP-RC4-MD5': 'TLS_RSA_EXPORT_WITH_RC4_40_MD5', + 'EXP1024-DES-CBC-SHA': 'TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA', + 'EXP1024-DHE-DSS-DES-CBC-SHA': 'TLS_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA', + 'EXP1024-DHE-DSS-RC4-SHA': 'TLS_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA', + 'EXP1024-RC4-SHA': 'TLS_RSA_EXPORT1024_WITH_RC4_56_SHA', + 'GOST2001-GOST89-GOST89': 'TLS_GOSTR341001_WITH_28147_CNT_IMIT', + 'GOST94-GOST89-GOST89': 'TLS_GOSTR341094_WITH_28147_CNT_IMIT', + 'IDEA-CBC-MD5': 'SSL_CK_IDEA_128_CBC_WITH_MD5', + 'IDEA-CBC-SHA': 'TLS_RSA_WITH_IDEA_CBC_SHA', + 'KRB5-DES-CBC-MD5': 'TLS_KRB5_WITH_DES_CBC_MD5', + 'KRB5-DES-CBC-SHA': 'TLS_KRB5_WITH_DES_CBC_SHA', + 'KRB5-DES-CBC3-MD5': 'TLS_KRB5_WITH_3DES_EDE_CBC_MD5', + 'KRB5-DES-CBC3-SHA': 'TLS_KRB5_WITH_3DES_EDE_CBC_SHA', + 'KRB5-IDEA-CBC-MD5': 'TLS_KRB5_WITH_IDEA_CBC_MD5', + 'KRB5-IDEA-CBC-SHA': 'TLS_KRB5_WITH_IDEA_CBC_SHA', + 'KRB5-RC4-MD5': 'TLS_KRB5_WITH_RC4_128_MD5', + 'KRB5-RC4-SHA': 'TLS_KRB5_WITH_RC4_128_SHA', + 'NULL-MD5': 'TLS_NULL_WITH_NULL_NULL', + 'NULL-MD5': 'TLS_RSA_WITH_NULL_MD5', + 'NULL-SHA': 'TLS_RSA_WITH_NULL_SHA', + 'NULL-SHA256': 'TLS_RSA_WITH_NULL_SHA256', + 'PSK-3DES-EDE-CBC-SHA': 'TLS_PSK_WITH_3DES_EDE_CBC_SHA', + 'PSK-AES128-CBC-SHA': 'TLS_PSK_WITH_AES_128_CBC_SHA', + 'PSK-AES256-CBC-SHA': 'TLS_PSK_WITH_AES_256_CBC_SHA', + 'PSK-RC4-SHA': 'TLS_PSK_WITH_RC4_128_SHA', + 'RC2-CBC-MD5': 'SSL_CK_RC2_128_CBC_WITH_MD5', + 'RC4-64-MD5': 'SSL_CK_RC4_64_WITH_MD5', + 'RC4-MD5': 'SSL_CK_RC4_128_WITH_MD5', + 'RC4-MD5': 'TLS_RSA_WITH_RC4_128_MD5', + 'RC4-SHA': 'TLS_RSA_WITH_RC4_128_SHA', + 'SEED-SHA': 'TLS_RSA_WITH_SEED_CBC_SHA', + 'SRP-3DES-EDE-CBC-SHA': 'TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA', + 'SRP-AES-128-CBC-SHA': 'TLS_SRP_SHA_WITH_AES_128_CBC_SHA', + 'SRP-AES-256-CBC-SHA': 'TLS_SRP_SHA_WITH_AES_256_CBC_SHA', + 'SRP-DSS-3DES-EDE-CBC-SHA': 'TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA', + 'SRP-DSS-AES-128-CBC-SHA': 'TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA', + 'SRP-DSS-AES-256-CBC-SHA': 'TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA', + 'SRP-RSA-3DES-EDE-CBC-SHA': 'TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA', + 'SRP-RSA-AES-128-CBC-SHA': 'TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA', + 'SRP-RSA-AES-256-CBC-SHA': 'TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA', + 'TLS_FALLBACK_SCSV': 'TLS_FALLBACK_SCSV' +} + +RFC_TO_OPENSSL_NAMES = sdk_utils.invert_dict(OPENSSL_TO_RFC_NAMES) + + +def rfc_name(openssl_name: str) -> str: + return OPENSSL_TO_RFC_NAMES[openssl_name] + + +def openssl_name(rfc_name: str) -> str: + return RFC_TO_OPENSSL_NAMES[rfc_name]