mirror of
https://github.com/Mbed-TLS/mbedtls.git
synced 2025-08-01 10:06:53 +03:00
Merge remote-tracking branch 'mbedtls-2.28' into calloc-also-zeroizes-2-28
This commit is contained in:
@ -175,6 +175,10 @@ pre_initialize_variables () {
|
||||
: ${ARMC6_BIN_DIR:=/usr/bin}
|
||||
: ${ARM_NONE_EABI_GCC_PREFIX:=arm-none-eabi-}
|
||||
: ${ARM_LINUX_GNUEABI_GCC_PREFIX:=arm-linux-gnueabi-}
|
||||
: ${CLANG_LATEST:="clang-latest"}
|
||||
: ${CLANG_EARLIEST:="clang-earliest"}
|
||||
: ${GCC_LATEST:="gcc-latest"}
|
||||
: ${GCC_EARLIEST:="gcc-earliest"}
|
||||
|
||||
# if MAKEFLAGS is not set add the -j option to speed up invocations of make
|
||||
if [ -z "${MAKEFLAGS+set}" ]; then
|
||||
@ -194,9 +198,7 @@ pre_initialize_variables () {
|
||||
|
||||
# Gather the list of available components. These are the functions
|
||||
# defined in this script whose name starts with "component_".
|
||||
# Parse the script with sed. This way we get the functions in the order
|
||||
# they are defined.
|
||||
ALL_COMPONENTS=$(sed -n 's/^ *component_\([0-9A-Z_a-z]*\) *().*/\1/p' <"$0")
|
||||
ALL_COMPONENTS=$(compgen -A function component_ | sed 's/component_//')
|
||||
|
||||
# Exclude components that are not supported on this platform.
|
||||
SUPPORTED_COMPONENTS=
|
||||
@ -278,6 +280,10 @@ General options:
|
||||
Tool path options:
|
||||
--armc5-bin-dir=<ARMC5_bin_dir_path> ARM Compiler 5 bin directory.
|
||||
--armc6-bin-dir=<ARMC6_bin_dir_path> ARM Compiler 6 bin directory.
|
||||
--clang-earliest=<Clang_earliest_path> Earliest version of clang available
|
||||
--clang-latest=<Clang_latest_path> Latest version of clang available
|
||||
--gcc-earliest=<GCC_earliest_path> Earliest version of GCC available
|
||||
--gcc-latest=<GCC_latest_path> Latest version of GCC available
|
||||
--gnutls-cli=<GnuTLS_cli_path> GnuTLS client executable to use for most tests.
|
||||
--gnutls-serv=<GnuTLS_serv_path> GnuTLS server executable to use for most tests.
|
||||
--gnutls-legacy-cli=<GnuTLS_cli_path> GnuTLS client executable to use for legacy tests.
|
||||
@ -421,9 +427,13 @@ pre_parse_command_line () {
|
||||
--armcc) no_armcc=;;
|
||||
--armc5-bin-dir) shift; ARMC5_BIN_DIR="$1";;
|
||||
--armc6-bin-dir) shift; ARMC6_BIN_DIR="$1";;
|
||||
--clang-earliest) shift; CLANG_EARLIEST="$1";;
|
||||
--clang-latest) shift; CLANG_LATEST="$1";;
|
||||
--error-test) error_test=$((error_test + 1));;
|
||||
--except) all_except=1;;
|
||||
--force|-f) FORCE=1;;
|
||||
--gcc-earliest) shift; GCC_EARLIEST="$1";;
|
||||
--gcc-latest) shift; GCC_LATEST="$1";;
|
||||
--gnutls-cli) shift; GNUTLS_CLI="$1";;
|
||||
--gnutls-legacy-cli) shift; GNUTLS_LEGACY_CLI="$1";;
|
||||
--gnutls-legacy-serv) shift; GNUTLS_LEGACY_SERV="$1";;
|
||||
@ -1248,6 +1258,21 @@ component_test_psa_external_rng_use_psa_crypto () {
|
||||
tests/ssl-opt.sh -f 'Default\|opaque'
|
||||
}
|
||||
|
||||
component_test_psa_inject_entropy () {
|
||||
msg "build: full + MBEDTLS_PSA_INJECT_ENTROPY"
|
||||
scripts/config.py full
|
||||
scripts/config.py set MBEDTLS_PSA_INJECT_ENTROPY
|
||||
scripts/config.py set MBEDTLS_ENTROPY_NV_SEED
|
||||
scripts/config.py set MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES
|
||||
scripts/config.py unset MBEDTLS_PLATFORM_NV_SEED_ALT
|
||||
scripts/config.py unset MBEDTLS_PLATFORM_STD_NV_SEED_READ
|
||||
scripts/config.py unset MBEDTLS_PLATFORM_STD_NV_SEED_WRITE
|
||||
make CFLAGS="$ASAN_CFLAGS '-DMBEDTLS_USER_CONFIG_FILE=\"../tests/configs/user-config-for-test.h\"'" LDFLAGS="$ASAN_CFLAGS"
|
||||
|
||||
msg "test: full + MBEDTLS_PSA_INJECT_ENTROPY"
|
||||
make test
|
||||
}
|
||||
|
||||
component_test_ecp_no_internal_rng () {
|
||||
msg "build: Default plus ECP_NO_INTERNAL_RNG minus DRBG modules"
|
||||
scripts/config.py set MBEDTLS_ECP_NO_INTERNAL_RNG
|
||||
@ -2500,6 +2525,43 @@ component_test_check_params_silent () {
|
||||
make CC=gcc CFLAGS='-Werror -O1' all test
|
||||
}
|
||||
|
||||
component_build_aes_variations() { # ~45s
|
||||
msg "build: aes.o for all combinations of relevant config options"
|
||||
|
||||
for a in set unset; do
|
||||
for b in set unset; do
|
||||
for c in set unset; do
|
||||
for d in set unset; do
|
||||
for e in set unset; do
|
||||
for f in set unset; do
|
||||
for g in set unset; do
|
||||
echo ./scripts/config.py $a MBEDTLS_AES_SETKEY_ENC_ALT
|
||||
echo ./scripts/config.py $b MBEDTLS_AES_DECRYPT_ALT
|
||||
echo ./scripts/config.py $c MBEDTLS_AES_ROM_TABLES
|
||||
echo ./scripts/config.py $d MBEDTLS_AES_ENCRYPT_ALT
|
||||
echo ./scripts/config.py $e MBEDTLS_AES_SETKEY_DEC_ALT
|
||||
echo ./scripts/config.py $f MBEDTLS_AES_FEWER_TABLES
|
||||
echo ./scripts/config.py $g MBEDTLS_PADLOCK_C
|
||||
|
||||
./scripts/config.py $a MBEDTLS_AES_SETKEY_ENC_ALT
|
||||
./scripts/config.py $b MBEDTLS_AES_DECRYPT_ALT
|
||||
./scripts/config.py $c MBEDTLS_AES_ROM_TABLES
|
||||
./scripts/config.py $d MBEDTLS_AES_ENCRYPT_ALT
|
||||
./scripts/config.py $e MBEDTLS_AES_SETKEY_DEC_ALT
|
||||
./scripts/config.py $f MBEDTLS_AES_FEWER_TABLES
|
||||
./scripts/config.py $g MBEDTLS_PADLOCK_C
|
||||
|
||||
rm -f library/aes.o
|
||||
make -C library aes.o CC="clang" CFLAGS="-O0 -std=c99 -Werror -Wall -Wextra -Wwrite-strings -Wpointer-arith -Wimplicit-fallthrough -Wshadow -Wvla -Wformat=2 -Wno-format-nonliteral -Wshadow -Wasm-operand-widths -Wunused"
|
||||
done
|
||||
done
|
||||
done
|
||||
done
|
||||
done
|
||||
done
|
||||
done
|
||||
}
|
||||
|
||||
component_test_no_platform () {
|
||||
# Full configuration build, without platform support, file IO and net sockets.
|
||||
# This should catch missing mbedtls_printf definitions, and by disabling file
|
||||
@ -2898,6 +2960,7 @@ component_test_cmake_shared () {
|
||||
|
||||
test_build_opt () {
|
||||
info=$1 cc=$2; shift 2
|
||||
$cc --version
|
||||
for opt in "$@"; do
|
||||
msg "build/test: $cc $opt, $info" # ~ 30s
|
||||
make CC="$cc" CFLAGS="$opt -std=c99 -pedantic -Wall -Wextra -Werror"
|
||||
@ -2910,14 +2973,45 @@ test_build_opt () {
|
||||
done
|
||||
}
|
||||
|
||||
component_test_clang_opt () {
|
||||
# For FreeBSD we invoke the function by name so this condition is added
|
||||
# to disable the existing test_clang_opt function for linux.
|
||||
if [[ $(uname) != "Linux" ]]; then
|
||||
component_test_clang_opt () {
|
||||
scripts/config.py full
|
||||
test_build_opt 'full config' clang -O0 -Os -O2
|
||||
}
|
||||
fi
|
||||
|
||||
component_test_clang_latest_opt () {
|
||||
scripts/config.py full
|
||||
test_build_opt 'full config' clang -O0 -Os -O2
|
||||
test_build_opt 'full config' "$CLANG_LATEST" -O0 -Os -O2
|
||||
}
|
||||
support_test_clang_latest_opt () {
|
||||
type "$CLANG_LATEST" >/dev/null 2>/dev/null
|
||||
}
|
||||
|
||||
component_test_gcc_opt () {
|
||||
component_test_clang_earliest_opt () {
|
||||
scripts/config.py full
|
||||
test_build_opt 'full config' gcc -O0 -Os -O2
|
||||
test_build_opt 'full config' "$CLANG_EARLIEST" -O0
|
||||
}
|
||||
support_test_clang_earliest_opt () {
|
||||
type "$CLANG_EARLIEST" >/dev/null 2>/dev/null
|
||||
}
|
||||
|
||||
component_test_gcc_latest_opt () {
|
||||
scripts/config.py full
|
||||
test_build_opt 'full config' "$GCC_LATEST" -O0 -Os -O2
|
||||
}
|
||||
support_test_gcc_latest_opt () {
|
||||
type "$GCC_LATEST" >/dev/null 2>/dev/null
|
||||
}
|
||||
|
||||
component_test_gcc_earliest_opt () {
|
||||
scripts/config.py full
|
||||
test_build_opt 'full config' "$GCC_EARLIEST" -O0
|
||||
}
|
||||
support_test_gcc_earliest_opt () {
|
||||
type "$GCC_EARLIEST" >/dev/null 2>/dev/null
|
||||
}
|
||||
|
||||
component_build_mbedtls_config_file () {
|
||||
@ -3160,6 +3254,25 @@ component_build_arm_none_eabi_gcc_no_64bit_multiplication () {
|
||||
not grep __aeabi_lmul library/*.o
|
||||
}
|
||||
|
||||
component_build_arm_clang_thumb () {
|
||||
# ~ 30s
|
||||
|
||||
scripts/config.py baremetal
|
||||
|
||||
msg "build: clang thumb 2, make"
|
||||
make clean
|
||||
make CC="clang" CFLAGS='-std=c99 -Werror -Os --target=arm-linux-gnueabihf -march=armv7-m -mthumb' lib
|
||||
|
||||
# Some Thumb 1 asm is sensitive to optimisation level, so test both -O0 and -Os
|
||||
msg "build: clang thumb 1 -O0, make"
|
||||
make clean
|
||||
make CC="clang" CFLAGS='-std=c99 -Werror -O0 --target=arm-linux-gnueabihf -mcpu=arm1136j-s -mthumb' lib
|
||||
|
||||
msg "build: clang thumb 1 -Os, make"
|
||||
make clean
|
||||
make CC="clang" CFLAGS='-std=c99 -Werror -Os --target=arm-linux-gnueabihf -mcpu=arm1136j-s -mthumb' lib
|
||||
}
|
||||
|
||||
component_build_armcc () {
|
||||
msg "build: ARM Compiler 5"
|
||||
scripts/config.py baremetal
|
||||
@ -3170,6 +3283,8 @@ component_build_armcc () {
|
||||
|
||||
make clean
|
||||
|
||||
# Compile mostly with -O1 since some Arm inline assembly is disabled for -O0.
|
||||
|
||||
# ARM Compiler 6 - Target ARMv7-A
|
||||
armc6_build_test "--target=arm-arm-none-eabi -march=armv7-a"
|
||||
|
||||
@ -3184,7 +3299,14 @@ component_build_armcc () {
|
||||
|
||||
# ARM Compiler 6 - Target ARMv8-A - AArch64
|
||||
armc6_build_test "--target=aarch64-arm-none-eabi -march=armv8.2-a"
|
||||
|
||||
# ARM Compiler 6 - Target Cortex-M0 - no optimisation
|
||||
armc6_build_test "-O0 --target=arm-arm-none-eabi -mcpu=cortex-m0"
|
||||
|
||||
# ARM Compiler 6 - Target Cortex-M0
|
||||
armc6_build_test "-Os --target=arm-arm-none-eabi -mcpu=cortex-m0"
|
||||
}
|
||||
|
||||
support_build_armcc () {
|
||||
armc5_cc="$ARMC5_BIN_DIR/armcc"
|
||||
armc6_cc="$ARMC6_BIN_DIR/armclang"
|
||||
@ -3351,6 +3473,69 @@ support_test_cmake_as_subdirectory () {
|
||||
support_test_cmake_out_of_source
|
||||
}
|
||||
|
||||
component_build_cmake_custom_config_file () {
|
||||
# Make a copy of config file to use for the in-tree test
|
||||
cp "$CONFIG_H" include/mbedtls_config_in_tree_copy.h
|
||||
|
||||
MBEDTLS_ROOT_DIR="$PWD"
|
||||
mkdir "$OUT_OF_SOURCE_DIR"
|
||||
cd "$OUT_OF_SOURCE_DIR"
|
||||
|
||||
# Build once to get the generated files (which need an intact config file)
|
||||
cmake "$MBEDTLS_ROOT_DIR"
|
||||
make
|
||||
|
||||
msg "build: cmake with -DMBEDTLS_CONFIG_FILE"
|
||||
scripts/config.py -w full_config.h full
|
||||
echo '#error "cmake -DMBEDTLS_CONFIG_FILE is not working."' > "$MBEDTLS_ROOT_DIR/$CONFIG_H"
|
||||
cmake -DGEN_FILES=OFF -DMBEDTLS_CONFIG_FILE=full_config.h "$MBEDTLS_ROOT_DIR"
|
||||
make
|
||||
|
||||
msg "build: cmake with -DMBEDTLS_CONFIG_FILE + -DMBEDTLS_USER_CONFIG_FILE"
|
||||
# In the user config, disable one feature (for simplicity, pick a feature
|
||||
# that nothing else depends on).
|
||||
echo '#undef MBEDTLS_NIST_KW_C' >user_config.h
|
||||
|
||||
cmake -DGEN_FILES=OFF -DMBEDTLS_CONFIG_FILE=full_config.h -DMBEDTLS_USER_CONFIG_FILE=user_config.h "$MBEDTLS_ROOT_DIR"
|
||||
make
|
||||
not programs/test/query_compile_time_config MBEDTLS_NIST_KW_C
|
||||
|
||||
rm -f user_config.h full_config.h
|
||||
|
||||
cd "$MBEDTLS_ROOT_DIR"
|
||||
rm -rf "$OUT_OF_SOURCE_DIR"
|
||||
|
||||
# Now repeat the test for an in-tree build:
|
||||
|
||||
# Restore config for the in-tree test
|
||||
mv include/mbedtls_config_in_tree_copy.h "$CONFIG_H"
|
||||
|
||||
# Build once to get the generated files (which need an intact config)
|
||||
cmake .
|
||||
make
|
||||
|
||||
msg "build: cmake (in-tree) with -DMBEDTLS_CONFIG_FILE"
|
||||
scripts/config.py -w full_config.h full
|
||||
echo '#error "cmake -DMBEDTLS_CONFIG_FILE is not working."' > "$MBEDTLS_ROOT_DIR/$CONFIG_H"
|
||||
cmake -DGEN_FILES=OFF -DMBEDTLS_CONFIG_FILE=full_config.h .
|
||||
make
|
||||
|
||||
msg "build: cmake (in-tree) with -DMBEDTLS_CONFIG_FILE + -DMBEDTLS_USER_CONFIG_FILE"
|
||||
# In the user config, disable one feature (for simplicity, pick a feature
|
||||
# that nothing else depends on).
|
||||
echo '#undef MBEDTLS_NIST_KW_C' >user_config.h
|
||||
|
||||
cmake -DGEN_FILES=OFF -DMBEDTLS_CONFIG_FILE=full_config.h -DMBEDTLS_USER_CONFIG_FILE=user_config.h .
|
||||
make
|
||||
not programs/test/query_compile_time_config MBEDTLS_NIST_KW_C
|
||||
|
||||
rm -f user_config.h full_config.h
|
||||
}
|
||||
support_build_cmake_custom_config_file () {
|
||||
support_test_cmake_out_of_source
|
||||
}
|
||||
|
||||
|
||||
component_test_zeroize () {
|
||||
# Test that the function mbedtls_platform_zeroize() is not optimized away by
|
||||
# different combinations of compilers and optimization flags by using an
|
||||
|
@ -196,7 +196,7 @@ class BignumOperation(BignumTarget, metaclass=ABCMeta):
|
||||
class BignumCmp(BignumOperation):
|
||||
"""Test cases for bignum value comparison."""
|
||||
count = 0
|
||||
test_function = "mbedtls_mpi_cmp_mpi"
|
||||
test_function = "mpi_cmp_mpi"
|
||||
test_name = "MPI compare"
|
||||
input_cases = [
|
||||
("-2", "-3"),
|
||||
@ -217,7 +217,7 @@ class BignumCmp(BignumOperation):
|
||||
class BignumCmpAbs(BignumCmp):
|
||||
"""Test cases for absolute bignum value comparison."""
|
||||
count = 0
|
||||
test_function = "mbedtls_mpi_cmp_abs"
|
||||
test_function = "mpi_cmp_abs"
|
||||
test_name = "MPI compare (abs)"
|
||||
|
||||
def __init__(self, val_a, val_b) -> None:
|
||||
@ -228,7 +228,7 @@ class BignumAdd(BignumOperation):
|
||||
"""Test cases for bignum value addition."""
|
||||
count = 0
|
||||
symbol = "+"
|
||||
test_function = "mbedtls_mpi_add_mpi"
|
||||
test_function = "mpi_add_mpi"
|
||||
test_name = "MPI add"
|
||||
input_cases = combination_pairs(
|
||||
[
|
||||
|
@ -171,6 +171,28 @@ import string
|
||||
import argparse
|
||||
|
||||
|
||||
# Types recognized as signed integer arguments in test functions.
|
||||
SIGNED_INTEGER_TYPES = frozenset([
|
||||
'char',
|
||||
'short',
|
||||
'short int',
|
||||
'int',
|
||||
'int8_t',
|
||||
'int16_t',
|
||||
'int32_t',
|
||||
'int64_t',
|
||||
'intmax_t',
|
||||
'long',
|
||||
'long int',
|
||||
'long long int',
|
||||
'mbedtls_mpi_sint',
|
||||
'psa_status_t',
|
||||
])
|
||||
# Types recognized as string arguments in test functions.
|
||||
STRING_TYPES = frozenset(['char*', 'const char*', 'char const*'])
|
||||
# Types recognized as hex data arguments in test functions.
|
||||
DATA_TYPES = frozenset(['data_t*', 'const data_t*', 'data_t const*'])
|
||||
|
||||
BEGIN_HEADER_REGEX = r'/\*\s*BEGIN_HEADER\s*\*/'
|
||||
END_HEADER_REGEX = r'/\*\s*END_HEADER\s*\*/'
|
||||
|
||||
@ -192,9 +214,6 @@ CONDITION_REGEX = r'({})(?:\s*({})\s*({}))?$'.format(C_IDENTIFIER_REGEX,
|
||||
CONDITION_OPERATOR_REGEX,
|
||||
CONDITION_VALUE_REGEX)
|
||||
TEST_FUNCTION_VALIDATION_REGEX = r'\s*void\s+(?P<func_name>\w+)\s*\('
|
||||
INT_CHECK_REGEX = r'int\s+.*'
|
||||
CHAR_CHECK_REGEX = r'char\s*\*\s*.*'
|
||||
DATA_T_CHECK_REGEX = r'data_t\s*\*\s*.*'
|
||||
FUNCTION_ARG_LIST_END_REGEX = r'.*\)'
|
||||
EXIT_LABEL_REGEX = r'^exit:'
|
||||
|
||||
@ -303,7 +322,7 @@ def gen_function_wrapper(name, local_vars, args_dispatch):
|
||||
:param name: Test function name
|
||||
:param local_vars: Local variables declaration code
|
||||
:param args_dispatch: List of dispatch arguments.
|
||||
Ex: ['(char *)params[0]', '*((int *)params[1])']
|
||||
Ex: ['(char *) params[0]', '*((int *) params[1])']
|
||||
:return: Test function wrapper.
|
||||
"""
|
||||
# Then create the wrapper
|
||||
@ -444,6 +463,49 @@ def parse_function_dependencies(line):
|
||||
return dependencies
|
||||
|
||||
|
||||
ARGUMENT_DECLARATION_REGEX = re.compile(r'(.+?) ?(?:\bconst\b)? ?(\w+)\Z', re.S)
|
||||
def parse_function_argument(arg, arg_idx, args, local_vars, args_dispatch):
|
||||
"""
|
||||
Parses one test function's argument declaration.
|
||||
|
||||
:param arg: argument declaration.
|
||||
:param arg_idx: current wrapper argument index.
|
||||
:param args: accumulator of arguments' internal types.
|
||||
:param local_vars: accumulator of internal variable declarations.
|
||||
:param args_dispatch: accumulator of argument usage expressions.
|
||||
:return: the number of new wrapper arguments,
|
||||
or None if the argument declaration is invalid.
|
||||
"""
|
||||
# Normalize whitespace
|
||||
arg = arg.strip()
|
||||
arg = re.sub(r'\s*\*\s*', r'*', arg)
|
||||
arg = re.sub(r'\s+', r' ', arg)
|
||||
# Extract name and type
|
||||
m = ARGUMENT_DECLARATION_REGEX.search(arg)
|
||||
if not m:
|
||||
# E.g. "int x[42]"
|
||||
return None
|
||||
typ, _ = m.groups()
|
||||
if typ in SIGNED_INTEGER_TYPES:
|
||||
args.append('int')
|
||||
args_dispatch.append('((mbedtls_test_argument_t *) params[%d])->sint' % arg_idx)
|
||||
return 1
|
||||
if typ in STRING_TYPES:
|
||||
args.append('char*')
|
||||
args_dispatch.append('(char *) params[%d]' % arg_idx)
|
||||
return 1
|
||||
if typ in DATA_TYPES:
|
||||
args.append('hex')
|
||||
# create a structure
|
||||
pointer_initializer = '(uint8_t *) params[%d]' % arg_idx
|
||||
len_initializer = '((mbedtls_test_argument_t *) params[%d])->len' % (arg_idx+1)
|
||||
local_vars.append(' data_t data%d = {%s, %s};\n' %
|
||||
(arg_idx, pointer_initializer, len_initializer))
|
||||
args_dispatch.append('&data%d' % arg_idx)
|
||||
return 2
|
||||
return None
|
||||
|
||||
ARGUMENT_LIST_REGEX = re.compile(r'\((.*?)\)', re.S)
|
||||
def parse_function_arguments(line):
|
||||
"""
|
||||
Parses test function signature for validation and generates
|
||||
@ -455,42 +517,27 @@ def parse_function_arguments(line):
|
||||
:return: argument list, local variables for
|
||||
wrapper function and argument dispatch code.
|
||||
"""
|
||||
args = []
|
||||
local_vars = ''
|
||||
args_dispatch = []
|
||||
arg_idx = 0
|
||||
# Remove characters before arguments
|
||||
line = line[line.find('(') + 1:]
|
||||
# Process arguments, ex: <type> arg1, <type> arg2 )
|
||||
# This script assumes that the argument list is terminated by ')'
|
||||
# i.e. the test functions will not have a function pointer
|
||||
# argument.
|
||||
for arg in line[:line.find(')')].split(','):
|
||||
arg = arg.strip()
|
||||
if arg == '':
|
||||
continue
|
||||
if re.search(INT_CHECK_REGEX, arg.strip()):
|
||||
args.append('int')
|
||||
args_dispatch.append('*( (int *) params[%d] )' % arg_idx)
|
||||
elif re.search(CHAR_CHECK_REGEX, arg.strip()):
|
||||
args.append('char*')
|
||||
args_dispatch.append('(char *) params[%d]' % arg_idx)
|
||||
elif re.search(DATA_T_CHECK_REGEX, arg.strip()):
|
||||
args.append('hex')
|
||||
# create a structure
|
||||
pointer_initializer = '(uint8_t *) params[%d]' % arg_idx
|
||||
len_initializer = '*( (uint32_t *) params[%d] )' % (arg_idx+1)
|
||||
local_vars += """ data_t data%d = {%s, %s};
|
||||
""" % (arg_idx, pointer_initializer, len_initializer)
|
||||
|
||||
args_dispatch.append('&data%d' % arg_idx)
|
||||
arg_idx += 1
|
||||
else:
|
||||
m = ARGUMENT_LIST_REGEX.search(line)
|
||||
arg_list = m.group(1).strip()
|
||||
if arg_list in ['', 'void']:
|
||||
return [], '', []
|
||||
args = []
|
||||
local_vars = []
|
||||
args_dispatch = []
|
||||
arg_idx = 0
|
||||
for arg in arg_list.split(','):
|
||||
indexes = parse_function_argument(arg, arg_idx,
|
||||
args, local_vars, args_dispatch)
|
||||
if indexes is None:
|
||||
raise ValueError("Test function arguments can only be 'int', "
|
||||
"'char *' or 'data_t'\n%s" % line)
|
||||
arg_idx += 1
|
||||
arg_idx += indexes
|
||||
|
||||
return args, local_vars, args_dispatch
|
||||
return args, ''.join(local_vars), args_dispatch
|
||||
|
||||
|
||||
def generate_function_code(name, code, local_vars, args_dispatch,
|
||||
@ -607,6 +654,11 @@ def parse_function_code(funcs_f, dependencies, suite_dependencies):
|
||||
code = code.replace(name, 'test_' + name, 1)
|
||||
name = 'test_' + name
|
||||
|
||||
# If a test function has no arguments then add 'void' argument to
|
||||
# avoid "-Wstrict-prototypes" warnings from clang
|
||||
if len(args) == 0:
|
||||
code = code.replace('()', '(void)', 1)
|
||||
|
||||
for line in funcs_f:
|
||||
if re.search(END_CASE_REGEX, line):
|
||||
break
|
||||
@ -705,7 +757,7 @@ def parse_test_data(data_f):
|
||||
execution.
|
||||
|
||||
:param data_f: file object of the data file.
|
||||
:return: Generator that yields test name, function name,
|
||||
:return: Generator that yields line number, test name, function name,
|
||||
dependency list and function argument list.
|
||||
"""
|
||||
__state_read_name = 0
|
||||
@ -748,7 +800,7 @@ def parse_test_data(data_f):
|
||||
parts = escaped_split(line, ':')
|
||||
test_function = parts[0]
|
||||
args = parts[1:]
|
||||
yield name, test_function, dependencies, args
|
||||
yield data_f.line_no, name, test_function, dependencies, args
|
||||
dependencies = []
|
||||
state = __state_read_name
|
||||
if state == __state_read_args:
|
||||
@ -846,6 +898,14 @@ def write_dependencies(out_data_f, test_dependencies, unique_dependencies):
|
||||
return dep_check_code
|
||||
|
||||
|
||||
INT_VAL_REGEX = re.compile(r'-?(\d+|0x[0-9a-f]+)$', re.I)
|
||||
def val_is_int(val: str) -> bool:
|
||||
"""Whether val is suitable as an 'int' parameter in the .datax file."""
|
||||
if not INT_VAL_REGEX.match(val):
|
||||
return False
|
||||
# Limit the range to what is guaranteed to get through strtol()
|
||||
return abs(int(val, 0)) <= 0x7fffffff
|
||||
|
||||
def write_parameters(out_data_f, test_args, func_args, unique_expressions):
|
||||
"""
|
||||
Writes test parameters to the intermediate data file, replacing
|
||||
@ -864,9 +924,9 @@ def write_parameters(out_data_f, test_args, func_args, unique_expressions):
|
||||
typ = func_args[i]
|
||||
val = test_args[i]
|
||||
|
||||
# check if val is a non literal int val (i.e. an expression)
|
||||
if typ == 'int' and not re.match(r'(\d+|0x[0-9a-f]+)$',
|
||||
val, re.I):
|
||||
# Pass small integer constants literally. This reduces the size of
|
||||
# the C code. Register anything else as an expression.
|
||||
if typ == 'int' and not val_is_int(val):
|
||||
typ = 'exp'
|
||||
if val not in unique_expressions:
|
||||
unique_expressions.append(val)
|
||||
@ -909,6 +969,24 @@ def gen_suite_dep_checks(suite_dependencies, dep_check_code, expression_code):
|
||||
return dep_check_code, expression_code
|
||||
|
||||
|
||||
def get_function_info(func_info, function_name, line_no):
|
||||
"""Look up information about a test function by name.
|
||||
|
||||
Raise an informative expression if function_name is not found.
|
||||
|
||||
:param func_info: dictionary mapping function names to their information.
|
||||
:param function_name: the function name as written in the .function and
|
||||
.data files.
|
||||
:param line_no: line number for error messages.
|
||||
:return Function information (id, args).
|
||||
"""
|
||||
test_function_name = 'test_' + function_name
|
||||
if test_function_name not in func_info:
|
||||
raise GeneratorInputError("%d: Function %s not found!" %
|
||||
(line_no, test_function_name))
|
||||
return func_info[test_function_name]
|
||||
|
||||
|
||||
def gen_from_test_data(data_f, out_data_f, func_info, suite_dependencies):
|
||||
"""
|
||||
This function reads test case name, dependencies and test vectors
|
||||
@ -931,7 +1009,7 @@ def gen_from_test_data(data_f, out_data_f, func_info, suite_dependencies):
|
||||
unique_expressions = []
|
||||
dep_check_code = ''
|
||||
expression_code = ''
|
||||
for test_name, function_name, test_dependencies, test_args in \
|
||||
for line_no, test_name, function_name, test_dependencies, test_args in \
|
||||
parse_test_data(data_f):
|
||||
out_data_f.write(test_name + '\n')
|
||||
|
||||
@ -940,18 +1018,15 @@ def gen_from_test_data(data_f, out_data_f, func_info, suite_dependencies):
|
||||
unique_dependencies)
|
||||
|
||||
# Write test function name
|
||||
test_function_name = 'test_' + function_name
|
||||
if test_function_name not in func_info:
|
||||
raise GeneratorInputError("Function %s not found!" %
|
||||
test_function_name)
|
||||
func_id, func_args = func_info[test_function_name]
|
||||
func_id, func_args = \
|
||||
get_function_info(func_info, function_name, line_no)
|
||||
out_data_f.write(str(func_id))
|
||||
|
||||
# Write parameters
|
||||
if len(test_args) != len(func_args):
|
||||
raise GeneratorInputError("Invalid number of arguments in test "
|
||||
raise GeneratorInputError("%d: Invalid number of arguments in test "
|
||||
"%s. See function %s signature." %
|
||||
(test_name, function_name))
|
||||
(line_no, test_name, function_name))
|
||||
expression_code += write_parameters(out_data_f, test_args, func_args,
|
||||
unique_expressions)
|
||||
|
||||
|
@ -1,13 +1,13 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Describe the test coverage of PSA functions in terms of return statuses.
|
||||
|
||||
1. Build Mbed Crypto with -DRECORD_PSA_STATUS_COVERAGE_LOG
|
||||
1. Build Mbed TLS with -DRECORD_PSA_STATUS_COVERAGE_LOG
|
||||
2. Run psa_collect_statuses.py
|
||||
|
||||
The output is a series of line of the form "psa_foo PSA_ERROR_XXX". Each
|
||||
function/status combination appears only once.
|
||||
|
||||
This script must be run from the top of an Mbed Crypto source tree.
|
||||
This script must be run from the top of an Mbed TLS source tree.
|
||||
The build command is "make -DRECORD_PSA_STATUS_COVERAGE_LOG", which is
|
||||
only supported with make (as opposed to CMake or other build methods).
|
||||
"""
|
||||
@ -46,7 +46,7 @@ class Statuses:
|
||||
def collect_log(self, log_file_name):
|
||||
"""Read logs from RECORD_PSA_STATUS_COVERAGE_LOG.
|
||||
|
||||
Read logs produced by running Mbed Crypto test suites built with
|
||||
Read logs produced by running Mbed TLS test suites built with
|
||||
-DRECORD_PSA_STATUS_COVERAGE_LOG.
|
||||
"""
|
||||
with open(log_file_name) as log:
|
||||
@ -82,7 +82,7 @@ class Statuses:
|
||||
def collect_status_logs(options):
|
||||
"""Build and run unit tests and report observed function return statuses.
|
||||
|
||||
Build Mbed Crypto with -DRECORD_PSA_STATUS_COVERAGE_LOG, run the
|
||||
Build Mbed TLS with -DRECORD_PSA_STATUS_COVERAGE_LOG, run the
|
||||
test suites and display information about observed return statuses.
|
||||
"""
|
||||
rebuilt = False
|
||||
|
@ -485,9 +485,10 @@ class ParseFuncSignature(TestCase):
|
||||
args, local, arg_dispatch = parse_function_arguments(line)
|
||||
self.assertEqual(args, ['char*', 'int', 'int'])
|
||||
self.assertEqual(local, '')
|
||||
self.assertEqual(arg_dispatch, ['(char *) params[0]',
|
||||
'*( (int *) params[1] )',
|
||||
'*( (int *) params[2] )'])
|
||||
self.assertEqual(arg_dispatch,
|
||||
['(char *) params[0]',
|
||||
'((mbedtls_test_argument_t *) params[1])->sint',
|
||||
'((mbedtls_test_argument_t *) params[2])->sint'])
|
||||
|
||||
def test_hex_params(self):
|
||||
"""
|
||||
@ -499,22 +500,22 @@ class ParseFuncSignature(TestCase):
|
||||
self.assertEqual(args, ['char*', 'hex', 'int'])
|
||||
self.assertEqual(local,
|
||||
' data_t data1 = {(uint8_t *) params[1], '
|
||||
'*( (uint32_t *) params[2] )};\n')
|
||||
'((mbedtls_test_argument_t *) params[2])->len};\n')
|
||||
self.assertEqual(arg_dispatch, ['(char *) params[0]',
|
||||
'&data1',
|
||||
'*( (int *) params[3] )'])
|
||||
'((mbedtls_test_argument_t *) params[3])->sint'])
|
||||
|
||||
def test_unsupported_arg(self):
|
||||
"""
|
||||
Test unsupported arguments (not among int, char * and data_t)
|
||||
Test unsupported argument type
|
||||
:return:
|
||||
"""
|
||||
line = 'void entropy_threshold( char * a, data_t * h, char result )'
|
||||
line = 'void entropy_threshold( char * a, data_t * h, unknown_t result )'
|
||||
self.assertRaises(ValueError, parse_function_arguments, line)
|
||||
|
||||
def test_no_params(self):
|
||||
def test_empty_params(self):
|
||||
"""
|
||||
Test no parameters.
|
||||
Test no parameters (nothing between parentheses).
|
||||
:return:
|
||||
"""
|
||||
line = 'void entropy_threshold()'
|
||||
@ -523,6 +524,39 @@ class ParseFuncSignature(TestCase):
|
||||
self.assertEqual(local, '')
|
||||
self.assertEqual(arg_dispatch, [])
|
||||
|
||||
def test_blank_params(self):
|
||||
"""
|
||||
Test no parameters (space between parentheses).
|
||||
:return:
|
||||
"""
|
||||
line = 'void entropy_threshold( )'
|
||||
args, local, arg_dispatch = parse_function_arguments(line)
|
||||
self.assertEqual(args, [])
|
||||
self.assertEqual(local, '')
|
||||
self.assertEqual(arg_dispatch, [])
|
||||
|
||||
def test_void_params(self):
|
||||
"""
|
||||
Test no parameters (void keyword).
|
||||
:return:
|
||||
"""
|
||||
line = 'void entropy_threshold(void)'
|
||||
args, local, arg_dispatch = parse_function_arguments(line)
|
||||
self.assertEqual(args, [])
|
||||
self.assertEqual(local, '')
|
||||
self.assertEqual(arg_dispatch, [])
|
||||
|
||||
def test_void_space_params(self):
|
||||
"""
|
||||
Test no parameters (void with spaces).
|
||||
:return:
|
||||
"""
|
||||
line = 'void entropy_threshold( void )'
|
||||
args, local, arg_dispatch = parse_function_arguments(line)
|
||||
self.assertEqual(args, [])
|
||||
self.assertEqual(local, '')
|
||||
self.assertEqual(arg_dispatch, [])
|
||||
|
||||
|
||||
class ParseFunctionCode(TestCase):
|
||||
"""
|
||||
@ -613,7 +647,7 @@ void func()
|
||||
self.assertEqual(arg, [])
|
||||
expected = '''#line 1 "test_suite_ut.function"
|
||||
|
||||
void test_func()
|
||||
void test_func(void)
|
||||
{
|
||||
ba ba black sheep
|
||||
have you any wool
|
||||
@ -656,7 +690,7 @@ exit:
|
||||
|
||||
expected = '''#line 1 "test_suite_ut.function"
|
||||
|
||||
void test_func()
|
||||
void test_func(void)
|
||||
{
|
||||
ba ba black sheep
|
||||
have you any wool
|
||||
@ -716,7 +750,7 @@ exit:
|
||||
void
|
||||
|
||||
|
||||
test_func()
|
||||
test_func(void)
|
||||
{
|
||||
ba ba black sheep
|
||||
have you any wool
|
||||
@ -769,7 +803,7 @@ exit:
|
||||
|
||||
|
||||
|
||||
void test_func()
|
||||
void test_func(void)
|
||||
{
|
||||
ba ba black sheep
|
||||
have you any wool
|
||||
@ -1105,7 +1139,7 @@ void func2()
|
||||
#if defined(MBEDTLS_ENTROPY_NV_SEED)
|
||||
#if defined(MBEDTLS_FS_IO)
|
||||
#line 13 "test_suite_ut.function"
|
||||
void test_func1()
|
||||
void test_func1(void)
|
||||
{
|
||||
exit:
|
||||
;
|
||||
@ -1122,7 +1156,7 @@ void test_func1_wrapper( void ** params )
|
||||
#if defined(MBEDTLS_ENTROPY_NV_SEED)
|
||||
#if defined(MBEDTLS_FS_IO)
|
||||
#line 19 "test_suite_ut.function"
|
||||
void test_func2()
|
||||
void test_func2(void)
|
||||
{
|
||||
exit:
|
||||
;
|
||||
@ -1264,29 +1298,33 @@ dhm_selftest:
|
||||
# List of (name, function_name, dependencies, args)
|
||||
tests = list(parse_test_data(stream))
|
||||
test1, test2, test3, test4 = tests
|
||||
self.assertEqual(test1[0], 'Diffie-Hellman full exchange #1')
|
||||
self.assertEqual(test1[1], 'dhm_do_dhm')
|
||||
self.assertEqual(test1[2], [])
|
||||
self.assertEqual(test1[3], ['10', '"23"', '10', '"5"'])
|
||||
self.assertEqual(test1[0], 3)
|
||||
self.assertEqual(test1[1], 'Diffie-Hellman full exchange #1')
|
||||
self.assertEqual(test1[2], 'dhm_do_dhm')
|
||||
self.assertEqual(test1[3], [])
|
||||
self.assertEqual(test1[4], ['10', '"23"', '10', '"5"'])
|
||||
|
||||
self.assertEqual(test2[0], 'Diffie-Hellman full exchange #2')
|
||||
self.assertEqual(test2[1], 'dhm_do_dhm')
|
||||
self.assertEqual(test2[2], [])
|
||||
self.assertEqual(test2[3], ['10', '"93450983094850938450983409623"',
|
||||
self.assertEqual(test2[0], 6)
|
||||
self.assertEqual(test2[1], 'Diffie-Hellman full exchange #2')
|
||||
self.assertEqual(test2[2], 'dhm_do_dhm')
|
||||
self.assertEqual(test2[3], [])
|
||||
self.assertEqual(test2[4], ['10', '"93450983094850938450983409623"',
|
||||
'10', '"9345098304850938450983409622"'])
|
||||
|
||||
self.assertEqual(test3[0], 'Diffie-Hellman full exchange #3')
|
||||
self.assertEqual(test3[1], 'dhm_do_dhm')
|
||||
self.assertEqual(test3[2], [])
|
||||
self.assertEqual(test3[3], ['10',
|
||||
self.assertEqual(test3[0], 9)
|
||||
self.assertEqual(test3[1], 'Diffie-Hellman full exchange #3')
|
||||
self.assertEqual(test3[2], 'dhm_do_dhm')
|
||||
self.assertEqual(test3[3], [])
|
||||
self.assertEqual(test3[4], ['10',
|
||||
'"9345098382739712938719287391879381271"',
|
||||
'10',
|
||||
'"9345098792137312973297123912791271"'])
|
||||
|
||||
self.assertEqual(test4[0], 'Diffie-Hellman selftest')
|
||||
self.assertEqual(test4[1], 'dhm_selftest')
|
||||
self.assertEqual(test4[2], [])
|
||||
self.assertEqual(test4[0], 12)
|
||||
self.assertEqual(test4[1], 'Diffie-Hellman selftest')
|
||||
self.assertEqual(test4[2], 'dhm_selftest')
|
||||
self.assertEqual(test4[3], [])
|
||||
self.assertEqual(test4[4], [])
|
||||
|
||||
def test_with_dependencies(self):
|
||||
"""
|
||||
@ -1306,15 +1344,17 @@ dhm_do_dhm:10:"93450983094850938450983409623":10:"9345098304850938450983409622"
|
||||
# List of (name, function_name, dependencies, args)
|
||||
tests = list(parse_test_data(stream))
|
||||
test1, test2 = tests
|
||||
self.assertEqual(test1[0], 'Diffie-Hellman full exchange #1')
|
||||
self.assertEqual(test1[1], 'dhm_do_dhm')
|
||||
self.assertEqual(test1[2], ['YAHOO'])
|
||||
self.assertEqual(test1[3], ['10', '"23"', '10', '"5"'])
|
||||
self.assertEqual(test1[0], 4)
|
||||
self.assertEqual(test1[1], 'Diffie-Hellman full exchange #1')
|
||||
self.assertEqual(test1[2], 'dhm_do_dhm')
|
||||
self.assertEqual(test1[3], ['YAHOO'])
|
||||
self.assertEqual(test1[4], ['10', '"23"', '10', '"5"'])
|
||||
|
||||
self.assertEqual(test2[0], 'Diffie-Hellman full exchange #2')
|
||||
self.assertEqual(test2[1], 'dhm_do_dhm')
|
||||
self.assertEqual(test2[2], [])
|
||||
self.assertEqual(test2[3], ['10', '"93450983094850938450983409623"',
|
||||
self.assertEqual(test2[0], 7)
|
||||
self.assertEqual(test2[1], 'Diffie-Hellman full exchange #2')
|
||||
self.assertEqual(test2[2], 'dhm_do_dhm')
|
||||
self.assertEqual(test2[3], [])
|
||||
self.assertEqual(test2[4], ['10', '"93450983094850938450983409623"',
|
||||
'10', '"9345098304850938450983409622"'])
|
||||
|
||||
def test_no_args(self):
|
||||
@ -1335,7 +1375,7 @@ dhm_do_dhm:10:"93450983094850938450983409623":10:"9345098304850938450983409622"
|
||||
stream = StringIOWrapper('test_suite_ut.function', data)
|
||||
err = None
|
||||
try:
|
||||
for _, _, _, _ in parse_test_data(stream):
|
||||
for _, _, _, _, _ in parse_test_data(stream):
|
||||
pass
|
||||
except GeneratorInputError as err:
|
||||
self.assertEqual(type(err), GeneratorInputError)
|
||||
@ -1353,7 +1393,7 @@ depends_on:YAHOO
|
||||
stream = StringIOWrapper('test_suite_ut.function', data)
|
||||
err = None
|
||||
try:
|
||||
for _, _, _, _ in parse_test_data(stream):
|
||||
for _, _, _, _, _ in parse_test_data(stream):
|
||||
pass
|
||||
except GeneratorInputError as err:
|
||||
self.assertEqual(type(err), GeneratorInputError)
|
||||
|
Reference in New Issue
Block a user