From 5c196fb599f82ce8a7325b95fd7d15c6946b17fd Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Fri, 17 May 2019 12:04:41 +0200 Subject: [PATCH 1/4] Readability improvements No indented semantic change. --- scripts/generate_psa_constants.py | 17 +++++++------ tests/scripts/test_psa_constant_names.py | 31 ++++++++++++++---------- 2 files changed, 28 insertions(+), 20 deletions(-) diff --git a/scripts/generate_psa_constants.py b/scripts/generate_psa_constants.py index bf76c2d7b..91d0b29d6 100755 --- a/scripts/generate_psa_constants.py +++ b/scripts/generate_psa_constants.py @@ -205,9 +205,12 @@ class MacroCollector: self.key_usages = set() # "#define" followed by a macro name with either no parameters - # or a single parameter. Grab the macro name in group 1, the - # parameter name if any in group 2 and the definition in group 3. - definition_re = re.compile(r'\s*#\s*define\s+(\w+)(?:\s+|\((\w+)\)\s*)(.+)(?:/[*/])?') + # or a single parameter and a non-empty expansion. + # Grab the macro name in group 1, the parameter name if any in group 2 + # and the expansion in group 3. + _define_directive_re = re.compile(r'\s*#\s*define\s+(\w+)' + + r'(?:\s+|\((\w+)\)\s*)' + + r'(.+)(?:/[*/])?') def read_line(self, line): """Parse a C header line and record the PSA identifier it defines if any. @@ -215,10 +218,10 @@ class MacroCollector: (up to non-significant whitespace) and skips all non-matching lines. """ # pylint: disable=too-many-branches - m = re.match(self.definition_re, line) + m = re.match(self._define_directive_re, line) if not m: return - name, parameter, definition = m.groups() + name, parameter, expansion = m.groups() if name.endswith('_FLAG') or name.endswith('MASK'): # Macro only to build actual values return @@ -251,10 +254,10 @@ class MacroCollector: return self.algorithms.add(name) # Ad hoc detection of hash algorithms - if re.search(r'0x010000[0-9A-Fa-f]{2}', definition): + if re.search(r'0x010000[0-9A-Fa-f]{2}', expansion): self.hash_algorithms.add(name) # Ad hoc detection of key agreement algorithms - if re.search(r'0x30[0-9A-Fa-f]{2}0000', definition): + if re.search(r'0x30[0-9A-Fa-f]{2}0000', expansion): self.ka_algorithms.add(name) elif name.startswith('PSA_ALG_') and parameter == 'hash_alg': if name in ['PSA_ALG_DSA', 'PSA_ALG_ECDSA']: diff --git a/tests/scripts/test_psa_constant_names.py b/tests/scripts/test_psa_constant_names.py index cf3a2243a..1469c3d41 100755 --- a/tests/scripts/test_psa_constant_names.py +++ b/tests/scripts/test_psa_constant_names.py @@ -159,19 +159,24 @@ class Inputs: # Regex of macro names to exclude. _excluded_name_re = re.compile(r'_(?:GET|IS|OF)_|_(?:BASE|FLAG|MASK)\Z') # Additional excluded macros. - # PSA_ALG_ECDH and PSA_ALG_FFDH are excluded for now as the script - # currently doesn't support them. Deprecated errors are also excluded. - _excluded_names = set(['PSA_ALG_AEAD_WITH_DEFAULT_TAG_LENGTH', - 'PSA_ALG_AEAD_WITH_DEFAULT_TAG_LENGTH_CASE', - 'PSA_ALG_FULL_LENGTH_MAC', - 'PSA_ALG_ECDH', - 'PSA_ALG_FFDH', - 'PSA_ERROR_UNKNOWN_ERROR', - 'PSA_ERROR_OCCUPIED_SLOT', - 'PSA_ERROR_EMPTY_SLOT', - 'PSA_ERROR_INSUFFICIENT_CAPACITY', - ]) - + _excluded_names = set([ + # Macros that provide an alternative way to build the same + # algorithm as another macro. + 'PSA_ALG_AEAD_WITH_DEFAULT_TAG_LENGTH', + 'PSA_ALG_FULL_LENGTH_MAC', + # Auxiliary macro whose name doesn't fit the usual patterns for + # auxiliary macros. + 'PSA_ALG_AEAD_WITH_DEFAULT_TAG_LENGTH_CASE', + # PSA_ALG_ECDH and PSA_ALG_FFDH are excluded for now as the script + # currently doesn't support them. + 'PSA_ALG_ECDH', + 'PSA_ALG_FFDH', + # Deprecated aliases. + 'PSA_ERROR_UNKNOWN_ERROR', + 'PSA_ERROR_OCCUPIED_SLOT', + 'PSA_ERROR_EMPTY_SLOT', + 'PSA_ERROR_INSUFFICIENT_CAPACITY', + ]) def parse_header_line(self, line): """Parse a C header line, looking for "#define PSA_xxx".""" m = re.match(self._header_line_re, line) From f30d4d9b34420f577852f90b4e0b4e85783efe67 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Fri, 17 May 2019 12:05:19 +0200 Subject: [PATCH 2/4] More accurate parsing of #define directives Support continuation lines and remove comments. --- scripts/generate_psa_constants.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/scripts/generate_psa_constants.py b/scripts/generate_psa_constants.py index 91d0b29d6..a3cd130a0 100755 --- a/scripts/generate_psa_constants.py +++ b/scripts/generate_psa_constants.py @@ -210,7 +210,7 @@ class MacroCollector: # and the expansion in group 3. _define_directive_re = re.compile(r'\s*#\s*define\s+(\w+)' + r'(?:\s+|\((\w+)\)\s*)' + - r'(.+)(?:/[*/])?') + r'(.+)') def read_line(self, line): """Parse a C header line and record the PSA identifier it defines if any. @@ -222,6 +222,7 @@ class MacroCollector: if not m: return name, parameter, expansion = m.groups() + expansion = re.sub(r'/\*.*?\*/|//.*', r' ', expansion) if name.endswith('_FLAG') or name.endswith('MASK'): # Macro only to build actual values return @@ -274,6 +275,9 @@ class MacroCollector: def read_file(self, header_file): for line in header_file: + while line.endswith('\\\n'): + cont = next(header_file) + line = line[:-2] + cont self.read_line(line) @staticmethod From 33b84f4db7cf33dbc486b937e423865b84b1e165 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Fri, 17 May 2019 12:05:59 +0200 Subject: [PATCH 3/4] Omit all deprecated definitions rather than a hard-coded list Rather than hard-coding a list of deprecated aliases, assume that anything that's deprecated is an alias or otherwise not desired. --- scripts/generate_psa_constants.py | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/scripts/generate_psa_constants.py b/scripts/generate_psa_constants.py index a3cd130a0..c2d255809 100755 --- a/scripts/generate_psa_constants.py +++ b/scripts/generate_psa_constants.py @@ -211,6 +211,7 @@ class MacroCollector: _define_directive_re = re.compile(r'\s*#\s*define\s+(\w+)' + r'(?:\s+|\((\w+)\)\s*)' + r'(.+)') + _deprecated_definition_re = re.compile(r'\s*MBEDTLS_DEPRECATED') def read_line(self, line): """Parse a C header line and record the PSA identifier it defines if any. @@ -223,20 +224,16 @@ class MacroCollector: return name, parameter, expansion = m.groups() expansion = re.sub(r'/\*.*?\*/|//.*', r' ', expansion) + if re.match(self._deprecated_definition_re, expansion): + # Skip deprecated values, which are assumed to be + # backward compatibility aliases that share + # numerical values with non-deprecated values. + return if name.endswith('_FLAG') or name.endswith('MASK'): # Macro only to build actual values return elif (name.startswith('PSA_ERROR_') or name == 'PSA_SUCCESS') \ and not parameter: - if name in ['PSA_ERROR_UNKNOWN_ERROR', - 'PSA_ERROR_OCCUPIED_SLOT', - 'PSA_ERROR_EMPTY_SLOT', - 'PSA_ERROR_INSUFFICIENT_CAPACITY', - ]: - # Ad hoc skipping of deprecated error codes, which share - # numerical values with non-deprecated error codes - return - self.statuses.add(name) elif name.startswith('PSA_KEY_TYPE_') and not parameter: self.key_types.add(name) From 19835128034658467fc495380704754edb0795d1 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Fri, 17 May 2019 12:06:55 +0200 Subject: [PATCH 4/4] Add backward compatibility alias for PSA_ERROR_CORRUPTION_DETECTED This was renamed from PSA_ERROR_TAMPERING_DETECTED. Add a backward compatibility alias in case somebody was already using it. --- include/psa/crypto_extra.h | 11 ++--------- tests/scripts/test_psa_constant_names.py | 1 + 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/include/psa/crypto_extra.h b/include/psa/crypto_extra.h index 636c88110..f0e47821c 100644 --- a/include/psa/crypto_extra.h +++ b/include/psa/crypto_extra.h @@ -45,21 +45,14 @@ extern "C" { #if !defined(MBEDTLS_DEPRECATED_REMOVED) #define PSA_ERROR_UNKNOWN_ERROR \ MBEDTLS_DEPRECATED_NUMERIC_CONSTANT( PSA_ERROR_GENERIC_ERROR ) -#endif - -#if !defined(MBEDTLS_DEPRECATED_REMOVED) #define PSA_ERROR_OCCUPIED_SLOT \ MBEDTLS_DEPRECATED_NUMERIC_CONSTANT( PSA_ERROR_ALREADY_EXISTS ) -#endif - -#if !defined(MBEDTLS_DEPRECATED_REMOVED) #define PSA_ERROR_EMPTY_SLOT \ MBEDTLS_DEPRECATED_NUMERIC_CONSTANT( PSA_ERROR_DOES_NOT_EXIST ) -#endif - -#if !defined(MBEDTLS_DEPRECATED_REMOVED) #define PSA_ERROR_INSUFFICIENT_CAPACITY \ MBEDTLS_DEPRECATED_NUMERIC_CONSTANT( PSA_ERROR_INSUFFICIENT_DATA ) +#define PSA_ERROR_TAMPERING_DETECTED \ + MBEDTLS_DEPRECATED_NUMERIC_CONSTANT( PSA_ERROR_CORRUPTION_DETECTED ) #endif /** \addtogroup attributes diff --git a/tests/scripts/test_psa_constant_names.py b/tests/scripts/test_psa_constant_names.py index 1469c3d41..724f8d94b 100755 --- a/tests/scripts/test_psa_constant_names.py +++ b/tests/scripts/test_psa_constant_names.py @@ -176,6 +176,7 @@ class Inputs: 'PSA_ERROR_OCCUPIED_SLOT', 'PSA_ERROR_EMPTY_SLOT', 'PSA_ERROR_INSUFFICIENT_CAPACITY', + 'PSA_ERROR_TAMPERING_DETECTED', ]) def parse_header_line(self, line): """Parse a C header line, looking for "#define PSA_xxx"."""