translate_ciphers.py 6.2 KB

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