Merge commit 'a39ba59344fd4f1d0ee267ca414b9420d5dca9f5' into mbedtls_test_psa_raw_key_agreement_with_self-iop-consistency-framework

This commit is contained in:
Gilles Peskine
2025-04-16 15:58:52 +02:00
29 changed files with 2505 additions and 226 deletions
+3 -3
View File
@@ -8,9 +8,9 @@ Please write a few sentences describing the overall goals of the pull request's
Please add the numbers (or links) of the associated pull requests for consuming branches. You can omit branches where this pull request is not needed.
- [ ] **crypto PR** Mbed-TLS/TF-PSA-Crypto#
- [ ] **development PR** Mbed-TLS/mbedtls#
- [ ] **3.6 PR** Mbed-TLS/mbedtls#
- [ ] **TF-PSA-Crypto PR** provided # | not required because:
- [ ] **development PR** provided # | not required because:
- [ ] **3.6 PR** provided # | not required because:
+15 -12
View File
@@ -67,15 +67,15 @@ helper_libtestdriver1_adjust_config() {
scripts/config.py "$base_config"
fi
# Enable PSA-based config (necessary to use drivers)
# MBEDTLS_PSA_CRYPTO_CONFIG is a legacy setting which should only be set on 3.6 LTS branches.
if in_mbedtls_repo && in_3_6_branch; then
# Enable PSA-based config (necessary to use drivers)
# MBEDTLS_PSA_CRYPTO_CONFIG is a legacy setting which should only be set on 3.6 LTS branches.
scripts/config.py set MBEDTLS_PSA_CRYPTO_CONFIG
fi
# Dynamic secure element support is a deprecated feature and needs to be disabled here.
# This is done to have the same form of psa_key_attributes_s for libdriver and library.
scripts/config.py unset MBEDTLS_PSA_CRYPTO_SE_C
# Dynamic secure element support is a deprecated feature and needs to be disabled here.
# This is done to have the same form of psa_key_attributes_s for libdriver and library.
scripts/config.py unset MBEDTLS_PSA_CRYPTO_SE_C
fi
# If threading is enabled on the normal build, then we need to enable it in the drivers as well,
# otherwise we will end up running multithreaded tests without mutexes to protect them.
@@ -139,12 +139,13 @@ helper_psasim_config() {
scripts/config.py full
scripts/config.py unset MBEDTLS_PSA_CRYPTO_C
scripts/config.py unset MBEDTLS_PSA_CRYPTO_STORAGE_C
# Dynamic secure element support is a deprecated feature and it is not
# available when CRYPTO_C and PSA_CRYPTO_STORAGE_C are disabled.
scripts/config.py unset MBEDTLS_PSA_CRYPTO_SE_C
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.
scripts/config.py unset MBEDTLS_PSA_CRYPTO_SE_C
fi
# Disable potentially problematic features
scripts/config.py unset MBEDTLS_X509_RSASSA_PSS_SUPPORT
scripts/config.py unset MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED
scripts/config.py unset MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED
scripts/config.py unset MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED
scripts/config.py unset MBEDTLS_ECP_RESTARTABLE
@@ -152,8 +153,10 @@ helper_psasim_config() {
else
scripts/config.py crypto_full
scripts/config.py unset MBEDTLS_PSA_CRYPTO_BUILTIN_KEYS
# We need to match the client with MBEDTLS_PSA_CRYPTO_SE_C
scripts/config.py unset MBEDTLS_PSA_CRYPTO_SE_C
if in_mbedtls_repo && in_3_6_branch; then
# We need to match the client with MBEDTLS_PSA_CRYPTO_SE_C
scripts/config.py unset MBEDTLS_PSA_CRYPTO_SE_C
fi
# Also ensure MBEDTLS_PSA_CRYPTO_KEY_ID_ENCODES_OWNER not set (to match client)
scripts/config.py unset MBEDTLS_PSA_CRYPTO_KEY_ID_ENCODES_OWNER
fi
+40 -9
View File
@@ -12,17 +12,48 @@
set -eu
CONFIG_H='include/mbedtls/mbedtls_config.h'
. $(dirname "$0")/project_detection.sh
if [ -r $CONFIG_H ]; then :; else
echo "$CONFIG_H not found" >&2
exit 1
if in_mbedtls_repo; then
CONFIG_H='include/mbedtls/mbedtls_config.h'
if [ -r $CONFIG_H ]; then :; else
echo "$CONFIG_H not found" >&2
fi
if ! in_3_6_branch; then
CRYPTO_CONFIG_H='tf-psa-crypto/include/psa/crypto_config.h'
fi
fi
CONFIG_BAK=${CONFIG_H}.bak
cp -p $CONFIG_H $CONFIG_BAK
if in_tf_psa_crypto_repo; then
CRYPTO_CONFIG_H='include/psa/crypto_config.h'
fi
scripts/config.py realfull
make apidoc
if in_tf_psa_crypto_repo || (in_mbedtls_repo && ! in_3_6_branch); then
if [ -r $CRYPTO_CONFIG_H ]; then :; else
echo "$CRYPTO_CONFIG_H not found" >&2
exit 1
fi
CRYPTO_CONFIG_BAK=${CRYPTO_CONFIG_H}.bak
cp -p $CRYPTO_CONFIG_H $CRYPTO_CONFIG_BAK
fi
mv $CONFIG_BAK $CONFIG_H
if in_mbedtls_repo; then
CONFIG_BAK=${CONFIG_H}.bak
cp -p $CONFIG_H $CONFIG_BAK
scripts/config.py realfull
make apidoc
mv $CONFIG_BAK $CONFIG_H
elif in_tf_psa_crypto_repo; then
scripts/config.py realfull
TF_PSA_CRYPTO_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
fi
if in_tf_psa_crypto_repo || (in_mbedtls_repo && ! in_3_6_branch); then
mv $CRYPTO_CONFIG_BAK $CRYPTO_CONFIG_H
fi
+15 -6
View File
@@ -16,7 +16,10 @@ use strict;
use File::Basename;
# C/header files in the following directories will be checked
my @directories = qw(include/mbedtls library doxygen/input);
my @mbedtls_directories = qw(include/mbedtls library doxygen/input);
my @tf_psa_crypto_directories = qw(include/psa include/tf-psa-crypto
drivers/builtin/include/mbedtls
drivers/builtin/src core doxygen/input);
# very naive pattern to find directives:
# everything with a backslach except '\0' and backslash at EOL
@@ -53,13 +56,19 @@ sub check_dir {
}
}
open my $project_file, "scripts/project_name.txt" or die "This script must be run from Mbed TLS or TF-PSA-Crypto root directory";
my $project = <$project_file>;
chomp($project);
my @directories;
if ($project eq "TF-PSA-Crypto") {
@directories = @tf_psa_crypto_directories
} elsif ($project eq "Mbed TLS") {
@directories = @mbedtls_directories
}
# Check that the script is being run from the project's root directory.
for my $dir (@directories) {
if (! -d $dir) {
die "This script must be run from the Mbed TLS root directory";
} else {
check_dir($dir)
}
check_dir($dir)
}
exit $exit_code;
+1 -1
View File
@@ -38,7 +38,7 @@ can_pylint () {
can_mypy () {
# mypy 0.770 is too old:
# tests/scripts/test_psa_constant_names.py:34: error: Cannot find implementation or library stub for module named 'mbedtls_framework'
# framework/scripts/test_psa_constant_names.py:34: error: Cannot find implementation or library stub for module named 'mbedtls_framework'
# mypy 0.780 from pip passed on the first commit containing this line.
check_version mypy.version 0.780
}
+322 -156
View File
@@ -8,12 +8,14 @@ This script confirms that the naming of all symbols and identifiers in Mbed TLS
are consistent with the house style and are also self-consistent. It only runs
on Linux and macOS since it depends on nm.
It contains two major Python classes, CodeParser and NameChecker. They both have
a comprehensive "run-all" function (comprehensive_parse() and perform_checks())
but the individual functions can also be used for specific needs.
It contains three major Python classes, TFPSACryptoCodeParser,
MBEDTLSCodeParser and NameChecker. They all have a comprehensive "run-all"
function (comprehensive_parse() and perform_checks()) but the individual
functions can also be used for specific needs.
CodeParser makes heavy use of regular expressions to parse the code, and is
dependent on the current code formatting. Many Python C parser libraries require
CodeParser(a inherent base class for TFPSACryptoCodeParser and MBEDTLSCodeParser)
makes heavy use of regular expressions to parse the code, and is dependent on
the current code formatting. Many Python C parser libraries require
preprocessed C code, which means no macro parsing. Compiler tools are also not
very helpful when we want the exact location in the original source (which
becomes impossible when e.g. comments are stripped).
@@ -43,6 +45,7 @@ import enum
import shutil
import subprocess
import logging
import tempfile
import project_scripts # pylint: disable=unused-import
from mbedtls_framework import build_tree
@@ -212,7 +215,8 @@ class CodeParser():
"""
def __init__(self, log):
self.log = log
build_tree.check_repo_path()
if not build_tree.looks_like_root(os.getcwd()):
raise Exception("This script must be run from Mbed TLS or TF-PSA-Crypto root")
# Memo for storing "glob expression": set(filepaths)
self.files = {}
@@ -221,126 +225,21 @@ class CodeParser():
# Note that "*" can match directory separators in exclude lists.
self.excluded_files = ["*/bn_mul", "*/compat-2.x.h"]
def comprehensive_parse(self):
def _parse(self, all_macros, enum_consts, identifiers,
excluded_identifiers, mbed_psa_words, symbols):
# pylint: disable=too-many-arguments
"""
Comprehensive ("default") function to call each parsing function and
retrieve various elements of the code, together with the source location.
Parse macros, enums, identifiers, excluded identifiers, Mbed PSA word and Symbols.
Returns a dict of parsed item key to the corresponding List of Matches.
"""
self.log.info("Parsing source code...")
self.log.debug(
"The following files are excluded from the search: {}"
.format(str(self.excluded_files))
)
all_macros = {"public": [], "internal": [], "private":[]}
if build_tree.is_mbedtls_3_6():
all_macros["public"] = self.parse_macros([
"include/mbedtls/*.h",
"include/psa/*.h",
"3rdparty/everest/include/everest/everest.h",
"3rdparty/everest/include/everest/x25519.h"
])
all_macros["internal"] = self.parse_macros([
"library/*.h",
"framework/tests/include/test/drivers/*.h",
])
all_macros["private"] = self.parse_macros([
"library/*.c",
])
enum_consts = self.parse_enum_consts([
"include/mbedtls/*.h",
"include/psa/*.h",
"library/*.h",
"library/*.c",
"3rdparty/everest/include/everest/everest.h",
"3rdparty/everest/include/everest/x25519.h"
])
identifiers, excluded_identifiers = self.parse_identifiers([
"include/mbedtls/*.h",
"include/psa/*.h",
"library/*.h",
"3rdparty/everest/include/everest/everest.h",
"3rdparty/everest/include/everest/x25519.h"
], ["3rdparty/p256-m/p256-m/p256-m.h"])
mbed_psa_words = self.parse_mbed_psa_words([
"include/mbedtls/*.h",
"include/psa/*.h",
"library/*.h",
"3rdparty/everest/include/everest/everest.h",
"3rdparty/everest/include/everest/x25519.h",
"library/*.c",
"3rdparty/everest/library/everest.c",
"3rdparty/everest/library/x25519.c"
], ["library/psa_crypto_driver_wrappers.h"])
else:
all_macros["public"] = self.parse_macros([
"include/mbedtls/*.h",
"include/psa/*.h",
"tf-psa-crypto/include/psa/*.h",
"tf-psa-crypto/include/tf-psa-crypto/*.h",
"tf-psa-crypto/drivers/builtin/include/mbedtls/*.h",
"tf-psa-crypto/drivers/everest/include/everest/everest.h",
"tf-psa-crypto/drivers/everest/include/everest/x25519.h"
])
all_macros["internal"] = self.parse_macros([
"library/*.h",
"tf-psa-crypto/core/*.h",
"tf-psa-crypto/drivers/builtin/src/*.h",
"framework/tests/include/test/drivers/*.h",
])
all_macros["private"] = self.parse_macros([
"library/*.c",
"tf-psa-crypto/core/*.c",
"tf-psa-crypto/drivers/builtin/src/*.c",
])
enum_consts = self.parse_enum_consts([
"include/mbedtls/*.h",
"include/psa/*.h",
"tf-psa-crypto/include/psa/*.h",
"tf-psa-crypto/include/tf-psa-crypto/*.h",
"tf-psa-crypto/drivers/builtin/include/mbedtls/*.h",
"library/*.h",
"tf-psa-crypto/core/*.h",
"tf-psa-crypto/drivers/builtin/src/*.h",
"library/*.c",
"tf-psa-crypto/core/*.c",
"tf-psa-crypto/drivers/builtin/src/*.c",
"tf-psa-crypto/drivers/everest/include/everest/everest.h",
"tf-psa-crypto/drivers/everest/include/everest/x25519.h"
])
identifiers, excluded_identifiers = self.parse_identifiers([
"include/mbedtls/*.h",
"include/psa/*.h",
"tf-psa-crypto/include/psa/*.h",
"tf-psa-crypto/include/tf-psa-crypto/*.h",
"tf-psa-crypto/drivers/builtin/include/mbedtls/*.h",
"library/*.h",
"tf-psa-crypto/core/*.h",
"tf-psa-crypto/drivers/builtin/src/*.h",
"tf-psa-crypto/drivers/everest/include/everest/everest.h",
"tf-psa-crypto/drivers/everest/include/everest/x25519.h"
], ["tf-psa-crypto/drivers/p256-m/p256-m/p256-m.h"])
mbed_psa_words = self.parse_mbed_psa_words([
"include/mbedtls/*.h",
"include/psa/*.h",
"tf-psa-crypto/include/psa/*.h",
"tf-psa-crypto/include/tf-psa-crypto/*.h",
"tf-psa-crypto/drivers/builtin/include/mbedtls/*.h",
"library/*.h",
"tf-psa-crypto/core/*.h",
"tf-psa-crypto/drivers/builtin/src/*.h",
"tf-psa-crypto/drivers/everest/include/everest/everest.h",
"tf-psa-crypto/drivers/everest/include/everest/x25519.h",
"library/*.c",
"tf-psa-crypto/core/*.c",
"tf-psa-crypto/drivers/builtin/src/*.c",
"tf-psa-crypto/drivers/everest/library/everest.c",
"tf-psa-crypto/drivers/everest/library/x25519.c"
], ["tf-psa-crypto/core/psa_crypto_driver_wrappers.h"])
symbols = self.parse_symbols()
# Remove identifier macros like mbedtls_printf or mbedtls_calloc
identifiers_justname = [x.name for x in identifiers]
actual_macros = {"public": [], "internal": []}
@@ -725,6 +624,304 @@ class CodeParser():
return (included_identifiers, excluded_identifiers)
def parse_symbols(self):
"""
Compile a library, and parse the object files using nm to retrieve the
list of referenced symbols. Exceptions thrown here are rethrown because
they would be critical errors that void several tests, and thus needs
to halt the program. This is explicitly done for clarity.
Returns a List of unique symbols defined and used in the libraries.
"""
raise NotImplementedError("parse_symbols must be implemented by a code parser")
def comprehensive_parse(self):
"""
(Must be defined as a class method)
Comprehensive ("default") function to call each parsing function and
retrieve various elements of the code, together with the source location.
Returns a dict of parsed item key to the corresponding List of Matches.
"""
raise NotImplementedError("comprehension_parse must be implemented by a code parser")
def parse_symbols_from_nm(self, object_files):
"""
Run nm to retrieve the list of referenced symbols in each object file.
Does not return the position data since it is of no use.
Args:
* object_files: a List of compiled object filepaths to search through.
Returns a List of unique symbols defined and used in any of the object
files.
"""
nm_undefined_regex = re.compile(r"^\S+: +U |^$|^\S+:$")
nm_valid_regex = re.compile(r"^\S+( [0-9A-Fa-f]+)* . _*(?P<symbol>\w+)")
exclusions = ("FStar", "Hacl")
symbols = []
# Gather all outputs of nm
nm_output = ""
for lib in object_files:
nm_output += subprocess.run(
["nm", "-og", lib],
universal_newlines=True,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
check=True
).stdout
for line in nm_output.splitlines():
if not nm_undefined_regex.search(line):
symbol = nm_valid_regex.search(line)
if (symbol and not symbol.group("symbol").startswith(exclusions)):
symbols.append(symbol.group("symbol"))
else:
self.log.error(line)
return symbols
class TFPSACryptoCodeParser(CodeParser):
"""
Class for retrieving files and parsing TF-PSA-Crypto code. This can be used
independently of the checks that NameChecker performs.
"""
def __init__(self, log):
super().__init__(log)
if not build_tree.looks_like_tf_psa_crypto_root(os.getcwd()):
raise Exception("This script must be run from TF-PSA-Crypto root.")
def comprehensive_parse(self):
"""
Comprehensive ("default") function to call each parsing function and
retrieve various elements of the code, together with the source location.
Returns a dict of parsed item key to the corresponding List of Matches.
"""
all_macros = {"public": [], "internal": [], "private":[]}
all_macros["public"] = self.parse_macros([
"include/psa/*.h",
"include/tf-psa-crypto/*.h",
"drivers/builtin/include/mbedtls/*.h",
"drivers/everest/include/everest/everest.h",
"drivers/everest/include/everest/x25519.h"
])
all_macros["internal"] = self.parse_macros([
"core/*.h",
"drivers/builtin/src/*.h",
"framework/tests/include/test/drivers/*.h",
])
all_macros["private"] = self.parse_macros([
"core/*.c",
"drivers/builtin/src/*.c",
])
enum_consts = self.parse_enum_consts([
"include/psa/*.h",
"include/tf-psa-crypto/*.h",
"drivers/builtin/include/mbedtls/*.h",
"core/*.h",
"drivers/builtin/src/*.h",
"core/*.c",
"drivers/builtin/src/*.c",
"drivers/everest/include/everest/everest.h",
"drivers/everest/include/everest/x25519.h"
])
identifiers, excluded_identifiers = self.parse_identifiers([
"include/psa/*.h",
"include/tf-psa-crypto/*.h",
"drivers/builtin/include/mbedtls/*.h",
"core/*.h",
"drivers/builtin/src/*.h",
"drivers/everest/include/everest/everest.h",
"drivers/everest/include/everest/x25519.h"
], ["drivers/p256-m/p256-m/p256-m.h"])
mbed_psa_words = self.parse_mbed_psa_words([
"include/psa/*.h",
"include/tf-psa-crypto/*.h",
"drivers/builtin/include/mbedtls/*.h",
"core/*.h",
"drivers/builtin/src/*.h",
"drivers/everest/include/everest/everest.h",
"drivers/everest/include/everest/x25519.h",
"core/*.c",
"drivers/builtin/src/*.c",
"drivers/everest/library/everest.c",
"drivers/everest/library/x25519.c"
], ["core/psa_crypto_driver_wrappers.h"])
symbols = self.parse_symbols()
return self._parse(all_macros, enum_consts, identifiers,
excluded_identifiers, mbed_psa_words, symbols)
def parse_symbols(self):
"""
Compile the TF-PSA-Crypto libraries, and parse the
object files using nm to retrieve the list of referenced symbols.
Exceptions thrown here are rethrown because they would be critical
errors that void several tests, and thus needs to halt the program. This
is explicitly done for clarity.
Returns a List of unique symbols defined and used in the libraries.
"""
self.log.info("Compiling...")
symbols = []
# Back up the config and atomically compile with the full configuration.
shutil.copy(
"include/psa/crypto_config.h",
"include/psa/crypto_config.h.bak"
)
try:
# Use check=True in all subprocess calls so that failures are raised
# as exceptions and logged.
subprocess.run(
["python3", "scripts/config.py", "full"],
universal_newlines=True,
check=True
)
my_environment = os.environ.copy()
my_environment["CFLAGS"] = "-fno-asynchronous-unwind-tables"
source_dir = os.getcwd()
build_dir = tempfile.mkdtemp()
os.chdir(build_dir)
subprocess.run(
["cmake", "-DGEN_FILES=ON", source_dir],
universal_newlines=True,
check=True
)
subprocess.run(
["make"],
env=my_environment,
universal_newlines=True,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
check=True
)
# Perform object file analysis using nm
symbols = self.parse_symbols_from_nm([
build_dir + "/drivers/builtin/libbuiltin.a",
build_dir + "/drivers/p256-m/libp256m.a",
build_dir + "/drivers/everest/libeverest.a",
build_dir + "/core/libtfpsacrypto.a"
])
os.chdir(source_dir)
shutil.rmtree(build_dir)
except subprocess.CalledProcessError as error:
self.log.debug(error.output)
raise error
finally:
# Put back the original config regardless of there being errors.
# Works also for keyboard interrupts.
shutil.move(
"include/psa/crypto_config.h.bak",
"include/psa/crypto_config.h"
)
return symbols
class MBEDTLSCodeParser(CodeParser):
"""
Class for retrieving files and parsing Mbed TLS code. This can be used
independently of the checks that NameChecker performs.
"""
def __init__(self, log):
super().__init__(log)
if not build_tree.looks_like_mbedtls_root(os.getcwd()):
raise Exception("This script must be run from Mbed TLS root.")
def comprehensive_parse(self):
"""
Comprehensive ("default") function to call each parsing function and
retrieve various elements of the code, together with the source location.
Returns a dict of parsed item key to the corresponding List of Matches.
"""
all_macros = {"public": [], "internal": [], "private":[]}
# TF-PSA-Crypto is in the same repo in 3.6 so initalise variable here.
tf_psa_crypto_parse_result = {}
if build_tree.is_mbedtls_3_6():
all_macros["public"] = self.parse_macros([
"include/mbedtls/*.h",
"include/psa/*.h",
"3rdparty/everest/include/everest/everest.h",
"3rdparty/everest/include/everest/x25519.h"
])
all_macros["internal"] = self.parse_macros([
"library/*.h",
"framework/tests/include/test/drivers/*.h",
])
all_macros["private"] = self.parse_macros([
"library/*.c",
])
enum_consts = self.parse_enum_consts([
"include/mbedtls/*.h",
"include/psa/*.h",
"library/*.h",
"library/*.c",
"3rdparty/everest/include/everest/everest.h",
"3rdparty/everest/include/everest/x25519.h"
])
identifiers, excluded_identifiers = self.parse_identifiers([
"include/mbedtls/*.h",
"include/psa/*.h",
"library/*.h",
"3rdparty/everest/include/everest/everest.h",
"3rdparty/everest/include/everest/x25519.h"
], ["3rdparty/p256-m/p256-m/p256-m.h"])
mbed_psa_words = self.parse_mbed_psa_words([
"include/mbedtls/*.h",
"include/psa/*.h",
"library/*.h",
"3rdparty/everest/include/everest/everest.h",
"3rdparty/everest/include/everest/x25519.h",
"library/*.c",
"3rdparty/everest/library/everest.c",
"3rdparty/everest/library/x25519.c"
], ["library/psa_crypto_driver_wrappers.h"])
else:
all_macros = {"public": [], "internal": [], "private":[]}
all_macros["public"] = self.parse_macros([
"include/mbedtls/*.h",
])
all_macros["internal"] = self.parse_macros([
"library/*.h",
"framework/tests/include/test/drivers/*.h",
])
all_macros["private"] = self.parse_macros([
"library/*.c",
])
enum_consts = self.parse_enum_consts([
"include/mbedtls/*.h",
"library/*.h",
"library/*.c",
])
identifiers, excluded_identifiers = self.parse_identifiers([
"include/mbedtls/*.h",
"library/*.h",
])
mbed_psa_words = self.parse_mbed_psa_words([
"include/mbedtls/*.h",
"library/*.h",
"library/*.c",
])
os.chdir("./tf-psa-crypto")
tf_psa_crypto_code_parser = TFPSACryptoCodeParser(self.log)
tf_psa_crypto_parse_result = tf_psa_crypto_code_parser.comprehensive_parse()
os.chdir("../")
symbols = self.parse_symbols()
mbedtls_parse_result = self._parse(all_macros, enum_consts,
identifiers, excluded_identifiers,
mbed_psa_words, symbols)
# Combile results for Mbed TLS and TF-PSA-Crypto
for key in tf_psa_crypto_parse_result:
mbedtls_parse_result[key] += tf_psa_crypto_parse_result[key]
return mbedtls_parse_result
def parse_symbols(self):
"""
Compile the Mbed TLS libraries, and parse the TLS, Crypto, and x509
@@ -794,44 +991,6 @@ class CodeParser():
return symbols
def parse_symbols_from_nm(self, object_files):
"""
Run nm to retrieve the list of referenced symbols in each object file.
Does not return the position data since it is of no use.
Args:
* object_files: a List of compiled object filepaths to search through.
Returns a List of unique symbols defined and used in any of the object
files.
"""
nm_undefined_regex = re.compile(r"^\S+: +U |^$|^\S+:$")
nm_valid_regex = re.compile(r"^\S+( [0-9A-Fa-f]+)* . _*(?P<symbol>\w+)")
exclusions = ("FStar", "Hacl")
symbols = []
# Gather all outputs of nm
nm_output = ""
for lib in object_files:
nm_output += subprocess.run(
["nm", "-og", lib],
universal_newlines=True,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
check=True
).stdout
for line in nm_output.splitlines():
if not nm_undefined_regex.search(line):
symbol = nm_valid_regex.search(line)
if (symbol and not symbol.group("symbol").startswith(exclusions)):
symbols.append(symbol.group("symbol"))
else:
self.log.error(line)
return symbols
class NameChecker():
"""
Representation of the core name checking operation performed by this script.
@@ -1016,8 +1175,15 @@ def main():
log.addHandler(logging.StreamHandler())
try:
code_parser = CodeParser(log)
parse_result = code_parser.comprehensive_parse()
if build_tree.looks_like_tf_psa_crypto_root(os.getcwd()):
tf_psa_crypto_code_parser = TFPSACryptoCodeParser(log)
parse_result = tf_psa_crypto_code_parser.comprehensive_parse()
elif build_tree.looks_like_mbedtls_root(os.getcwd()):
# Mbed TLS uses TF-PSA-Crypto, so we need to parse TF-PSA-Crypto too
mbedtls_code_parser = MBEDTLSCodeParser(log)
parse_result = mbedtls_code_parser.comprehensive_parse()
else:
raise Exception("This script must be run from Mbed TLS or TF-PSA-Crypto root")
except Exception: # pylint: disable=broad-except
traceback.print_exc()
sys.exit(2)
+25 -13
View File
@@ -41,16 +41,29 @@ def list_generated_files() -> FrozenSet[str]:
would conform to the code style, but this would be difficult, especially
with respect to the placement of line breaks in long logical lines.
"""
# Parse check-generated-files.sh to get an up-to-date list of
# generated files. Read the file rather than calling it so that
# this script only depends on Git, Python and uncrustify, and not other
# tools such as sh or grep which might not be available on Windows.
# This introduces a limitation: check-generated-files.sh must have
# the expected format and must list the files explicitly, not through
# wildcards or command substitution.
content = open(CHECK_GENERATED_FILES, encoding="utf-8").read()
checks = re.findall(CHECK_CALL_RE, content)
return frozenset(word for s in checks for word in s.split())
if build_tree.is_mbedtls_3_6():
# Parse check-generated-files.sh to get an up-to-date list of
# generated files. Read the file rather than calling it so that
# this script only depends on Git, Python and uncrustify, and not other
# tools such as sh or grep which might not be available on Windows.
# This introduces a limitation: check-generated-files.sh must have
# the expected format and must list the files explicitly, not through
# wildcards or command substitution.
content = open(CHECK_GENERATED_FILES, encoding="utf-8").read()
checks = re.findall(CHECK_CALL_RE, content)
return frozenset(word for s in checks for word in s.split())
else:
output = subprocess.check_output(["framework/scripts/make_generated_files.py",
"--list"], universal_newlines=True)
# psa_test_wrappers.[hc], generated by generate_psa_wrappers.py, are
# currently committed and unknown to make_generated_files.py. Add them
# here to the list of generated file as we do not want to check their
# coding style.
if build_tree.looks_like_tf_psa_crypto_root("."):
output += "tests/include/test/psa_test_wrappers.h\n"
output += "tests/src/psa_test_wrappers.c"
return frozenset(line for line in output.splitlines())
# Check for comment string indicating an auto-generated file
AUTOGEN_RE = re.compile(r"Warning[ :-]+This file is (now )?auto[ -]?generated",
@@ -72,7 +85,6 @@ def get_src_files(since: Optional[str]) -> List[str]:
"""
file_patterns = ["*.[hc]",
"tests/suites/*.function",
"tf-psa-crypto/tests/suites/*.function",
"scripts/data_files/*.fmt"]
output = subprocess.check_output(["git", "ls-files"] + file_patterns,
universal_newlines=True)
@@ -140,8 +152,8 @@ def get_src_files(since: Optional[str]) -> List[str]:
is_file_autogenerated(filename))]
else:
src_files = [filename for filename in src_files
if not (filename.startswith("tf-psa-crypto/drivers/everest/") or
filename.startswith("tf-psa-crypto/drivers/p256-m/") or
if not (filename.startswith("drivers/everest/") or
filename.startswith("drivers/p256-m/") or
filename in generated_files or
is_file_autogenerated(filename))]
return src_files
+169
View File
@@ -0,0 +1,169 @@
## Common shell functions used by demo scripts programs/*/*.sh.
## How to write a demo script
## ==========================
##
## Include this file near the top of each demo script:
## . "${0%/*}/demo_common.sh"
##
## Start with a "msg" call that explains the purpose of the script.
## Then call the "depends_on" function to ensure that all config
## dependencies are met.
##
## As the last thing in the script, call the cleanup function.
##
## You can use the functions and variables described below.
set -e -u
DEMO_COMMON_NEED_QUERY_COMPILE_TIME_CONFIG=${DEMO_COMMON_NEED_QUERY_COMPILE_TIME_CONFIG:-1}
need_query_compile_time_config () {
if [ $DEMO_COMMON_NEED_QUERY_COMPILE_TIME_CONFIG -eq 1 ]; then
return 0;
else
return 1;
fi
}
## At the end of the while loop below $root_dir will point to the root directory
## of the Mbed TLS or TF-PSA-Crypto source tree.
root_dir="${0%/*}"
## Find a nice path to the root directory, avoiding unnecessary "../".
##
## The code supports demo scripts nested up to 4 levels deep.
##
## The code works no matter where the demo script is relative to the current
## directory, even if it is called with a relative path.
n=5
while true; do
# If we went up too many folders, then give up and return a failure.
if [ $n -eq 0 ]; then
echo >&2 "This doesn't seem to be an Mbed TLS source tree."
exit 125
fi
# If we reached the Mbed TLS root folder then we're done.
if is_mbedtls_root "$root_dir"; then
break;
fi
# If we reached the TF-PSA-Crypto root folder and the script that sourced
# this file does not need query_compile_time_config (which is only available
# in Mbed TLS repo) then we're done.
if is_tf_psa_crypto_root "$root_dir" && ! need_query_compile_time_config; then
break;
fi
n=$((n - 1))
case $root_dir in
.) root_dir="..";;
..|?*/..) root_dir="$root_dir/..";;
?*/*) root_dir="${root_dir%/*}";;
/*) root_dir="/";;
*) root_dir=".";;
esac
done
## msg LINE...
## msg <TEXT_ORIGIN
## Display an informational message.
msg () {
if [ $# -eq 0 ]; then
sed 's/^/# /'
else
for x in "$@"; do
echo "# $x"
done
fi
}
## run "Message" COMMAND ARGUMENT...
## Display the message, then run COMMAND with the specified arguments.
run () {
echo
echo "# $1"
shift
echo "+ $*"
"$@"
}
## Like '!', but stop on failure with 'set -e'
not () {
if "$@"; then false; fi
}
## run_bad "Message" COMMAND ARGUMENT...
## Like run, but the command is expected to fail.
run_bad () {
echo
echo "$1 This must fail."
shift
echo "+ ! $*"
not "$@"
}
## $programs_dir is the directory containing the sample programs.
## Assume an in-tree build.
programs_dir="$root_dir/programs"
## config_has SYMBOL...
## Succeeds if the library configuration has all SYMBOLs set.
##
## Note: "query_compile_time_config" is only available when in Mbed TLS project,
## so "config_has" is not available in TF-PSA-Crypto one. If this function is
## called from the latter we fail immediately.
config_has () {
if ! is_mbedtls_root "$root_dir"; then
return 1;
fi
for x in "$@"; do
"$programs_dir/test/query_compile_time_config" "$x"
done
}
## depends_on SYMBOL...
## Exit if the library configuration does not have all SYMBOLs set.
depends_on () {
m=
for x in "$@"; do
if ! config_has "$x"; then
m="$m $x"
fi
done
if [ -n "$m" ]; then
cat >&2 <<EOF
$0: this demo requires the following
configuration options to be enabled at compile time:
$m
EOF
# Exit with a success status so that this counts as a pass for run_demos.py.
exit
fi
}
## Add the names of files to clean up to this whitespace-separated variable.
## The file names must not contain whitespace characters.
files_to_clean=
## Call this function at the end of each script.
## It is called automatically if the script is killed by a signal.
cleanup () {
rm -f -- $files_to_clean
}
################################################################
## End of the public interfaces. Code beyond this point is not
## meant to be called directly from a demo script.
trap 'cleanup; trap - HUP; kill -HUP $$' HUP
trap 'cleanup; trap - INT; kill -INT $$' INT
trap 'cleanup; trap - TERM; kill -TERM $$' TERM
if config_has MBEDTLS_ENTROPY_NV_SEED; then
# Create a seedfile that's sufficiently long in all library configurations.
# This is necessary for programs that use randomness.
# Assume that the name of the seedfile is the default name.
files_to_clean="$files_to_clean seedfile"
dd if=/dev/urandom of=seedfile ibs=64 obs=64 count=1
fi
+8 -3
View File
@@ -8,8 +8,10 @@
# Abort on errors (and uninitialised variables)
set -eu
if [ -d library -a -d include -a -d tests ]; then :; else
echo "Must be run from Mbed TLS root" >&2
. $(dirname "$0")/project_detection.sh
if in_mbedtls_repo || in_tf_psa_crypto_repo; then :; else
echo "Must be run from Mbed TLS root or TF-PSA-Crypto root" >&2
exit 1
fi
@@ -28,5 +30,8 @@ if grep -E "(warning|error):" doc.filtered; then
exit 1;
fi
make apidoc_clean
if in_mbedtls_repo; then
make apidoc_clean
fi
rm -f doc.out doc.err doc.filtered
+5 -3
View File
@@ -12,6 +12,7 @@ from typing import Iterable, Iterator, List, Optional, Tuple
import project_scripts # pylint: disable=unused-import
import config
from mbedtls_framework import build_tree
from mbedtls_framework import config_common
from mbedtls_framework import test_case
from mbedtls_framework import test_data_generation
@@ -172,9 +173,10 @@ class ConfigTestGenerator(test_data_generation.TestGenerator):
self.targets['test_suite_config.mbedtls_boolean'] = \
lambda: enumerate_boolean_setting_cases(self.mbedtls_config)
if 'CryptoConfig' in config_members:
self.psa_config = config.CryptoConfig()
self.targets['test_suite_config.psa_boolean'] = \
lambda: enumerate_boolean_setting_cases(self.psa_config)
if build_tree.is_mbedtls_3_6():
self.psa_config = config.CryptoConfig()
self.targets['test_suite_config.psa_boolean'] = \
lambda: enumerate_boolean_setting_cases(self.psa_config)
elif 'TFPSACryptoConfig' in config_members:
self.psa_config = config.TFPSACryptoConfig()
self.targets['test_suite_config.psa_boolean'] = \
+1 -1
View File
@@ -54,7 +54,7 @@ INPUT_ARGS = [
def main():
parser = argparse.ArgumentParser()
default_output_path = os.path.join(TESTS_DIR, 'src', 'test_certs.h')
default_output_path = os.path.join(TESTS_DIR, 'include', 'test', 'test_certs.h')
parser.add_argument('--output', type=str, default=default_output_path)
parser.add_argument('--list-dependencies', action='store_true')
args = parser.parse_args()
+1 -1
View File
@@ -168,7 +168,7 @@ def collect_keys() -> Tuple[str, str]:
return ''.join(arrays), '\n'.join(look_up_table)
def main() -> None:
default_output_path = guess_project_root() + "/framework/tests/include/test/test_keys.h"
default_output_path = guess_project_root() + "/tests/include/test/test_keys.h"
argparser = argparse.ArgumentParser()
argparser.add_argument("--output", help="Output file", default=default_output_path)
+219
View File
@@ -0,0 +1,219 @@
#!/usr/bin/env python3
"""
Generate miscellaneous TLS test cases relating to the handshake.
"""
# Copyright The Mbed TLS Contributors
# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
import argparse
import os
import sys
from typing import Optional
from mbedtls_framework import tls_test_case
from mbedtls_framework import typing_util
from mbedtls_framework.tls_test_case import Side, Version
import translate_ciphers
# Assume that a TLS 1.2 ClientHello used in these tests will be at most
# this many bytes long.
TLS12_CLIENT_HELLO_ASSUMED_MAX_LENGTH = 255
# Minimum handshake fragment length that Mbed TLS supports.
TLS_HANDSHAKE_FRAGMENT_MIN_LENGTH = 4
def write_tls_handshake_defragmentation_test(
#pylint: disable=too-many-arguments
out: typing_util.Writable,
side: Side,
length: Optional[int],
version: Optional[Version] = None,
cipher: Optional[str] = None,
etm: Optional[bool] = None, #encrypt-then-mac (only relevant for CBC)
variant: str = ''
) -> None:
"""Generate one TLS handshake defragmentation test.
:param out: file to write to.
:param side: which side is Mbed TLS.
:param length: fragment length, or None to not fragment.
:param version: protocol version, if forced.
"""
#pylint: disable=chained-comparison,too-many-branches,too-many-statements
our_args = ''
their_args = ''
if length is None:
description = 'no fragmentation, for reference'
else:
description = 'len=' + str(length)
if version is not None:
description += ', TLS 1.' + str(version.value)
description = f'Handshake defragmentation on {side.name.lower()}: {description}'
tc = tls_test_case.TestCase(description)
if version is not None:
their_args += ' ' + version.openssl_option()
# Emit a version requirement, because we're forcing the version via
# OpenSSL, not via Mbed TLS, and the automatic depdendencies in
# ssl-opt.sh only handle forcing the version via Mbed TLS.
tc.requirements.append(version.requires_command())
if side == Side.SERVER and version == Version.TLS12 and \
length is not None and \
length <= TLS12_CLIENT_HELLO_ASSUMED_MAX_LENGTH:
# Server-side ClientHello defragmentation is only supported in
# the TLS 1.3 message parser. When that parser sees an 1.2-only
# ClientHello, it forwards the reassembled record to the
# TLS 1.2 ClientHello parser so the ClientHello can be fragmented.
# When TLS 1.3 support is disabled in the server (at compile-time
# or at runtime), the TLS 1.2 ClientHello parser only sees
# the first fragment of the ClientHello.
tc.requirements.append('requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3')
tc.description += ' with 1.3 support'
# To guarantee that the handhake messages are large enough and need to be
# split into fragments, the tests require certificate authentication.
# The party in control of the fragmentation operations is OpenSSL and
# will always use server5.crt (548 Bytes).
if length is not None and \
length >= TLS_HANDSHAKE_FRAGMENT_MIN_LENGTH:
tc.requirements.append('requires_certificate_authentication')
if version == Version.TLS12 and side == Side.CLIENT:
#The server uses an ECDSA cert, so make sure we have a compatible key exchange
tc.requirements.append(
'requires_config_enabled MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED')
else:
# This test case may run in a pure-PSK configuration. OpenSSL doesn't
# allow this by default with TLS 1.3.
their_args += ' -allow_no_dhe_kex'
if length is None:
forbidden_patterns = [
'waiting for more fragments',
]
wanted_patterns = []
elif length < TLS_HANDSHAKE_FRAGMENT_MIN_LENGTH:
their_args += ' -split_send_frag ' + str(length)
tc.exit_code = 1
forbidden_patterns = []
wanted_patterns = [
'handshake message too short: ' + str(length),
'SSL - An invalid SSL record was received',
]
if side == Side.SERVER:
wanted_patterns[0:0] = ['<= parse client hello']
elif version == Version.TLS13:
wanted_patterns[0:0] = ['=> ssl_tls13_process_server_hello']
else:
their_args += ' -split_send_frag ' + str(length)
forbidden_patterns = []
wanted_patterns = [
'reassembled record',
fr'initial handshake fragment: {length}, 0\.\.{length} of [0-9]\+',
fr'subsequent handshake fragment: [0-9]\+, {length}\.\.',
fr'Prepare: waiting for more handshake fragments {length}/',
fr'Consume: waiting for more handshake fragments {length}/',
]
if cipher is not None:
mbedtls_cipher = translate_ciphers.translate_mbedtls(cipher)
if side == Side.CLIENT:
our_args += ' force_ciphersuite=' + mbedtls_cipher
if 'NULL' in cipher:
their_args += ' -cipher ALL@SECLEVEL=0:COMPLEMENTOFALL@SECLEVEL=0'
else:
# For TLS 1.2, when Mbed TLS is the server, we must force the
# cipher suite on the client side, because passing
# force_ciphersuite to ssl_server2 would force a TLS-1.2-only
# server, which does not support a fragmented ClientHello.
tc.requirements.append('requires_ciphersuite_enabled ' + mbedtls_cipher)
their_args += ' -cipher ' + translate_ciphers.translate_ossl(cipher)
if 'NULL' in cipher:
their_args += '@SECLEVEL=0'
if etm is not None:
if etm:
tc.requirements.append('requires_config_enabled MBEDTLS_SSL_ENCRYPT_THEN_MAC')
our_args += ' etm=' + str(int(etm))
(wanted_patterns if etm else forbidden_patterns)[0:0] = [
'using encrypt then mac',
]
tc.description += variant
if side == Side.CLIENT:
tc.client = '$P_CLI debug_level=4' + our_args
tc.server = '$O_NEXT_SRV' + their_args
tc.wanted_client_patterns = wanted_patterns
tc.forbidden_client_patterns = forbidden_patterns
else:
their_args += ' -cert $DATA_FILES_PATH/server5.crt -key $DATA_FILES_PATH/server5.key'
our_args += ' auth_mode=required'
tc.client = '$O_NEXT_CLI' + their_args
tc.server = '$P_SRV debug_level=4' + our_args
tc.wanted_server_patterns = wanted_patterns
tc.forbidden_server_patterns = forbidden_patterns
tc.write(out)
CIPHERS_FOR_TLS12_HANDSHAKE_DEFRAGMENTATION = [
(None, 'default', None),
('TLS_ECDHE_ECDSA_WITH_NULL_SHA', 'null', None),
('TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256', 'ChachaPoly', None),
('TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256', 'GCM', None),
('TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256', 'CBC, etm=n', False),
('TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256', 'CBC, etm=y', True),
]
def write_tls_handshake_defragmentation_tests(out: typing_util.Writable) -> None:
"""Generate TLS handshake defragmentation tests."""
for side in Side.CLIENT, Side.SERVER:
write_tls_handshake_defragmentation_test(out, side, None)
for length in [512, 513, 256, 128, 64, 36, 32, 16, 13, 5, 4, 3]:
write_tls_handshake_defragmentation_test(out, side, length,
Version.TLS13)
if length == 4:
for (cipher_suite, nickname, etm) in \
CIPHERS_FOR_TLS12_HANDSHAKE_DEFRAGMENTATION:
write_tls_handshake_defragmentation_test(
out, side, length, Version.TLS12,
cipher=cipher_suite, etm=etm,
variant=', '+nickname)
else:
write_tls_handshake_defragmentation_test(out, side, length,
Version.TLS12)
def write_handshake_tests(out: typing_util.Writable) -> None:
"""Generate handshake tests."""
out.write(f"""\
# Miscellaneous tests related to the TLS handshake layer.
#
# Automatically generated by {os.path.basename(sys.argv[0])}. Do not edit!
# Copyright The Mbed TLS Contributors
# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
""")
write_tls_handshake_defragmentation_tests(out)
out.write("""\
# End of automatically generated file.
""")
def main() -> None:
"""Command line entry point."""
parser = argparse.ArgumentParser()
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('-o', '--output',
default='tests/opt-testcases/handshake-generated.sh',
help='Output file (default: tests/opt-testcases/handshake-generated.sh)')
args = parser.parse_args()
with open(args.output, 'w') as out:
write_handshake_tests(out)
if __name__ == '__main__':
main()
+258
View File
@@ -0,0 +1,258 @@
#!/usr/bin/env python3
# make_generated_files.py
#
# Copyright The Mbed TLS Contributors
# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
"""
Generate the TF-PSA-Crypto generated files
"""
import argparse
import filecmp
import shutil
import subprocess
import sys
from pathlib import Path
from typing import List, Optional
from mbedtls_framework import build_tree
class GenerationScript:
"""
Representation of a script generating a configuration independent file.
"""
# pylint: disable=too-few-public-methods
def __init__(self, script: Path, files: List[Path],
output_dir_option: Optional[str] = None,
output_file_option: Optional[str] = None):
# Path from the root of Mbed TLS or TF-PSA-Crypto of the generation script
self.script = script
# Executable to run the script, needed for Windows
if script.suffix == ".py":
self.exe = "python"
elif script.suffix == ".pl":
self.exe = "perl"
# List of the default paths from the Mbed TLS or TF-PSA-Crypto root of the
# files the script generates.
self.files = files
# Output directory script argument. Can be an empty string in case it is a
# positional argument.
self.output_dir_option = output_dir_option
# Output file script argument. Can be an empty string in case it is a
# positional argument.
self.output_file_option = output_file_option
def get_generation_script_files(generation_script: str):
"""
Get the list of the default paths of the files that a given script
generates. It is assumed that the script supports the "--list" option.
"""
files = []
if generation_script.endswith(".py"):
cmd = ["python"]
elif generation_script.endswith(".pl"):
cmd = ["perl"]
cmd += [generation_script, "--list"]
output = subprocess.check_output(cmd, universal_newlines=True)
for line in output.splitlines():
files.append(Path(line))
return files
if build_tree.looks_like_tf_psa_crypto_root("."):
TF_PSA_CRYPTO_GENERATION_SCRIPTS = [
GenerationScript(
Path("scripts/generate_driver_wrappers.py"),
[Path("core/psa_crypto_driver_wrappers.h"),
Path("core/psa_crypto_driver_wrappers_no_static.c")],
"", None
),
GenerationScript(
Path("framework/scripts/generate_test_keys.py"),
[Path("tests/include/test/test_keys.h")],
None, "--output"
),
GenerationScript(
Path("scripts/generate_psa_constants.py"),
[Path("programs/psa/psa_constant_names_generated.c")],
"", None
),
GenerationScript(
Path("framework/scripts/generate_bignum_tests.py"),
get_generation_script_files("framework/scripts/generate_bignum_tests.py"),
"--directory", None
),
GenerationScript(
Path("framework/scripts/generate_config_tests.py"),
get_generation_script_files("framework/scripts/generate_config_tests.py"),
"--directory", None
),
GenerationScript(
Path("framework/scripts/generate_ecp_tests.py"),
get_generation_script_files("framework/scripts/generate_ecp_tests.py"),
"--directory", None
),
GenerationScript(
Path("framework/scripts/generate_psa_tests.py"),
get_generation_script_files("framework/scripts/generate_psa_tests.py"),
"--directory", None
),
]
if build_tree.looks_like_mbedtls_root(".") and not build_tree.is_mbedtls_3_6():
MBEDTLS_GENERATION_SCRIPTS = [
GenerationScript(
Path("scripts/generate_errors.pl"),
[Path("library/error.c")],
None, "tf-psa-crypto/drivers/builtin/include/mbedtls \
include/mbedtls/ \
scripts/data_files"
),
GenerationScript(
Path("scripts/generate_features.pl"),
[Path("library/version_features.c")],
None, "include/mbedtls/ scripts/data_files"
),
GenerationScript(
Path("framework/scripts/generate_ssl_debug_helpers.py"),
[Path("library/ssl_debug_helpers_generated.c")],
"", None
),
GenerationScript(
Path("framework/scripts/generate_test_keys.py"),
[Path("tests/include/test/test_keys.h")],
None, "--output"
),
GenerationScript(
Path("framework/scripts/generate_test_cert_macros.py"),
[Path("tests/include/test/test_certs.h")],
None, "--output"
),
GenerationScript(
Path("scripts/generate_query_config.pl"),
[Path("programs/test/query_config.c")],
None, "include/mbedtls/mbedtls_config.h \
tf-psa-crypto/include/psa/crypto_config.h \
scripts/data_files/query_config.fmt"
),
GenerationScript(
Path("framework/scripts/generate_config_tests.py"),
get_generation_script_files("framework/scripts/generate_config_tests.py"),
"--directory", None
),
GenerationScript(
Path("framework/scripts/generate_tls13_compat_tests.py"),
[Path("tests/opt-testcases/tls13-compat.sh")],
None, "--output"
),
GenerationScript(
Path("framework/scripts/generate_tls_handshake_tests.py"),
[Path("tests/opt-testcases/handshake-generated.sh")],
None, "--output"
),
GenerationScript(
Path("scripts/generate_visualc_files.pl"),
get_generation_script_files("scripts/generate_visualc_files.pl"),
"--directory", None
),
]
def get_generated_files(generation_scripts: List[GenerationScript]):
"""
List the generated files in Mbed TLS or TF-PSA-Crypto. The path from root
is returned for each generated files.
"""
files = []
for generation_script in generation_scripts:
files += generation_script.files
return files
def make_generated_files(generation_scripts: List[GenerationScript]):
"""
Generate the configuration independent files in their default location in
the Mbed TLS or TF-PSA-Crypto tree.
"""
for generation_script in generation_scripts:
subprocess.run([generation_script.exe, str(generation_script.script)], check=True)
def check_generated_files(generation_scripts: List[GenerationScript], root: Path):
"""
Check that the given root directory contains the generated files as expected/
generated by this script.
"""
for generation_script in generation_scripts:
for file in generation_script.files:
file = root / file
bak_file = file.with_name(file.name + ".bak")
if bak_file.exists():
bak_file.unlink()
file.rename(bak_file)
command = [generation_script.exe, str(generation_script.script)]
if generation_script.output_dir_option is not None:
command += [generation_script.output_dir_option,
str(root / Path(generation_script.files[0].parent))]
elif generation_script.output_file_option is not None:
command += generation_script.output_file_option.split()
command += [str(root / Path(generation_script.files[0]))]
subprocess.run([item for item in command if item.strip()], check=True)
for file in generation_script.files:
file = root / file
bak_file = file.with_name(file.name + ".bak")
if not filecmp.cmp(file, bak_file):
ref_file = file.with_name(file.name + ".ref")
ref_file = root / ref_file
if ref_file.exists():
ref_file.unlink()
shutil.copy(file, ref_file)
print(f"Generated file {file} not identical to the reference one {ref_file}.")
file.unlink()
bak_file.rename(file)
def main():
"""
Main function of this program
"""
parser = argparse.ArgumentParser()
parser.add_argument('--list', action='store_true',
default=False, help='List generated files.')
parser.add_argument('--root', metavar='DIR',
help='Root of the tree containing the generated files \
to check (default: Mbed TLS or TF-PSA-Cryto root.)')
parser.add_argument('--check', action='store_true',
default=False, help='Check the generated files in root')
args = parser.parse_args()
if not build_tree.looks_like_root("."):
raise RuntimeError("This script must be run from Mbed TLS or TF-PSA-Crypto root.")
if build_tree.looks_like_tf_psa_crypto_root("."):
generation_scripts = TF_PSA_CRYPTO_GENERATION_SCRIPTS
elif not build_tree.is_mbedtls_3_6():
generation_scripts = MBEDTLS_GENERATION_SCRIPTS
else:
raise Exception("No support for Mbed TLS 3.6")
if args.list:
files = get_generated_files(generation_scripts)
for file in files:
print(str(file))
elif args.check:
check_generated_files(generation_scripts, Path(args.root or "."))
else:
make_generated_files(generation_scripts)
if __name__ == "__main__":
sys.exit(main())
+4 -4
View File
@@ -73,10 +73,10 @@ def check_repo_path():
raise Exception("This script must be run from Mbed TLS root")
def chdir_to_root() -> None:
"""Detect the root of the Mbed TLS source tree and change to it.
"""Detect the root of the Mbed TLS or TF-PSA-Crypto source tree and change to it.
The current directory must be up to two levels deep inside an Mbed TLS
source tree.
The current directory must be up to two levels deep inside an Mbed TLS or
TF-PSA-Crypto source tree.
"""
for d in [os.path.curdir,
os.path.pardir,
@@ -84,7 +84,7 @@ def chdir_to_root() -> None:
if looks_like_root(d):
os.chdir(d)
return
raise Exception('Mbed TLS source tree not found')
raise Exception('Mbed TLS or TF-PSA-Crypto source tree not found')
def guess_project_root():
"""Guess project source code directory.
@@ -79,7 +79,7 @@ class PSAWrapper(c_wrapper_generator.Base):
self.out_c_f = out_c_f
self.out_h_f = out_h_f
self.mbedtls_root = build_tree.guess_mbedtls_root()
self.project_root = build_tree.guess_project_root()
self.read_config(config)
self.read_headers(in_headers)
@@ -99,18 +99,19 @@ class PSAWrapper(c_wrapper_generator.Base):
c_parsing_helper.read_function_declarations(self.functions, header_path)
def rel_path(self, filename: str, path_list: List[str] = ['include', 'psa']) -> str:
"""Return the estimated path in relationship to the mbedtls_root.
"""Return the estimated path in relationship to the project_root.
The method allows overriding the targetted sub-directory.
Currently the default is set to mbedtls_root/include/psa."""
Currently the default is set to project_root/include/psa."""
# 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 not build_tree.is_mbedtls_3_6():
if build_tree.looks_like_mbedtls_root(self.project_root) and \
not build_tree.is_mbedtls_3_6():
path_list = ['tf-psa-crypto' ] + path_list
return os.path.join(self.mbedtls_root, *path_list, filename)
return os.path.join(self.project_root, *path_list, filename)
return os.path.join(self.mbedtls_root, *path_list, filename)
return os.path.join(self.project_root, *path_list, filename)
# Utility Methods
@staticmethod
+101
View File
@@ -0,0 +1,101 @@
"""Library for constructing an Mbed TLS ssl-opt test case.
"""
# Copyright The Mbed TLS Contributors
# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
import enum
import re
from typing import List
from . import typing_util
class TestCase:
"""Data about an ssl-opt test case."""
#pylint: disable=too-few-public-methods
def __init__(self, description: str) -> None:
# List of shell snippets to call before run_test, typically
# calls to requires_xxx functions.
self.requirements = [] #type: List[str]
# Test case description (first argument to run_test).
self.description = description
# Client command line.
# This will be placed directly inside double quotes in the shell script.
self.client = '$P_CLI'
# Server command line.
# This will be placed directly inside double quotes in the shell script.
self.server = '$P_SRV'
# Expected client exit code.
self.exit_code = 0
# Note that all patterns matched in the logs are in BRE
# (Basic Regular Expression) syntax, more precisely in the BRE
# dialect that is the default for GNU grep. The main difference
# with Python regular expressions is that the operators for
# grouping `\(...\)`, alternation `x\|y`, option `x\?`,
# one-or-more `x\+` and repetition ranges `x\{M,N\}` must be
# preceded by a backslash. The characters `()|?+{}` stand for
# themselves.
# BRE for text that must be present in the client log (run_test -c).
self.wanted_client_patterns = [] #type: List[str]
# BRE for text that must be present in the server log (run_test -s).
self.wanted_server_patterns = [] #type: List[str]
# BRE for text that must not be present in the client log (run_test -C).
self.forbidden_client_patterns = [] #type: List[str]
# BRE for text that must not be present in the server log (run_test -S).
self.forbidden_server_patterns = [] #type: List[str]
@staticmethod
def _quote(raw: str) -> str:
"""Quote the given string for sh.
Use double quotes, because that's currently the norm in ssl-opt.sh.
"""
return '"' + re.sub(r'([$"\\`])', r'\\\1', raw) + '"'
def write(self, out: typing_util.Writable) -> None:
"""Write the test case to the specified file."""
for req in self.requirements:
out.write(req + '\n')
out.write(f'run_test {self._quote(self.description)} \\\n')
out.write(f' "{self.server}" \\\n')
out.write(f' "{self.client}" \\\n')
out.write(f' {self.exit_code}')
for pat in self.wanted_server_patterns:
out.write(' \\\n -s ' + self._quote(pat))
for pat in self.forbidden_server_patterns:
out.write(' \\\n -S ' + self._quote(pat))
for pat in self.wanted_client_patterns:
out.write(' \\\n -c ' + self._quote(pat))
for pat in self.forbidden_client_patterns:
out.write(' \\\n -C ' + self._quote(pat))
out.write('\n\n')
class Side(enum.Enum):
CLIENT = 0
SERVER = 1
class Version(enum.Enum):
"""TLS protocol version.
This class doesn't know about DTLS yet.
"""
TLS12 = 2
TLS13 = 3
def force_version(self) -> str:
"""Argument to pass to ssl_client2 or ssl_server2 to force this version."""
return f'force_version=tls1{self.value}'
def openssl_option(self) -> str:
"""Option to pass to openssl s_client or openssl s_server to select this version."""
return f'-tls1_{self.value}'
def requires_command(self) -> str:
"""Command to require this protocol version in an ssl-opt.sh test case."""
return 'requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_' + str(self.value)
+61 -7
View File
@@ -9,25 +9,79 @@
# help detect which project (Mbed TLS, TF-PSA-Crypto)
# or which Mbed TLS branch they are in.
# Project detection
# Project detection.
#
# Both Mbed TLS and TF-PSA-Cryto repos have a "scripts/project_name.txt" file
# which contains the name of the project. They are used in scripts to know in
# which project/folder we're in.
# This function accepts 2 parameters:
# - $1: boolean value which defines the behavior in case
# "scripts/project_name.txt" is not found:
# - 1: exit with error message
# - 0: simply return an error
# - $2: mandatory value which defined the root folder where to look for
# "scripts/project_name.txt".
read_project_name_file () {
SCRIPT_DIR=$(pwd)
EXIT_IF_NOT_FOUND=$1
ROOT_PATH=$2
PROJECT_NAME_FILE="scripts/project_name.txt"
if read -r PROJECT_NAME < "$PROJECT_NAME_FILE"; then :; else
echo "$PROJECT_NAME_FILE does not exist... Exiting..." >&2
exit 1
# Check if file exists.
if [ ! -f "$ROOT_PATH/$PROJECT_NAME_FILE" ]; then
if $EXIT_IF_NOT_FOUND ; then
echo "$ROOT_PATH/$PROJECT_NAME_FILE does not exist... Exiting..." >&2
exit 1
fi
# Simply return a failure in case we were asked not to fail in case of
# missing file.
return 1
fi
if read -r PROJECT_NAME < "$ROOT_PATH/$PROJECT_NAME_FILE"; then :; else
return 1
fi
}
# Check if the current folder is the Mbed TLS root one.
#
# Warning: if this is not run from Mbed TLS/TF-PSA-Crypto root folder, the
# script is terminated with a failure.
in_mbedtls_repo () {
read_project_name_file
read_project_name_file true .
test "$PROJECT_NAME" = "Mbed TLS"
}
# Check if the current folder is the TF-PSA-Crypto root one.
#
# Warning: if this is not run from Mbed TLS/TF-PSA-Crypto root folder, the
# script is terminated with a failure.
in_tf_psa_crypto_repo () {
read_project_name_file
read_project_name_file true .
test "$PROJECT_NAME" = "TF-PSA-Crypto"
}
# Check if $1 is an Mbed TLS root folder.
#
# Differently from in_mbedtls_repo() above, this can be run on any folder
# without causing the script to exit.
is_mbedtls_root() {
if ! read_project_name_file false $1 ; then
return 1
fi
test "$PROJECT_NAME" = "Mbed TLS"
}
# Check if $1 is a TF-PSA-Crypto root folder.
#
# Differently from in_tf_psa_crypto_repo() above, this can be run on any folder
# without causing the script to exit.
is_tf_psa_crypto_root() {
if ! read_project_name_file false $1 ; then
return 1
fi
test "$PROJECT_NAME" = "TF-PSA-Crypto"
}
+151
View File
@@ -0,0 +1,151 @@
#!/usr/bin/env python3
"""Run the PSA Crypto API compliance test suite.
Clone the repo and check out the commit specified by PSA_ARCH_TEST_REPO and PSA_ARCH_TEST_REF,
then compile and run the test suite. The clone is stored at <repository root>/psa-arch-tests.
Known defects in either the test suite or mbedtls / TF-PSA-Crypto - identified by their test
number - are ignored, while unexpected failures AND successes are reported as errors, to help
keep the list of known defects as up to date as possible.
"""
# Copyright The Mbed TLS Contributors
# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
import argparse
import os
import re
import shutil
import subprocess
import sys
from typing import List
from pathlib import Path
from mbedtls_framework import build_tree
# PSA Compliance tests we expect to fail due to known defects in Mbed TLS /
# TF-PSA-Crypto (or the test suite).
# 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
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):
root_dir = os.getcwd()
install_dir = Path(library_build_dir + "/install_dir").resolve()
tmp_env = os.environ
tmp_env['CC'] = 'gcc'
subprocess.check_call(['cmake', '.', '-GUnix Makefiles',
'-B' + library_build_dir,
'-DCMAKE_INSTALL_PREFIX=' + str(install_dir)],
env=tmp_env)
subprocess.check_call(['cmake', '--build', library_build_dir, '--target', 'install'])
if build_tree.is_mbedtls_3_6():
libraries_to_link = [str(install_dir.joinpath("lib/libmbedcrypto.a"))]
else:
libraries_to_link = [str(install_dir.joinpath("lib/" + lib))
for lib in ["libtfpsacrypto.a", "libbuiltin.a",
"libp256m.a", "libeverest.a"]]
psa_arch_tests_dir = 'psa-arch-tests'
os.makedirs(psa_arch_tests_dir, exist_ok=True)
try:
os.chdir(psa_arch_tests_dir)
# Reuse existing local clone
subprocess.check_call(['git', 'init'])
subprocess.check_call(['git', 'fetch', PSA_ARCH_TESTS_REPO, PSA_ARCH_TESTS_REF])
subprocess.check_call(['git', 'checkout', 'FETCH_HEAD'])
build_dir = 'api-tests/build'
try:
shutil.rmtree(build_dir)
except FileNotFoundError:
pass
os.mkdir(build_dir)
os.chdir(build_dir)
#pylint: disable=bad-continuation
subprocess.check_call([
'cmake', '..',
'-GUnix Makefiles',
'-DTARGET=tgt_dev_apis_stdc',
'-DTOOLCHAIN=HOST_GCC',
'-DSUITE=CRYPTO',
'-DPSA_CRYPTO_LIB_FILENAME={}'.format(';'.join(libraries_to_link)),
'-DPSA_INCLUDE_PATHS=' + str(install_dir.joinpath("include"))
])
subprocess.check_call(['cmake', '--build', '.'])
proc = subprocess.Popen(['./psa-arch-tests-crypto'],
bufsize=1, stdout=subprocess.PIPE, universal_newlines=True)
test_re = re.compile(
'^TEST: (?P<test_num>[0-9]*)|'
'^TEST RESULT: (?P<test_result>FAILED|PASSED)'
)
test = -1
unexpected_successes = set(EXPECTED_FAILURES)
expected_failures = [] # type: List[int]
unexpected_failures = [] # type: List[int]
if proc.stdout is None:
return 1
for line in proc.stdout:
print(line, end='')
match = test_re.match(line)
if match is not None:
groupdict = match.groupdict()
test_num = groupdict['test_num']
if test_num is not None:
test = int(test_num)
elif groupdict['test_result'] == 'FAILED':
try:
unexpected_successes.remove(test)
expected_failures.append(test)
print('Expected failure, ignoring')
except KeyError:
unexpected_failures.append(test)
print('ERROR: Unexpected failure')
elif test in unexpected_successes:
print('ERROR: Unexpected success')
proc.wait()
print()
print('***** test_psa_compliance.py report ******')
print()
print('Expected failures:', ', '.join(str(i) for i in expected_failures))
print('Unexpected failures:', ', '.join(str(i) for i in unexpected_failures))
print('Unexpected successes:', ', '.join(str(i) for i in sorted(unexpected_successes)))
print()
if unexpected_successes or unexpected_failures:
if unexpected_successes:
print('Unexpected successes encountered.')
print('Please remove the corresponding tests from '
'EXPECTED_FAILURES in tests/scripts/compliance_test.py')
print()
print('FAILED')
return 1
else:
print('SUCCESS')
return 0
finally:
os.chdir(root_dir)
if __name__ == '__main__':
BUILD_DIR = 'out_of_source_build'
# pylint: disable=invalid-name
parser = argparse.ArgumentParser()
parser.add_argument('--build-dir', nargs=1,
help='path to Mbed TLS / TF-PSA-Crypto build directory')
args = parser.parse_args()
if args.build_dir is not None:
BUILD_DIR = args.build_dir[0]
sys.exit(main(BUILD_DIR))
+208
View File
@@ -0,0 +1,208 @@
#!/usr/bin/env python3
"""Test the program psa_constant_names.
Gather constant names from header files and test cases. Compile a C program
to print out their numerical values, feed these numerical values to
psa_constant_names, and check that the output is the original name.
Return 0 if all test cases pass, 1 if the output was not always as expected,
or 1 (with a Python backtrace) if there was an operational error.
"""
# Copyright The Mbed TLS Contributors
# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
import argparse
from collections import namedtuple
import os
import re
import subprocess
import sys
from typing import Iterable, List, Optional, Tuple
from mbedtls_framework import build_tree
from mbedtls_framework import c_build_helper
from mbedtls_framework.macro_collector import InputsForTest, PSAMacroEnumerator
from mbedtls_framework import typing_util
def gather_inputs(headers: Iterable[str],
test_suites: Iterable[str],
inputs_class=InputsForTest) -> PSAMacroEnumerator:
"""Read the list of inputs to test psa_constant_names with."""
inputs = inputs_class()
for header in headers:
inputs.parse_header(header)
for test_cases in test_suites:
inputs.parse_test_cases(test_cases)
inputs.add_numerical_values()
inputs.gather_arguments()
return inputs
def run_c(type_word: str,
expressions: Iterable[str],
include_path: Optional[str] = None,
keep_c: bool = False) -> List[str]:
"""Generate and run a program to print out numerical values of C expressions."""
if type_word == 'status':
cast_to = 'long'
printf_format = '%ld'
else:
cast_to = 'unsigned long'
printf_format = '0x%08lx'
return c_build_helper.get_c_expression_values(
cast_to, printf_format,
expressions,
caller='test_psa_constant_names.py for {} values'.format(type_word),
file_label=type_word,
header='#include <psa/crypto.h>',
include_path=include_path,
keep_c=keep_c
)
NORMALIZE_STRIP_RE = re.compile(r'\s+')
def normalize(expr: str) -> str:
"""Normalize the C expression so as not to care about trivial differences.
Currently "trivial differences" means whitespace.
"""
return re.sub(NORMALIZE_STRIP_RE, '', expr)
ALG_TRUNCATED_TO_SELF_RE = \
re.compile(r'PSA_ALG_AEAD_WITH_SHORTENED_TAG\('
r'PSA_ALG_(?:CCM|CHACHA20_POLY1305|GCM)'
r', *16\)\Z')
def is_simplifiable(expr: str) -> bool:
"""Determine whether an expression is simplifiable.
Simplifiable expressions can't be output in their input form, since
the output will be the simple form. Therefore they must be excluded
from testing.
"""
if ALG_TRUNCATED_TO_SELF_RE.match(expr):
return True
return False
def collect_values(inputs: InputsForTest,
type_word: str,
include_path: Optional[str] = None,
keep_c: bool = False) -> Tuple[List[str], List[str]]:
"""Generate expressions using known macro names and calculate their values.
Return a list of pairs of (expr, value) where expr is an expression and
value is a string representation of its integer value.
"""
names = inputs.get_names(type_word)
expressions = sorted(expr
for expr in inputs.generate_expressions(names)
if not is_simplifiable(expr))
values = run_c(type_word, expressions,
include_path=include_path, keep_c=keep_c)
return expressions, values
class Tests:
"""An object representing tests and their results."""
Error = namedtuple('Error',
['type', 'expression', 'value', 'output'])
def __init__(self, options) -> None:
self.options = options
self.count = 0
self.errors = [] #type: List[Tests.Error]
def run_one(self, inputs: InputsForTest, type_word: str) -> None:
"""Test psa_constant_names for the specified type.
Run the program on the names for this type.
Use the inputs to figure out what arguments to pass to macros that
take arguments.
"""
expressions, values = collect_values(inputs, type_word,
include_path=self.options.include,
keep_c=self.options.keep_c)
output_bytes = subprocess.check_output([self.options.program,
type_word] + values)
output = output_bytes.decode('ascii')
outputs = output.strip().split('\n')
self.count += len(expressions)
for expr, value, output in zip(expressions, values, outputs):
if self.options.show:
sys.stdout.write('{} {}\t{}\n'.format(type_word, value, output))
if normalize(expr) != normalize(output):
self.errors.append(self.Error(type=type_word,
expression=expr,
value=value,
output=output))
def run_all(self, inputs: InputsForTest) -> None:
"""Run psa_constant_names on all the gathered inputs."""
for type_word in ['status', 'algorithm', 'ecc_curve', 'dh_group',
'key_type', 'key_usage']:
self.run_one(inputs, type_word)
def report(self, out: typing_util.Writable) -> None:
"""Describe each case where the output is not as expected.
Write the errors to ``out``.
Also write a total.
"""
for error in self.errors:
out.write('For {} "{}", got "{}" (value: {})\n'
.format(error.type, error.expression,
error.output, error.value))
out.write('{} test cases'.format(self.count))
if self.errors:
out.write(', {} FAIL\n'.format(len(self.errors)))
else:
out.write(' PASS\n')
HEADERS = ['psa/crypto.h', 'psa/crypto_extra.h', 'psa/crypto_values.h']
if build_tree.is_mbedtls_3_6():
TEST_SUITES = ['tests/suites/test_suite_psa_crypto_metadata.data']
else:
TEST_SUITES = ['tf-psa-crypto/tests/suites/test_suite_psa_crypto_metadata.data']
def main():
parser = argparse.ArgumentParser(description=globals()['__doc__'])
if build_tree.is_mbedtls_3_6():
parser.add_argument('--include', '-I',
action='append', default=['include'],
help='Directory for header files')
else:
parser.add_argument('--include', '-I',
action='append', default=['tf-psa-crypto/include',
'tf-psa-crypto/drivers/builtin/include',
'tf-psa-crypto/drivers/everest/include',
'include'],
help='Directory for header files')
parser.add_argument('--keep-c',
action='store_true', dest='keep_c', default=False,
help='Keep the intermediate C file')
parser.add_argument('--no-keep-c',
action='store_false', dest='keep_c',
help='Don\'t keep the intermediate C file (default)')
if build_tree.is_mbedtls_3_6():
parser.add_argument('--program',
default='programs/psa/psa_constant_names',
help='Program to test')
else:
parser.add_argument('--program',
default='tf-psa-crypto/programs/psa/psa_constant_names',
help='Program to test')
parser.add_argument('--show',
action='store_true',
help='Show tested values on stdout')
parser.add_argument('--no-show',
action='store_false', dest='show',
help='Don\'t show tested values (default)')
options = parser.parse_args()
headers = [os.path.join(options.include[0], h) for h in HEADERS]
inputs = gather_inputs(headers, TEST_SUITES)
tests = Tests(options)
tests.run_all(inputs)
tests.report(sys.stdout)
if tests.errors:
sys.exit(1)
if __name__ == '__main__':
main()
+56
View File
@@ -0,0 +1,56 @@
#!/bin/sh
# Run the shared library dynamic loading demo program.
# This is only expected to work when Mbed TLS is built as a shared library.
# Copyright The Mbed TLS Contributors
# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
DEMO_COMMON_NEED_QUERY_COMPILE_TIME_CONFIG=0
SCRIPT_DIR=$(dirname "$0")
. "${SCRIPT_DIR}/../../scripts/project_detection.sh"
. "${SCRIPT_DIR}/../../scripts/demo_common.sh"
msg "Test the dynamic loading of libmbed*"
# Once demo_common.sh is sourced we'll have the following variables set:
# - $root_dir points to the root path of Mbed TLS or TF-PSA-Crypto;
# - $programs_dir points to "$root_dir/programs" folder.
if is_mbedtls_root $root_dir; then
msg "Running in Mbed TLS repo"
program="$programs_dir/test/dlopen"
library_dir="$root_dir/library"
else
msg "Running in TF-PSA-Crypto repo"
program="$root_dir/programs/test/tfpsacrypto_dlopen"
library_dir="$root_dir/core"
fi
# Skip this test if we don't have a shared library build. Detect this
# through the absence of the demo program.
if [ ! -e "$program" ]; then
msg "Error: demo program $program not found."
# Exit with a success status so that this counts as a pass for run_demos.py.
exit
fi
# ELF-based Unix-like (Linux, *BSD, Solaris, ...)
if [ -n "${LD_LIBRARY_PATH-}" ]; then
LD_LIBRARY_PATH="$library_dir:$LD_LIBRARY_PATH"
else
LD_LIBRARY_PATH="$library_dir"
fi
export LD_LIBRARY_PATH
# OSX/macOS
if [ -n "${DYLD_LIBRARY_PATH-}" ]; then
DYLD_LIBRARY_PATH="$library_dir:$DYLD_LIBRARY_PATH"
else
DYLD_LIBRARY_PATH="$library_dir"
fi
export DYLD_LIBRARY_PATH
msg "Running dynamic loading test program: $program"
msg "Loading libraries from: $library_dir"
"$program"
+484
View File
@@ -0,0 +1,484 @@
/** \file metatest.c
*
* \brief Test features of the test framework.
*
* When you run this program, it runs a single "meta-test". A meta-test
* performs an operation which should be caught as a failure by our
* test framework. The meta-test passes if this program calls `exit` with
* a nonzero status, or aborts, or is terminated by a signal, or if the
* framework running the program considers the run an error (this happens
* with Valgrind for a memory leak). The non-success of the meta-test
* program means that the test failure has been caught correctly.
*
* Some failures are purely functional: the logic of the code causes the
* test result to be set to FAIL. Other failures come from extra
* instrumentation which is not present in a normal build; for example,
* Asan or Valgrind to detect memory leaks. This is reflected by the
* "platform" associated with each meta-test.
*
* Use the companion script `tests/scripts/run-metatests.sh` to run all
* the meta-tests for a given platform and validate that they trigger a
* detected failure as expected.
*/
/*
* Copyright The Mbed TLS Contributors
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
*/
#include <mbedtls/debug.h>
#include <mbedtls/platform.h>
#include <mbedtls/platform_util.h>
#include "test/helpers.h"
#include "test/threading_helpers.h"
#include "test/macros.h"
#include "test/memory.h"
#include "common.h"
#include <stdio.h>
#include <string.h>
#if defined(MBEDTLS_THREADING_C)
#include <mbedtls/threading.h>
#endif
/* This is an external variable, so the compiler doesn't know that we're never
* changing its value.
*/
volatile int false_but_the_compiler_does_not_know = 0;
/* Hide calls to calloc/free from static checkers such as
* `gcc-12 -Wuse-after-free`, to avoid compile-time complaints about
* code where we do mean to cause a runtime error. */
void * (* volatile calloc_but_the_compiler_does_not_know)(size_t, size_t) = mbedtls_calloc;
void(*volatile free_but_the_compiler_does_not_know)(void *) = mbedtls_free;
/* Set n bytes at the address p to all-bits-zero, in such a way that
* the compiler should not know that p is all-bits-zero. */
static void set_to_zero_but_the_compiler_does_not_know(volatile void *p, size_t n)
{
memset((void *) p, false_but_the_compiler_does_not_know, n);
}
/* Simulate an access to the given object, to avoid compiler optimizations
* in code that prepares or consumes the object. */
static void do_nothing_with_object(void *p)
{
(void) p;
}
void(*volatile do_nothing_with_object_but_the_compiler_does_not_know)(void *) =
do_nothing_with_object;
/****************************************************************/
/* Test framework features */
/****************************************************************/
static void meta_test_fail(const char *name)
{
(void) name;
mbedtls_test_fail("Forced test failure", __LINE__, __FILE__);
}
static void meta_test_not_equal(const char *name)
{
int left = 20;
int right = 10;
(void) name;
TEST_EQUAL(left, right);
exit:
;
}
static void meta_test_not_le_s(const char *name)
{
int left = 20;
int right = 10;
(void) name;
TEST_LE_S(left, right);
exit:
;
}
static void meta_test_not_le_u(const char *name)
{
size_t left = 20;
size_t right = 10;
(void) name;
TEST_LE_U(left, right);
exit:
;
}
/****************************************************************/
/* Platform features */
/****************************************************************/
static void null_pointer_dereference(const char *name)
{
(void) name;
volatile char *volatile p;
set_to_zero_but_the_compiler_does_not_know(&p, sizeof(p));
/* Undefined behavior (read from null data pointer) */
mbedtls_printf("%p -> %u\n", (void *) p, (unsigned) *p);
}
static void null_pointer_call(const char *name)
{
(void) name;
unsigned(*volatile p)(void);
set_to_zero_but_the_compiler_does_not_know(&p, sizeof(p));
/* Undefined behavior (execute null function pointer) */
/* The pointer representation may be truncated, but we don't care:
* the only point of printing it is to have some use of the pointer
* to dissuade the compiler from optimizing it away. */
mbedtls_printf("%lx() -> %u\n", (unsigned long) (uintptr_t) p, p());
}
/****************************************************************/
/* Memory */
/****************************************************************/
static void read_after_free(const char *name)
{
(void) name;
volatile char *p = calloc_but_the_compiler_does_not_know(1, 1);
*p = 'a';
free_but_the_compiler_does_not_know((void *) p);
/* Undefined behavior (read after free) */
mbedtls_printf("%u\n", (unsigned) *p);
}
static void double_free(const char *name)
{
(void) name;
volatile char *p = calloc_but_the_compiler_does_not_know(1, 1);
*p = 'a';
free_but_the_compiler_does_not_know((void *) p);
/* Undefined behavior (double free) */
free_but_the_compiler_does_not_know((void *) p);
}
static void read_uninitialized_stack(const char *name)
{
(void) name;
char buf[1];
if (false_but_the_compiler_does_not_know) {
buf[0] = '!';
}
char *volatile p = buf;
if (*p != 0) {
/* Unspecified result (read from uninitialized memory) */
mbedtls_printf("%u\n", (unsigned) *p);
}
}
static void memory_leak(const char *name)
{
(void) name;
volatile char *p = calloc_but_the_compiler_does_not_know(1, 1);
mbedtls_printf("%u\n", (unsigned) *p);
/* Leak of a heap object */
}
/* name = "test_memory_poison_%(start)_%(offset)_%(count)_%(direction)"
* Poison a region starting at start from an 8-byte aligned origin,
* encompassing count bytes. Access the region at offset from the start.
* %(start), %(offset) and %(count) are decimal integers.
* %(direction) is either the character 'r' for read or 'w' for write.
*/
static void test_memory_poison(const char *name)
{
size_t start = 0, offset = 0, count = 0;
char direction = 'r';
if (sscanf(name,
"%*[^0-9]%" MBEDTLS_PRINTF_SIZET
"%*[^0-9]%" MBEDTLS_PRINTF_SIZET
"%*[^0-9]%" MBEDTLS_PRINTF_SIZET
"_%c",
&start, &offset, &count, &direction) != 4) {
mbedtls_fprintf(stderr, "%s: Bad name format: %s\n", __func__, name);
return;
}
union {
long long ll;
unsigned char buf[32];
} aligned;
memset(aligned.buf, 'a', sizeof(aligned.buf));
if (start > sizeof(aligned.buf)) {
mbedtls_fprintf(stderr,
"%s: start=%" MBEDTLS_PRINTF_SIZET
" > size=%" MBEDTLS_PRINTF_SIZET,
__func__, start, sizeof(aligned.buf));
return;
}
if (start + count > sizeof(aligned.buf)) {
mbedtls_fprintf(stderr,
"%s: start+count=%" MBEDTLS_PRINTF_SIZET
" > size=%" MBEDTLS_PRINTF_SIZET,
__func__, start + count, sizeof(aligned.buf));
return;
}
if (offset >= count) {
mbedtls_fprintf(stderr,
"%s: offset=%" MBEDTLS_PRINTF_SIZET
" >= count=%" MBEDTLS_PRINTF_SIZET,
__func__, offset, count);
return;
}
MBEDTLS_TEST_MEMORY_POISON(aligned.buf + start, count);
if (direction == 'w') {
aligned.buf[start + offset] = 'b';
do_nothing_with_object_but_the_compiler_does_not_know(aligned.buf);
} else {
do_nothing_with_object_but_the_compiler_does_not_know(aligned.buf);
mbedtls_printf("%u\n", (unsigned) aligned.buf[start + offset]);
}
}
/****************************************************************/
/* Threading */
/****************************************************************/
static void mutex_lock_not_initialized(const char *name)
{
(void) name;
#if defined(MBEDTLS_THREADING_C)
mbedtls_threading_mutex_t mutex;
memset(&mutex, 0, sizeof(mutex));
/* This mutex usage error is detected by our test framework's mutex usage
* verification framework. See framework/tests/src/threading_helpers.c. Other
* threading implementations (e.g. pthread without our instrumentation)
* might consider this normal usage. */
TEST_ASSERT(mbedtls_mutex_lock(&mutex) == 0);
exit:
;
#endif
}
static void mutex_unlock_not_initialized(const char *name)
{
(void) name;
#if defined(MBEDTLS_THREADING_C)
mbedtls_threading_mutex_t mutex;
memset(&mutex, 0, sizeof(mutex));
/* This mutex usage error is detected by our test framework's mutex usage
* verification framework. See framework/tests/src/threading_helpers.c. Other
* threading implementations (e.g. pthread without our instrumentation)
* might consider this normal usage. */
TEST_ASSERT(mbedtls_mutex_unlock(&mutex) == 0);
exit:
;
#endif
}
static void mutex_free_not_initialized(const char *name)
{
(void) name;
#if defined(MBEDTLS_THREADING_C)
mbedtls_threading_mutex_t mutex;
memset(&mutex, 0, sizeof(mutex));
/* This mutex usage error is detected by our test framework's mutex usage
* verification framework. See framework/tests/src/threading_helpers.c. Other
* threading implementations (e.g. pthread without our instrumentation)
* might consider this normal usage. */
mbedtls_mutex_free(&mutex);
#endif
}
static void mutex_double_init(const char *name)
{
(void) name;
#if defined(MBEDTLS_THREADING_C)
mbedtls_threading_mutex_t mutex;
mbedtls_mutex_init(&mutex);
/* This mutex usage error is detected by our test framework's mutex usage
* verification framework. See framework/tests/src/threading_helpers.c. Other
* threading implementations (e.g. pthread without our instrumentation)
* might consider this normal usage. */
mbedtls_mutex_init(&mutex);
mbedtls_mutex_free(&mutex);
#endif
}
static void mutex_double_free(const char *name)
{
(void) name;
#if defined(MBEDTLS_THREADING_C)
mbedtls_threading_mutex_t mutex;
mbedtls_mutex_init(&mutex);
mbedtls_mutex_free(&mutex);
/* This mutex usage error is detected by our test framework's mutex usage
* verification framework. See framework/tests/src/threading_helpers.c. Other
* threading implementations (e.g. pthread without our instrumentation)
* might consider this normal usage. */
mbedtls_mutex_free(&mutex);
#endif
}
static void mutex_leak(const char *name)
{
(void) name;
#if defined(MBEDTLS_THREADING_C)
mbedtls_threading_mutex_t mutex;
mbedtls_mutex_init(&mutex);
#endif
/* This mutex usage error is detected by our test framework's mutex usage
* verification framework. See framework/tests/src/threading_helpers.c. Other
* threading implementations (e.g. pthread without our instrumentation)
* might consider this normal usage. */
}
/****************************************************************/
/* Command line entry point */
/****************************************************************/
typedef struct {
/** Command line argument that will trigger that metatest.
*
* Conventionally matches "[a-z0-9_]+". */
const char *name;
/** Platform under which that metatest is valid.
*
* - "any": should work anywhere.
* - "asan": triggers ASan (Address Sanitizer).
* - "msan": triggers MSan (Memory Sanitizer).
* - "pthread": requires MBEDTLS_THREADING_PTHREAD and MBEDTLS_TEST_HOOKS,
* which enables MBEDTLS_TEST_MUTEX_USAGE internally in the test
* framework (see framework/tests/src/threading_helpers.c).
*/
const char *platform;
/** Function that performs the metatest.
*
* The function receives the name as an argument. This allows using the
* same function to perform multiple variants of a test based on the name.
*
* When executed on a conforming platform, the function is expected to
* either cause a test failure (mbedtls_test_fail()), or cause the
* program to abort in some way (e.g. by causing a segfault or by
* triggering a sanitizer).
*
* When executed on a non-conforming platform, the function may return
* normally or may have unpredictable behavior.
*/
void (*entry_point)(const char *name);
} metatest_t;
/* The list of available meta-tests. Remember to register new functions here!
*
* Note that we always compile all the functions, so that `metatest --list`
* will always list all the available meta-tests.
*
* See the documentation of metatest_t::platform for the meaning of
* platform values.
*/
metatest_t metatests[] = {
{ "test_fail", "any", meta_test_fail },
{ "test_not_equal", "any", meta_test_not_equal },
{ "test_not_le_s", "any", meta_test_not_le_s },
{ "test_not_le_u", "any", meta_test_not_le_u },
{ "null_dereference", "any", null_pointer_dereference },
{ "null_call", "any", null_pointer_call },
{ "read_after_free", "asan", read_after_free },
{ "double_free", "asan", double_free },
{ "read_uninitialized_stack", "msan", read_uninitialized_stack },
{ "memory_leak", "asan", memory_leak },
{ "test_memory_poison_0_0_8_r", "poison", test_memory_poison },
{ "test_memory_poison_0_0_8_w", "poison", test_memory_poison },
{ "test_memory_poison_0_7_8_r", "poison", test_memory_poison },
{ "test_memory_poison_0_7_8_w", "poison", test_memory_poison },
{ "test_memory_poison_0_0_1_r", "poison", test_memory_poison },
{ "test_memory_poison_0_0_1_w", "poison", test_memory_poison },
{ "test_memory_poison_0_1_2_r", "poison", test_memory_poison },
{ "test_memory_poison_0_1_2_w", "poison", test_memory_poison },
{ "test_memory_poison_7_0_8_r", "poison", test_memory_poison },
{ "test_memory_poison_7_0_8_w", "poison", test_memory_poison },
{ "test_memory_poison_7_7_8_r", "poison", test_memory_poison },
{ "test_memory_poison_7_7_8_w", "poison", test_memory_poison },
{ "test_memory_poison_7_0_1_r", "poison", test_memory_poison },
{ "test_memory_poison_7_0_1_w", "poison", test_memory_poison },
{ "test_memory_poison_7_1_2_r", "poison", test_memory_poison },
{ "test_memory_poison_7_1_2_w", "poison", test_memory_poison },
{ "mutex_lock_not_initialized", "pthread", mutex_lock_not_initialized },
{ "mutex_unlock_not_initialized", "pthread", mutex_unlock_not_initialized },
{ "mutex_free_not_initialized", "pthread", mutex_free_not_initialized },
{ "mutex_double_init", "pthread", mutex_double_init },
{ "mutex_double_free", "pthread", mutex_double_free },
{ "mutex_leak", "pthread", mutex_leak },
{ NULL, NULL, NULL }
};
static void help(FILE *out, const char *argv0)
{
mbedtls_fprintf(out, "Usage: %s list|TEST\n", argv0);
mbedtls_fprintf(out, "Run a meta-test that should cause a test failure.\n");
mbedtls_fprintf(out, "With 'list', list the available tests and their platform requirement.\n");
}
int main(int argc, char *argv[])
{
const char *argv0 = argc > 0 ? argv[0] : "metatest";
if (argc != 2) {
help(stderr, argv0);
mbedtls_exit(MBEDTLS_EXIT_FAILURE);
}
/* Support "-help", "--help", "--list", etc. */
const char *command = argv[1];
while (*command == '-') {
++command;
}
if (strcmp(argv[1], "help") == 0) {
help(stdout, argv0);
mbedtls_exit(MBEDTLS_EXIT_SUCCESS);
}
if (strcmp(argv[1], "list") == 0) {
for (const metatest_t *p = metatests; p->name != NULL; p++) {
mbedtls_printf("%s %s\n", p->name, p->platform);
}
mbedtls_exit(MBEDTLS_EXIT_SUCCESS);
}
#if defined(MBEDTLS_TEST_MUTEX_USAGE)
mbedtls_test_mutex_usage_init();
#endif
for (const metatest_t *p = metatests; p->name != NULL; p++) {
if (strcmp(argv[1], p->name) == 0) {
mbedtls_printf("Running metatest %s...\n", argv[1]);
p->entry_point(argv[1]);
#if defined(MBEDTLS_TEST_MUTEX_USAGE)
mbedtls_test_mutex_usage_check();
#endif
int result = (int) mbedtls_test_get_result();
mbedtls_printf("Running metatest %s... done, result=%d\n",
argv[1], result);
mbedtls_exit(result == MBEDTLS_TEST_RESULT_SUCCESS ?
MBEDTLS_EXIT_SUCCESS :
MBEDTLS_EXIT_FAILURE);
}
}
mbedtls_fprintf(stderr, "%s: FATAL: No such metatest: %s\n",
argv0, command);
mbedtls_exit(MBEDTLS_EXIT_FAILURE);
}
@@ -0,0 +1,66 @@
/*
* Query the Mbed TLS compile time configuration
*
* Copyright The Mbed TLS Contributors
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
*/
#include "mbedtls/build_info.h"
#include "mbedtls/platform.h"
#define USAGE \
"usage: %s [ -all | -any | -l ] <MBEDTLS_CONFIG> ...\n\n" \
"This program takes command line arguments which correspond to\n" \
"the string representation of Mbed TLS compile time configurations.\n\n" \
"If \"--all\" and \"--any\" are not used, then, if all given arguments\n" \
"are defined in the Mbed TLS build, 0 is returned; otherwise 1 is\n" \
"returned. Macro expansions of configurations will be printed (if any).\n" \
"-l\tPrint all available configuration.\n" \
"-all\tReturn 0 if all configurations are defined. Otherwise, return 1\n" \
"-any\tReturn 0 if any configuration is defined. Otherwise, return 1\n" \
"-h\tPrint this usage\n"
#include <string.h>
#include "query_config.h"
int main(int argc, char *argv[])
{
int i;
if (argc < 2 || strcmp(argv[1], "-h") == 0) {
mbedtls_printf(USAGE, argv[0]);
return MBEDTLS_EXIT_FAILURE;
}
if (strcmp(argv[1], "-l") == 0) {
list_config();
return 0;
}
if (strcmp(argv[1], "-all") == 0) {
for (i = 2; i < argc; i++) {
if (query_config(argv[i]) != 0) {
return 1;
}
}
return 0;
}
if (strcmp(argv[1], "-any") == 0) {
for (i = 2; i < argc; i++) {
if (query_config(argv[i]) == 0) {
return 0;
}
}
return 1;
}
for (i = 1; i < argc; i++) {
if (query_config(argv[i]) != 0) {
return 1;
}
}
return 0;
}
+34
View File
@@ -0,0 +1,34 @@
/*
* Query Mbed TLS compile time configurations from mbedtls_config.h
*
* Copyright The Mbed TLS Contributors
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
*/
#ifndef MBEDTLS_PROGRAMS_TEST_QUERY_CONFIG_H
#define MBEDTLS_PROGRAMS_TEST_QUERY_CONFIG_H
#include "mbedtls/build_info.h"
/** Check whether a given configuration symbol is enabled.
*
* \param config The symbol to query (e.g. "MBEDTLS_RSA_C").
* \return \c 0 if the symbol was defined at compile time
* (in MBEDTLS_CONFIG_FILE or mbedtls_config.h),
* \c 1 otherwise.
*
* \note This function is defined in `programs/test/query_config.c`
* which is automatically generated by
* `scripts/generate_query_config.pl`.
*/
int query_config(const char *config);
/** List all enabled configuration symbols
*
* \note This function is defined in `programs/test/query_config.c`
* which is automatically generated by
* `scripts/generate_query_config.pl`.
*/
void list_config(void);
#endif /* MBEDTLS_PROGRAMS_TEST_QUERY_CONFIG_H */
+29
View File
@@ -0,0 +1,29 @@
/* Ad hoc report on included headers. */
/*
* Copyright The Mbed TLS Contributors
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
*/
#include <psa/crypto.h>
#include <mbedtls/platform.h>
int main(void)
{
/* Which PSA platform header? */
#if defined(PSA_CRYPTO_PLATFORM_H)
mbedtls_printf("PSA_CRYPTO_PLATFORM_H\n");
#endif
#if defined(PSA_CRYPTO_PLATFORM_ALT_H)
mbedtls_printf("PSA_CRYPTO_PLATFORM_ALT_H\n");
#endif
/* Which PSA struct header? */
#if defined(PSA_CRYPTO_STRUCT_H)
mbedtls_printf("PSA_CRYPTO_STRUCT_H\n");
#endif
#if defined(PSA_CRYPTO_STRUCT_ALT_H)
mbedtls_printf("PSA_CRYPTO_STRUCT_ALT_H\n");
#endif
}
+64
View File
@@ -0,0 +1,64 @@
# test_zeroize.gdb
#
# Copyright The Mbed TLS Contributors
# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
#
# Purpose
#
# Run a test using the debugger to check that the mbedtls_platform_zeroize()
# function in platform_util.h is not being optimized out by the compiler. To do
# so, the script loads the test program at programs/test/zeroize and sets a
# breakpoint at the last return statement in main(). When the breakpoint is
# hit, the debugger manually checks the contents to be zeroized and checks that
# it is actually cleared.
#
# The mbedtls_platform_zeroize() test is debugger driven because there does not
# seem to be a mechanism to reliably check whether the zeroize calls are being
# eliminated by compiler optimizations from within the compiled program. The
# problem is that a compiler would typically remove what it considers to be
# "unnecessary" assignments as part of redundant code elimination. To identify
# such code, the compilar will create some form dependency graph between
# reads and writes to variables (among other situations). It will then use this
# data structure to remove redundant code that does not have an impact on the
# program's observable behavior. In the case of mbedtls_platform_zeroize(), an
# intelligent compiler could determine that this function clears a block of
# memory that is not accessed later in the program, so removing the call to
# mbedtls_platform_zeroize() does not have an observable behavior. However,
# inserting a test after a call to mbedtls_platform_zeroize() to check whether
# the block of memory was correctly zeroed would force the compiler to not
# eliminate the mbedtls_platform_zeroize() call. If this does not occur, then
# the compiler potentially has a bug.
#
# Note: This test requires that the test program is compiled with -g3.
set confirm off
file ./programs/test/zeroize
search GDB_BREAK_HERE
break $_
set args ./framework/tests/programs/zeroize.c
run
set $i = 0
set $len = sizeof(buf)
set $buf = buf
while $i < $len
if $buf[$i++] != 0
echo The buffer at was not zeroized\n
quit 1
end
end
echo The buffer was correctly zeroized\n
continue
if $_exitcode != 0
echo The program did not terminate correctly\n
quit 1
end
quit 0
+72
View File
@@ -0,0 +1,72 @@
/*
* Zeroize application for debugger-driven testing
*
* This is a simple test application used for debugger-driven testing to check
* whether calls to mbedtls_platform_zeroize() are being eliminated by compiler
* optimizations. This application is used by the GDB script at
* tests/programs/test_zeroize.gdb: the script sets a breakpoint at the last
* return statement in the main() function of this program. The debugger
* facilities are then used to manually inspect the memory and verify that the
* call to mbedtls_platform_zeroize() was not eliminated.
*
* Copyright The Mbed TLS Contributors
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
*/
#include "mbedtls/build_info.h"
#include <stdio.h>
#include "mbedtls/platform.h"
#include "mbedtls/platform_util.h"
#define BUFFER_LEN 1024
static void usage(void)
{
mbedtls_printf("Zeroize is a simple program to assist with testing\n");
mbedtls_printf("the mbedtls_platform_zeroize() function by using the\n");
mbedtls_printf("debugger. This program takes a file as input and\n");
mbedtls_printf("prints the first %d characters. Usage:\n\n", BUFFER_LEN);
mbedtls_printf(" zeroize <FILE>\n");
}
int main(int argc, char **argv)
{
int exit_code = MBEDTLS_EXIT_FAILURE;
FILE *fp;
char buf[BUFFER_LEN];
char *p = buf;
char *end = p + BUFFER_LEN;
int c;
if (argc != 2) {
mbedtls_printf("This program takes exactly 1 argument\n");
usage();
mbedtls_exit(exit_code);
}
fp = fopen(argv[1], "r");
if (fp == NULL) {
mbedtls_printf("Could not open file '%s'\n", argv[1]);
mbedtls_exit(exit_code);
}
while ((c = fgetc(fp)) != EOF && p < end - 1) {
*p++ = (char) c;
}
*p = '\0';
if (p - buf != 0) {
mbedtls_printf("%s\n", buf);
exit_code = MBEDTLS_EXIT_SUCCESS;
} else {
mbedtls_printf("The file is empty!\n");
}
fclose(fp);
mbedtls_platform_zeroize(buf, sizeof(buf));
mbedtls_exit(exit_code); // GDB_BREAK_HERE -- don't remove this comment!
}
+28 -1
View File
@@ -1,6 +1,11 @@
/** \file fake_external_rng_for_test.c
*
* \brief Helper functions to test PSA crypto functionality.
* Helper functions to test external functions:
* - mbedtls_psa_external_get_random()
* - mbedtls_platform_get_entropy_alt()
*
* These functions are provided only for test purposes and they should not be
* used for production.
*/
/*
@@ -11,6 +16,7 @@
#include <test/fake_external_rng_for_test.h>
#if defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG)
#include <test/random.h>
#include <psa/crypto.h>
@@ -42,4 +48,25 @@ psa_status_t mbedtls_psa_external_get_random(
*output_length = output_size;
return PSA_SUCCESS;
}
#endif /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
#if defined(MBEDTLS_PLATFORM_GET_ENTROPY_ALT)
#include <test/random.h>
# include <mbedtls/platform.h>
int mbedtls_platform_get_entropy_alt(unsigned char *output, size_t output_size,
size_t *output_len, size_t *entropy_content)
{
mbedtls_test_rnd_std_rand(NULL, output, output_size);
*output_len = output_size;
if (entropy_content != NULL) {
*entropy_content = output_size * 8;
}
return 0;
}
#endif /* MBEDTLS_PLATFORM_GET_ENTROPY_ALT */
+58
View File
@@ -72,4 +72,62 @@ psa_status_t psa_import_key(const psa_key_attributes_t *attributes,
return PSA_ERROR_COMMUNICATION_FAILURE;
}
int psa_can_do_hash(psa_algorithm_t hash_alg)
{
(void) hash_alg;
return 0;
}
psa_status_t psa_hash_clone(const psa_hash_operation_t *source_operation,
psa_hash_operation_t *target_operation)
{
(void) source_operation;
(void) target_operation;
return PSA_ERROR_COMMUNICATION_FAILURE;
}
psa_status_t psa_hash_setup(psa_hash_operation_t *operation,
psa_algorithm_t alg)
{
(void) operation;
(void) alg;
return PSA_ERROR_COMMUNICATION_FAILURE;
}
psa_status_t psa_hash_update(psa_hash_operation_t *operation,
const uint8_t *input_external,
size_t input_length)
{
(void) operation;
(void) input_external;
(void) input_length;
return PSA_ERROR_COMMUNICATION_FAILURE;
}
psa_status_t psa_hash_finish(psa_hash_operation_t *operation,
uint8_t *hash_external,
size_t hash_size,
size_t *hash_length)
{
(void) operation;
(void) hash_external;
(void) hash_size;
(void) hash_length;
return PSA_ERROR_COMMUNICATION_FAILURE;
}
psa_status_t psa_hash_compute(psa_algorithm_t alg,
const uint8_t *input_external, size_t input_length,
uint8_t *hash_external, size_t hash_size,
size_t *hash_length)
{
(void) alg;
(void) input_external;
(void) input_length;
(void) hash_external;
(void) hash_size;
(void) hash_length;
return PSA_ERROR_COMMUNICATION_FAILURE;
}
#endif /* MBEDTLS_PSA_CRYPTO_CLIENT && !MBEDTLS_PSA_CRYPTO_C */