From 09c02ee95fbbebf4075a0e6798ceff8335056b75 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Thu, 25 Nov 2021 20:30:47 +0100 Subject: [PATCH 01/18] Make PSA headers more self-contained Several files among include/psa/crypto_*.h are not meant to be included directly, and are not guaranteed to be valid if included directly. This makes it harder to perform some static analyses. So make these files more self-contained so that at least, if included on their own, there is no missing macro or type definition (excluding the deliberate use of forward declarations of structs and unions). Signed-off-by: Gilles Peskine --- include/psa/crypto_driver_common.h | 3 +++ include/psa/crypto_extra.h | 1 + include/psa/crypto_struct.h | 2 +- 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/include/psa/crypto_driver_common.h b/include/psa/crypto_driver_common.h index 1b6f322567..26363c6b2f 100644 --- a/include/psa/crypto_driver_common.h +++ b/include/psa/crypto_driver_common.h @@ -42,6 +42,9 @@ * of these types. */ #include "crypto_types.h" #include "crypto_values.h" +/* Include size definitions which are used to size some arrays in operation + * structures. */ +#include /** For encrypt-decrypt functions, whether the operation is an encryption * or a decryption. */ diff --git a/include/psa/crypto_extra.h b/include/psa/crypto_extra.h index 2c0b1067c8..1f68925ff6 100644 --- a/include/psa/crypto_extra.h +++ b/include/psa/crypto_extra.h @@ -31,6 +31,7 @@ #include "mbedtls/platform_util.h" +#include "crypto_types.h" #include "crypto_compat.h" #ifdef __cplusplus diff --git a/include/psa/crypto_struct.h b/include/psa/crypto_struct.h index 26894156c5..9b696ca329 100644 --- a/include/psa/crypto_struct.h +++ b/include/psa/crypto_struct.h @@ -186,7 +186,7 @@ typedef struct { uint8_t *MBEDTLS_PRIVATE(info); size_t MBEDTLS_PRIVATE(info_length); - psa_mac_operation_t MBEDTLS_PRIVATE(hmac); + struct psa_mac_operation_s MBEDTLS_PRIVATE(hmac); uint8_t MBEDTLS_PRIVATE(prk)[PSA_HASH_MAX_SIZE]; uint8_t MBEDTLS_PRIVATE(output_block)[PSA_HASH_MAX_SIZE]; #if PSA_HASH_MAX_SIZE > 0xff From c8794202e69cc329d6391c0e15fbf9298e7b2a94 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Tue, 16 Nov 2021 20:48:59 +0100 Subject: [PATCH 02/18] Fix comment parsing Fix cases like ``` /*short comment*/ /*long comment */ int mbedtls_foo; ``` where the previous code thought that the second line started outside of a comment and ended inside of a comment. I believe that the new code strips comments correctly. It also strips string literals, just in case. Fixes #5191. Signed-off-by: Gilles Peskine --- tests/scripts/check_names.py | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/tests/scripts/check_names.py b/tests/scripts/check_names.py index ac2490fc1e..94f4cb1e85 100755 --- a/tests/scripts/check_names.py +++ b/tests/scripts/check_names.py @@ -509,18 +509,19 @@ class CodeParser(): previous_line = "" for line_no, line in enumerate(header): - # Skip parsing this line if a block comment ends on it, - # but don't skip if it has just started -- there is a chance - # it ends on the same line. - if re.search(r"/\*", line): - in_block_comment = not in_block_comment - if re.search(r"\*/", line): - in_block_comment = not in_block_comment - continue - + # Terminate current comment? if in_block_comment: - previous_line = "" - continue + line = re.sub(r".*?\*/", r"", line, 1) + in_block_comment = False + # Remove full comments and string literals + line = re.sub(r'/\*.*?\*/|(")(?:[^\\\"]|\\.)*"', + lambda s: '""' if s.group(1) else ' ', + line) + # Start an unfinished comment? + m = re.match(r"/\*", line) + if m: + in_block_comment = True + line = line[:m.end(0)] if exclusion_lines.search(line): previous_line = "" From 152de235186fe92145e95e2c384ff739cc85f46c Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Tue, 16 Nov 2021 20:56:47 +0100 Subject: [PATCH 03/18] Lift some code out of parse_identifiers Make parse_identifiers less complex. Pylint was complaining that it had too many local variables, and it had a point. * Lift the constants identifier_regex and exclusion_lines to class constants (renamed to uppercase because they're constants). * Lift the per-file loop into a new function parse_identifiers_in_file. No intended behavior change. Signed-off-by: Gilles Peskine --- tests/scripts/check_names.py | 188 +++++++++++++++++++---------------- 1 file changed, 100 insertions(+), 88 deletions(-) diff --git a/tests/scripts/check_names.py b/tests/scripts/check_names.py index 94f4cb1e85..1fb6487202 100755 --- a/tests/scripts/check_names.py +++ b/tests/scripts/check_names.py @@ -457,6 +457,105 @@ class CodeParser(): return enum_consts + IDENTIFIER_REGEX = re.compile( + # Match " something(a" or " *something(a". Functions. + # Assumptions: + # - function definition from return type to one of its arguments is + # all on one line + # - function definition line only contains alphanumeric, asterisk, + # underscore, and open bracket + r".* \**(\w+) *\( *\w|" + # Match "(*something)(". + r".*\( *\* *(\w+) *\) *\(|" + # Match names of named data structures. + r"(?:typedef +)?(?:struct|union|enum) +(\w+)(?: *{)?$|" + # Match names of typedef instances, after closing bracket. + r"}? *(\w+)[;[].*" + ) + # The regex below is indented for clarity. + EXCLUSION_LINES = re.compile( + r"^(" + r"extern +\"C\"|" # pylint: disable=bad-continuation + r"(typedef +)?(struct|union|enum)( *{)?$|" + r"} *;?$|" + r"$|" + r"//|" + r"#" + r")" + ) + + def parse_identifiers_in_file(self, header_file, identifiers): + """ + Parse all lines of a header where a function/enum/struct/union/typedef + identifier is declared, based on some regex and heuristics. Highly + dependent on formatting style. + + Append found matches to the list ``identifiers``. + """ + + with open(header_file, "r", encoding="utf-8") as header: + in_block_comment = False + # The previous line variable is used for concatenating lines + # when identifiers are formatted and spread across multiple + # lines. + previous_line = "" + + for line_no, line in enumerate(header): + # Terminate current comment? + if in_block_comment: + line = re.sub(r".*?\*/", r"", line, 1) + in_block_comment = False + # Remove full comments and string literals + line = re.sub(r'/\*.*?\*/|(")(?:[^\\\"]|\\.)*"', + lambda s: '""' if s.group(1) else ' ', + line) + # Start an unfinished comment? + m = re.match(r"/\*", line) + if m: + in_block_comment = True + line = line[:m.end(0)] + + if self.EXCLUSION_LINES.search(line): + previous_line = "" + continue + + # If the line contains only space-separated alphanumeric + # characters (or underscore, asterisk, or, open bracket), + # and nothing else, high chance it's a declaration that + # continues on the next line + if re.search(r"^([\w\*\(]+\s+)+$", line): + previous_line += line + continue + + # If previous line seemed to start an unfinished declaration + # (as above), concat and treat them as one. + if previous_line: + line = previous_line.strip() + " " + line.strip() + "\n" + previous_line = "" + + # Skip parsing if line has a space in front = heuristic to + # skip function argument lines (highly subject to formatting + # changes) + if line[0] == " ": + continue + + identifier = self.IDENTIFIER_REGEX.search(line) + + if not identifier: + continue + + # Find the group that matched, and append it + for group in identifier.groups(): + if not group: + continue + + identifiers.append(Match( + header_file, + line, + line_no, + identifier.span(), + group)) + def parse_identifiers(self, include, exclude=None): """ Parse all lines of a header where a function/enum/struct/union/typedef @@ -469,100 +568,13 @@ class CodeParser(): Returns a List of Match objects with identifiers. """ - identifier_regex = re.compile( - # Match " something(a" or " *something(a". Functions. - # Assumptions: - # - function definition from return type to one of its arguments is - # all on one line - # - function definition line only contains alphanumeric, asterisk, - # underscore, and open bracket - r".* \**(\w+) *\( *\w|" - # Match "(*something)(". - r".*\( *\* *(\w+) *\) *\(|" - # Match names of named data structures. - r"(?:typedef +)?(?:struct|union|enum) +(\w+)(?: *{)?$|" - # Match names of typedef instances, after closing bracket. - r"}? *(\w+)[;[].*" - ) - # The regex below is indented for clarity. - exclusion_lines = re.compile( - r"^(" - r"extern +\"C\"|" # pylint: disable=bad-continuation - r"(typedef +)?(struct|union|enum)( *{)?$|" - r"} *;?$|" - r"$|" - r"//|" - r"#" - r")" - ) files = self.get_files(include, exclude) self.log.debug("Looking for identifiers in {} files".format(len(files))) identifiers = [] for header_file in files: - with open(header_file, "r", encoding="utf-8") as header: - in_block_comment = False - # The previous line variable is used for concatenating lines - # when identifiers are formatted and spread across multiple - # lines. - previous_line = "" - - for line_no, line in enumerate(header): - # Terminate current comment? - if in_block_comment: - line = re.sub(r".*?\*/", r"", line, 1) - in_block_comment = False - # Remove full comments and string literals - line = re.sub(r'/\*.*?\*/|(")(?:[^\\\"]|\\.)*"', - lambda s: '""' if s.group(1) else ' ', - line) - # Start an unfinished comment? - m = re.match(r"/\*", line) - if m: - in_block_comment = True - line = line[:m.end(0)] - - if exclusion_lines.search(line): - previous_line = "" - continue - - # If the line contains only space-separated alphanumeric - # characters (or underscore, asterisk, or, open bracket), - # and nothing else, high chance it's a declaration that - # continues on the next line - if re.search(r"^([\w\*\(]+\s+)+$", line): - previous_line += line - continue - - # If previous line seemed to start an unfinished declaration - # (as above), concat and treat them as one. - if previous_line: - line = previous_line.strip() + " " + line.strip() + "\n" - previous_line = "" - - # Skip parsing if line has a space in front = heuristic to - # skip function argument lines (highly subject to formatting - # changes) - if line[0] == " ": - continue - - identifier = identifier_regex.search(line) - - if not identifier: - continue - - # Find the group that matched, and append it - for group in identifier.groups(): - if not group: - continue - - identifiers.append(Match( - header_file, - line, - line_no, - identifier.span(), - group)) + self.parse_identifiers_in_file(header_file, identifiers) return identifiers From 9b2fa72a4317f42cbbd9df7f0092234911307058 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Wed, 17 Nov 2021 20:23:18 +0100 Subject: [PATCH 04/18] Simplify some regex definitions Use '|'.join([comma-separated list]) rather than r'...|' r'...|'. This way there's less risk of forgetting a '|'. Pylint will yell if we forget a comma between list elements. Use match rather than search + mandatory start anchor for EXCLUSION_LINES. Signed-off-by: Gilles Peskine --- tests/scripts/check_names.py | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/tests/scripts/check_names.py b/tests/scripts/check_names.py index 1fb6487202..eb50fc1c71 100755 --- a/tests/scripts/check_names.py +++ b/tests/scripts/check_names.py @@ -457,32 +457,30 @@ class CodeParser(): return enum_consts - IDENTIFIER_REGEX = re.compile( + IDENTIFIER_REGEX = re.compile('|'.join([ # Match " something(a" or " *something(a". Functions. # Assumptions: # - function definition from return type to one of its arguments is # all on one line # - function definition line only contains alphanumeric, asterisk, # underscore, and open bracket - r".* \**(\w+) *\( *\w|" + r".* \**(\w+) *\( *\w", # Match "(*something)(". - r".*\( *\* *(\w+) *\) *\(|" + r".*\( *\* *(\w+) *\) *\(", # Match names of named data structures. - r"(?:typedef +)?(?:struct|union|enum) +(\w+)(?: *{)?$|" + r"(?:typedef +)?(?:struct|union|enum) +(\w+)(?: *{)?$", # Match names of typedef instances, after closing bracket. - r"}? *(\w+)[;[].*" - ) + r"}? *(\w+)[;[].*", + ])) # The regex below is indented for clarity. - EXCLUSION_LINES = re.compile( - r"^(" - r"extern +\"C\"|" # pylint: disable=bad-continuation - r"(typedef +)?(struct|union|enum)( *{)?$|" - r"} *;?$|" - r"$|" - r"//|" - r"#" - r")" - ) + EXCLUSION_LINES = re.compile("|".join([ + r"extern +\"C\"", + r"(typedef +)?(struct|union|enum)( *{)?$", + r"} *;?$", + r"$", + r"//", + r"#", + ])) def parse_identifiers_in_file(self, header_file, identifiers): """ @@ -515,7 +513,7 @@ class CodeParser(): in_block_comment = True line = line[:m.end(0)] - if self.EXCLUSION_LINES.search(line): + if self.EXCLUSION_LINES.match(line): previous_line = "" continue From b9fc488559ea9732066fb59e33f1c9f80415dbf1 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Wed, 17 Nov 2021 20:32:31 +0100 Subject: [PATCH 05/18] Move comment and string literal processing to a new function No intended behavior change. Signed-off-by: Gilles Peskine --- tests/scripts/check_names.py | 45 +++++++++++++++++++++++++----------- 1 file changed, 32 insertions(+), 13 deletions(-) diff --git a/tests/scripts/check_names.py b/tests/scripts/check_names.py index eb50fc1c71..9fc610b797 100755 --- a/tests/scripts/check_names.py +++ b/tests/scripts/check_names.py @@ -457,6 +457,36 @@ class CodeParser(): return enum_consts + def strip_comments_and_literals(self, line, in_block_comment): + """Strip comments and string literals from line. + + Continuation lines are not supported. + + If in_block_comment is true, assume that the line starts inside a + block comment. + + Return updated values of (line, in_block_comment) where: + * Comments in line have been replaced by a space (or nothing at the + start or end of the line). + * String contents have been removed. + * in_block_comment indicates whether the line ends inside a block + comment that continues on the next line. + """ + # Terminate current comment? + if in_block_comment: + line = re.sub(r".*?\*/", r"", line, 1) + in_block_comment = False + # Remove full comments and string literals + line = re.sub(r'/\*.*?\*/|(")(?:[^\\\"]|\\.)*"', + lambda s: '""' if s.group(1) else ' ', + line) + # Start an unfinished comment? + m = re.match(r"/\*", line) + if m: + in_block_comment = True + line = line[:m.end(0)] + return line, in_block_comment + IDENTIFIER_REGEX = re.compile('|'.join([ # Match " something(a" or " *something(a". Functions. # Assumptions: @@ -499,19 +529,8 @@ class CodeParser(): previous_line = "" for line_no, line in enumerate(header): - # Terminate current comment? - if in_block_comment: - line = re.sub(r".*?\*/", r"", line, 1) - in_block_comment = False - # Remove full comments and string literals - line = re.sub(r'/\*.*?\*/|(")(?:[^\\\"]|\\.)*"', - lambda s: '""' if s.group(1) else ' ', - line) - # Start an unfinished comment? - m = re.match(r"/\*", line) - if m: - in_block_comment = True - line = line[:m.end(0)] + line, in_block_comment = \ + self.strip_comments_and_literals(line, in_block_comment) if self.EXCLUSION_LINES.match(line): previous_line = "" From bc1e8f6a7c343a80c3169e8b1f2e2bbdc44ec28e Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Wed, 17 Nov 2021 20:39:56 +0100 Subject: [PATCH 06/18] Fix terminology in comment In computing, brackets are []. () are called parentheses. Signed-off-by: Gilles Peskine --- tests/scripts/check_names.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/scripts/check_names.py b/tests/scripts/check_names.py index 9fc610b797..730d6fc741 100755 --- a/tests/scripts/check_names.py +++ b/tests/scripts/check_names.py @@ -537,7 +537,7 @@ class CodeParser(): continue # If the line contains only space-separated alphanumeric - # characters (or underscore, asterisk, or, open bracket), + # characters (or underscore, asterisk, or open parenthesis), # and nothing else, high chance it's a declaration that # continues on the next line if re.search(r"^([\w\*\(]+\s+)+$", line): From b4b18c1155d93ead1436bba959a2f8920b9dce9a Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Wed, 17 Nov 2021 20:43:35 +0100 Subject: [PATCH 07/18] Improve comment and string stripping Make that part of the code more readable. Add support for // line comments. Signed-off-by: Gilles Peskine --- tests/scripts/check_names.py | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/tests/scripts/check_names.py b/tests/scripts/check_names.py index 730d6fc741..164d730229 100755 --- a/tests/scripts/check_names.py +++ b/tests/scripts/check_names.py @@ -457,6 +457,12 @@ class CodeParser(): return enum_consts + IGNORED_CHUNK_REGEX = re.compile('|'.join([ + r'/\*.*?\*/', # block comment entirely on one line + r'//.*', # line comment + r'(?P")(?:[^\\\"]|\\.)*"', # string literal + ])) + def strip_comments_and_literals(self, line, in_block_comment): """Strip comments and string literals from line. @@ -476,15 +482,21 @@ class CodeParser(): if in_block_comment: line = re.sub(r".*?\*/", r"", line, 1) in_block_comment = False - # Remove full comments and string literals - line = re.sub(r'/\*.*?\*/|(")(?:[^\\\"]|\\.)*"', - lambda s: '""' if s.group(1) else ' ', + + # Remove full comments and string literals. + # Do it all together to handle cases like "/*" correctly. + # Note that continuation lines are not supported. + line = re.sub(self.IGNORED_CHUNK_REGEX, + lambda s: '""' if s.group('string') else ' ', line) + # Start an unfinished comment? + # (If `/*` was part of a complete comment, it's already been removed.) m = re.match(r"/\*", line) if m: in_block_comment = True line = line[:m.end(0)] + return line, in_block_comment IDENTIFIER_REGEX = re.compile('|'.join([ From f303c0ddeb33d418f810d0c59f116693f208f62a Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Wed, 17 Nov 2021 20:45:39 +0100 Subject: [PATCH 08/18] Fix several bugs with multiline comments Empty the current line if it's entirely inside a comment. Don't incorrectly end a block comment at the second line if it doesn't contain `*/`. Recognize `/*` to start a multiline comment even if it isn't at the start of the line. When stripping off comments, consistently strip off `/*` and `*/`. Signed-off-by: Gilles Peskine --- tests/scripts/check_names.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/tests/scripts/check_names.py b/tests/scripts/check_names.py index 164d730229..5737cd6fdf 100755 --- a/tests/scripts/check_names.py +++ b/tests/scripts/check_names.py @@ -478,10 +478,15 @@ class CodeParser(): * in_block_comment indicates whether the line ends inside a block comment that continues on the next line. """ - # Terminate current comment? + + # Terminate current multiline comment? if in_block_comment: - line = re.sub(r".*?\*/", r"", line, 1) - in_block_comment = False + m = re.search(r"\*/", line) + if m: + in_block_comment = False + line = line[m.end(0):] + else: + return '', True # Remove full comments and string literals. # Do it all together to handle cases like "/*" correctly. @@ -492,10 +497,10 @@ class CodeParser(): # Start an unfinished comment? # (If `/*` was part of a complete comment, it's already been removed.) - m = re.match(r"/\*", line) + m = re.search(r"/\*", line) if m: in_block_comment = True - line = line[:m.end(0)] + line = line[:m.start(0)] return line, in_block_comment From e3d9c9d99bbb7536b75557ed190c2e18d30d9471 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Mon, 8 Nov 2021 22:12:47 +0100 Subject: [PATCH 09/18] PSA operation structures: move less-used fields to the end Move fields around to have fewer accesses outside the 128-element Thumb direct access window. In psa_hkdf_key_derivation_t, move the large fields (output_block, prk, hmac) after the state bit-fields. Experimentally, it's slightly better to put hmac last. Other operations structures don't go outside the window, at least when not considering nested structures. Results (arm-none-eabi-gcc 7.3.1, build_arm_none_eabi_gcc_m0plus build): library/psa_crypto.o: 16510 -> 16434 (diff: 76) Signed-off-by: Gilles Peskine --- include/psa/crypto_struct.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/psa/crypto_struct.h b/include/psa/crypto_struct.h index 9b696ca329..2c61e53cf9 100644 --- a/include/psa/crypto_struct.h +++ b/include/psa/crypto_struct.h @@ -186,9 +186,6 @@ typedef struct { uint8_t *MBEDTLS_PRIVATE(info); size_t MBEDTLS_PRIVATE(info_length); - struct psa_mac_operation_s MBEDTLS_PRIVATE(hmac); - uint8_t MBEDTLS_PRIVATE(prk)[PSA_HASH_MAX_SIZE]; - uint8_t MBEDTLS_PRIVATE(output_block)[PSA_HASH_MAX_SIZE]; #if PSA_HASH_MAX_SIZE > 0xff #error "PSA_HASH_MAX_SIZE does not fit in uint8_t" #endif @@ -196,6 +193,9 @@ typedef struct uint8_t MBEDTLS_PRIVATE(block_number); unsigned int MBEDTLS_PRIVATE(state) : 2; unsigned int MBEDTLS_PRIVATE(info_set) : 1; + uint8_t MBEDTLS_PRIVATE(output_block)[PSA_HASH_MAX_SIZE]; + uint8_t MBEDTLS_PRIVATE(prk)[PSA_HASH_MAX_SIZE]; + struct psa_mac_operation_s MBEDTLS_PRIVATE(hmac); } psa_hkdf_key_derivation_t; #endif /* MBEDTLS_PSA_BUILTIN_ALG_HKDF */ From 2d8a1824071275770218116e041355c8243c1405 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Mon, 8 Nov 2021 22:20:03 +0100 Subject: [PATCH 10/18] PSA global data: move fields around to save code size Move fields around to have fewer accesses outside the 128-element Thumb direct access window. Make the same change as in 2.27+, for the same small benefit. Results (arm-none-eabi-gcc 7.3.1, build_arm_none_eabi_gcc_m0plus build): library/psa_crypto.o: 16434 -> 16414 (diff: 20) Signed-off-by: Gilles Peskine --- library/psa_crypto.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/psa_crypto.c b/library/psa_crypto.c index 0a04ba1061..c74cb3cac8 100644 --- a/library/psa_crypto.c +++ b/library/psa_crypto.c @@ -103,9 +103,9 @@ static int key_type_is_raw_bytes( psa_key_type_t type ) typedef struct { - mbedtls_psa_random_context_t rng; unsigned initialized : 1; unsigned rng_state : 2; + mbedtls_psa_random_context_t rng; } psa_global_data_t; static psa_global_data_t global_data; From 8716f17961fd7760176bfaebc9b3827f70de6d9f Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Tue, 16 Nov 2021 15:21:44 +0100 Subject: [PATCH 11/18] Tweak whitespace for readability Signed-off-by: Gilles Peskine --- library/ssl_misc.h | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/library/ssl_misc.h b/library/ssl_misc.h index 36a071263d..b3569fab22 100644 --- a/library/ssl_misc.h +++ b/library/ssl_misc.h @@ -541,9 +541,11 @@ struct mbedtls_ssl_handshake_params defined(MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED) mbedtls_ssl_sig_hash_set_t hash_algs; /*!< Set of suitable sig-hash pairs */ #endif + #if defined(MBEDTLS_DHM_C) mbedtls_dhm_context dhm_ctx; /*!< DHM key exchange */ #endif + /* Adding guard for MBEDTLS_ECDSA_C to ensure no compile errors due * to guards also being in ssl_srv.c and ssl_cli.c. There is a gap * in functionality that access to ecdh_ctx structure is needed for @@ -568,10 +570,12 @@ struct mbedtls_ssl_handshake_params size_t ecjpake_cache_len; /*!< Length of cached data */ #endif #endif /* MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */ -#if defined(MBEDTLS_ECDH_C) || defined(MBEDTLS_ECDSA_C) || \ + +#if defined(MBEDTLS_ECDH_C) || defined(MBEDTLS_ECDSA_C) || \ defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) const mbedtls_ecp_curve_info **curves; /*!< Supported elliptic curves */ #endif + #if defined(MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED) #if defined(MBEDTLS_USE_PSA_CRYPTO) psa_key_id_t psk_opaque; /*!< Opaque PSK from the callback */ @@ -579,6 +583,7 @@ struct mbedtls_ssl_handshake_params unsigned char *psk; /*!< PSK from the callback */ size_t psk_len; /*!< Length of PSK from callback */ #endif /* MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED */ + #if defined(MBEDTLS_X509_CRT_PARSE_C) mbedtls_ssl_key_cert *key_cert; /*!< chosen key/cert pair (server) */ #if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) @@ -588,6 +593,7 @@ struct mbedtls_ssl_handshake_params mbedtls_x509_crl *sni_ca_crl; /*!< trusted CAs CRLs from SNI */ #endif /* MBEDTLS_SSL_SERVER_NAME_INDICATION */ #endif /* MBEDTLS_X509_CRT_PARSE_C */ + #if defined(MBEDTLS_SSL_ECP_RESTARTABLE_ENABLED) int ecrs_enabled; /*!< Handshake supports EC restart? */ mbedtls_x509_crt_restart_ctx ecrs_ctx; /*!< restart context */ @@ -601,10 +607,12 @@ struct mbedtls_ssl_handshake_params mbedtls_x509_crt *ecrs_peer_cert; /*!< The peer's CRT chain. */ size_t ecrs_n; /*!< place for saving a length */ #endif -#if defined(MBEDTLS_X509_CRT_PARSE_C) && \ + +#if defined(MBEDTLS_X509_CRT_PARSE_C) && \ !defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) mbedtls_pk_context peer_pubkey; /*!< The public key from the peer. */ #endif /* MBEDTLS_X509_CRT_PARSE_C && !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ + #if defined(MBEDTLS_SSL_PROTO_DTLS) unsigned int out_msg_seq; /*!< Outgoing handshake sequence number */ unsigned int in_msg_seq; /*!< Incoming handshake sequence number */ @@ -773,6 +781,7 @@ struct mbedtls_ssl_handshake_params #if defined(MBEDTLS_SSL_SESSION_TICKETS) int new_session_ticket; /*!< use NewSessionTicket? */ #endif /* MBEDTLS_SSL_SESSION_TICKETS */ + #if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET) int extended_ms; /*!< use Extended Master Secret? */ #endif From 55490d4e1f944cb33271e03cdc946b9a8b2ec865 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Mon, 29 Nov 2021 12:01:39 +0100 Subject: [PATCH 12/18] mbedtls_ssl_handshake_params: use bytes for some small values Replace bitfields mbedtls_ssl_handshake_params by bytes. This saves some code size, and since the bitfields weren't group, this doesn't increase the RAM usage. Replace several ints that only store values in the range 0..255 by uint8_t. This can increase or decrease the code size depending on the architecture and on how the field is used. I chose changes that save code size on Arm Thumb builds and will save more after field reordering. Leave the bitfields in struct mbedtls_ssl_hs_buffer alone: replacing them by uint8_t slightly increases the code size. Results (arm-none-eabi-gcc 7.3.1, build_arm_none_eabi_gcc_m0plus build): library/ssl_cli.o: 19759 -> 19763 (diff: -4) library/ssl_srv.o: 20790 -> 20754 (diff: 36) library/ssl_tls13_keys.o: 5153 -> 5133 (diff: 20) Signed-off-by: Gilles Peskine --- library/ssl_misc.h | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/library/ssl_misc.h b/library/ssl_misc.h index b3569fab22..e4d7d72ccd 100644 --- a/library/ssl_misc.h +++ b/library/ssl_misc.h @@ -587,7 +587,7 @@ struct mbedtls_ssl_handshake_params #if defined(MBEDTLS_X509_CRT_PARSE_C) mbedtls_ssl_key_cert *key_cert; /*!< chosen key/cert pair (server) */ #if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) - int sni_authmode; /*!< authmode from SNI callback */ + uint8_t sni_authmode; /*!< authmode from SNI callback */ mbedtls_ssl_key_cert *sni_key_cert; /*!< key/cert list from SNI */ mbedtls_x509_crt *sni_ca_chain; /*!< trusted CAs from SNI callback */ mbedtls_x509_crl *sni_ca_crl; /*!< trusted CAs CRLs from SNI */ @@ -595,7 +595,7 @@ struct mbedtls_ssl_handshake_params #endif /* MBEDTLS_X509_CRT_PARSE_C */ #if defined(MBEDTLS_SSL_ECP_RESTARTABLE_ENABLED) - int ecrs_enabled; /*!< Handshake supports EC restart? */ + uint8_t ecrs_enabled; /*!< Handshake supports EC restart? */ mbedtls_x509_crt_restart_ctx ecrs_ctx; /*!< restart context */ enum { /* this complements ssl->state with info on intra-state operations */ ssl_ecrs_none = 0, /*!< nothing going on (yet) */ @@ -759,10 +759,10 @@ struct mbedtls_ssl_handshake_params unsigned char premaster[MBEDTLS_PREMASTER_SIZE]; /*!< premaster secret */ - int resume; /*!< session resume indicator*/ - int max_major_ver; /*!< max. major version client*/ - int max_minor_ver; /*!< max. minor version client*/ - int cli_exts; /*!< client extension presence*/ + uint8_t max_major_ver; /*!< max. major version client*/ + uint8_t max_minor_ver; /*!< max. minor version client*/ + uint8_t resume; /*!< session resume indicator*/ + uint8_t cli_exts; /*!< client extension presence*/ #if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) int extensions_present; /*!< extension presence; Each bitfield represents an extension and defined @@ -779,15 +779,15 @@ struct mbedtls_ssl_handshake_params #endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ #if defined(MBEDTLS_SSL_SESSION_TICKETS) - int new_session_ticket; /*!< use NewSessionTicket? */ + uint8_t new_session_ticket; /*!< use NewSessionTicket? */ #endif /* MBEDTLS_SSL_SESSION_TICKETS */ #if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET) - int extended_ms; /*!< use Extended Master Secret? */ + uint8_t extended_ms; /*!< use Extended Master Secret? */ #endif #if defined(MBEDTLS_SSL_ASYNC_PRIVATE) - unsigned int async_in_progress : 1; /*!< an asynchronous operation is in progress */ + uint8_t async_in_progress; /*!< an asynchronous operation is in progress */ #endif /* MBEDTLS_SSL_ASYNC_PRIVATE */ #if defined(MBEDTLS_SSL_ASYNC_PRIVATE) From ec45c1e1740ff5ded75e8e9b2b42036ba99c5df4 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Mon, 29 Nov 2021 12:18:09 +0100 Subject: [PATCH 13/18] mbedtls_ssl_handshake_params: reorder fields to save code size Reorder fields mbedtls_ssl_handshake_params in order to save code on Arm Thumb builds. The general idea is to put often-used fields in the direct access window of 128 elements from the beginning of the structure. The reordering is a human selection based on a report of field offset and use counts, and informed by measuring the code size with various arrangements. Some notes: * This is the same reordering as the corresponding commit in #5189 for 2.2x. * I moved most byte-sized fields at the beginning where they're sure to be in the direct access window. * I moved buffering earlier because it can be around the threshold depending on the configuration, and it's accessed in a lot of places. * I moved several fields, including update_checksum and friends, early so that they're guaranteed to be in the early access window. Results (arm-none-eabi-gcc 7.3.1, build_arm_none_eabi_gcc_m0plus build): library/ssl_cli.o: 19763 -> 19687 (diff: 76) library/ssl_msg.o: 24874 -> 24834 (diff: 40) library/ssl_srv.o: 20754 -> 20562 (diff: 192) library/ssl_tls.o: 21003 -> 20907 (diff: 96) library/ssl_tls13_client.o: 7284 -> 7272 (diff: 12) library/ssl_tls13_generic.o: 4749 -> 4721 (diff: 28) library/ssl_tls13_keys.o: 5133 -> 5077 (diff: 56) Results (same architecture, config-suite-b.h + MBEDTLS_ECDH_LEGACY_CONTEXT + MBEDTLS_ECP_RESTARTABLE): library/ssl_cli.o: 3000 -> 2936 (diff: 64) library/ssl_msg.o: 3084 -> 3080 (diff: 4) library/ssl_srv.o: 3428 -> 3400 (diff: 28) library/ssl_tls.o: 6754 -> 6730 (diff: 24) Signed-off-by: Gilles Peskine --- library/ssl_misc.h | 165 ++++++++++++++++++++++++--------------------- 1 file changed, 87 insertions(+), 78 deletions(-) diff --git a/library/ssl_misc.h b/library/ssl_misc.h index e4d7d72ccd..6af125f704 100644 --- a/library/ssl_misc.h +++ b/library/ssl_misc.h @@ -525,6 +525,56 @@ typedef struct */ struct mbedtls_ssl_handshake_params { + /* Frequently-used boolean or byte fields (placed early to take + * advantage of smaller code size for indirect access on Arm Thumb) */ + uint8_t max_major_ver; /*!< max. major version client*/ + uint8_t max_minor_ver; /*!< max. minor version client*/ + uint8_t resume; /*!< session resume indicator*/ + uint8_t cli_exts; /*!< client extension presence*/ + +#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) + uint8_t sni_authmode; /*!< authmode from SNI callback */ +#endif + +#if defined(MBEDTLS_SSL_SESSION_TICKETS) + uint8_t new_session_ticket; /*!< use NewSessionTicket? */ +#endif /* MBEDTLS_SSL_SESSION_TICKETS */ + +#if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET) + uint8_t extended_ms; /*!< use Extended Master Secret? */ +#endif + +#if defined(MBEDTLS_SSL_ASYNC_PRIVATE) + uint8_t async_in_progress; /*!< an asynchronous operation is in progress */ +#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */ + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + unsigned char retransmit_state; /*!< Retransmission state */ +#endif + +#if defined(MBEDTLS_SSL_ECP_RESTARTABLE_ENABLED) + uint8_t ecrs_enabled; /*!< Handshake supports EC restart? */ + mbedtls_x509_crt_restart_ctx ecrs_ctx; /*!< restart context */ + enum { /* this complements ssl->state with info on intra-state operations */ + ssl_ecrs_none = 0, /*!< nothing going on (yet) */ + ssl_ecrs_crt_verify, /*!< Certificate: crt_verify() */ + ssl_ecrs_ske_start_processing, /*!< ServerKeyExchange: pk_verify() */ + ssl_ecrs_cke_ecdh_calc_secret, /*!< ClientKeyExchange: ECDH step 2 */ + ssl_ecrs_crt_vrfy_sign, /*!< CertificateVerify: pk_sign() */ + } ecrs_state; /*!< current (or last) operation */ + mbedtls_x509_crt *ecrs_peer_cert; /*!< The peer's CRT chain. */ + size_t ecrs_n; /*!< place for saving a length */ +#endif + + size_t pmslen; /*!< premaster length */ + + mbedtls_ssl_ciphersuite_t const *ciphersuite_info; + + void (*update_checksum)(mbedtls_ssl_context *, const unsigned char *, size_t); + void (*calc_verify)(const mbedtls_ssl_context *, unsigned char *, size_t *); + void (*calc_finished)(mbedtls_ssl_context *, unsigned char *, int); + mbedtls_ssl_tls_prf_cb *tls_prf; + /* * Handshake specific crypto variables */ @@ -532,11 +582,6 @@ struct mbedtls_ssl_handshake_params int tls1_3_kex_modes; /*!< key exchange modes for TLS 1.3 */ #endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ -#if !defined(MBEDTLS_DEPRECATED_REMOVED) - const uint16_t *group_list; - unsigned char group_list_heap_allocated; -#endif - #if defined(MBEDTLS_SSL_PROTO_TLS1_2) && \ defined(MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED) mbedtls_ssl_sig_hash_set_t hash_algs; /*!< Set of suitable sig-hash pairs */ @@ -587,65 +632,17 @@ struct mbedtls_ssl_handshake_params #if defined(MBEDTLS_X509_CRT_PARSE_C) mbedtls_ssl_key_cert *key_cert; /*!< chosen key/cert pair (server) */ #if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) - uint8_t sni_authmode; /*!< authmode from SNI callback */ mbedtls_ssl_key_cert *sni_key_cert; /*!< key/cert list from SNI */ mbedtls_x509_crt *sni_ca_chain; /*!< trusted CAs from SNI callback */ mbedtls_x509_crl *sni_ca_crl; /*!< trusted CAs CRLs from SNI */ #endif /* MBEDTLS_SSL_SERVER_NAME_INDICATION */ #endif /* MBEDTLS_X509_CRT_PARSE_C */ -#if defined(MBEDTLS_SSL_ECP_RESTARTABLE_ENABLED) - uint8_t ecrs_enabled; /*!< Handshake supports EC restart? */ - mbedtls_x509_crt_restart_ctx ecrs_ctx; /*!< restart context */ - enum { /* this complements ssl->state with info on intra-state operations */ - ssl_ecrs_none = 0, /*!< nothing going on (yet) */ - ssl_ecrs_crt_verify, /*!< Certificate: crt_verify() */ - ssl_ecrs_ske_start_processing, /*!< ServerKeyExchange: pk_verify() */ - ssl_ecrs_cke_ecdh_calc_secret, /*!< ClientKeyExchange: ECDH step 2 */ - ssl_ecrs_crt_vrfy_sign, /*!< CertificateVerify: pk_sign() */ - } ecrs_state; /*!< current (or last) operation */ - mbedtls_x509_crt *ecrs_peer_cert; /*!< The peer's CRT chain. */ - size_t ecrs_n; /*!< place for saving a length */ -#endif - #if defined(MBEDTLS_X509_CRT_PARSE_C) && \ !defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) mbedtls_pk_context peer_pubkey; /*!< The public key from the peer. */ #endif /* MBEDTLS_X509_CRT_PARSE_C && !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ -#if defined(MBEDTLS_SSL_PROTO_DTLS) - unsigned int out_msg_seq; /*!< Outgoing handshake sequence number */ - unsigned int in_msg_seq; /*!< Incoming handshake sequence number */ - - unsigned char *verify_cookie; /*!< Cli: HelloVerifyRequest cookie - Srv: unused */ - unsigned char verify_cookie_len; /*!< Cli: cookie length - Srv: flag for sending a cookie */ - - uint32_t retransmit_timeout; /*!< Current value of timeout */ - unsigned char retransmit_state; /*!< Retransmission state */ - mbedtls_ssl_flight_item *flight; /*!< Current outgoing flight */ - mbedtls_ssl_flight_item *cur_msg; /*!< Current message in flight */ - unsigned char *cur_msg_p; /*!< Position in current message */ - unsigned int in_flight_start_seq; /*!< Minimum message sequence in the - flight being received */ - mbedtls_ssl_transform *alt_transform_out; /*!< Alternative transform for - resending messages */ - unsigned char alt_out_ctr[MBEDTLS_SSL_SEQUENCE_NUMBER_LEN]; /*!< Alternative record epoch/counter - for resending messages */ - -#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) - /* The state of CID configuration in this handshake. */ - - uint8_t cid_in_use; /*!< This indicates whether the use of the CID extension - * has been negotiated. Possible values are - * #MBEDTLS_SSL_CID_ENABLED and - * #MBEDTLS_SSL_CID_DISABLED. */ - unsigned char peer_cid[ MBEDTLS_SSL_CID_OUT_LEN_MAX ]; /*! The peer's CID */ - uint8_t peer_cid_len; /*!< The length of - * \c peer_cid. */ -#endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */ - struct { size_t total_bytes_buffered; /*!< Cumulative size of heap allocated @@ -672,6 +669,38 @@ struct mbedtls_ssl_handshake_params } buffering; +#if defined(MBEDTLS_SSL_PROTO_DTLS) + unsigned int out_msg_seq; /*!< Outgoing handshake sequence number */ + unsigned int in_msg_seq; /*!< Incoming handshake sequence number */ + + unsigned char *verify_cookie; /*!< Cli: HelloVerifyRequest cookie + Srv: unused */ + unsigned char verify_cookie_len; /*!< Cli: cookie length + Srv: flag for sending a cookie */ + + uint32_t retransmit_timeout; /*!< Current value of timeout */ + mbedtls_ssl_flight_item *flight; /*!< Current outgoing flight */ + mbedtls_ssl_flight_item *cur_msg; /*!< Current message in flight */ + unsigned char *cur_msg_p; /*!< Position in current message */ + unsigned int in_flight_start_seq; /*!< Minimum message sequence in the + flight being received */ + mbedtls_ssl_transform *alt_transform_out; /*!< Alternative transform for + resending messages */ + unsigned char alt_out_ctr[MBEDTLS_SSL_SEQUENCE_NUMBER_LEN]; /*!< Alternative record epoch/counter + for resending messages */ + +#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) + /* The state of CID configuration in this handshake. */ + + uint8_t cid_in_use; /*!< This indicates whether the use of the CID extension + * has been negotiated. Possible values are + * #MBEDTLS_SSL_CID_ENABLED and + * #MBEDTLS_SSL_CID_DISABLED. */ + unsigned char peer_cid[ MBEDTLS_SSL_CID_OUT_LEN_MAX ]; /*! The peer's CID */ + uint8_t peer_cid_len; /*!< The length of + * \c peer_cid. */ +#endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */ + uint16_t mtu; /*!< Handshake mtu, used to fragment outgoing messages */ #endif /* MBEDTLS_SSL_PROTO_DTLS */ @@ -702,11 +731,6 @@ struct mbedtls_ssl_handshake_params #endif #endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ - void (*update_checksum)(mbedtls_ssl_context *, const unsigned char *, size_t); - void (*calc_verify)(const mbedtls_ssl_context *, unsigned char *, size_t *); - void (*calc_finished)(mbedtls_ssl_context *, unsigned char *, int); - mbedtls_ssl_tls_prf_cb *tls_prf; - #if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) uint16_t offered_group_id; /* The NamedGroup value for the group * that is being used for ephemeral @@ -749,20 +773,12 @@ struct mbedtls_ssl_handshake_params /* End of state-local variables. */ - mbedtls_ssl_ciphersuite_t const *ciphersuite_info; - - size_t pmslen; /*!< premaster length */ - unsigned char randbytes[MBEDTLS_CLIENT_HELLO_RANDOM_LEN + MBEDTLS_SERVER_HELLO_RANDOM_LEN]; /*!< random bytes */ unsigned char premaster[MBEDTLS_PREMASTER_SIZE]; /*!< premaster secret */ - uint8_t max_major_ver; /*!< max. major version client*/ - uint8_t max_minor_ver; /*!< max. minor version client*/ - uint8_t resume; /*!< session resume indicator*/ - uint8_t cli_exts; /*!< client extension presence*/ #if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) int extensions_present; /*!< extension presence; Each bitfield represents an extension and defined @@ -778,18 +794,6 @@ struct mbedtls_ssl_handshake_params mbedtls_ssl_tls1_3_handshake_secrets tls13_hs_secrets; #endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ -#if defined(MBEDTLS_SSL_SESSION_TICKETS) - uint8_t new_session_ticket; /*!< use NewSessionTicket? */ -#endif /* MBEDTLS_SSL_SESSION_TICKETS */ - -#if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET) - uint8_t extended_ms; /*!< use Extended Master Secret? */ -#endif - -#if defined(MBEDTLS_SSL_ASYNC_PRIVATE) - uint8_t async_in_progress; /*!< an asynchronous operation is in progress */ -#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */ - #if defined(MBEDTLS_SSL_ASYNC_PRIVATE) /** Asynchronous operation context. This field is meant for use by the * asynchronous operation callbacks (mbedtls_ssl_config::f_async_sign_start, @@ -798,6 +802,11 @@ struct mbedtls_ssl_handshake_params * The library does not use it internally. */ void *user_async_ctx; #endif /* MBEDTLS_SSL_ASYNC_PRIVATE */ + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) + const uint16_t *group_list; + unsigned char group_list_heap_allocated; +#endif }; typedef struct mbedtls_ssl_hs_buffer mbedtls_ssl_hs_buffer; From 8834d87ef65443871cbe3b0cd1b167e43eb6f42f Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Mon, 29 Nov 2021 12:36:50 +0100 Subject: [PATCH 14/18] mbedtls_ssl_config, mbedtls_ssl_session: reorder fields Move small fields first so that more fields can be within the Arm Thumb 128-element direct access window. Keep the int section after the pointer section: moving int fields first cost a few bytes on the reference baremetal-m0plus build. The ordering in this commit is not based on field access frequency. Results (arm-none-eabi-gcc 7.3.1, build_arm_none_eabi_gcc_m0plus build): library/ssl_cli.o: 19687 -> 19543 (diff: 144) library/ssl_msg.o: 24834 -> 24726 (diff: 108) library/ssl_srv.o: 20562 -> 20462 (diff: 100) library/ssl_tls.o: 20907 -> 20707 (diff: 200) library/ssl_tls13_client.o: 7272 -> 7252 (diff: 20) library/ssl_tls13_generic.o: 4721 -> 4705 (diff: 16) Results (same architecture, config-suite-b.h + MBEDTLS_ECDH_LEGACY_CONTEXT + MBEDTLS_ECP_RESTARTABLE): library/ssl_cli.o: 2936 -> 2876 (diff: 60) library/ssl_msg.o: 3080 -> 3068 (diff: 12) library/ssl_srv.o: 3400 -> 3372 (diff: 28) library/ssl_tls.o: 6730 -> 6658 (diff: 72) Signed-off-by: Gilles Peskine --- include/mbedtls/ssl.h | 127 +++++++++++++++++++++--------------------- 1 file changed, 65 insertions(+), 62 deletions(-) diff --git a/include/mbedtls/ssl.h b/include/mbedtls/ssl.h index 45e05447be..47f336cdd8 100644 --- a/include/mbedtls/ssl.h +++ b/include/mbedtls/ssl.h @@ -1108,6 +1108,17 @@ mbedtls_dtls_srtp_info; */ struct mbedtls_ssl_session { +#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) + unsigned char MBEDTLS_PRIVATE(mfl_code); /*!< MaxFragmentLength negotiated by peer */ +#endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */ + + unsigned char MBEDTLS_PRIVATE(exported); + + /* This field is temporarily duplicated with mbedtls_ssl_context.minor_ver. + * Once runtime negotiation of TLS 1.2 and TLS 1.3 is implemented, it needs + * to be studied whether one of them can be removed. */ + unsigned char MBEDTLS_PRIVATE(minor_ver); /*!< The TLS version used in the session. */ + #if defined(MBEDTLS_HAVE_TIME) mbedtls_time_t MBEDTLS_PRIVATE(start); /*!< starting time */ #endif @@ -1117,13 +1128,6 @@ struct mbedtls_ssl_session unsigned char MBEDTLS_PRIVATE(id)[32]; /*!< session identifier */ unsigned char MBEDTLS_PRIVATE(master)[48]; /*!< the master secret */ - unsigned char MBEDTLS_PRIVATE(exported); - - /* This field is temporarily duplicated with mbedtls_ssl_context.minor_ver. - * Once runtime negotiation of TLS 1.2 and TLS 1.3 is implemented, it needs - * to be studied whether one of them can be removed. */ - unsigned char MBEDTLS_PRIVATE(minor_ver); /*!< The TLS version used in the session. */ - #if defined(MBEDTLS_X509_CRT_PARSE_C) #if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) mbedtls_x509_crt *MBEDTLS_PRIVATE(peer_cert); /*!< peer X.509 cert chain */ @@ -1143,10 +1147,6 @@ struct mbedtls_ssl_session uint32_t MBEDTLS_PRIVATE(ticket_lifetime); /*!< ticket lifetime hint */ #endif /* MBEDTLS_SSL_SESSION_TICKETS && MBEDTLS_SSL_CLI_C */ -#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) - unsigned char MBEDTLS_PRIVATE(mfl_code); /*!< MaxFragmentLength negotiated by peer */ -#endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */ - #if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) int MBEDTLS_PRIVATE(encrypt_then_mac); /*!< flag for EtM activation */ #endif @@ -1210,7 +1210,59 @@ typedef void mbedtls_ssl_export_keys_t( void *p_expkey, */ struct mbedtls_ssl_config { - /* Group items by size (largest first) to minimize padding overhead */ + /* Group items mostly by size. This helps to reduce memory wasted to + * padding. It also helps to keep smaller fields early in the structure, + * so that elements tend to be in the 128-element direct access window + * on Arm Thumb, which reduces the code size. */ + + unsigned char MBEDTLS_PRIVATE(max_major_ver); /*!< max. major version used */ + unsigned char MBEDTLS_PRIVATE(max_minor_ver); /*!< max. minor version used */ + unsigned char MBEDTLS_PRIVATE(min_major_ver); /*!< min. major version used */ + unsigned char MBEDTLS_PRIVATE(min_minor_ver); /*!< min. minor version used */ + + /* + * Flags (bitfields) + */ + + unsigned int MBEDTLS_PRIVATE(endpoint) : 1; /*!< 0: client, 1: server */ + unsigned int MBEDTLS_PRIVATE(transport) : 1; /*!< stream (TLS) or datagram (DTLS) */ + unsigned int MBEDTLS_PRIVATE(authmode) : 2; /*!< MBEDTLS_SSL_VERIFY_XXX */ + /* needed even with renego disabled for LEGACY_BREAK_HANDSHAKE */ + unsigned int MBEDTLS_PRIVATE(allow_legacy_renegotiation) : 2 ; /*!< MBEDTLS_LEGACY_XXX */ +#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) + unsigned int MBEDTLS_PRIVATE(mfl_code) : 3; /*!< desired fragment length */ +#endif +#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) + unsigned int MBEDTLS_PRIVATE(encrypt_then_mac) : 1 ; /*!< negotiate encrypt-then-mac? */ +#endif +#if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET) + unsigned int MBEDTLS_PRIVATE(extended_ms) : 1; /*!< negotiate extended master secret? */ +#endif +#if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY) + unsigned int MBEDTLS_PRIVATE(anti_replay) : 1; /*!< detect and prevent replay? */ +#endif +#if defined(MBEDTLS_SSL_RENEGOTIATION) + unsigned int MBEDTLS_PRIVATE(disable_renegotiation) : 1; /*!< disable renegotiation? */ +#endif +#if defined(MBEDTLS_SSL_SESSION_TICKETS) + unsigned int MBEDTLS_PRIVATE(session_tickets) : 1; /*!< use session tickets? */ +#endif +#if defined(MBEDTLS_SSL_SRV_C) + unsigned int MBEDTLS_PRIVATE(cert_req_ca_list) : 1; /*!< enable sending CA list in + Certificate Request messages? */ + unsigned int MBEDTLS_PRIVATE(respect_cli_pref) : 1; /*!< pick the ciphersuite according to + the client's preferences rather + than ours */ +#endif +#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) + unsigned int MBEDTLS_PRIVATE(ignore_unexpected_cid) : 1; /*!< Determines whether DTLS + * record with unexpected CID + * should lead to failure. */ +#endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */ +#if defined(MBEDTLS_SSL_DTLS_SRTP) + unsigned int MBEDTLS_PRIVATE(dtls_srtp_mki_support) : 1; /* support having mki_value + in the use_srtp extension */ +#endif /* * Pointers @@ -1365,7 +1417,7 @@ struct mbedtls_ssl_config #endif /* MBEDTLS_SSL_DTLS_SRTP */ /* - * Numerical settings (int then char) + * Numerical settings (int) */ uint32_t MBEDTLS_PRIVATE(read_timeout); /*!< timeout for mbedtls_ssl_read (ms) */ @@ -1388,55 +1440,6 @@ struct mbedtls_ssl_config #if defined(MBEDTLS_DHM_C) && defined(MBEDTLS_SSL_CLI_C) unsigned int MBEDTLS_PRIVATE(dhm_min_bitlen); /*!< min. bit length of the DHM prime */ #endif - - unsigned char MBEDTLS_PRIVATE(max_major_ver); /*!< max. major version used */ - unsigned char MBEDTLS_PRIVATE(max_minor_ver); /*!< max. minor version used */ - unsigned char MBEDTLS_PRIVATE(min_major_ver); /*!< min. major version used */ - unsigned char MBEDTLS_PRIVATE(min_minor_ver); /*!< min. minor version used */ - - /* - * Flags (bitfields) - */ - - unsigned int MBEDTLS_PRIVATE(endpoint) : 1; /*!< 0: client, 1: server */ - unsigned int MBEDTLS_PRIVATE(transport) : 1; /*!< stream (TLS) or datagram (DTLS) */ - unsigned int MBEDTLS_PRIVATE(authmode) : 2; /*!< MBEDTLS_SSL_VERIFY_XXX */ - /* needed even with renego disabled for LEGACY_BREAK_HANDSHAKE */ - unsigned int MBEDTLS_PRIVATE(allow_legacy_renegotiation) : 2 ; /*!< MBEDTLS_LEGACY_XXX */ -#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) - unsigned int MBEDTLS_PRIVATE(mfl_code) : 3; /*!< desired fragment length */ -#endif -#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) - unsigned int MBEDTLS_PRIVATE(encrypt_then_mac) : 1 ; /*!< negotiate encrypt-then-mac? */ -#endif -#if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET) - unsigned int MBEDTLS_PRIVATE(extended_ms) : 1; /*!< negotiate extended master secret? */ -#endif -#if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY) - unsigned int MBEDTLS_PRIVATE(anti_replay) : 1; /*!< detect and prevent replay? */ -#endif -#if defined(MBEDTLS_SSL_RENEGOTIATION) - unsigned int MBEDTLS_PRIVATE(disable_renegotiation) : 1; /*!< disable renegotiation? */ -#endif -#if defined(MBEDTLS_SSL_SESSION_TICKETS) - unsigned int MBEDTLS_PRIVATE(session_tickets) : 1; /*!< use session tickets? */ -#endif -#if defined(MBEDTLS_SSL_SRV_C) - unsigned int MBEDTLS_PRIVATE(cert_req_ca_list) : 1; /*!< enable sending CA list in - Certificate Request messages? */ - unsigned int MBEDTLS_PRIVATE(respect_cli_pref) : 1; /*!< pick the ciphersuite according to - the client's preferences rather - than ours */ -#endif -#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) - unsigned int MBEDTLS_PRIVATE(ignore_unexpected_cid) : 1; /*!< Determines whether DTLS - * record with unexpected CID - * should lead to failure. */ -#endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */ -#if defined(MBEDTLS_SSL_DTLS_SRTP) - unsigned int MBEDTLS_PRIVATE(dtls_srtp_mki_support) : 1; /* support having mki_value - in the use_srtp extension */ -#endif }; struct mbedtls_ssl_context From 533a7283922d9702c59e54360d3fca53314044c0 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Tue, 16 Nov 2021 18:31:46 +0100 Subject: [PATCH 15/18] mbedtls_ssl_config: Replace bit-fields by separate bytes This slightly increases the RAM consumption per context, but saves code size on architectures with an instruction for direct byte access (which is most of them). Although this is technically an API break, in practice, a realistic application won't break: it would have had to bypass API functions and rely on the field size (e.g. relying on -1 == 1 in a 1-bit field). Results (arm-none-eabi-gcc 7.3.1, build_arm_none_eabi_gcc_m0plus build): library/ssl_cli.o: 19543 -> 19559 (diff: -16) library/ssl_msg.o: 24726 -> 24690 (diff: 36) library/ssl_srv.o: 20462 -> 20418 (diff: 44) library/ssl_tls.o: 20707 -> 20555 (diff: 152) library/ssl_tls13_client.o: 7252 -> 7244 (diff: 8) library/ssl_tls13_generic.o: 4705 -> 4693 (diff: 12) Results (same architecture, config-suite-b.h + MBEDTLS_ECDH_LEGACY_CONTEXT + MBEDTLS_ECP_RESTARTABLE): library/ssl_cli.o: 2876 -> 2864 (diff: 12) library/ssl_msg.o: 3068 -> 3080 (diff: -12) library/ssl_srv.o: 3372 -> 3340 (diff: 32) library/ssl_tls.o: 6658 -> 6566 (diff: 92) Signed-off-by: Gilles Peskine --- include/mbedtls/ssl.h | 44 ++++++++++++++++++++++--------------------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/include/mbedtls/ssl.h b/include/mbedtls/ssl.h index 47f336cdd8..b41ad44357 100644 --- a/include/mbedtls/ssl.h +++ b/include/mbedtls/ssl.h @@ -1221,47 +1221,49 @@ struct mbedtls_ssl_config unsigned char MBEDTLS_PRIVATE(min_minor_ver); /*!< min. minor version used */ /* - * Flags (bitfields) + * Flags (could be bit-fields to save RAM, but separate bytes make + * the code smaller on architectures with an instruction for direct + * byte access). */ - unsigned int MBEDTLS_PRIVATE(endpoint) : 1; /*!< 0: client, 1: server */ - unsigned int MBEDTLS_PRIVATE(transport) : 1; /*!< stream (TLS) or datagram (DTLS) */ - unsigned int MBEDTLS_PRIVATE(authmode) : 2; /*!< MBEDTLS_SSL_VERIFY_XXX */ + uint8_t MBEDTLS_PRIVATE(endpoint); /*!< 0: client, 1: server */ + uint8_t MBEDTLS_PRIVATE(transport); /*!< stream (TLS) or datagram (DTLS) */ + uint8_t MBEDTLS_PRIVATE(authmode); /*!< MBEDTLS_SSL_VERIFY_XXX */ /* needed even with renego disabled for LEGACY_BREAK_HANDSHAKE */ - unsigned int MBEDTLS_PRIVATE(allow_legacy_renegotiation) : 2 ; /*!< MBEDTLS_LEGACY_XXX */ + uint8_t MBEDTLS_PRIVATE(allow_legacy_renegotiation); /*!< MBEDTLS_LEGACY_XXX */ #if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) - unsigned int MBEDTLS_PRIVATE(mfl_code) : 3; /*!< desired fragment length */ + uint8_t MBEDTLS_PRIVATE(mfl_code); /*!< desired fragment length */ #endif #if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) - unsigned int MBEDTLS_PRIVATE(encrypt_then_mac) : 1 ; /*!< negotiate encrypt-then-mac? */ + uint8_t MBEDTLS_PRIVATE(encrypt_then_mac); /*!< negotiate encrypt-then-mac? */ #endif #if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET) - unsigned int MBEDTLS_PRIVATE(extended_ms) : 1; /*!< negotiate extended master secret? */ + uint8_t MBEDTLS_PRIVATE(extended_ms); /*!< negotiate extended master secret? */ #endif #if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY) - unsigned int MBEDTLS_PRIVATE(anti_replay) : 1; /*!< detect and prevent replay? */ + uint8_t MBEDTLS_PRIVATE(anti_replay); /*!< detect and prevent replay? */ #endif #if defined(MBEDTLS_SSL_RENEGOTIATION) - unsigned int MBEDTLS_PRIVATE(disable_renegotiation) : 1; /*!< disable renegotiation? */ + uint8_t MBEDTLS_PRIVATE(disable_renegotiation); /*!< disable renegotiation? */ #endif #if defined(MBEDTLS_SSL_SESSION_TICKETS) - unsigned int MBEDTLS_PRIVATE(session_tickets) : 1; /*!< use session tickets? */ + uint8_t MBEDTLS_PRIVATE(session_tickets); /*!< use session tickets? */ #endif #if defined(MBEDTLS_SSL_SRV_C) - unsigned int MBEDTLS_PRIVATE(cert_req_ca_list) : 1; /*!< enable sending CA list in - Certificate Request messages? */ - unsigned int MBEDTLS_PRIVATE(respect_cli_pref) : 1; /*!< pick the ciphersuite according to - the client's preferences rather - than ours */ + uint8_t MBEDTLS_PRIVATE(cert_req_ca_list); /*!< enable sending CA list in + Certificate Request messages? */ + uint8_t MBEDTLS_PRIVATE(respect_cli_pref); /*!< pick the ciphersuite according to + the client's preferences rather + than ours */ #endif #if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) - unsigned int MBEDTLS_PRIVATE(ignore_unexpected_cid) : 1; /*!< Determines whether DTLS - * record with unexpected CID - * should lead to failure. */ + uint8_t MBEDTLS_PRIVATE(ignore_unexpected_cid); /*!< Determines whether DTLS + * record with unexpected CID + * should lead to failure. */ #endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */ #if defined(MBEDTLS_SSL_DTLS_SRTP) - unsigned int MBEDTLS_PRIVATE(dtls_srtp_mki_support) : 1; /* support having mki_value - in the use_srtp extension */ + uint8_t MBEDTLS_PRIVATE(dtls_srtp_mki_support); /* support having mki_value + in the use_srtp extension */ #endif /* From 41139a2541becc709e687ee7f623098310329ec6 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Wed, 8 Dec 2021 18:25:39 +0100 Subject: [PATCH 16/18] mbedtls_ssl_handshake_params: move group_list earlier to save code size Placing group_list earlier seems to help significantly, not just as a matter of placing it in the 128-element (512-byte) access window. Results (arm-none-eabi-gcc 7.3.1, build_arm_none_eabi_gcc_m0plus build): library/ssl_cli.o: 19559 -> 19551 (diff: 8) library/ssl_msg.o: 24690 -> 24674 (diff: 16) library/ssl_srv.o: 20418 -> 20406 (diff: 12) library/ssl_tls.o: 20555 -> 20519 (diff: 36) library/ssl_tls13_client.o: 7244 -> 7240 (diff: 4) library/ssl_tls13_generic.o: 4693 -> 4697 (diff: -4) Results (same architecture, config-suite-b.h + MBEDTLS_ECDH_LEGACY_CONTEXT + MBEDTLS_ECP_RESTARTABLE): library/ssl_cli.o: 2864 -> 2860 (diff: 4) library/ssl_tls.o: 6566 -> 6546 (diff: 20) Signed-off-by: Gilles Peskine --- library/ssl_misc.h | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/library/ssl_misc.h b/library/ssl_misc.h index 6af125f704..8a882f2aeb 100644 --- a/library/ssl_misc.h +++ b/library/ssl_misc.h @@ -552,6 +552,10 @@ struct mbedtls_ssl_handshake_params unsigned char retransmit_state; /*!< Retransmission state */ #endif +#if !defined(MBEDTLS_DEPRECATED_REMOVED) + unsigned char group_list_heap_allocated; +#endif + #if defined(MBEDTLS_SSL_ECP_RESTARTABLE_ENABLED) uint8_t ecrs_enabled; /*!< Handshake supports EC restart? */ mbedtls_x509_crt_restart_ctx ecrs_ctx; /*!< restart context */ @@ -587,6 +591,10 @@ struct mbedtls_ssl_handshake_params mbedtls_ssl_sig_hash_set_t hash_algs; /*!< Set of suitable sig-hash pairs */ #endif +#if !defined(MBEDTLS_DEPRECATED_REMOVED) + const uint16_t *group_list; +#endif + #if defined(MBEDTLS_DHM_C) mbedtls_dhm_context dhm_ctx; /*!< DHM key exchange */ #endif @@ -802,11 +810,6 @@ struct mbedtls_ssl_handshake_params * The library does not use it internally. */ void *user_async_ctx; #endif /* MBEDTLS_SSL_ASYNC_PRIVATE */ - -#if !defined(MBEDTLS_DEPRECATED_REMOVED) - const uint16_t *group_list; - unsigned char group_list_heap_allocated; -#endif }; typedef struct mbedtls_ssl_hs_buffer mbedtls_ssl_hs_buffer; From b3ec69dba57acb3a07506b1187762ad99b398774 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Wed, 8 Dec 2021 18:32:12 +0100 Subject: [PATCH 17/18] mbedtls_ssl_config: better document former bit-fields Ensure that the documentation of fields affected by "mbedtls_ssl_config: Replace bit-fields by separate bytes" conveys information that may have been lost by removing the exact size of the type. Extend the preexisting pattern "do this?" for formerly 1-bit boolean fields. Indicate the possible values for non-boolean fields. Signed-off-by: Gilles Peskine --- include/mbedtls/ssl.h | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/include/mbedtls/ssl.h b/include/mbedtls/ssl.h index b41ad44357..90d80157d6 100644 --- a/include/mbedtls/ssl.h +++ b/include/mbedtls/ssl.h @@ -1227,12 +1227,13 @@ struct mbedtls_ssl_config */ uint8_t MBEDTLS_PRIVATE(endpoint); /*!< 0: client, 1: server */ - uint8_t MBEDTLS_PRIVATE(transport); /*!< stream (TLS) or datagram (DTLS) */ + uint8_t MBEDTLS_PRIVATE(transport); /*!< 0: stream (TLS), 1: datagram (DTLS) */ uint8_t MBEDTLS_PRIVATE(authmode); /*!< MBEDTLS_SSL_VERIFY_XXX */ /* needed even with renego disabled for LEGACY_BREAK_HANDSHAKE */ uint8_t MBEDTLS_PRIVATE(allow_legacy_renegotiation); /*!< MBEDTLS_LEGACY_XXX */ #if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) - uint8_t MBEDTLS_PRIVATE(mfl_code); /*!< desired fragment length */ + uint8_t MBEDTLS_PRIVATE(mfl_code); /*!< desired fragment length indicator + (MBEDTLS_SSL_MAX_FRAG_LEN_XXX) */ #endif #if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) uint8_t MBEDTLS_PRIVATE(encrypt_then_mac); /*!< negotiate encrypt-then-mac? */ @@ -1254,16 +1255,16 @@ struct mbedtls_ssl_config Certificate Request messages? */ uint8_t MBEDTLS_PRIVATE(respect_cli_pref); /*!< pick the ciphersuite according to the client's preferences rather - than ours */ + than ours? */ #endif #if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) - uint8_t MBEDTLS_PRIVATE(ignore_unexpected_cid); /*!< Determines whether DTLS - * record with unexpected CID - * should lead to failure. */ + uint8_t MBEDTLS_PRIVATE(ignore_unexpected_cid); /*!< Should DTLS record with + * unexpected CID + * lead to failure? */ #endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */ #if defined(MBEDTLS_SSL_DTLS_SRTP) uint8_t MBEDTLS_PRIVATE(dtls_srtp_mki_support); /* support having mki_value - in the use_srtp extension */ + in the use_srtp extension? */ #endif /* From cfe74a37b9eaf971e7a0f953c7a655433b90e066 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Wed, 8 Dec 2021 18:38:51 +0100 Subject: [PATCH 18/18] mbedtls_ssl_handshake_params: move ecrs_ctx back further "mbedtls_ssl_handshake_params: reorder fields to save code size" moved this filed earlier along with byte-sized fields that should be in the 128-element access window on Arm Thumb. This took away precious room in the 128-byte window. Move it back further out. Results (same architecture, config-suite-b.h + MBEDTLS_ECDH_LEGACY_CONTEXT + MBEDTLS_ECP_RESTARTABLE): library/ssl_cli.o: 2860 -> 2816 (diff: 44) library/ssl_msg.o: 3080 -> 3076 (diff: 4) library/ssl_srv.o: 3340 -> 3300 (diff: 40) library/ssl_tls.o: 6546 -> 6478 (diff: 68) Signed-off-by: Gilles Peskine --- library/ssl_misc.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/library/ssl_misc.h b/library/ssl_misc.h index 8a882f2aeb..88fa5609c1 100644 --- a/library/ssl_misc.h +++ b/library/ssl_misc.h @@ -558,7 +558,6 @@ struct mbedtls_ssl_handshake_params #if defined(MBEDTLS_SSL_ECP_RESTARTABLE_ENABLED) uint8_t ecrs_enabled; /*!< Handshake supports EC restart? */ - mbedtls_x509_crt_restart_ctx ecrs_ctx; /*!< restart context */ enum { /* this complements ssl->state with info on intra-state operations */ ssl_ecrs_none = 0, /*!< nothing going on (yet) */ ssl_ecrs_crt_verify, /*!< Certificate: crt_verify() */ @@ -637,6 +636,10 @@ struct mbedtls_ssl_handshake_params size_t psk_len; /*!< Length of PSK from callback */ #endif /* MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED */ +#if defined(MBEDTLS_SSL_ECP_RESTARTABLE_ENABLED) + mbedtls_x509_crt_restart_ctx ecrs_ctx; /*!< restart context */ +#endif + #if defined(MBEDTLS_X509_CRT_PARSE_C) mbedtls_ssl_key_cert *key_cert; /*!< chosen key/cert pair (server) */ #if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION)