From 44f3415283690767de457194bbffa6c267bfbbb7 Mon Sep 17 00:00:00 2001 From: Minos Galanakis Date: Fri, 7 Jun 2024 17:24:34 +0100 Subject: [PATCH] code_wrapper: Created placeholder directory. Created subpackage where all the dynamically-generated code will reside. generate_psa_wrappers.py has been updated to use the new modules. Signed-off-by: Minos Galanakis --- scripts/generate_psa_wrappers.py | 257 +----------------- .../code_wrapper/__init__.py | 0 .../code_wrapper/psa_buffer.py | 26 ++ .../code_wrapper/psa_wrapper.py | 201 ++++++++++++++ 4 files changed, 238 insertions(+), 246 deletions(-) mode change 100755 => 100644 scripts/generate_psa_wrappers.py create mode 100644 scripts/mbedtls_framework/code_wrapper/__init__.py create mode 100644 scripts/mbedtls_framework/code_wrapper/psa_buffer.py create mode 100644 scripts/mbedtls_framework/code_wrapper/psa_wrapper.py diff --git a/scripts/generate_psa_wrappers.py b/scripts/generate_psa_wrappers.py old mode 100755 new mode 100644 index 641149b6a..8ed10ed40 --- a/scripts/generate_psa_wrappers.py +++ b/scripts/generate_psa_wrappers.py @@ -10,249 +10,14 @@ ### for robustness and maintainability. import argparse -import itertools -import os -from typing import Iterator, List, Optional, Tuple - -from mbedtls_framework import build_tree -from mbedtls_framework import c_parsing_helper -from mbedtls_framework import c_wrapper_generator -from mbedtls_framework import typing_util - - -class BufferParameter: - """Description of an input or output buffer parameter sequence to a PSA function.""" - #pylint: disable=too-few-public-methods - - def __init__(self, i: int, is_output: bool, - buffer_name: str, size_name: str) -> None: - """Initialize the parameter information. - - i is the index of the function argument that is the pointer to the buffer. - The size is argument i+1. For a variable-size output, the actual length - goes in argument i+2. - - buffer_name and size_names are the names of arguments i and i+1. - This class does not yet help with the output length. - """ - self.index = i - self.buffer_name = buffer_name - self.size_name = size_name - self.is_output = is_output - - -class PSAWrapperGenerator(c_wrapper_generator.Base): - """Generate a C source file containing wrapper functions for PSA Crypto API calls.""" - - _CPP_GUARDS = ('defined(MBEDTLS_PSA_CRYPTO_C) && ' + - 'defined(MBEDTLS_TEST_HOOKS) && \\\n ' + - '!defined(RECORD_PSA_STATUS_COVERAGE_LOG)') - _WRAPPER_NAME_PREFIX = 'mbedtls_test_wrap_' - _WRAPPER_NAME_SUFFIX = '' - - def gather_data(self) -> None: - """Gather PSA Crypto API function names.""" - root_dir = build_tree.guess_mbedtls_root() - for header_name in ['crypto.h', 'crypto_extra.h']: - # Temporary, while Mbed TLS does not just rely on the TF-PSA-Crypto - # build system to build its crypto library. When it does, the first - # case can just be removed. - if os.path.isdir(os.path.join(root_dir, 'tf-psa-crypto')): - header_path = os.path.join(root_dir, 'tf-psa-crypto', - 'include', 'psa', header_name) - else: - header_path = os.path.join(root_dir, 'include', 'psa', header_name) - c_parsing_helper.read_function_declarations(self.functions, header_path) - - _SKIP_FUNCTIONS = frozenset([ - 'mbedtls_psa_external_get_random', # not a library function - 'psa_get_key_domain_parameters', # client-side function - 'psa_get_key_slot_number', # client-side function - 'psa_key_derivation_verify_bytes', # not implemented yet - 'psa_key_derivation_verify_key', # not implemented yet - 'psa_set_key_domain_parameters', # client-side function - ]) - - def _skip_function(self, function: c_wrapper_generator.FunctionInfo) -> bool: - if function.return_type != 'psa_status_t': - return True - if function.name in self._SKIP_FUNCTIONS: - return True - return False - - # PAKE stuff: not implemented yet - _PAKE_STUFF = frozenset([ - 'psa_crypto_driver_pake_inputs_t *', - 'psa_pake_cipher_suite_t *', - ]) - - def _return_variable_name(self, - function: c_wrapper_generator.FunctionInfo) -> str: - """The name of the variable that will contain the return value.""" - if function.return_type == 'psa_status_t': - return 'status' - return super()._return_variable_name(function) - - _FUNCTION_GUARDS = c_wrapper_generator.Base._FUNCTION_GUARDS.copy() \ - #pylint: disable=protected-access - _FUNCTION_GUARDS.update({ - 'mbedtls_psa_register_se_key': 'defined(MBEDTLS_PSA_CRYPTO_SE_C)', - 'mbedtls_psa_inject_entropy': 'defined(MBEDTLS_PSA_INJECT_ENTROPY)', - 'mbedtls_psa_external_get_random': 'defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG)', - 'mbedtls_psa_platform_get_builtin_key': 'defined(MBEDTLS_PSA_CRYPTO_BUILTIN_KEYS)', - 'psa_crypto_driver_pake_get_cipher_suite' : 'defined(PSA_WANT_ALG_SOME_PAKE)', - 'psa_crypto_driver_pake_get_password' : 'defined(PSA_WANT_ALG_SOME_PAKE)', - 'psa_crypto_driver_pake_get_password_len' : 'defined(PSA_WANT_ALG_SOME_PAKE)', - 'psa_crypto_driver_pake_get_peer' : 'defined(PSA_WANT_ALG_SOME_PAKE)', - 'psa_crypto_driver_pake_get_peer_len' : 'defined(PSA_WANT_ALG_SOME_PAKE)', - 'psa_crypto_driver_pake_get_user' : 'defined(PSA_WANT_ALG_SOME_PAKE)', - 'psa_crypto_driver_pake_get_user_len' : 'defined(PSA_WANT_ALG_SOME_PAKE)', - 'psa_pake_abort' : 'defined(PSA_WANT_ALG_SOME_PAKE)', - 'psa_pake_get_implicit_key' : 'defined(PSA_WANT_ALG_SOME_PAKE)', - 'psa_pake_input' : 'defined(PSA_WANT_ALG_SOME_PAKE)', - 'psa_pake_output' : 'defined(PSA_WANT_ALG_SOME_PAKE)', - 'psa_pake_set_password_key' : 'defined(PSA_WANT_ALG_SOME_PAKE)', - 'psa_pake_set_peer' : 'defined(PSA_WANT_ALG_SOME_PAKE)', - 'psa_pake_set_role' : 'defined(PSA_WANT_ALG_SOME_PAKE)', - 'psa_pake_set_user' : 'defined(PSA_WANT_ALG_SOME_PAKE)', - 'psa_pake_setup' : 'defined(PSA_WANT_ALG_SOME_PAKE)', - }) - - @staticmethod - def _detect_buffer_parameters(arguments: List[c_parsing_helper.ArgumentInfo], - argument_names: List[str]) -> Iterator[BufferParameter]: - """Detect function arguments that are buffers (pointer, size [,length]).""" - types = ['' if arg.suffix else arg.type for arg in arguments] - # pairs = list of (type_of_arg_N, type_of_arg_N+1) - # where each type_of_arg_X is the empty string if the type is an array - # or there is no argument X. - pairs = enumerate(itertools.zip_longest(types, types[1:], fillvalue='')) - for i, t01 in pairs: - if (t01[0] == 'const uint8_t *' or t01[0] == 'uint8_t *') and \ - t01[1] == 'size_t': - yield BufferParameter(i, not t01[0].startswith('const '), - argument_names[i], argument_names[i+1]) - - @staticmethod - def _write_poison_buffer_parameter(out: typing_util.Writable, - param: BufferParameter, - poison: bool) -> None: - """Write poisoning or unpoisoning code for a buffer parameter. - - Write poisoning code if poison is true, unpoisoning code otherwise. - """ - out.write(' MBEDTLS_TEST_MEMORY_{}({}, {});\n'.format( - 'POISON' if poison else 'UNPOISON', - param.buffer_name, param.size_name - )) - - def _write_poison_buffer_parameters(self, out: typing_util.Writable, - buffer_parameters: List[BufferParameter], - poison: bool) -> None: - """Write poisoning or unpoisoning code for the buffer parameters. - - Write poisoning code if poison is true, unpoisoning code otherwise. - """ - if not buffer_parameters: - return - out.write('#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)\n') - for param in buffer_parameters: - self._write_poison_buffer_parameter(out, param, poison) - out.write('#endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */\n') - - @staticmethod - def _parameter_should_be_copied(function_name: str, - _buffer_name: Optional[str]) -> bool: - """Whether the specified buffer argument to a PSA function should be copied. - """ - # False-positives that do not need buffer copying - if function_name in ('mbedtls_psa_inject_entropy', - 'psa_crypto_driver_pake_get_password', - 'psa_crypto_driver_pake_get_user', - 'psa_crypto_driver_pake_get_peer'): - return False - - return True - - def _write_function_call(self, out: typing_util.Writable, - function: c_wrapper_generator.FunctionInfo, - argument_names: List[str]) -> None: - buffer_parameters = list( - param - for param in self._detect_buffer_parameters(function.arguments, - argument_names) - if self._parameter_should_be_copied(function.name, - function.arguments[param.index].name)) - self._write_poison_buffer_parameters(out, buffer_parameters, True) - super()._write_function_call(out, function, argument_names) - self._write_poison_buffer_parameters(out, buffer_parameters, False) - - def _write_prologue(self, out: typing_util.Writable, header: bool) -> None: - super()._write_prologue(out, header) - out.write(""" -#if {} - -#include - -#include -#include -#include -""" - .format(self._CPP_GUARDS)) - - def _write_epilogue(self, out: typing_util.Writable, header: bool) -> None: - out.write(""" -#endif /* {} */ -""" - .format(self._CPP_GUARDS)) - super()._write_epilogue(out, header) - - -class PSALoggingWrapperGenerator(PSAWrapperGenerator, c_wrapper_generator.Logging): - """Generate a C source file containing wrapper functions that log PSA Crypto API calls.""" - - def __init__(self, stream: str) -> None: - super().__init__() - self.set_stream(stream) - - _PRINTF_TYPE_CAST = c_wrapper_generator.Logging._PRINTF_TYPE_CAST.copy() - _PRINTF_TYPE_CAST.update({ - 'mbedtls_svc_key_id_t': 'unsigned', - 'psa_algorithm_t': 'unsigned', - 'psa_drv_slot_number_t': 'unsigned long long', - 'psa_key_derivation_step_t': 'int', - 'psa_key_id_t': 'unsigned', - 'psa_key_slot_number_t': 'unsigned long long', - 'psa_key_lifetime_t': 'unsigned', - 'psa_key_type_t': 'unsigned', - 'psa_key_usage_flags_t': 'unsigned', - 'psa_pake_role_t': 'int', - 'psa_pake_step_t': 'int', - 'psa_status_t': 'int', - }) - - def _printf_parameters(self, typ: str, var: str) -> Tuple[str, List[str]]: - if typ.startswith('const '): - typ = typ[6:] - if typ == 'uint8_t *': - # Skip buffers - return '', [] - if typ.endswith('operation_t *'): - return '', [] - if typ in self._PAKE_STUFF: - return '', [] - if typ == 'psa_key_attributes_t *': - return (var + '={id=%u, lifetime=0x%08x, type=0x%08x, bits=%u, alg=%08x, usage=%08x}', - ['(unsigned) psa_get_key_{}({})'.format(field, var) - for field in ['id', 'lifetime', 'type', 'bits', 'algorithm', 'usage_flags']]) - return super()._printf_parameters(typ, var) - +from mbedtls_framework.code_wrapper import * DEFAULT_C_OUTPUT_FILE_NAME = 'tests/src/psa_test_wrappers.c' DEFAULT_H_OUTPUT_FILE_NAME = 'tests/include/test/psa_test_wrappers.h' -def main() -> None: - parser = argparse.ArgumentParser(description=globals()['__doc__']) +if __name__ == '__main__': + + parser = argparse.ArgumentParser(description=globals()['__doc__']) #pylint: disable=invalid-name parser.add_argument('--log', help='Stream to log to (default: no logging code)') parser.add_argument('--output-c', @@ -265,16 +30,16 @@ def main() -> None: default=DEFAULT_H_OUTPUT_FILE_NAME, help=('Output .h file path (default: {}; skip .h output if empty)' .format(DEFAULT_H_OUTPUT_FILE_NAME))) - options = parser.parse_args() + options = parser.parse_args() #pylint: disable=invalid-name if options.log: - generator = PSALoggingWrapperGenerator(options.log) #type: PSAWrapperGenerator + generator = psa_test_wrapper.PSALoggingTestWrapper(DEFAULT_H_OUTPUT_FILE_NAME, #pylint: disable=invalid-name + DEFAULT_C_OUTPUT_FILE_NAME, + options.log) #type: PSATestWrapper else: - generator = PSAWrapperGenerator() - generator.gather_data() + generator = psa_test_wrapper.PSATestWrapper(DEFAULT_H_OUTPUT_FILE_NAME, #pylint: disable=invalid-name + DEFAULT_C_OUTPUT_FILE_NAME) + if options.output_h: generator.write_h_file(options.output_h) if options.output_c: generator.write_c_file(options.output_c) - -if __name__ == '__main__': - main() diff --git a/scripts/mbedtls_framework/code_wrapper/__init__.py b/scripts/mbedtls_framework/code_wrapper/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/scripts/mbedtls_framework/code_wrapper/psa_buffer.py b/scripts/mbedtls_framework/code_wrapper/psa_buffer.py new file mode 100644 index 000000000..f9c3aaaf9 --- /dev/null +++ b/scripts/mbedtls_framework/code_wrapper/psa_buffer.py @@ -0,0 +1,26 @@ +import os +from typing import Iterator, List, Optional, Tuple + +from mbedtls_framework import build_tree +from mbedtls_framework import c_parsing_helper +from mbedtls_framework import c_wrapper_generator +from mbedtls_framework import typing_util + + +class BufferParameter: + """Description of an input or output buffer parameter sequence to a PSA function.""" + #pylint: disable=too-few-public-methods + + def __init__(self, i: int, is_output: bool, + buffer_name: str, size_name: str) -> None: + """Initialize the parameter information. + i is the index of the function argument that is the pointer to the buffer. + The size is argument i+1. For a variable-size output, the actual length + goes in argument i+2. + buffer_name and size_names are the names of arguments i and i+1. + This class does not yet help with the output length. + """ + self.index = i + self.buffer_name = buffer_name + self.size_name = size_name + self.is_output = is_output diff --git a/scripts/mbedtls_framework/code_wrapper/psa_wrapper.py b/scripts/mbedtls_framework/code_wrapper/psa_wrapper.py new file mode 100644 index 000000000..b3a192cd1 --- /dev/null +++ b/scripts/mbedtls_framework/code_wrapper/psa_wrapper.py @@ -0,0 +1,201 @@ +class PSAWrapperGenerator(c_wrapper_generator.Base): + """Generate a C source file containing wrapper functions for PSA Crypto API calls.""" + + _CPP_GUARDS = ('defined(MBEDTLS_PSA_CRYPTO_C) && ' + + 'defined(MBEDTLS_TEST_HOOKS) && \\\n ' + + '!defined(RECORD_PSA_STATUS_COVERAGE_LOG)') + _WRAPPER_NAME_PREFIX = 'mbedtls_test_wrap_' + _WRAPPER_NAME_SUFFIX = '' + + def gather_data(self) -> None: + """Gather PSA Crypto API function names.""" + root_dir = build_tree.guess_mbedtls_root() + for header_name in ['crypto.h', 'crypto_extra.h']: + # Temporary, while Mbed TLS does not just rely on the TF-PSA-Crypto + # build system to build its crypto library. When it does, the first + # case can just be removed. + if os.path.isdir(os.path.join(root_dir, 'tf-psa-crypto')): + header_path = os.path.join(root_dir, 'tf-psa-crypto', + 'include', 'psa', header_name) + else: + header_path = os.path.join(root_dir, 'include', 'psa', header_name) + c_parsing_helper.read_function_declarations(self.functions, header_path) + + _SKIP_FUNCTIONS = frozenset([ + 'mbedtls_psa_external_get_random', # not a library function + 'psa_get_key_domain_parameters', # client-side function + 'psa_get_key_slot_number', # client-side function + 'psa_key_derivation_verify_bytes', # not implemented yet + 'psa_key_derivation_verify_key', # not implemented yet + 'psa_set_key_domain_parameters', # client-side function + ]) + + def _skip_function(self, function: c_wrapper_generator.FunctionInfo) -> bool: + if function.return_type != 'psa_status_t': + return True + if function.name in self._SKIP_FUNCTIONS: + return True + return False + + # PAKE stuff: not implemented yet + _PAKE_STUFF = frozenset([ + 'psa_crypto_driver_pake_inputs_t *', + 'psa_pake_cipher_suite_t *', + ]) + + def _return_variable_name(self, + function: c_wrapper_generator.FunctionInfo) -> str: + """The name of the variable that will contain the return value.""" + if function.return_type == 'psa_status_t': + return 'status' + return super()._return_variable_name(function) + + _FUNCTION_GUARDS = c_wrapper_generator.Base._FUNCTION_GUARDS.copy() \ + #pylint: disable=protected-access + _FUNCTION_GUARDS.update({ + 'mbedtls_psa_register_se_key': 'defined(MBEDTLS_PSA_CRYPTO_SE_C)', + 'mbedtls_psa_inject_entropy': 'defined(MBEDTLS_PSA_INJECT_ENTROPY)', + 'mbedtls_psa_external_get_random': 'defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG)', + 'mbedtls_psa_platform_get_builtin_key': 'defined(MBEDTLS_PSA_CRYPTO_BUILTIN_KEYS)', + 'psa_crypto_driver_pake_get_cipher_suite' : 'defined(PSA_WANT_ALG_SOME_PAKE)', + 'psa_crypto_driver_pake_get_password' : 'defined(PSA_WANT_ALG_SOME_PAKE)', + 'psa_crypto_driver_pake_get_password_len' : 'defined(PSA_WANT_ALG_SOME_PAKE)', + 'psa_crypto_driver_pake_get_peer' : 'defined(PSA_WANT_ALG_SOME_PAKE)', + 'psa_crypto_driver_pake_get_peer_len' : 'defined(PSA_WANT_ALG_SOME_PAKE)', + 'psa_crypto_driver_pake_get_user' : 'defined(PSA_WANT_ALG_SOME_PAKE)', + 'psa_crypto_driver_pake_get_user_len' : 'defined(PSA_WANT_ALG_SOME_PAKE)', + 'psa_pake_abort' : 'defined(PSA_WANT_ALG_SOME_PAKE)', + 'psa_pake_get_implicit_key' : 'defined(PSA_WANT_ALG_SOME_PAKE)', + 'psa_pake_input' : 'defined(PSA_WANT_ALG_SOME_PAKE)', + 'psa_pake_output' : 'defined(PSA_WANT_ALG_SOME_PAKE)', + 'psa_pake_set_password_key' : 'defined(PSA_WANT_ALG_SOME_PAKE)', + 'psa_pake_set_peer' : 'defined(PSA_WANT_ALG_SOME_PAKE)', + 'psa_pake_set_role' : 'defined(PSA_WANT_ALG_SOME_PAKE)', + 'psa_pake_set_user' : 'defined(PSA_WANT_ALG_SOME_PAKE)', + 'psa_pake_setup' : 'defined(PSA_WANT_ALG_SOME_PAKE)' + }) + + @staticmethod + def _detect_buffer_parameters(arguments: List[c_parsing_helper.ArgumentInfo], + argument_names: List[str]) -> Iterator[BufferParameter]: + """Detect function arguments that are buffers (pointer, size [,length]).""" + types = ['' if arg.suffix else arg.type for arg in arguments] + # pairs = list of (type_of_arg_N, type_of_arg_N+1) + # where each type_of_arg_X is the empty string if the type is an array + # or there is no argument X. + pairs = enumerate(itertools.zip_longest(types, types[1:], fillvalue='')) + for i, t01 in pairs: + if (t01[0] == 'const uint8_t *' or t01[0] == 'uint8_t *') and \ + t01[1] == 'size_t': + yield BufferParameter(i, not t01[0].startswith('const '), + argument_names[i], argument_names[i+1]) + + @staticmethod + def _write_poison_buffer_parameter(out: typing_util.Writable, + param: BufferParameter, + poison: bool) -> None: + """Write poisoning or unpoisoning code for a buffer parameter. + Write poisoning code if poison is true, unpoisoning code otherwise. + """ + out.write(' MBEDTLS_TEST_MEMORY_{}({}, {});\n'.format( + 'POISON' if poison else 'UNPOISON', + param.buffer_name, param.size_name + )) + + def _write_poison_buffer_parameters(self, out: typing_util.Writable, + buffer_parameters: List[BufferParameter], + poison: bool) -> None: + """Write poisoning or unpoisoning code for the buffer parameters. + Write poisoning code if poison is true, unpoisoning code otherwise. + """ + if not buffer_parameters: + return + out.write('#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)\n') + for param in buffer_parameters: + self._write_poison_buffer_parameter(out, param, poison) + out.write('#endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */\n') + + @staticmethod + def _parameter_should_be_copied(function_name: str, + _buffer_name: Optional[str]) -> bool: + """Whether the specified buffer argument to a PSA function should be copied. + """ + # False-positives that do not need buffer copying + if function_name in ('mbedtls_psa_inject_entropy', + 'psa_crypto_driver_pake_get_password', + 'psa_crypto_driver_pake_get_user', + 'psa_crypto_driver_pake_get_peer'): + return False + + return True + + def _write_function_call(self, out: typing_util.Writable, + function: c_wrapper_generator.FunctionInfo, + argument_names: List[str]) -> None: + buffer_parameters = list( + param + for param in self._detect_buffer_parameters(function.arguments, + argument_names) + if self._parameter_should_be_copied(function.name, + function.arguments[param.index].name)) + self._write_poison_buffer_parameters(out, buffer_parameters, True) + super()._write_function_call(out, function, argument_names) + self._write_poison_buffer_parameters(out, buffer_parameters, False) + + def _write_prologue(self, out: typing_util.Writable, header: bool) -> None: + super()._write_prologue(out, header) + out.write(""" +#if {} +#include +#include +#include +#include +""" + .format(self._CPP_GUARDS)) + + def _write_epilogue(self, out: typing_util.Writable, header: bool) -> None: + out.write(""" +#endif /* {} */ +""" + .format(self._CPP_GUARDS)) + super()._write_epilogue(out, header) + + +class PSALoggingWrapperGenerator(PSAWrapperGenerator, c_wrapper_generator.Logging): + """Generate a C source file containing wrapper functions that log PSA Crypto API calls.""" + + def __init__(self, stream: str) -> None: + super().__init__() + self.set_stream(stream) + + _PRINTF_TYPE_CAST = c_wrapper_generator.Logging._PRINTF_TYPE_CAST.copy() + _PRINTF_TYPE_CAST.update({ + 'mbedtls_svc_key_id_t': 'unsigned', + 'psa_algorithm_t': 'unsigned', + 'psa_drv_slot_number_t': 'unsigned long long', + 'psa_key_derivation_step_t': 'int', + 'psa_key_id_t': 'unsigned', + 'psa_key_slot_number_t': 'unsigned long long', + 'psa_key_lifetime_t': 'unsigned', + 'psa_key_type_t': 'unsigned', + 'psa_key_usage_flags_t': 'unsigned', + 'psa_pake_role_t': 'int', + 'psa_pake_step_t': 'int', + 'psa_status_t': 'int', + }) + + def _printf_parameters(self, typ: str, var: str) -> Tuple[str, List[str]]: + if typ.startswith('const '): + typ = typ[6:] + if typ == 'uint8_t *': + # Skip buffers + return '', [] + if typ.endswith('operation_t *'): + return '', [] + if typ in self._PAKE_STUFF: + return '', [] + if typ == 'psa_key_attributes_t *': + return (var + '={id=%u, lifetime=0x%08x, type=0x%08x, bits=%u, alg=%08x, usage=%08x}', + ['(unsigned) psa_get_key_{}({})'.format(field, var) + for field in ['id', 'lifetime', 'type', 'bits', 'algorithm', 'usage_flags']]) + return super()._printf_parameters(typ, var) \ No newline at end of file