1#!/usr/bin/env python3 2 3# translate_ciphers.py 4# 5# Copyright The Mbed TLS Contributors 6# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later 7 8""" 9Translate standard ciphersuite names to GnuTLS, OpenSSL and Mbed TLS standards. 10 11To test the translation functions run: 12python3 -m unittest translate_cipher.py 13""" 14 15import re 16import argparse 17import unittest 18 19class TestTranslateCiphers(unittest.TestCase): 20 """ 21 Ensure translate_ciphers.py translates and formats ciphersuite names 22 correctly 23 """ 24 def test_translate_all_cipher_names(self): 25 """ 26 Translate standard ciphersuite names to GnuTLS, OpenSSL and 27 Mbed TLS counterpart. Use only a small subset of ciphers 28 that exercise each step of the translation functions 29 """ 30 ciphers = [ 31 ("TLS_ECDHE_ECDSA_WITH_NULL_SHA", 32 "+ECDHE-ECDSA:+NULL:+SHA1", 33 "ECDHE-ECDSA-NULL-SHA", 34 "TLS-ECDHE-ECDSA-WITH-NULL-SHA"), 35 ("TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", 36 "+ECDHE-ECDSA:+AES-128-GCM:+AEAD", 37 "ECDHE-ECDSA-AES128-GCM-SHA256", 38 "TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256"), 39 ("TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA", 40 "+DHE-RSA:+3DES-CBC:+SHA1", 41 "EDH-RSA-DES-CBC3-SHA", 42 "TLS-DHE-RSA-WITH-3DES-EDE-CBC-SHA"), 43 ("TLS_RSA_WITH_AES_256_CBC_SHA", 44 "+RSA:+AES-256-CBC:+SHA1", 45 "AES256-SHA", 46 "TLS-RSA-WITH-AES-256-CBC-SHA"), 47 ("TLS_PSK_WITH_3DES_EDE_CBC_SHA", 48 "+PSK:+3DES-CBC:+SHA1", 49 "PSK-3DES-EDE-CBC-SHA", 50 "TLS-PSK-WITH-3DES-EDE-CBC-SHA"), 51 ("TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256", 52 None, 53 "ECDHE-ECDSA-CHACHA20-POLY1305", 54 "TLS-ECDHE-ECDSA-WITH-CHACHA20-POLY1305-SHA256"), 55 ("TLS_ECDHE_ECDSA_WITH_AES_128_CCM", 56 "+ECDHE-ECDSA:+AES-128-CCM:+AEAD", 57 None, 58 "TLS-ECDHE-ECDSA-WITH-AES-128-CCM"), 59 ("TLS_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384", 60 None, 61 "ECDHE-ARIA256-GCM-SHA384", 62 "TLS-ECDHE-RSA-WITH-ARIA-256-GCM-SHA384"), 63 ] 64 65 for s, g_exp, o_exp, m_exp in ciphers: 66 67 if g_exp is not None: 68 g = translate_gnutls(s) 69 self.assertEqual(g, g_exp) 70 71 if o_exp is not None: 72 o = translate_ossl(s) 73 self.assertEqual(o, o_exp) 74 75 if m_exp is not None: 76 m = translate_mbedtls(s) 77 self.assertEqual(m, m_exp) 78 79def translate_gnutls(s_cipher): 80 """ 81 Translate s_cipher from standard ciphersuite naming convention 82 and return the GnuTLS naming convention 83 """ 84 85 # Replace "_" with "-" to handle ciphersuite names based on Mbed TLS 86 # naming convention 87 s_cipher = s_cipher.replace("_", "-") 88 89 s_cipher = re.sub(r'\ATLS-', '+', s_cipher) 90 s_cipher = s_cipher.replace("-WITH-", ":+") 91 s_cipher = s_cipher.replace("-EDE", "") 92 93 # SHA in Mbed TLS == SHA1 GnuTLS, 94 # if the last 3 chars are SHA append 1 95 if s_cipher[-3:] == "SHA": 96 s_cipher = s_cipher+"1" 97 98 # CCM or CCM-8 should be followed by ":+AEAD" 99 # Replace "GCM:+SHAxyz" with "GCM:+AEAD" 100 if "CCM" in s_cipher or "GCM" in s_cipher: 101 s_cipher = re.sub(r"GCM-SHA\d\d\d", "GCM", s_cipher) 102 s_cipher = s_cipher+":+AEAD" 103 104 # Replace the last "-" with ":+" 105 else: 106 index = s_cipher.rindex("-") 107 s_cipher = s_cipher[:index] + ":+" + s_cipher[index+1:] 108 109 return s_cipher 110 111def translate_ossl(s_cipher): 112 """ 113 Translate s_cipher from standard ciphersuite naming convention 114 and return the OpenSSL naming convention 115 """ 116 117 # Replace "_" with "-" to handle ciphersuite names based on Mbed TLS 118 # naming convention 119 s_cipher = s_cipher.replace("_", "-") 120 121 s_cipher = re.sub(r'^TLS-', '', s_cipher) 122 s_cipher = s_cipher.replace("-WITH", "") 123 124 # Remove the "-" from "ABC-xyz" 125 s_cipher = s_cipher.replace("AES-", "AES") 126 s_cipher = s_cipher.replace("CAMELLIA-", "CAMELLIA") 127 s_cipher = s_cipher.replace("ARIA-", "ARIA") 128 129 # Remove "RSA" if it is at the beginning 130 s_cipher = re.sub(r'^RSA-', r'', s_cipher) 131 132 # For all circumstances outside of PSK 133 if "PSK" not in s_cipher: 134 s_cipher = s_cipher.replace("-EDE", "") 135 s_cipher = s_cipher.replace("3DES-CBC", "DES-CBC3") 136 137 # Remove "CBC" if it is not prefixed by DES 138 s_cipher = re.sub(r'(?<!DES-)CBC-', r'', s_cipher) 139 140 # ECDHE-RSA-ARIA does not exist in OpenSSL 141 s_cipher = s_cipher.replace("ECDHE-RSA-ARIA", "ECDHE-ARIA") 142 143 # POLY1305 should not be followed by anything 144 if "POLY1305" in s_cipher: 145 index = s_cipher.rindex("POLY1305") 146 s_cipher = s_cipher[:index+8] 147 148 # If DES is being used, Replace DHE with EDH 149 if "DES" in s_cipher and "DHE" in s_cipher and "ECDHE" not in s_cipher: 150 s_cipher = s_cipher.replace("DHE", "EDH") 151 152 return s_cipher 153 154def translate_mbedtls(s_cipher): 155 """ 156 Translate s_cipher from standard ciphersuite naming convention 157 and return Mbed TLS ciphersuite naming convention 158 """ 159 160 # Replace "_" with "-" 161 s_cipher = s_cipher.replace("_", "-") 162 163 return s_cipher 164 165def format_ciphersuite_names(mode, names): 166 t = {"g": translate_gnutls, 167 "o": translate_ossl, 168 "m": translate_mbedtls 169 }[mode] 170 return " ".join(c + '=' + t(c) for c in names) 171 172def main(target, names): 173 print(format_ciphersuite_names(target, names)) 174 175if __name__ == "__main__": 176 PARSER = argparse.ArgumentParser() 177 PARSER.add_argument('target', metavar='TARGET', choices=['o', 'g', 'm']) 178 PARSER.add_argument('names', metavar='NAMES', nargs='+') 179 ARGS = PARSER.parse_args() 180 main(ARGS.target, ARGS.names) 181