diff --git a/scripts/generate_ssl_debug_helpers.py b/scripts/generate_ssl_debug_helpers.py deleted file mode 100755 index 600d16096e..0000000000 --- a/scripts/generate_ssl_debug_helpers.py +++ /dev/null @@ -1,416 +0,0 @@ -#!/usr/bin/env python3 - -"""Generate library/ssl_debug_helpers_generated.c - -The code generated by this module includes debug helper functions that can not be -implemented by fixed codes. - -""" - -# Copyright The Mbed TLS Contributors -# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later -import sys -import re -import os -import textwrap -import argparse - -import framework_scripts_path # pylint: disable=unused-import -from mbedtls_framework import build_tree - - -def remove_c_comments(string): - """ - Remove C style comments from input string - """ - string_pattern = r"(?P\".*?\"|\'.*?\')" - comment_pattern = r"(?P/\*.*?\*/|//[^\r\n]*$)" - pattern = re.compile(string_pattern + r'|' + comment_pattern, - re.MULTILINE | re.DOTALL) - - def replacer(match): - if match.lastgroup == 'comment': - return "" - return match.group() - return pattern.sub(replacer, string) - - -class CondDirectiveNotMatch(Exception): - pass - - -def preprocess_c_source_code(source, *classes): - """ - Simple preprocessor for C source code. - - Only processes condition directives without expanding them. - Yield object according to the classes input. Most match firstly - - If the directive pair does not match , raise CondDirectiveNotMatch. - - Assume source code does not include comments and compile pass. - - """ - - pattern = re.compile(r"^[ \t]*#[ \t]*" + - r"(?P(if[ \t]|ifndef[ \t]|ifdef[ \t]|else|endif))" + - r"[ \t]*(?P(.*\\\n)*.*$)", - re.MULTILINE) - stack = [] - - def _yield_objects(s, d, p, st, end): - """ - Output matched source piece - """ - nonlocal stack - start_line, end_line = '', '' - if stack: - start_line = '#{} {}'.format(d, p) - if d == 'if': - end_line = '#endif /* {} */'.format(p) - elif d == 'ifdef': - end_line = '#endif /* defined({}) */'.format(p) - else: - end_line = '#endif /* !defined({}) */'.format(p) - has_instance = False - for cls in classes: - for instance in cls.extract(s, st, end): - if has_instance is False: - has_instance = True - yield pair_start, start_line - yield instance.span()[0], instance - if has_instance: - yield start, end_line - - for match in pattern.finditer(source): - - directive = match.groupdict()['directive'].strip() - param = match.groupdict()['param'] - start, end = match.span() - - if directive in ('if', 'ifndef', 'ifdef'): - stack.append((directive, param, start, end)) - continue - - if not stack: - raise CondDirectiveNotMatch() - - pair_directive, pair_param, pair_start, pair_end = stack.pop() - yield from _yield_objects(source, - pair_directive, - pair_param, - pair_end, - start) - - if directive == 'endif': - continue - - if pair_directive == 'if': - directive = 'if' - param = "!( {} )".format(pair_param) - elif pair_directive == 'ifdef': - directive = 'ifndef' - param = pair_param - else: - directive = 'ifdef' - param = pair_param - - stack.append((directive, param, start, end)) - assert not stack, len(stack) - - -class EnumDefinition: - """ - Generate helper functions around enumeration. - - Currently, it generate translation function from enum value to string. - Enum definition looks like: - [typedef] enum [prefix name] { [body] } [suffix name]; - - Known limitation: - - the '}' and ';' SHOULD NOT exist in different macro blocks. Like - ``` - enum test { - .... - #if defined(A) - .... - }; - #else - .... - }; - #endif - ``` - """ - - @classmethod - def extract(cls, source_code, start=0, end=-1): - enum_pattern = re.compile(r'enum\s*(?P\w*)\s*' + - r'{\s*(?P[^}]*)}' + - r'\s*(?P\w*)\s*;', - re.MULTILINE | re.DOTALL) - - for match in enum_pattern.finditer(source_code, start, end): - yield EnumDefinition(source_code, - span=match.span(), - group=match.groupdict()) - - def __init__(self, source_code, span=None, group=None): - assert isinstance(group, dict) - prefix_name = group.get('prefix_name', None) - suffix_name = group.get('suffix_name', None) - body = group.get('body', None) - assert prefix_name or suffix_name - assert body - assert span - # If suffix_name exists, it is a typedef - self._prototype = suffix_name if suffix_name else 'enum ' + prefix_name - self._name = suffix_name if suffix_name else prefix_name - self._body = body - self._source = source_code - self._span = span - - def __repr__(self): - return 'Enum({},{})'.format(self._name, self._span) - - def __str__(self): - return repr(self) - - def span(self): - return self._span - - def generate_translation_function(self): - """ - Generate function for translating value to string - """ - translation_table = [] - - for line in self._body.splitlines(): - - if line.strip().startswith('#'): - # Preprocess directive, keep it in table - translation_table.append(line.strip()) - continue - - if not line.strip(): - continue - - for field in line.strip().split(','): - if not field.strip(): - continue - member = field.strip().split()[0] - translation_table.append( - '{space}case {member}:\n{space} return "{member}";' - .format(member=member, space=' '*8) - ) - - body = textwrap.dedent('''\ - const char *{name}_str( {prototype} in ) - {{ - switch (in) {{ - {translation_table} - default: - return "UNKNOWN_VALUE"; - }} - }} - ''') - body = body.format(translation_table='\n'.join(translation_table), - name=self._name, - prototype=self._prototype) - return body - - -class SignatureAlgorithmDefinition: - """ - Generate helper functions for signature algorithms. - - It generates translation function from signature algorithm define to string. - Signature algorithm definition looks like: - #define MBEDTLS_TLS1_3_SIG_[ upper case signature algorithm ] [ value(hex) ] - - Known limitation: - - the definitions SHOULD exist in same macro blocks. - """ - - @classmethod - def extract(cls, source_code, start=0, end=-1): - sig_alg_pattern = re.compile(r'#define\s+(?PMBEDTLS_TLS1_3_SIG_\w+)\s+' + - r'(?P0[xX][0-9a-fA-F]+)$', - re.MULTILINE | re.DOTALL) - matches = list(sig_alg_pattern.finditer(source_code, start, end)) - if matches: - yield SignatureAlgorithmDefinition(source_code, definitions=matches) - - def __init__(self, source_code, definitions=None): - if definitions is None: - definitions = [] - assert isinstance(definitions, list) and definitions - self._definitions = definitions - self._source = source_code - - def __repr__(self): - return 'SigAlgs({})'.format(self._definitions[0].span()) - - def span(self): - return self._definitions[0].span() - - def __str__(self): - """ - Generate function for translating value to string - """ - translation_table = [] - for m in self._definitions: - name = m.groupdict()['name'] - return_val = name[len('MBEDTLS_TLS1_3_SIG_'):].lower() - translation_table.append( - ' case {}:\n return "{}";'.format(name, return_val)) - - body = textwrap.dedent('''\ - const char *mbedtls_ssl_sig_alg_to_str( uint16_t in ) - {{ - switch( in ) - {{ - {translation_table} - }}; - - return "UNKNOWN"; - }}''') - body = body.format(translation_table='\n'.join(translation_table)) - return body - - -class NamedGroupDefinition: - """ - Generate helper functions for named group - - It generates translation function from named group define to string. - Named group definition looks like: - #define MBEDTLS_SSL_IANA_TLS_GROUP_[ upper case named group ] [ value(hex) ] - - Known limitation: - - the definitions SHOULD exist in same macro blocks. - """ - - @classmethod - def extract(cls, source_code, start=0, end=-1): - named_group_pattern = re.compile(r'#define\s+(?PMBEDTLS_SSL_IANA_TLS_GROUP_\w+)\s+' + - r'(?P0[xX][0-9a-fA-F]+)$', - re.MULTILINE | re.DOTALL) - matches = list(named_group_pattern.finditer(source_code, start, end)) - if matches: - yield NamedGroupDefinition(source_code, definitions=matches) - - def __init__(self, source_code, definitions=None): - if definitions is None: - definitions = [] - assert isinstance(definitions, list) and definitions - self._definitions = definitions - self._source = source_code - - def __repr__(self): - return 'NamedGroup({})'.format(self._definitions[0].span()) - - def span(self): - return self._definitions[0].span() - - def __str__(self): - """ - Generate function for translating value to string - """ - translation_table = [] - for m in self._definitions: - name = m.groupdict()['name'] - iana_name = name[len('MBEDTLS_SSL_IANA_TLS_GROUP_'):].lower() - translation_table.append(' case {}:\n return "{}";'.format(name, iana_name)) - - body = textwrap.dedent('''\ - const char *mbedtls_ssl_named_group_to_str( uint16_t in ) - {{ - switch( in ) - {{ - {translation_table} - }}; - - return "UNKNOWN"; - }}''') - body = body.format(translation_table='\n'.join(translation_table)) - return body - - -OUTPUT_C_TEMPLATE = '''\ -/* Automatically generated by generate_ssl_debug_helpers.py. DO NOT EDIT. */ - -/** - * \\file ssl_debug_helpers_generated.c - * - * \\brief Automatically generated helper functions for debugging - */ -/* - * Copyright The Mbed TLS Contributors - * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later - * - */ - -#include "common.h" - -#if defined(MBEDTLS_DEBUG_C) - -#include "ssl_debug_helpers.h" - -{functions} - -#endif /* MBEDTLS_DEBUG_C */ -/* End of automatically generated file. */ - -''' - - -def generate_ssl_debug_helpers(output_directory, mbedtls_root): - """ - Generate functions of debug helps - """ - mbedtls_root = os.path.abspath( - mbedtls_root or build_tree.guess_mbedtls_root()) - with open(os.path.join(mbedtls_root, 'include/mbedtls/ssl.h')) as f: - source_code = remove_c_comments(f.read()) - - definitions = dict() - for start, instance in preprocess_c_source_code(source_code, - EnumDefinition, - SignatureAlgorithmDefinition, - NamedGroupDefinition): - if start in definitions: - continue - if isinstance(instance, EnumDefinition): - definition = instance.generate_translation_function() - else: - definition = instance - definitions[start] = definition - - function_definitions = [str(v) for _, v in sorted(definitions.items())] - if output_directory == sys.stdout: - sys.stdout.write(OUTPUT_C_TEMPLATE.format( - functions='\n'.join(function_definitions))) - else: - with open(os.path.join(output_directory, 'ssl_debug_helpers_generated.c'), 'w') as f: - f.write(OUTPUT_C_TEMPLATE.format( - functions='\n'.join(function_definitions))) - - -def main(): - """ - Command line entry - """ - parser = argparse.ArgumentParser() - parser.add_argument('--mbedtls-root', nargs='?', default=None, - help='root directory of mbedtls source code') - parser.add_argument('output_directory', nargs='?', - default='library', help='source/header files location') - - args = parser.parse_args() - - generate_ssl_debug_helpers(args.output_directory, args.mbedtls_root) - return 0 - - -if __name__ == '__main__': - sys.exit(main()) diff --git a/tests/scripts/generate_tls13_compat_tests.py b/tests/scripts/generate_tls13_compat_tests.py deleted file mode 100755 index b9dcff4e10..0000000000 --- a/tests/scripts/generate_tls13_compat_tests.py +++ /dev/null @@ -1,649 +0,0 @@ -#!/usr/bin/env python3 - -# generate_tls13_compat_tests.py -# -# Copyright The Mbed TLS Contributors -# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later - -""" -Generate TLSv1.3 Compat test cases - -""" - -import sys -import os -import argparse -import itertools -from collections import namedtuple - -# define certificates configuration entry -Certificate = namedtuple("Certificate", ['cafile', 'certfile', 'keyfile']) -# define the certificate parameters for signature algorithms -CERTIFICATES = { - 'ecdsa_secp256r1_sha256': Certificate('$DATA_FILES_PATH/test-ca2.crt', - '$DATA_FILES_PATH/ecdsa_secp256r1.crt', - '$DATA_FILES_PATH/ecdsa_secp256r1.key'), - 'ecdsa_secp384r1_sha384': Certificate('$DATA_FILES_PATH/test-ca2.crt', - '$DATA_FILES_PATH/ecdsa_secp384r1.crt', - '$DATA_FILES_PATH/ecdsa_secp384r1.key'), - 'ecdsa_secp521r1_sha512': Certificate('$DATA_FILES_PATH/test-ca2.crt', - '$DATA_FILES_PATH/ecdsa_secp521r1.crt', - '$DATA_FILES_PATH/ecdsa_secp521r1.key'), - 'rsa_pss_rsae_sha256': Certificate('$DATA_FILES_PATH/test-ca_cat12.crt', - '$DATA_FILES_PATH/server2-sha256.crt', - '$DATA_FILES_PATH/server2.key') -} - -CIPHER_SUITE_IANA_VALUE = { - "TLS_AES_128_GCM_SHA256": 0x1301, - "TLS_AES_256_GCM_SHA384": 0x1302, - "TLS_CHACHA20_POLY1305_SHA256": 0x1303, - "TLS_AES_128_CCM_SHA256": 0x1304, - "TLS_AES_128_CCM_8_SHA256": 0x1305 -} - -SIG_ALG_IANA_VALUE = { - "ecdsa_secp256r1_sha256": 0x0403, - "ecdsa_secp384r1_sha384": 0x0503, - "ecdsa_secp521r1_sha512": 0x0603, - 'rsa_pss_rsae_sha256': 0x0804, -} - -NAMED_GROUP_IANA_VALUE = { - 'secp256r1': 0x17, - 'secp384r1': 0x18, - 'secp521r1': 0x19, - 'x25519': 0x1d, - 'x448': 0x1e, - # Only one finite field group to keep testing time within reasonable bounds. - 'ffdhe2048': 0x100, -} - -class TLSProgram: - """ - Base class for generate server/client command. - """ - - # pylint: disable=too-many-arguments - def __init__(self, ciphersuite=None, signature_algorithm=None, named_group=None, - cert_sig_alg=None): - self._ciphers = [] - self._sig_algs = [] - self._named_groups = [] - self._cert_sig_algs = [] - if ciphersuite: - self.add_ciphersuites(ciphersuite) - if named_group: - self.add_named_groups(named_group) - if signature_algorithm: - self.add_signature_algorithms(signature_algorithm) - if cert_sig_alg: - self.add_cert_signature_algorithms(cert_sig_alg) - - # add_ciphersuites should not override by sub class - def add_ciphersuites(self, *ciphersuites): - self._ciphers.extend( - [cipher for cipher in ciphersuites if cipher not in self._ciphers]) - - # add_signature_algorithms should not override by sub class - def add_signature_algorithms(self, *signature_algorithms): - self._sig_algs.extend( - [sig_alg for sig_alg in signature_algorithms if sig_alg not in self._sig_algs]) - - # add_named_groups should not override by sub class - def add_named_groups(self, *named_groups): - self._named_groups.extend( - [named_group for named_group in named_groups if named_group not in self._named_groups]) - - # add_cert_signature_algorithms should not override by sub class - def add_cert_signature_algorithms(self, *signature_algorithms): - self._cert_sig_algs.extend( - [sig_alg for sig_alg in signature_algorithms if sig_alg not in self._cert_sig_algs]) - - # pylint: disable=no-self-use - def pre_checks(self): - return [] - - # pylint: disable=no-self-use - def cmd(self): - if not self._cert_sig_algs: - self._cert_sig_algs = list(CERTIFICATES.keys()) - return self.pre_cmd() - - # pylint: disable=no-self-use - def post_checks(self): - return [] - - # pylint: disable=no-self-use - def pre_cmd(self): - return ['false'] - - # pylint: disable=unused-argument,no-self-use - def hrr_post_checks(self, named_group): - return [] - - -class OpenSSLBase(TLSProgram): - """ - Generate base test commands for OpenSSL. - """ - - NAMED_GROUP = { - 'secp256r1': 'P-256', - 'secp384r1': 'P-384', - 'secp521r1': 'P-521', - 'x25519': 'X25519', - 'x448': 'X448', - 'ffdhe2048': 'ffdhe2048', - } - - def cmd(self): - ret = super().cmd() - - if self._ciphers: - ciphersuites = ':'.join(self._ciphers) - ret += ["-ciphersuites {ciphersuites}".format(ciphersuites=ciphersuites)] - - if self._sig_algs: - signature_algorithms = set(self._sig_algs + self._cert_sig_algs) - signature_algorithms = ':'.join(signature_algorithms) - ret += ["-sigalgs {signature_algorithms}".format( - signature_algorithms=signature_algorithms)] - - if self._named_groups: - named_groups = ':'.join( - map(lambda named_group: self.NAMED_GROUP[named_group], self._named_groups)) - ret += ["-groups {named_groups}".format(named_groups=named_groups)] - - ret += ['-msg -tls1_3'] - - return ret - - def pre_checks(self): - ret = ["requires_openssl_tls1_3"] - - # ffdh groups require at least openssl 3.0 - ffdh_groups = ['ffdhe2048'] - - if any(x in ffdh_groups for x in self._named_groups): - ret = ["requires_openssl_tls1_3_with_ffdh"] - - return ret - - -class OpenSSLServ(OpenSSLBase): - """ - Generate test commands for OpenSSL server. - """ - - def cmd(self): - ret = super().cmd() - ret += ['-num_tickets 0 -no_resume_ephemeral -no_cache'] - return ret - - def post_checks(self): - return ['-c "HTTP/1.0 200 ok"'] - - def pre_cmd(self): - ret = ['$O_NEXT_SRV_NO_CERT'] - for _, cert, key in map(lambda sig_alg: CERTIFICATES[sig_alg], self._cert_sig_algs): - ret += ['-cert {cert} -key {key}'.format(cert=cert, key=key)] - return ret - - -class OpenSSLCli(OpenSSLBase): - """ - Generate test commands for OpenSSL client. - """ - - def pre_cmd(self): - return ['$O_NEXT_CLI_NO_CERT', - '-CAfile {cafile}'.format(cafile=CERTIFICATES[self._cert_sig_algs[0]].cafile)] - - -class GnuTLSBase(TLSProgram): - """ - Generate base test commands for GnuTLS. - """ - - CIPHER_SUITE = { - 'TLS_AES_256_GCM_SHA384': [ - 'AES-256-GCM', - 'SHA384', - 'AEAD'], - 'TLS_AES_128_GCM_SHA256': [ - 'AES-128-GCM', - 'SHA256', - 'AEAD'], - 'TLS_CHACHA20_POLY1305_SHA256': [ - 'CHACHA20-POLY1305', - 'SHA256', - 'AEAD'], - 'TLS_AES_128_CCM_SHA256': [ - 'AES-128-CCM', - 'SHA256', - 'AEAD'], - 'TLS_AES_128_CCM_8_SHA256': [ - 'AES-128-CCM-8', - 'SHA256', - 'AEAD']} - - SIGNATURE_ALGORITHM = { - 'ecdsa_secp256r1_sha256': ['SIGN-ECDSA-SECP256R1-SHA256'], - 'ecdsa_secp521r1_sha512': ['SIGN-ECDSA-SECP521R1-SHA512'], - 'ecdsa_secp384r1_sha384': ['SIGN-ECDSA-SECP384R1-SHA384'], - 'rsa_pss_rsae_sha256': ['SIGN-RSA-PSS-RSAE-SHA256']} - - NAMED_GROUP = { - 'secp256r1': ['GROUP-SECP256R1'], - 'secp384r1': ['GROUP-SECP384R1'], - 'secp521r1': ['GROUP-SECP521R1'], - 'x25519': ['GROUP-X25519'], - 'x448': ['GROUP-X448'], - 'ffdhe2048': ['GROUP-FFDHE2048'], - } - - def pre_checks(self): - return ["requires_gnutls_tls1_3", - "requires_gnutls_next_no_ticket"] - - def cmd(self): - ret = super().cmd() - - priority_string_list = [] - - def update_priority_string_list(items, map_table): - for item in items: - for i in map_table[item]: - if i not in priority_string_list: - yield i - - if self._ciphers: - priority_string_list.extend(update_priority_string_list( - self._ciphers, self.CIPHER_SUITE)) - else: - priority_string_list.extend(['CIPHER-ALL', 'MAC-ALL']) - - if self._sig_algs: - signature_algorithms = set(self._sig_algs + self._cert_sig_algs) - priority_string_list.extend(update_priority_string_list( - signature_algorithms, self.SIGNATURE_ALGORITHM)) - else: - priority_string_list.append('SIGN-ALL') - - - if self._named_groups: - priority_string_list.extend(update_priority_string_list( - self._named_groups, self.NAMED_GROUP)) - else: - priority_string_list.append('GROUP-ALL') - - priority_string_list = ['NONE'] + \ - priority_string_list + ['VERS-TLS1.3'] - - priority_string = ':+'.join(priority_string_list) - priority_string += ':%NO_TICKETS' - - ret += ['--priority={priority_string}'.format( - priority_string=priority_string)] - return ret - -class GnuTLSServ(GnuTLSBase): - """ - Generate test commands for GnuTLS server. - """ - - def pre_cmd(self): - ret = ['$G_NEXT_SRV_NO_CERT', '--http', '--disable-client-cert', '--debug=4'] - - for _, cert, key in map(lambda sig_alg: CERTIFICATES[sig_alg], self._cert_sig_algs): - ret += ['--x509certfile {cert} --x509keyfile {key}'.format( - cert=cert, key=key)] - return ret - - def post_checks(self): - return ['-c "HTTP/1.0 200 OK"'] - - -class GnuTLSCli(GnuTLSBase): - """ - Generate test commands for GnuTLS client. - """ - - def pre_cmd(self): - return ['$G_NEXT_CLI_NO_CERT', '--debug=4', '--single-key-share', - '--x509cafile {cafile}'.format(cafile=CERTIFICATES[self._cert_sig_algs[0]].cafile)] - - -class MbedTLSBase(TLSProgram): - """ - Generate base test commands for mbedTLS. - """ - - CIPHER_SUITE = { - 'TLS_AES_256_GCM_SHA384': 'TLS1-3-AES-256-GCM-SHA384', - 'TLS_AES_128_GCM_SHA256': 'TLS1-3-AES-128-GCM-SHA256', - 'TLS_CHACHA20_POLY1305_SHA256': 'TLS1-3-CHACHA20-POLY1305-SHA256', - 'TLS_AES_128_CCM_SHA256': 'TLS1-3-AES-128-CCM-SHA256', - 'TLS_AES_128_CCM_8_SHA256': 'TLS1-3-AES-128-CCM-8-SHA256'} - - def cmd(self): - ret = super().cmd() - ret += ['debug_level=4'] - - - if self._ciphers: - ciphers = ','.join( - map(lambda cipher: self.CIPHER_SUITE[cipher], self._ciphers)) - ret += ["force_ciphersuite={ciphers}".format(ciphers=ciphers)] - - if self._sig_algs + self._cert_sig_algs: - ret += ['sig_algs={sig_algs}'.format( - sig_algs=','.join(set(self._sig_algs + self._cert_sig_algs)))] - - if self._named_groups: - named_groups = ','.join(self._named_groups) - ret += ["groups={named_groups}".format(named_groups=named_groups)] - return ret - - #pylint: disable=missing-function-docstring - def add_ffdh_group_requirements(self, requirement_list): - if 'ffdhe2048' in self._named_groups: - requirement_list.append('requires_config_enabled PSA_WANT_DH_RFC7919_2048') - if 'ffdhe3072' in self._named_groups: - requirement_list.append('requires_config_enabled PSA_WANT_DH_RFC7919_2048') - if 'ffdhe4096' in self._named_groups: - requirement_list.append('requires_config_enabled PSA_WANT_DH_RFC7919_2048') - if 'ffdhe6144' in self._named_groups: - requirement_list.append('requires_config_enabled PSA_WANT_DH_RFC7919_2048') - if 'ffdhe8192' in self._named_groups: - requirement_list.append('requires_config_enabled PSA_WANT_DH_RFC7919_2048') - - def pre_checks(self): - ret = ['requires_config_enabled MBEDTLS_DEBUG_C', - 'requires_config_enabled MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL_ENABLED'] - - if 'rsa_pss_rsae_sha256' in self._sig_algs + self._cert_sig_algs: - ret.append( - 'requires_config_enabled MBEDTLS_X509_RSASSA_PSS_SUPPORT') - - ec_groups = ['secp256r1', 'secp384r1', 'secp521r1', 'x25519', 'x448'] - ffdh_groups = ['ffdhe2048', 'ffdhe3072', 'ffdhe4096', 'ffdhe6144', 'ffdhe8192'] - - if any(x in ec_groups for x in self._named_groups): - ret.append('requires_config_enabled PSA_WANT_ALG_ECDH') - - if any(x in ffdh_groups for x in self._named_groups): - ret.append('requires_config_enabled PSA_WANT_ALG_FFDH') - self.add_ffdh_group_requirements(ret) - - return ret - - -class MbedTLSServ(MbedTLSBase): - """ - Generate test commands for mbedTLS server. - """ - - def cmd(self): - ret = super().cmd() - ret += ['tls13_kex_modes=ephemeral cookies=0 tickets=0'] - return ret - - def pre_checks(self): - return ['requires_config_enabled MBEDTLS_SSL_SRV_C'] + super().pre_checks() - - def post_checks(self): - check_strings = ["Protocol is TLSv1.3"] - if self._ciphers: - check_strings.append( - "server hello, chosen ciphersuite: {} ( id={:04d} )".format( - self.CIPHER_SUITE[self._ciphers[0]], - CIPHER_SUITE_IANA_VALUE[self._ciphers[0]])) - if self._sig_algs: - check_strings.append( - "received signature algorithm: 0x{:x}".format( - SIG_ALG_IANA_VALUE[self._sig_algs[0]])) - - for named_group in self._named_groups: - check_strings += ['got named group: {named_group}({iana_value:04x})'.format( - named_group=named_group, - iana_value=NAMED_GROUP_IANA_VALUE[named_group])] - - check_strings.append("Certificate verification was skipped") - return ['-s "{}"'.format(i) for i in check_strings] - - def pre_cmd(self): - ret = ['$P_SRV'] - for _, cert, key in map(lambda sig_alg: CERTIFICATES[sig_alg], self._cert_sig_algs): - ret += ['crt_file={cert} key_file={key}'.format(cert=cert, key=key)] - return ret - - def hrr_post_checks(self, named_group): - return ['-s "HRR selected_group: {:s}"'.format(named_group)] - - -class MbedTLSCli(MbedTLSBase): - """ - Generate test commands for mbedTLS client. - """ - - def pre_cmd(self): - return ['$P_CLI', - 'ca_file={cafile}'.format(cafile=CERTIFICATES[self._cert_sig_algs[0]].cafile)] - - def pre_checks(self): - return ['requires_config_enabled MBEDTLS_SSL_CLI_C'] + super().pre_checks() - - def hrr_post_checks(self, named_group): - ret = ['-c "received HelloRetryRequest message"'] - ret += ['-c "selected_group ( {:d} )"'.format(NAMED_GROUP_IANA_VALUE[named_group])] - return ret - - def post_checks(self): - check_strings = ["Protocol is TLSv1.3"] - if self._ciphers: - check_strings.append( - "server hello, chosen ciphersuite: ( {:04x} ) - {}".format( - CIPHER_SUITE_IANA_VALUE[self._ciphers[0]], - self.CIPHER_SUITE[self._ciphers[0]])) - if self._sig_algs: - check_strings.append( - "Certificate Verify: Signature algorithm ( {:04x} )".format( - SIG_ALG_IANA_VALUE[self._sig_algs[0]])) - - for named_group in self._named_groups: - check_strings += ['NamedGroup: {named_group} ( {iana_value:x} )'.format( - named_group=named_group, - iana_value=NAMED_GROUP_IANA_VALUE[named_group])] - - check_strings.append("Verifying peer X.509 certificate... ok") - return ['-c "{}"'.format(i) for i in check_strings] - - -SERVER_CLASSES = {'OpenSSL': OpenSSLServ, 'GnuTLS': GnuTLSServ, 'mbedTLS': MbedTLSServ} -CLIENT_CLASSES = {'OpenSSL': OpenSSLCli, 'GnuTLS': GnuTLSCli, 'mbedTLS': MbedTLSCli} - - -def generate_compat_test(client=None, server=None, cipher=None, named_group=None, sig_alg=None): - """ - Generate test case with `ssl-opt.sh` format. - """ - name = 'TLS 1.3 {client[0]}->{server[0]}: {cipher},{named_group},{sig_alg}'.format( - client=client, server=server, cipher=cipher[4:], sig_alg=sig_alg, named_group=named_group) - - server_object = SERVER_CLASSES[server](ciphersuite=cipher, - named_group=named_group, - signature_algorithm=sig_alg, - cert_sig_alg=sig_alg) - client_object = CLIENT_CLASSES[client](ciphersuite=cipher, - named_group=named_group, - signature_algorithm=sig_alg, - cert_sig_alg=sig_alg) - - cmd = ['run_test "{}"'.format(name), - '"{}"'.format(' '.join(server_object.cmd())), - '"{}"'.format(' '.join(client_object.cmd())), - '0'] - cmd += server_object.post_checks() - cmd += client_object.post_checks() - cmd += ['-C "received HelloRetryRequest message"'] - prefix = ' \\\n' + (' '*9) - cmd = prefix.join(cmd) - return '\n'.join(server_object.pre_checks() + client_object.pre_checks() + [cmd]) - - -def generate_hrr_compat_test(client=None, server=None, - client_named_group=None, server_named_group=None, - cert_sig_alg=None): - """ - Generate Hello Retry Request test case with `ssl-opt.sh` format. - """ - name = 'TLS 1.3 {client[0]}->{server[0]}: HRR {c_named_group} -> {s_named_group}'.format( - client=client, server=server, c_named_group=client_named_group, - s_named_group=server_named_group) - server_object = SERVER_CLASSES[server](named_group=server_named_group, - cert_sig_alg=cert_sig_alg) - - client_object = CLIENT_CLASSES[client](named_group=client_named_group, - cert_sig_alg=cert_sig_alg) - client_object.add_named_groups(server_named_group) - - cmd = ['run_test "{}"'.format(name), - '"{}"'.format(' '.join(server_object.cmd())), - '"{}"'.format(' '.join(client_object.cmd())), - '0'] - cmd += server_object.post_checks() - cmd += client_object.post_checks() - cmd += server_object.hrr_post_checks(server_named_group) - cmd += client_object.hrr_post_checks(server_named_group) - prefix = ' \\\n' + (' '*9) - cmd = prefix.join(cmd) - return '\n'.join(server_object.pre_checks() + - client_object.pre_checks() + - [cmd]) - -SSL_OUTPUT_HEADER = '''\ -# TLS 1.3 interoperability test cases (equivalent of compat.sh for TLS 1.3). -# -# Automatically generated by {cmd}. Do not edit! - -# Copyright The Mbed TLS Contributors -# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later -''' -DATA_FILES_PATH_VAR = ''' -DATA_FILES_PATH=../framework/data_files -''' - -def main(): - """ - Main function of this program - """ - parser = argparse.ArgumentParser() - - parser.add_argument('-o', '--output', - default='tests/opt-testcases/tls13-compat.sh', - help='Output file path (not used with -1)') - - parser.add_argument('-1', '--single', action='store_true', - help='Print a single test case') - # Single mode used to be the default. - parser.add_argument('-a', '--generate-all-tls13-compat-tests', - action='store_false', dest='single', - help='Generate all test cases (negates -1) (default)') - - parser.add_argument('--list-ciphers', action='store_true', - default=False, help='List supported ciphersuites') - - parser.add_argument('--list-sig-algs', action='store_true', - default=False, help='List supported signature algorithms') - - parser.add_argument('--list-named-groups', action='store_true', - default=False, help='List supported named groups') - - parser.add_argument('--list-servers', action='store_true', - default=False, help='List supported TLS servers') - - parser.add_argument('--list-clients', action='store_true', - default=False, help='List supported TLS Clients') - - parser.add_argument('server', choices=SERVER_CLASSES.keys(), nargs='?', - default=list(SERVER_CLASSES.keys())[0], - help='Choose TLS server program for test') - parser.add_argument('client', choices=CLIENT_CLASSES.keys(), nargs='?', - default=list(CLIENT_CLASSES.keys())[0], - help='Choose TLS client program for test') - parser.add_argument('cipher', choices=CIPHER_SUITE_IANA_VALUE.keys(), nargs='?', - default=list(CIPHER_SUITE_IANA_VALUE.keys())[0], - help='Choose cipher suite for test') - parser.add_argument('sig_alg', choices=SIG_ALG_IANA_VALUE.keys(), nargs='?', - default=list(SIG_ALG_IANA_VALUE.keys())[0], - help='Choose cipher suite for test') - parser.add_argument('named_group', choices=NAMED_GROUP_IANA_VALUE.keys(), nargs='?', - default=list(NAMED_GROUP_IANA_VALUE.keys())[0], - help='Choose cipher suite for test') - - args = parser.parse_args() - - def get_all_test_cases(): - # Generate normal compat test cases - for client, server, cipher, named_group, sig_alg in \ - itertools.product(CLIENT_CLASSES.keys(), - SERVER_CLASSES.keys(), - CIPHER_SUITE_IANA_VALUE.keys(), - NAMED_GROUP_IANA_VALUE.keys(), - SIG_ALG_IANA_VALUE.keys()): - if server == 'mbedTLS' or client == 'mbedTLS': - yield generate_compat_test(client=client, server=server, - cipher=cipher, named_group=named_group, - sig_alg=sig_alg) - - - # Generate Hello Retry Request compat test cases - for client, server, client_named_group, server_named_group in \ - itertools.product(CLIENT_CLASSES.keys(), - SERVER_CLASSES.keys(), - NAMED_GROUP_IANA_VALUE.keys(), - NAMED_GROUP_IANA_VALUE.keys()): - - if (client == 'mbedTLS' or server == 'mbedTLS') and \ - client_named_group != server_named_group: - yield generate_hrr_compat_test(client=client, server=server, - client_named_group=client_named_group, - server_named_group=server_named_group, - cert_sig_alg="ecdsa_secp256r1_sha256") - - if not args.single: - if args.output: - with open(args.output, 'w', encoding="utf-8") as f: - f.write(SSL_OUTPUT_HEADER.format( - filename=os.path.basename(args.output), - cmd=os.path.basename(sys.argv[0]))) - f.write(DATA_FILES_PATH_VAR) - f.write('\n\n'.join(get_all_test_cases())) - f.write('\n') - else: - print('\n\n'.join(get_all_test_cases())) - return 0 - - if args.list_ciphers or args.list_sig_algs or args.list_named_groups \ - or args.list_servers or args.list_clients: - if args.list_ciphers: - print(*CIPHER_SUITE_IANA_VALUE.keys()) - if args.list_sig_algs: - print(*SIG_ALG_IANA_VALUE.keys()) - if args.list_named_groups: - print(*NAMED_GROUP_IANA_VALUE.keys()) - if args.list_servers: - print(*SERVER_CLASSES.keys()) - if args.list_clients: - print(*CLIENT_CLASSES.keys()) - return 0 - - print(generate_compat_test(server=args.server, client=args.client, sig_alg=args.sig_alg, - cipher=args.cipher, named_group=args.named_group)) - return 0 - - -if __name__ == "__main__": - sys.exit(main()) diff --git a/tests/scripts/translate_ciphers.py b/tests/scripts/translate_ciphers.py deleted file mode 100755 index 90514fca15..0000000000 --- a/tests/scripts/translate_ciphers.py +++ /dev/null @@ -1,180 +0,0 @@ -#!/usr/bin/env python3 - -# translate_ciphers.py -# -# Copyright The Mbed TLS Contributors -# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later - -""" -Translate standard ciphersuite names to GnuTLS, OpenSSL and Mbed TLS standards. - -To test the translation functions run: -python3 -m unittest translate_cipher.py -""" - -import re -import argparse -import unittest - -class TestTranslateCiphers(unittest.TestCase): - """ - Ensure translate_ciphers.py translates and formats ciphersuite names - correctly - """ - def test_translate_all_cipher_names(self): - """ - Translate standard ciphersuite names to GnuTLS, OpenSSL and - Mbed TLS counterpart. Use only a small subset of ciphers - that exercise each step of the translation functions - """ - ciphers = [ - ("TLS_ECDHE_ECDSA_WITH_NULL_SHA", - "+ECDHE-ECDSA:+NULL:+SHA1", - "ECDHE-ECDSA-NULL-SHA", - "TLS-ECDHE-ECDSA-WITH-NULL-SHA"), - ("TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", - "+ECDHE-ECDSA:+AES-128-GCM:+AEAD", - "ECDHE-ECDSA-AES128-GCM-SHA256", - "TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256"), - ("TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA", - "+DHE-RSA:+3DES-CBC:+SHA1", - "EDH-RSA-DES-CBC3-SHA", - "TLS-DHE-RSA-WITH-3DES-EDE-CBC-SHA"), - ("TLS_RSA_WITH_AES_256_CBC_SHA", - "+RSA:+AES-256-CBC:+SHA1", - "AES256-SHA", - "TLS-RSA-WITH-AES-256-CBC-SHA"), - ("TLS_PSK_WITH_3DES_EDE_CBC_SHA", - "+PSK:+3DES-CBC:+SHA1", - "PSK-3DES-EDE-CBC-SHA", - "TLS-PSK-WITH-3DES-EDE-CBC-SHA"), - ("TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256", - None, - "ECDHE-ECDSA-CHACHA20-POLY1305", - "TLS-ECDHE-ECDSA-WITH-CHACHA20-POLY1305-SHA256"), - ("TLS_ECDHE_ECDSA_WITH_AES_128_CCM", - "+ECDHE-ECDSA:+AES-128-CCM:+AEAD", - None, - "TLS-ECDHE-ECDSA-WITH-AES-128-CCM"), - ("TLS_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384", - None, - "ECDHE-ARIA256-GCM-SHA384", - "TLS-ECDHE-RSA-WITH-ARIA-256-GCM-SHA384"), - ] - - for s, g_exp, o_exp, m_exp in ciphers: - - if g_exp is not None: - g = translate_gnutls(s) - self.assertEqual(g, g_exp) - - if o_exp is not None: - o = translate_ossl(s) - self.assertEqual(o, o_exp) - - if m_exp is not None: - m = translate_mbedtls(s) - self.assertEqual(m, m_exp) - -def translate_gnutls(s_cipher): - """ - Translate s_cipher from standard ciphersuite naming convention - and return the GnuTLS naming convention - """ - - # Replace "_" with "-" to handle ciphersuite names based on Mbed TLS - # naming convention - s_cipher = s_cipher.replace("_", "-") - - s_cipher = re.sub(r'\ATLS-', '+', s_cipher) - s_cipher = s_cipher.replace("-WITH-", ":+") - s_cipher = s_cipher.replace("-EDE", "") - - # SHA in Mbed TLS == SHA1 GnuTLS, - # if the last 3 chars are SHA append 1 - if s_cipher[-3:] == "SHA": - s_cipher = s_cipher+"1" - - # CCM or CCM-8 should be followed by ":+AEAD" - # Replace "GCM:+SHAxyz" with "GCM:+AEAD" - if "CCM" in s_cipher or "GCM" in s_cipher: - s_cipher = re.sub(r"GCM-SHA\d\d\d", "GCM", s_cipher) - s_cipher = s_cipher+":+AEAD" - - # Replace the last "-" with ":+" - else: - index = s_cipher.rindex("-") - s_cipher = s_cipher[:index] + ":+" + s_cipher[index+1:] - - return s_cipher - -def translate_ossl(s_cipher): - """ - Translate s_cipher from standard ciphersuite naming convention - and return the OpenSSL naming convention - """ - - # Replace "_" with "-" to handle ciphersuite names based on Mbed TLS - # naming convention - s_cipher = s_cipher.replace("_", "-") - - s_cipher = re.sub(r'^TLS-', '', s_cipher) - s_cipher = s_cipher.replace("-WITH", "") - - # Remove the "-" from "ABC-xyz" - s_cipher = s_cipher.replace("AES-", "AES") - s_cipher = s_cipher.replace("CAMELLIA-", "CAMELLIA") - s_cipher = s_cipher.replace("ARIA-", "ARIA") - - # Remove "RSA" if it is at the beginning - s_cipher = re.sub(r'^RSA-', r'', s_cipher) - - # For all circumstances outside of PSK - if "PSK" not in s_cipher: - s_cipher = s_cipher.replace("-EDE", "") - s_cipher = s_cipher.replace("3DES-CBC", "DES-CBC3") - - # Remove "CBC" if it is not prefixed by DES - s_cipher = re.sub(r'(?