Merge remote-tracking branch 'main' into restricted-framework-merge-public-20250916

This commit is contained in:
Gilles Peskine
2025-09-16 16:16:24 +02:00
119 changed files with 2495 additions and 206 deletions
+15 -6
View File
@@ -188,7 +188,10 @@ pre_initialize_variables () {
files_to_back_up="$config_files"
if in_mbedtls_repo; then
# Files clobbered by in-tree cmake
files_to_back_up="$files_to_back_up Makefile library/Makefile programs/Makefile tests/Makefile programs/fuzz/Makefile"
if [ -e Makefile ]; then
files_to_back_up="$files_to_back_up Makefile"
fi
files_to_back_up="$files_to_back_up library/Makefile programs/Makefile tests/Makefile programs/fuzz/Makefile"
fi
append_outcome=0
@@ -228,6 +231,12 @@ pre_initialize_variables () {
: ${CLANG_EARLIEST:="clang-earliest"}
: ${GCC_LATEST:="gcc-latest"}
: ${GCC_EARLIEST:="gcc-earliest"}
: ${MAKE_COMMAND:="make"}
if [ -e "scripts/legacy.make" ]; then
MAKE_COMMAND="${MAKE_COMMAND} -f ./scripts/legacy.make"
fi
# if MAKEFLAGS is not set add the -j option to speed up invocations of make
if [ -z "${MAKEFLAGS+set}" ]; then
export MAKEFLAGS="-j$(all_sh_nproc)"
@@ -366,7 +375,7 @@ EOF
cleanup()
{
if in_mbedtls_repo; then
command make clean
command $MAKE_COMMAND clean
fi
# Remove CMake artefacts
@@ -877,11 +886,11 @@ pre_check_tools () {
pre_generate_files() {
# since make doesn't have proper dependencies, remove any possibly outdate
# file that might be around before generating fresh ones
make neat
$MAKE_COMMAND neat
if [ $QUIET -eq 1 ]; then
make generated_files >/dev/null
$MAKE_COMMAND generated_files >/dev/null
else
make generated_files
$MAKE_COMMAND generated_files
fi
}
@@ -920,7 +929,7 @@ pseudo_component_error_test () {
# Expected error: '! grep -q . tests/scripts/all.sh -> 1'
not grep -q . "$0"
# Expected error: 'make unknown_target -> 2'
make unknown_target
$MAKE_COMMAND unknown_target
false "this should not be executed"
}
+7 -3
View File
@@ -122,7 +122,7 @@ helper_libtestdriver1_make_main() {
# we need flags both with and without the LIBTESTDRIVER1_ prefix
loc_accel_flags=$( echo "$loc_accel_list" | sed 's/[^ ]* */-DLIBTESTDRIVER1_MBEDTLS_PSA_ACCEL_&/g' )
loc_accel_flags="$loc_accel_flags $( echo "$loc_accel_list" | sed 's/[^ ]* */-DMBEDTLS_PSA_ACCEL_&/g' )"
make CC=$ASAN_CC CFLAGS="$ASAN_CFLAGS -I../tests/include -I../framework/tests/include -I../tests -I../../tests -DPSA_CRYPTO_DRIVER_TEST -DMBEDTLS_TEST_LIBTESTDRIVER1 $loc_accel_flags" LDFLAGS="-ltestdriver1 $ASAN_CFLAGS" "$@"
$MAKE_COMMAND CC=$ASAN_CC CFLAGS="$ASAN_CFLAGS -I../tests/include -I../framework/tests/include -I../tests -I../../tests -DPSA_CRYPTO_DRIVER_TEST -DMBEDTLS_TEST_LIBTESTDRIVER1 $loc_accel_flags" LDFLAGS="-ltestdriver1 $ASAN_CFLAGS" "$@"
}
################################################################
@@ -139,6 +139,8 @@ helper_psasim_config() {
scripts/config.py full
scripts/config.py unset MBEDTLS_PSA_CRYPTO_C
scripts/config.py unset MBEDTLS_PSA_CRYPTO_STORAGE_C
scripts/config.py unset MBEDTLS_ENTROPY_NV_SEED
scripts/config.py unset MBEDTLS_PLATFORM_NV_SEED_ALT
if in_mbedtls_repo && in_3_6_branch; then
# Dynamic secure element support is a deprecated feature and it is not
# available when CRYPTO_C and PSA_CRYPTO_STORAGE_C are disabled.
@@ -149,6 +151,8 @@ helper_psasim_config() {
scripts/config.py unset MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED
scripts/config.py unset MBEDTLS_ECP_RESTARTABLE
scripts/config.py unset MBEDTLS_PSA_CRYPTO_KEY_ID_ENCODES_OWNER
scripts/config.py unset MBEDTLS_PK_PARSE_EC_EXTENDED
scripts/config.py unset MBEDTLS_PK_PARSE_EC_COMPRESSED
scripts/config.py unset-all MBEDTLS_SHA256_USE_.*_CRYPTO_
scripts/config.py unset-all MBEDTLS_SHA512_USE_.*_CRYPTO_
@@ -261,9 +265,9 @@ helper_armc6_build_test()
msg "build: ARM Compiler 6 ($FLAGS)"
make clean
$MAKE_COMMAND clean
ARM_TOOL_VARIANT="ult" CC="$ARMC6_CC" AR="$ARMC6_AR" CFLAGS="$FLAGS" \
WARNING_CFLAGS='-Werror -xc -std=c99' make lib
WARNING_CFLAGS='-Werror -xc -std=c99' $MAKE_COMMAND lib
msg "size: ARM Compiler 6 ($FLAGS)"
"$ARMC6_FROMELF" -z library/*.o
+19 -9
View File
@@ -22,6 +22,8 @@ if in_mbedtls_repo; then
if ! in_3_6_branch; then
CRYPTO_CONFIG_H='tf-psa-crypto/include/psa/crypto_config.h'
fi
CONFIG_BAK=${CONFIG_H}.bak
cp -p $CONFIG_H $CONFIG_BAK
fi
if in_tf_psa_crypto_repo; then
@@ -37,21 +39,29 @@ if in_tf_psa_crypto_repo || (in_mbedtls_repo && ! in_3_6_branch); then
cp -p $CRYPTO_CONFIG_H $CRYPTO_CONFIG_BAK
fi
if in_mbedtls_repo; then
CONFIG_BAK=${CONFIG_H}.bak
cp -p $CONFIG_H $CONFIG_BAK
if in_mbedtls_repo && in_3_6_branch; then
scripts/config.py realfull
make apidoc
mv $CONFIG_BAK $CONFIG_H
elif in_tf_psa_crypto_repo; then
else
scripts/config.py realfull
TF_PSA_CRYPTO_ROOT_DIR=$PWD
ROOT_DIR=$PWD
rm -rf doxygen/build-apidoc-full
mkdir doxygen/build-apidoc-full
cd doxygen/build-apidoc-full
cmake -DCMAKE_BUILD_TYPE:String=Check -DGEN_FILES=ON $TF_PSA_CRYPTO_ROOT_DIR
make tfpsacrypto-apidoc
cd $TF_PSA_CRYPTO_ROOT_DIR
cmake -DCMAKE_BUILD_TYPE:String=Check -DGEN_FILES=ON $ROOT_DIR
if in_mbedtls_repo; then
cmake --build . --target mbedtls-apidoc
else
cmake --build . --target tfpsacrypto-apidoc
fi
cd $ROOT_DIR
# The documentation is built in the source tree thus we can delete the
# build tree.
rm -rf doxygen/build-apidoc-full
fi
if in_mbedtls_repo; then
mv $CONFIG_BAK $CONFIG_H
fi
if in_tf_psa_crypto_repo || (in_mbedtls_repo && ! in_3_6_branch); then
+25 -15
View File
@@ -810,7 +810,7 @@ class TFPSACryptoCodeParser(CodeParser):
check=True
)
subprocess.run(
["make"],
["cmake", "--build", "."],
env=my_environment,
universal_newlines=True,
stdout=subprocess.PIPE,
@@ -903,6 +903,7 @@ class MBEDTLSCodeParser(CodeParser):
all_macros = {"public": [], "internal": [], "private":[]}
all_macros["public"] = self.parse_macros([
"include/mbedtls/*.h",
"include/mbedtls/private/*.h",
])
all_macros["internal"] = self.parse_macros([
"library/*.h",
@@ -913,15 +914,18 @@ class MBEDTLSCodeParser(CodeParser):
])
enum_consts = self.parse_enum_consts([
"include/mbedtls/*.h",
"include/mbedtls/private/*.h",
"library/*.h",
"library/*.c",
])
identifiers, excluded_identifiers = self.parse_identifiers([
"include/mbedtls/*.h",
"include/mbedtls/private/*.h",
"library/*.h",
])
mbed_psa_words = self.parse_mbed_psa_words([
"include/mbedtls/*.h",
"include/mbedtls/private/*.h",
"library/*.h",
"library/*.c",
])
@@ -967,15 +971,17 @@ class MBEDTLSCodeParser(CodeParser):
)
my_environment = os.environ.copy()
my_environment["CFLAGS"] = "-fno-asynchronous-unwind-tables"
# Run make clean separately to lib to prevent unwanted behavior when
# make is invoked with parallelism.
source_dir = os.getcwd()
build_dir = tempfile.mkdtemp()
os.chdir(build_dir)
subprocess.run(
["make", "clean"],
["cmake", "-DGEN_FILES=ON", source_dir],
universal_newlines=True,
check=True
)
subprocess.run(
["make", "lib"],
["cmake", "--build", "."],
env=my_environment,
universal_newlines=True,
stdout=subprocess.PIPE,
@@ -984,17 +990,21 @@ class MBEDTLSCodeParser(CodeParser):
)
# Perform object file analysis using nm
symbols = self.parse_symbols_from_nm([
"library/libmbedcrypto.a",
"library/libmbedtls.a",
"library/libmbedx509.a"
])
if build_tree.is_mbedtls_3_6():
symbols = self.parse_symbols_from_nm([
"library/libmbedcrypto.a",
"library/libmbedtls.a",
"library/libmbedx509.a"
])
else:
symbols = self.parse_symbols_from_nm([
"library/libtfpsacrypto.a",
"library/libmbedtls.a",
"library/libmbedx509.a"
])
subprocess.run(
["make", "clean"],
universal_newlines=True,
check=True
)
os.chdir(source_dir)
shutil.rmtree(build_dir)
except subprocess.CalledProcessError as error:
self.log.debug(error.output)
raise error
+1 -1
View File
@@ -30,7 +30,7 @@ if grep -E "(warning|error):" doc.filtered; then
exit 1;
fi
if in_mbedtls_repo; then
if in_mbedtls_repo && in_3_6_branch; then
make apidoc_clean
fi
+7 -3
View File
@@ -10,7 +10,7 @@ from typing import Iterator, List, Tuple
import re
import argparse
from mbedtls_framework.asymmetric_key_data import ASYMMETRIC_KEY_DATA
from mbedtls_framework.build_tree import guess_project_root
from mbedtls_framework import build_tree
BYTES_PER_LINE = 16
@@ -49,7 +49,6 @@ def get_ec_key_family(key: str) -> str:
EC_NAME_CONVERSION = {
'PSA_ECC_FAMILY_SECP_K1': {
192: ('secp', 'k1'),
224: ('secp', 'k1'),
256: ('secp', 'k1')
},
'PSA_ECC_FAMILY_SECP_R1': {
@@ -168,7 +167,7 @@ def collect_keys() -> Tuple[str, str]:
return ''.join(arrays), '\n'.join(look_up_table)
def main() -> None:
default_output_path = guess_project_root() + "/tests/include/test/test_keys.h"
default_output_path = build_tree.guess_project_root() + "/tests/include/test/test_keys.h"
argparser = argparse.ArgumentParser()
argparser.add_argument("--output", help="Output file", default=default_output_path)
@@ -176,6 +175,11 @@ def main() -> None:
output_file = args.output
# Support for 224 bit EC curves (secp224r1 and secp224k1) was removed from
# tf-psa-crypto. It only remains available for 3.6 LTS branch.
if not build_tree.is_mbedtls_3_6():
del EC_NAME_CONVERSION['PSA_ECC_FAMILY_SECP_R1'][224]
arrays, look_up_table = collect_keys()
write_output_file(output_file, arrays, look_up_table)
+14
View File
@@ -10,6 +10,7 @@ Generate the TF-PSA-Crypto generated files
"""
import argparse
import filecmp
import os
import shutil
import subprocess
import sys
@@ -66,6 +67,18 @@ def get_generation_script_files(generation_script: str):
return files
COMMON_GENERATION_SCRIPTS = [
]
# Once the script has been added to both Mbed TLS and TF-PSA-Crypto,
# we can include this unconditionally.
# https://github.com/Mbed-TLS/mbedtls/issues/10305
if os.path.exists("scripts/generate_config_checks.py"):
COMMON_GENERATION_SCRIPTS.append(GenerationScript(
Path("scripts/generate_config_checks.py"),
get_generation_script_files("scripts/generate_config_checks.py"),
"", None))
if build_tree.looks_like_tf_psa_crypto_root("."):
TF_PSA_CRYPTO_GENERATION_SCRIPTS = [
GenerationScript(
@@ -244,6 +257,7 @@ def main():
generation_scripts = MBEDTLS_GENERATION_SCRIPTS
else:
raise Exception("No support for Mbed TLS 3.6")
generation_scripts += COMMON_GENERATION_SCRIPTS
if args.list:
files = get_generated_files(generation_scripts)
@@ -0,0 +1,228 @@
"""Generate C preprocessor code to check for bad configurations.
The headers are meant to be included in a specific way in PROJECT_config.c.
See framework/docs/architecture/config-check-framework.md for information.
"""
## Copyright The Mbed TLS Contributors
## SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
import argparse
import enum
import os
import re
import sys
import textwrap
import typing
from typing import Iterator, List
from . import build_tree
from . import typing_util
class Position(enum.Enum):
BEFORE = 0 # Before build_info.h
USER = 1 # Just after reading PROJECT_CONFIG_FILE (*config.h) and PROJECT_USER_CONFIG_FILE
FINAL = 2 # After *adjust*.h and the rest of build_info.h
class Checker:
"""Description of checks for one option.
By default, this class triggers an error if the option is set after
reading the user configuration. To change the behavior, override
the methods `before`, `user` and `final` as needed.
"""
def __init__(self, name: str, suggestion: str = '') -> None:
"""Construct a checker for the given preprocessor macro name.
If suggestion is given, it is appended to the error message.
It should be a short sentence intended for human readers.
This sentence follows a sentence like "<macro_name> is not
a valid configuration option".
"""
self.name = name
self.suggestion = suggestion
def _basic_message(self) -> str:
"""The first sentence of the message to display on error.
It should end with a full stop or other sentence-ending punctuation.
"""
return f'{self.name} is not a valid configuration option.'
def message(self) -> str:
"""The message to display on error."""
message = self._basic_message()
if self.suggestion:
message += ' Suggestion: ' + self.suggestion
return message
def _quoted_message(self) -> str:
"""Quote message() in double quotes. Useful for #error directives."""
return ('"' +
str.replace(str.replace(self.message(),
'\\', '\\\\'),
'"', '\\"') +
'"')
def before(self, _prefix: str) -> str:
"""C code to inject before including the config."""
#pylint: disable=no-self-use
# Derived classes will add content where needed.
return ''
def user(self, _prefix: str) -> str:
"""C code to inject immediately after including the user config."""
return f'''
#if defined({self.name})
# error {self._quoted_message()}
#endif
'''
def final(self, _prefix: str) -> str:
"""C code to inject after finalizing the config."""
#pylint: disable=no-self-use
# Derived classes will add content where needed.
return ''
def code(self, position: Position, prefix: str) -> str:
"""C code to inject at the given position.
Use the given prefix for auxiliary macro names.
"""
methods = {
Position.BEFORE: self.before,
Position.USER: self.user,
Position.FINAL: self.final,
}
method = methods[position]
snippet = method(prefix)
return textwrap.dedent(snippet)
class Internal(Checker):
"""Checker for an internal-only option."""
class Removed(Checker):
"""Checker for an option that has been removed."""
def __init__(self, name: str, version: str, suggestion: str = '') -> None:
super().__init__(name, suggestion)
self.version = version
def _basic_message(self) -> str:
"""The first sentence of the message to display on error.
It should end with a full stop or other sentence-ending punctuation.
"""
return f'{self.name} was removed in {self.version}.'
def user(self, prefix: str) -> str:
"""C code to inject immediately after including the user config."""
# A removed option is forbidden, just like an internal option.
# But since we're checking a macro that is not defined anywhere,
# we need to tell check_names.py that this is a false positive.
code = super().user(prefix)
return re.sub(rf'^ *# *\w+.*\b{self.name}\b.*$',
lambda m: m.group(0) + ' //no-check-names',
code, flags=re.M)
class BranchData(typing.NamedTuple):
"""The relevant aspects of the configuration on a branch."""
# Subdirectory where the generated headers will be located.
header_directory: str
# Prefix used for the generated headers' basename.
header_prefix: str
# Prefix used for C preprocessor macros.
project_cpp_prefix: str
# Options to check
checkers: List[Checker]
class HeaderGenerator:
"""Generate a header to include before or after the user config."""
def __init__(self, branch_data: BranchData, position: Position) -> None:
self.branch_data = branch_data
self.position = position
self.prefix = branch_data.project_cpp_prefix + '_CONFIG_CHECK'
self.bypass_checks = self.prefix + '_BYPASS'
def write_stanza(self, out: typing_util.Writable, checker: Checker) -> None:
"""Write the part of the output corresponding to one config option."""
code = checker.code(self.position, self.prefix)
out.write(code)
def write_content(self, out: typing_util.Writable) -> None:
"""Write the output for all config options to be processed."""
for checker in self.branch_data.checkers:
self.write_stanza(out, checker)
def output_file_name(self) -> str:
"""The base name of the output file."""
return ''.join([self.branch_data.header_prefix,
'config_check_',
self.position.name.lower(),
'.h'])
def write(self, directory: str) -> None:
"""Write the whole output file."""
basename = self.output_file_name()
with open(os.path.join(directory, basename), 'w') as out:
out.write(f'''\
/* {basename} (generated part of {self.branch_data.header_prefix}config.c). */
/* Automatically generated by {os.path.basename(sys.argv[0])}. Do not edit! */
#if !defined({self.bypass_checks}) //no-check-names
/* *INDENT-OFF* */
''')
self.write_content(out)
out.write(f'''
/* *INDENT-ON* */
#endif /* !defined({self.bypass_checks}) */ //no-check-names
/* End of automatically generated {basename} */
''')
def generate_header_files(branch_data: BranchData,
directory: str,
list_only: bool = False) -> Iterator[str]:
"""Generate the header files to include before and after *config.h."""
for position in Position:
generator = HeaderGenerator(branch_data, position)
yield os.path.join(directory, generator.output_file_name())
if not list_only:
generator.write(directory)
def main(branch_data: BranchData) -> None:
root = build_tree.guess_project_root()
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('--list', action='store_true',
help='List generated files and exit')
parser.add_argument('--list-for-cmake', action='store_true',
help='List generated files in CMake-friendly format and exit')
parser.add_argument('output_directory', metavar='DIR', nargs='?',
default=os.path.join(root, branch_data.header_directory),
help='output file location (default: %(default)s)')
options = parser.parse_args()
list_only = options.list or options.list_for_cmake
output_files = list(generate_header_files(branch_data,
options.output_directory,
list_only=list_only))
if options.list_for_cmake:
sys.stdout.write(';'.join(output_files))
elif options.list:
for filename in output_files:
print(filename)
+7 -2
View File
@@ -7,6 +7,7 @@ from typing import List
from . import test_data_generation
from . import bignum_common
from . import build_tree
class EcpTarget(test_data_generation.BaseTarget):
@@ -164,7 +165,9 @@ class EcpP224R1Raw(bignum_common.ModOperationCommon,
@property
def is_valid(self) -> bool:
return True
# secp224r1 support has been removed from development, but it's stil
# available in 3.6 branch.
return build_tree.is_mbedtls_3_6()
def arguments(self)-> List[str]:
args = super().arguments()
@@ -624,7 +627,9 @@ class EcpP224K1Raw(bignum_common.ModOperationCommon,
@property
def is_valid(self) -> bool:
return True
# secp224k1 support has been removed from development, but it's stil
# available in 3.6 branch.
return build_tree.is_mbedtls_3_6()
def arguments(self):
args = super().arguments()
+14 -5
View File
@@ -26,13 +26,13 @@ from mbedtls_framework import build_tree
# The test numbers correspond to the numbers used by the console output of the test suite.
# Test number 2xx corresponds to the files in the folder
# psa-arch-tests/api-tests/dev_apis/crypto/test_c0xx
EXPECTED_FAILURES = {} # type: dict
EXPECTED_FAILURES = [] # type: List[int]
PSA_ARCH_TESTS_REPO = 'https://github.com/ARM-software/psa-arch-tests.git'
PSA_ARCH_TESTS_REF = 'v23.06_API1.5_ADAC_EAC'
#pylint: disable=too-many-branches,too-many-statements,too-many-locals
def main(library_build_dir: str):
def main(library_build_dir: str, expected_failures: List[int]):
root_dir = os.getcwd()
install_dir = Path(library_build_dir + "/install_dir").resolve()
tmp_env = os.environ
@@ -87,8 +87,8 @@ def main(library_build_dir: str):
'^TEST RESULT: (?P<test_result>FAILED|PASSED)'
)
test = -1
unexpected_successes = set(EXPECTED_FAILURES)
expected_failures = [] # type: List[int]
unexpected_successes = expected_failures.copy()
expected_failures.clear()
unexpected_failures = [] # type: List[int]
if proc.stdout is None:
return 1
@@ -141,9 +141,18 @@ if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('--build-dir', nargs=1,
help='path to Mbed TLS / TF-PSA-Crypto build directory')
parser.add_argument('--expected-failures', nargs='+',
help='''set the list of test codes which are expected to fail
from the command line. If omitted the list given by
EXPECTED_FAILURES (inside the script) is used.''')
args = parser.parse_args()
if args.build_dir is not None:
BUILD_DIR = args.build_dir[0]
sys.exit(main(BUILD_DIR))
if args.expected_failures is not None:
expected_failures_list = [int(i) for i in args.expected_failures]
else:
expected_failures_list = EXPECTED_FAILURES
sys.exit(main(BUILD_DIR, expected_failures_list))