feat(mbedtls): update to tf-psa-crypto 1.1

This commit is contained in:
Ashish Sharma
2026-04-02 14:28:28 +08:00
parent 521d2eb1fe
commit 67a6a4091d
3205 changed files with 666642 additions and 8 deletions
-6
View File
@@ -1,6 +0,0 @@
[submodule "framework"]
path = framework
url = https://github.com/Mbed-TLS/mbedtls-framework
[submodule "tf-psa-crypto"]
path = tf-psa-crypto
url = https://github.com/Mbed-TLS/TF-PSA-Crypto.git
Submodule framework deleted from dff9da0443
Submodule tf-psa-crypto deleted from 29160dd877
+109
View File
@@ -0,0 +1,109 @@
# Maintained branches
At any point in time, we have a number of maintained branches, currently consisting of:
- The [`main`](https://github.com/Mbed-TLS/TF-PSA-Crypto/tree/main) branch:
this always contains the latest release, including all publicly available
security fixes.
- The [`development`](https://github.com/Mbed-TLS/TF-PSA-Crypto/tree/development) branch:
This branch was used to prepare version 1.0.0 of TF-PSA-Crypto and continues to host
development for future versions.
- [`tf-psa-crypto-1.1`](https://github.com/Mbed-TLS/TF-PSA-Crypto/tree/tf-psa-crypto-1.1)
maintained until March 2029, see
<https://github.com/Mbed-TLS/TF-PSA-Crypto/releases/tag/v1.1.0>.
We use [Semantic Versioning](https://semver.org/). In particular, we maintain
API compatibility in the `main` branch across minor version changes (e.g.
the API of 1.(x+1) is backward compatible with 1.x). We only break API
compatibility on major version changes (e.g. from 1.x to 2.0). We also maintain
ABI compatibility within LTS branches; see the next section for details.
We will make regular LTS releases on an 18-month cycle, each of which will have
a 3 year support lifetime. The release date of the first 1.x LTS is yet to be
determined.
Mbed TLS currently maintains the LTS branch [`mbedtls-3.6`](https://github.com/Mbed-TLS/mbedtls/tree/mbedtls-3.6).
This branch contains the implementation of the PSA Cryptography API prior to the
Mbed TLS repository split. Any relevant bug fixes made in the TF-PSA-Crypto
development branch should be backported to this branch to ensure proper
maintenance. This does not apply to Mbed TLS LTS branches created after
the repository split, such as mbedtls-4.1.
## Backwards Compatibility for application code
We maintain API compatibility in released versions of TF-PSA-Crypto. If you
have code that's working and secure with TF-PSA-Crypto x.y.z and does not rely
on undocumented features, then you should be able to re-compile it without
modification with any later release x.y'.z' with the same major version
number, and your code will still build, be secure, and work.
Note that this guarantee only applies if you either use the default
compile-time configuration (`psa/crypto_config.h`) or the same modified
compile-time configuration. Changing compile-time configuration options can
result in an incompatible API or ABI, although features will generally not
affect unrelated features (for example, enabling or disabling a
cryptographic algorithm does not break code that does not use that
algorithm).
Note that new releases of TF-PSA-Crypto may extend the API. Here are some
examples of changes that are common in minor releases of TF-PSA-Crypto, and are
not considered API compatibility breaks:
* Adding or reordering fields in a structure or union.
* Removing a field from a structure, unless the field is documented as public.
* Adding items to an enum.
* Returning an error code that was not previously documented for a function
when a new error condition arises.
* Changing which error code is returned in a case where multiple error
conditions apply.
* Changing the behavior of a function from failing to succeeding, when the
change is a reasonable extension of the current behavior, i.e. the
addition of a new feature.
There are rare exceptions where we break API compatibility: code that was
relying on something that became insecure in the meantime (for example,
crypto that was found to be weak) may need to be changed. In case security
comes in conflict with backwards compatibility, we will put security first,
but always attempt to provide a compatibility option.
## Backward compatibility for the key store
We maintain backward compatibility with previous versions of the
PSA Crypto persistent storage since Mbed TLS 2.25.0, provided that the
storage backend (PSA ITS implementation) is configured in a compatible way.
We intend to maintain this backward compatibility throughout a major version
of TF-PSA-Crypto (for example, all TF-PSA-Crypto 1.y versions will be able to
read keys written under any TF-PSA-Crypto 1.x with x <= y).
Future major version upgrades (for example from 1.x to 2.y) may require the use
of an upgrade tool.
Note that this guarantee does not currently fully extend to drivers, which
are an experimental feature. We intend to maintain compatibility with the
basic use of drivers from Mbed TLS 2.28.0 onwards, even if driver APIs
change. However, for more experimental parts of the driver interface, such
as the use of driver state, we do not yet guarantee backward compatibility.
## Long-time support branches
For the LTS branches, additionally we try very hard to also maintain ABI
compatibility (same definition as API except with re-linking instead of
re-compiling) and to avoid any increase in code size or RAM usage, or in the
minimum version of tools needed to build the code. The only exception, as
before, is in case those goals would conflict with fixing a security issue, we
will put security first but provide a compatibility option. (So far we never
had to break ABI compatibility in an LTS branch, but we occasionally had to
increase code size for a security fix.)
For contributors, see the [Backwards Compatibility section of
CONTRIBUTING](CONTRIBUTING.md#backwards-compatibility).
## Current Branches
The following branches are currently maintained:
- [main](https://github.com/Mbed-TLS/TF-PSA-Crypto/tree/main)
- [`development`](https://github.com/Mbed-TLS/TF-PSA-Crypto/)
- [`tf-psa-crypto-1.1`](https://github.com/Mbed-TLS/TF-PSA-Crypto/tree/tf-psa-crypto-1.1)
maintained until March 2029, see
<https://github.com/Mbed-TLS/TF-PSA-Crypto/releases/tag/v1.1.0>.
+21
View File
@@ -0,0 +1,21 @@
## Known issues
Known issues in TF-PSA-Crypto are [tracked on GitHub](https://github.com/Mbed-TLS/TF-PSA-Crypto/issues).
## Reporting a bug
If you think you've found a bug in TF-PSA-Crypto, please follow these steps:
1. Make sure you're using the latest version of a
[maintained branch](BRANCHES.md): `main`, `development`,
or a long-time support branch.
2. Check [GitHub](https://github.com/Mbed-TLS/TF-PSA-Crypto/issues) to see if
your issue has already been reported. If not, …
3. If the issue is a security risk (for example: buffer overflow,
data leak), please report it confidentially as described in
[`SECURITY.md`](SECURITY.md). If not, …
4. Please [create an issue on GitHub](https://github.com/Mbed-TLS/TF-PSA-Crypto/issues).
Please do not use GitHub for support questions. If you want to know
how to do something with TF-PSA-Crypto, please see [`SUPPORT.md`](SUPPORT.md)
for available documentation and support channels.
+587
View File
@@ -0,0 +1,587 @@
#
# CMake build system design considerations:
#
# - Include directories:
# + Do not define include directories globally using the include_directories
# command but rather at the target level using the
# target_include_directories command. That way, it is easier to guarantee
# that targets are built using the proper list of include directories.
# + Use the PUBLIC and PRIVATE keywords to specify the scope of include
# directories. That way, a target linking to a library (using the
# target_link_libraries command) inherits from the library PUBLIC include
# directories and not from the PRIVATE ones.
# - TF_PSA_CRYPTO_TARGET_PREFIX: CMake targets are designed to be alterable by
# calling CMake in order to avoid target name clashes, via the use of
# TF_PSA_CRYPTO_TARGET_PREFIX. The value of this variable is prefixed to the
# tfpsacrypto and tfpsacrypto-apidoc targets.
#
# We specify a minimum requirement of 3.10.2, but for now use 3.5.1 here
# until our infrastructure catches up.
# Espressif: Updating the version to 3.10.2. CMake versions
# older than 3.10 are getting deprecated
cmake_minimum_required(VERSION 3.10.2)
include(CMakePackageConfigHelpers)
# Include convenience functions for printing properties and variables, like
# cmake_print_properties(), cmake_print_variables().
include(CMakePrintHelpers)
# https://cmake.org/cmake/help/latest/policy/CMP0011.html
# Setting this policy is required in CMake >= 3.18.0, otherwise a warning is generated. The OLD
# policy setting is deprecated, and will be removed in future versions.
cmake_policy(SET CMP0011 NEW)
# https://cmake.org/cmake/help/latest/policy/CMP0012.html
# Setting the CMP0012 policy to NEW is required for FindPython3 to work with CMake 3.18.2
# (there is a bug in this particular version), otherwise, setting the CMP0012 policy is required
# for CMake versions >= 3.18.3 otherwise a deprecated warning is generated. The OLD policy setting
# is deprecated and will be removed in future versions.
cmake_policy(SET CMP0012 NEW)
set(TF_PSA_CRYPTO_VERSION 1.1.0)
set(TF_PSA_CRYPTO_SOVERSION 2)
if(TEST_CPP)
project("TF-PSA-Crypto"
LANGUAGES C CXX
VERSION ${TF_PSA_CRYPTO_VERSION}
)
else()
project("TF-PSA-Crypto"
LANGUAGES C
VERSION ${TF_PSA_CRYPTO_VERSION}
)
endif()
include(GNUInstallDirs)
# Determine if TF-PSA-Crypto is being built as a subproject using add_subdirectory()
if(NOT DEFINED TF_PSA_CRYPTO_AS_SUBPROJECT)
set(TF_PSA_CRYPTO_AS_SUBPROJECT ON)
if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
set(TF_PSA_CRYPTO_AS_SUBPROJECT OFF)
endif()
endif()
# Set the project, Mbed TLS and framework root directory.
set(TF_PSA_CRYPTO_FRAMEWORK_DIR ${CMAKE_CURRENT_SOURCE_DIR}/framework)
# Put the version numbers into relevant files
# set(version_number_files
# doxygen/input/doc_mainpage.h
# doxygen/tfpsacrypto.doxyfile)
# foreach(file ${version_number_files})
# configure_file(${file}.in
# ${TF_PSA_CRYPTO_DIR}/${file})
# endforeach(file)
ADD_CUSTOM_TARGET(${TF_PSA_CRYPTO_TARGET_PREFIX}tfpsacrypto-apidoc
COMMAND doxygen tfpsacrypto.doxyfile
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/doxygen)
option(ENABLE_PROGRAMS "Build TF-PSA-Crypto programs." ON)
option(TF_PSA_CRYPTO_FATAL_WARNINGS "Compiler warnings treated as errors" ON)
if(CMAKE_HOST_WIN32)
# N.B. The comment on the next line is significant! If you change it,
# edit the sed command in prepare_release.sh that modifies
# CMakeLists.txt.
option(GEN_FILES "Generate the auto-generated files as needed" OFF) # off in development
else()
option(GEN_FILES "Generate the auto-generated files as needed" ON)
endif()
# Support for package config and install to be added later.
option(DISABLE_PACKAGE_CONFIG_AND_INSTALL "Disable package configuration, target export and installation" ${TF_PSA_CRYPTO_AS_SUBPROJECT})
if (CMAKE_C_SIMULATE_ID)
set(COMPILER_ID ${CMAKE_C_SIMULATE_ID})
else()
set(COMPILER_ID ${CMAKE_C_COMPILER_ID})
endif(CMAKE_C_SIMULATE_ID)
string(REGEX MATCH "Clang" CMAKE_COMPILER_IS_CLANG "${COMPILER_ID}")
string(REGEX MATCH "GNU" CMAKE_COMPILER_IS_GNU "${COMPILER_ID}")
string(REGEX MATCH "IAR" CMAKE_COMPILER_IS_IAR "${COMPILER_ID}")
string(REGEX MATCH "MSVC" CMAKE_COMPILER_IS_MSVC "${COMPILER_ID}")
# the test suites currently have compile errors with MSVC
if(CMAKE_COMPILER_IS_MSVC)
option(ENABLE_TESTING "Build TF-PSA-Crypto tests." OFF)
else()
option(ENABLE_TESTING "Build TF-PSA-Crypto tests." ON)
endif()
option(TF_PSA_CRYPTO_TEST_DRIVER "Build TF-PSA-Crypto test driver for driver dispatch testing" OFF)
option(USE_STATIC_TF_PSA_CRYPTO_LIBRARY "Build TF-PSA-Crypto static library." ON)
option(USE_SHARED_TF_PSA_CRYPTO_LIBRARY "Build TF-PSA-Crypto shared library." OFF)
option(LINK_WITH_PTHREAD "Explicitly link Mbed TLS library to pthread." OFF)
option(LINK_WITH_TRUSTED_STORAGE "Explicitly link Mbed TLS library to trusted_storage." OFF)
option(MSVC_STATIC_RUNTIME "Build the libraries with /MT compiler flag" OFF)
set(tfpsacrypto_target "${TF_PSA_CRYPTO_TARGET_PREFIX}tfpsacrypto")
if (USE_STATIC_TF_PSA_CRYPTO_LIBRARY)
set(tfpsacrypto_static_target ${tfpsacrypto_target})
endif()
if(USE_STATIC_TF_PSA_CRYPTO_LIBRARY AND USE_SHARED_TF_PSA_CRYPTO_LIBRARY)
string(APPEND tfpsacrypto_static_target "_static")
endif()
# Python 3 is only needed here to check for configuration warnings.
if(NOT CMAKE_VERSION VERSION_LESS 3.15.0)
set(Python3_FIND_STRATEGY LOCATION)
find_package(Python3 COMPONENTS Interpreter)
if(Python3_Interpreter_FOUND)
set(TF_PSA_CRYPTO_PYTHON_EXECUTABLE ${Python3_EXECUTABLE})
endif()
else()
find_package(PythonInterp 3)
if(PYTHONINTERP_FOUND)
set(TF_PSA_CRYPTO_PYTHON_EXECUTABLE ${PYTHON_EXECUTABLE})
endif()
endif()
# We now potentially need to link all executables against PThreads, if available
set(CMAKE_THREAD_PREFER_PTHREAD TRUE)
set(THREADS_PREFER_PTHREAD_FLAG TRUE)
find_package(Threads)
# If this is the root project add longer list of available CMAKE_BUILD_TYPE values
if(NOT TF_PSA_CRYPTO_AS_SUBPROJECT)
set(CMAKE_BUILD_TYPE ${CMAKE_BUILD_TYPE}
CACHE STRING "Choose the type of build: None Debug Release Coverage ASan ASanDbg MemSan MemSanDbg Check CheckFull TSan TSanDbg"
FORCE)
endif()
# Make TF_PSA_CRYPTO_CONFIG_FILE and TF_PSA_CRYPTO_USER_CONFIG_FILE into PATHs
set(TF_PSA_CRYPTO_CONFIG_FILE "" CACHE FILEPATH "TF-PSA-Crypto config file (overrides default).")
set(TF_PSA_CRYPTO_USER_CONFIG_FILE "" CACHE FILEPATH "TF-PSA-Crypto user config file (appended to default).")
set(TF_PSA_CRYPTO_CONFIG_NAME "" CACHE STRING "Name of the configuration to use (see config.py documentation)")
if(NOT "${TF_PSA_CRYPTO_CONFIG_NAME}" STREQUAL "")
if(NOT "${TF_PSA_CRYPTO_CONFIG_FILE}" STREQUAL "")
message(FATAL_ERROR "TF_PSA_CRYPTO_CONFIG_NAME and TF_PSA_CRYPTO_CONFIG_FILE are incompatible.")
endif()
endif(NOT "${TF_PSA_CRYPTO_CONFIG_NAME}" STREQUAL "")
# Create a symbolic link from ${base_name} in the binary directory
# to the corresponding path in the source directory.
# Note: Copies the file(s) on Windows.
function(tf_psa_crypto_link_to_source base_name)
set(link "${CMAKE_CURRENT_BINARY_DIR}/${base_name}")
set(target "${CMAKE_CURRENT_SOURCE_DIR}/${base_name}")
# Linking to non-existent file is not desirable. At best you will have a
# dangling link, but when building in tree, this can create a symbolic link
# to itself.
if (EXISTS ${target} AND NOT EXISTS ${link})
if (CMAKE_HOST_UNIX)
execute_process(COMMAND ln -s ${target} ${link}
RESULT_VARIABLE result
ERROR_VARIABLE output)
if (NOT ${result} EQUAL 0)
message(FATAL_ERROR "Could not create symbolic link for: ${target} --> ${output}")
endif()
else()
if (IS_DIRECTORY ${target})
file(GLOB_RECURSE files FOLLOW_SYMLINKS LIST_DIRECTORIES false RELATIVE ${target} "${target}/*")
foreach(file IN LISTS files)
configure_file("${target}/${file}" "${link}/${file}" COPYONLY)
endforeach(file)
else()
configure_file(${target} ${link} COPYONLY)
endif()
endif()
endif()
endfunction(tf_psa_crypto_link_to_source)
# Get the filename without the final extension (i.e. convert "a.b.c" to "a.b")
function(tf_psa_crypto_get_name_without_last_ext dest_var full_name)
# Split into a list on '.' (but a cmake list is just a ';'-separated string)
string(REPLACE "." ";" ext_parts "${full_name}")
# Remove the last item if there are more than one
list(LENGTH ext_parts ext_parts_len)
if (${ext_parts_len} GREATER "1")
math(EXPR ext_parts_last_item "${ext_parts_len} - 1")
list(REMOVE_AT ext_parts ${ext_parts_last_item})
endif()
# Convert back to a string by replacing separators with '.'
string(REPLACE ";" "." no_ext_name "${ext_parts}")
# Copy into the desired variable
set(${dest_var} ${no_ext_name} PARENT_SCOPE)
endfunction(tf_psa_crypto_get_name_without_last_ext)
include(CheckCCompilerFlag)
set(CMAKE_C_EXTENSIONS OFF)
# Espressif: We set C standard in ESP-IDF build system
# No need to set it here
# set(CMAKE_C_STANDARD 99)
# Set base compile options to be used for the compilation of all C files of
# all targets.
function(tf_psa_crypto_set_base_compile_options target)
if(CMAKE_COMPILER_IS_GNU)
tf_psa_crypto_set_gnu_base_compile_options(${target})
elseif(CMAKE_COMPILER_IS_CLANG)
tf_psa_crypto_set_clang_base_compile_options(${target})
elseif(CMAKE_COMPILER_IS_IAR)
tf_psa_crypto_set_iar_base_compile_options(${target})
elseif(CMAKE_COMPILER_IS_MSVC)
tf_psa_crypto_set_msvc_base_compile_options(${target})
endif()
if(TF_PSA_CRYPTO_TEST_DRIVER)
target_compile_definitions(${target}
PRIVATE "-DPSA_CRYPTO_DRIVER_TEST"
"-DMBEDTLS_TEST_LIBTESTDRIVER1"
"-DTF_PSA_CRYPTO_TEST_LIBTESTDRIVER1"
)
endif()
endfunction(tf_psa_crypto_set_base_compile_options)
function(tf_psa_crypto_set_gnu_base_compile_options target)
# some warnings we want are not available with old GCC versions
# note: starting with CMake 2.8 we could use CMAKE_C_COMPILER_VERSION
execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion
OUTPUT_VARIABLE GCC_VERSION)
target_compile_options(${target} PRIVATE -Wall -Wextra -Wwrite-strings -Wmissing-prototypes)
if (GCC_VERSION VERSION_GREATER 3.0 OR GCC_VERSION VERSION_EQUAL 3.0)
target_compile_options(${target} PRIVATE -Wformat=2 -Wno-format-nonliteral)
endif()
if (GCC_VERSION VERSION_GREATER 4.3 OR GCC_VERSION VERSION_EQUAL 4.3)
target_compile_options(${target} PRIVATE -Wvla)
endif()
if (GCC_VERSION VERSION_GREATER 4.5 OR GCC_VERSION VERSION_EQUAL 4.5)
target_compile_options(${target} PRIVATE -Wlogical-op)
endif()
if (GCC_VERSION VERSION_GREATER 4.8 OR GCC_VERSION VERSION_EQUAL 4.8)
target_compile_options(${target} PRIVATE -Wshadow)
endif()
if (GCC_VERSION VERSION_GREATER 5.0)
CHECK_C_COMPILER_FLAG("-Wformat-signedness" C_COMPILER_SUPPORTS_WFORMAT_SIGNEDNESS)
if(C_COMPILER_SUPPORTS_WFORMAT_SIGNEDNESS)
target_compile_options(${target} PRIVATE -Wformat-signedness)
endif()
endif()
if (GCC_VERSION VERSION_GREATER 7.0 OR GCC_VERSION VERSION_EQUAL 7.0)
target_compile_options(${target} PRIVATE -Wformat-overflow=2 -Wformat-truncation)
endif()
target_compile_options(${target} PRIVATE $<$<CONFIG:Release>:-O2>)
target_compile_options(${target} PRIVATE $<$<CONFIG:Debug>:-O0 -g3>)
target_compile_options(${target} PRIVATE $<$<CONFIG:Coverage>:-O0 -g3 --coverage>)
set_target_properties(${target} PROPERTIES LINK_FLAGS_COVERAGE "--coverage")
# Old GCC versions hit a performance problem with test_suite_pkwrite
# "Private keey write check EC" tests when building with Asan+UBSan
# and -O3: those tests take more than 100x time than normal, with
# test_suite_pkwrite taking >3h on the CI. Observed with GCC 5.4 on
# Ubuntu 16.04 x86_64 and GCC 6.5 on Ubuntu 18.04 x86_64.
# GCC 7.5 and above on Ubuntu 18.04 appear fine.
# To avoid the performance problem, we use -O2 when GCC version is lower than 7.0.
# It doesn't slow down much even with modern compiler versions.
target_compile_options(${target} PRIVATE $<$<CONFIG:ASan>:-fsanitize=address -fno-common -fsanitize=undefined -fno-sanitize-recover=all>)
if (GCC_VERSION VERSION_LESS 7.0)
target_compile_options(${target} PRIVATE $<$<CONFIG:ASan>:-O2>)
else()
target_compile_options(${target} PRIVATE $<$<CONFIG:ASan>:-O3>)
endif()
set_target_properties(${target} PROPERTIES LINK_FLAGS_ASAN "-fsanitize=address -fsanitize=undefined")
target_compile_options(${target} PRIVATE $<$<CONFIG:ASanDbg>:-fsanitize=address -fno-common -fsanitize=undefined -fno-sanitize-recover=all -O1 -g3 -fno-omit-frame-pointer -fno-optimize-sibling-calls>)
set_target_properties(${target} PROPERTIES LINK_FLAGS_ASANDBG "-fsanitize=address -fsanitize=undefined")
target_compile_options(${target} PRIVATE $<$<CONFIG:TSan>:-fsanitize=thread -O3>)
set_target_properties(${target} PROPERTIES LINK_FLAGS_TSAN "-fsanitize=thread")
target_compile_options(${target} PRIVATE $<$<CONFIG:TSanDbg>:-fsanitize=thread -O1 -g3 -fno-omit-frame-pointer -fno-optimize-sibling-calls>)
set_target_properties(${target} PROPERTIES LINK_FLAGS_TSANDBG "-fsanitize=thread")
target_compile_options(${target} PRIVATE $<$<CONFIG:Check>:-Os>)
target_compile_options(${target} PRIVATE $<$<CONFIG:CheckFull>:-Os -Wcast-qual>)
if(TF_PSA_CRYPTO_FATAL_WARNINGS)
target_compile_options(${target} PRIVATE -Werror)
endif(TF_PSA_CRYPTO_FATAL_WARNINGS)
endfunction(tf_psa_crypto_set_gnu_base_compile_options)
function(tf_psa_crypto_set_clang_base_compile_options target)
target_compile_options(${target} PRIVATE -Wall -Wextra -Wwrite-strings -Wmissing-prototypes -Wpointer-arith -Wimplicit-fallthrough -Wshadow -Wvla -Wformat=2 -Wno-format-nonliteral)
target_compile_options(${target} PRIVATE $<$<CONFIG:Release>:-O2>)
target_compile_options(${target} PRIVATE $<$<CONFIG:Debug>:-O0 -g3>)
target_compile_options(${target} PRIVATE $<$<CONFIG:Coverage>:-O0 -g3 --coverage>)
set_target_properties(${target} PROPERTIES LINK_FLAGS_COVERAGE "--coverage")
target_compile_options(${target} PRIVATE $<$<CONFIG:ASan>:-fsanitize=address -fno-common -fsanitize=undefined -fno-sanitize-recover=all -O3>)
set_target_properties(${target} PROPERTIES LINK_FLAGS_ASAN "-fsanitize=address -fsanitize=undefined")
target_compile_options(${target} PRIVATE $<$<CONFIG:ASanDbg>:-fsanitize=address -fno-common -fsanitize=undefined -fno-sanitize-recover=all -O1 -g3 -fno-omit-frame-pointer -fno-optimize-sibling-calls>)
set_target_properties(${target} PROPERTIES LINK_FLAGS_ASANDBG "-fsanitize=address -fsanitize=undefined")
target_compile_options(${target} PRIVATE $<$<CONFIG:MemSan>:-fsanitize=memory>)
set_target_properties(${target} PROPERTIES LINK_FLAGS_MEMSAN "-fsanitize=memory")
target_compile_options(${target} PRIVATE $<$<CONFIG:MemSanDbg>:-fsanitize=memory -O1 -g3 -fno-omit-frame-pointer -fno-optimize-sibling-calls -fsanitize-memory-track-origins=2>)
set_target_properties(${target} PROPERTIES LINK_FLAGS_MEMSANDBG "-fsanitize=memory")
target_compile_options(${target} PRIVATE $<$<CONFIG:TSan>:-fsanitize=thread -O3>)
set_target_properties(${target} PROPERTIES LINK_FLAGS_TSAN "-fsanitize=thread")
target_compile_options(${target} PRIVATE $<$<CONFIG:TSanDbg>:-fsanitize=thread -O1 -g3 -fno-omit-frame-pointer -fno-optimize-sibling-calls>)
set_target_properties(${target} PROPERTIES LINK_FLAGS_TSANDBG "-fsanitize=thread")
target_compile_options(${target} PRIVATE $<$<CONFIG:Check>:-Os>)
if(TF_PSA_CRYPTO_FATAL_WARNINGS)
target_compile_options(${target} PRIVATE -Werror)
endif(TF_PSA_CRYPTO_FATAL_WARNINGS)
endfunction(tf_psa_crypto_set_clang_base_compile_options)
function(tf_psa_crypto_set_iar_base_compile_options target)
target_compile_options(${target} PRIVATE --warn_about_c_style_casts)
target_compile_options(${target} PRIVATE $<$<CONFIG:Release>:-Ohz>)
target_compile_options(${target} PRIVATE $<$<CONFIG:Debug>:--debug -On>)
if(TF_PSA_CRYPTO_FATAL_WARNINGS)
target_compile_options(${target} PRIVATE --warnings_are_errors)
endif(TF_PSA_CRYPTO_FATAL_WARNINGS)
endfunction(tf_psa_crypto_set_iar_base_compile_options)
function(tf_psa_crypto_set_msvc_base_compile_options target)
# Strictest warnings, UTF-8 source and execution charset
target_compile_options(${target} PRIVATE /W3 /utf-8)
if(TF_PSA_CRYPTO_FATAL_WARNINGS)
target_compile_options(${target} PRIVATE /WX)
endif(TF_PSA_CRYPTO_FATAL_WARNINGS)
if(MSVC_STATIC_RUNTIME)
foreach(flag_var
CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE
CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO
CMAKE_C_FLAGS_CHECK)
string(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}")
endforeach(flag_var)
endif()
endfunction(tf_psa_crypto_set_msvc_base_compile_options)
# Set extra compile options. These options are expected to be set for the
# compilation of the TF-PSA-Crypto library files. Not necessarily for the test
# or third party driver files.
function(tf_psa_crypto_set_extra_compile_options target)
if(CMAKE_COMPILER_IS_GNU)
tf_psa_crypto_set_gnu_extra_compile_options(${target})
elseif(CMAKE_COMPILER_IS_CLANG)
tf_psa_crypto_set_clang_extra_compile_options(${target})
endif()
endfunction(tf_psa_crypto_set_extra_compile_options)
function(tf_psa_crypto_set_gnu_extra_compile_options target)
target_compile_options(${target} PRIVATE -Wmissing-declarations)
endfunction(tf_psa_crypto_set_gnu_extra_compile_options)
function(tf_psa_crypto_set_clang_extra_compile_options target)
target_compile_options(${target} PRIVATE
-Wmissing-declarations
-Wdocumentation
-Wno-documentation-deprecated-sync
-Wunreachable-code
)
endfunction(tf_psa_crypto_set_clang_extra_compile_options)
function(tf_psa_crypto_set_config_files_compile_definitions target)
if(TF_PSA_CRYPTO_CONFIG_FILE)
target_compile_definitions(${target}
PUBLIC TF_PSA_CRYPTO_CONFIG_FILE="${TF_PSA_CRYPTO_CONFIG_FILE}")
endif()
if(TF_PSA_CRYPTO_USER_CONFIG_FILE)
target_compile_definitions(${target}
PUBLIC TF_PSA_CRYPTO_USER_CONFIG_FILE="${TF_PSA_CRYPTO_USER_CONFIG_FILE}")
endif()
endfunction(tf_psa_crypto_set_config_files_compile_definitions)
if(CMAKE_BUILD_TYPE STREQUAL "Check" AND TEST_CPP)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
if(CMAKE_COMPILER_IS_CLANG OR CMAKE_COMPILER_IS_GNU)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pedantic")
endif()
endif()
# Espressif: We do not use framework submodule to build TF-PSA-Crypto
# if (NOT EXISTS "${TF_PSA_CRYPTO_FRAMEWORK_DIR}/CMakeLists.txt")
# message(FATAL_ERROR "${TF_PSA_CRYPTO_FRAMEWORK_DIR}/CMakeLists.txt not found. Run `git submodule update --init` from the source tree to fetch the submodule contents.")
# endif()
#
# Directories with internal headers. The headers in that directories are not
# exposed to applications and thus not installed. These headers are currently
# consumed by Mbed TLS, eventually not so when we've finished cleaning up.
# Here we list all the directories containing such headers but the ones from
# drivers, that are appended in `drivers/CMakeLists.txt`.
#
set(TF_PSA_CRYPTO_PRIVATE_INCLUDE_DIRS
${CMAKE_CURRENT_SOURCE_DIR}/core
${CMAKE_CURRENT_SOURCE_DIR}/dispatch
${CMAKE_CURRENT_SOURCE_DIR}/extras
${CMAKE_CURRENT_SOURCE_DIR}/platform
${CMAKE_CURRENT_SOURCE_DIR}/utilities
)
#
# `drivers` must be added before `core` because the build of the main library
# set up in `core` depends on the list of available drivers, which is
# constructed in `drivers/CMakeLists.txt`. This list may include a generated
# test driver.
#
# add_subdirectory(framework)
add_subdirectory(include)
add_subdirectory(drivers) # must precede core
add_subdirectory(extras)
add_subdirectory(platform)
add_subdirectory(utilities)
add_subdirectory(core)
add_subdirectory(pkgconfig)
#
# The C files in tests/src directory contain test code shared among test suites
# and programs. This shared test code is compiled and linked to test suites and
# programs objects as a set of compiled objects. The compiled objects are NOT
# built into a library that the test suite and program objects would link
# against as they link against the tfpsacrypto library. The reason is that such
# library is expected to have mutual dependencies with the aforementioned
# library and that there is as of today no portable way of handling such
# dependencies (only toolchain specific solutions).
#
# Thus the below definition of the `tf_psa_crypto_test` CMake library of
# objects target. This library of objects is used by tests and programs CMake
# files to define the test executables.
#
if(ENABLE_TESTING OR ENABLE_PROGRAMS)
file(GLOB TF_PSA_CRYPTO_TEST_FILES
${TF_PSA_CRYPTO_FRAMEWORK_DIR}/tests/src/*.c
${TF_PSA_CRYPTO_FRAMEWORK_DIR}/tests/src/drivers/*.c
tests/src/*.c)
add_library(tf_psa_crypto_test OBJECT ${TF_PSA_CRYPTO_TEST_FILES})
tf_psa_crypto_set_base_compile_options(tf_psa_crypto_test)
if(GEN_FILES)
add_custom_command(
OUTPUT
${CMAKE_CURRENT_BINARY_DIR}/tests/include/test/test_keys.h
COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/tests/include/test
COMMAND
"${TF_PSA_CRYPTO_PYTHON_EXECUTABLE}"
"${TF_PSA_CRYPTO_FRAMEWORK_DIR}/scripts/generate_test_keys.py"
"--output"
"${CMAKE_CURRENT_BINARY_DIR}/tests/include/test/test_keys.h"
DEPENDS
${TF_PSA_CRYPTO_FRAMEWORK_DIR}/scripts/generate_test_keys.py
)
add_custom_target(tf_psa_crypto_test_keys_header
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/tests/include/test/test_keys.h)
add_dependencies(tf_psa_crypto_test tf_psa_crypto_test_keys_header)
if(TF_PSA_CRYPTO_TEST_DRIVER)
add_dependencies(tf_psa_crypto_test ${TF_PSA_CRYPTO_TEST_DRIVER_GENERATION_TARGETS})
endif()
endif()
file(WRITE
${CMAKE_CURRENT_BINARY_DIR}/tests/seedfile
"This is a seedfile that contains 64 bytes ......................"
)
# Note: "tests/include/test" exists solely to provide access to
# "mbedtls/build_info.h". That header is an alias of
# "tf-psa-crypto/build_info.h".
#
# It is included in framework headers and C modules because those
# components are also used in the Mbed TLS context.
target_include_directories(tf_psa_crypto_test
PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/tests/include
${TF_PSA_CRYPTO_FRAMEWORK_DIR}/tests/include
tests/include
tests/include/test
# Add the build-tree include directory before the source-tree one
# so that generated headers in the build tree take precedence.
${CMAKE_CURRENT_BINARY_DIR}/include
include
${TF_PSA_CRYPTO_PRIVATE_INCLUDE_DIRS})
foreach(driver_target ${TF_PSA_CRYPTO_DRIVER_TARGETS})
get_target_property(public_includes ${driver_target} INTERFACE_INCLUDE_DIRECTORIES)
target_include_directories(tf_psa_crypto_test PUBLIC ${public_includes})
endforeach()
# Request C11, needed for memory poisoning tests
set_target_properties(tf_psa_crypto_test PROPERTIES C_STANDARD 11)
tf_psa_crypto_set_config_files_compile_definitions(tf_psa_crypto_test)
endif()
if(ENABLE_PROGRAMS)
add_subdirectory(programs)
endif()
if(ENABLE_TESTING)
enable_testing()
add_subdirectory(tests)
# additional convenience targets for Unix only
if(UNIX AND (NOT TF_PSA_CRYPTO_AS_SUBPROJECT))
# For coverage testing:
# 1. Build with:
# cmake -D CMAKE_BUILD_TYPE=Coverage /path/to/source && make
# 2. Run the relevant tests for the part of the code you're interested in.
# For the reference coverage measurement, see
# tests/scripts/basic-build-test.sh
# 3. Run framework/scripts/lcov.sh to generate an HTML report.
ADD_CUSTOM_TARGET(lcov
COMMAND framework/scripts/lcov.sh
)
ADD_CUSTOM_TARGET(memcheck
COMMAND sed -i.bak s+/usr/bin/valgrind+`which valgrind`+ DartConfiguration.tcl
COMMAND ctest -O memcheck.log -D ExperimentalMemCheck
COMMAND tail -n1 memcheck.log | grep 'Memory checking results:' > /dev/null
COMMAND rm -f memcheck.log
COMMAND mv DartConfiguration.tcl.bak DartConfiguration.tcl
)
endif()
# Make scripts needed for testing available in an out-of-source build.
if (NOT ${CMAKE_CURRENT_BINARY_DIR} STREQUAL ${CMAKE_CURRENT_SOURCE_DIR})
tf_psa_crypto_link_to_source(scripts)
# Copy (don't link) DartConfiguration.tcl, needed for memcheck, to
# keep things simple with the sed commands in the memcheck target.
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/DartConfiguration.tcl
${CMAKE_CURRENT_BINARY_DIR}/DartConfiguration.tcl COPYONLY)
endif()
endif()
if(NOT DISABLE_PACKAGE_CONFIG_AND_INSTALL)
configure_package_config_file(
"cmake/TF-PSA-CryptoConfig.cmake.in"
"cmake/TF-PSA-CryptoConfig.cmake"
INSTALL_DESTINATION "cmake")
write_basic_package_version_file(
"cmake/TF-PSA-CryptoConfigVersion.cmake"
COMPATIBILITY SameMajorVersion
VERSION "${TF_PSA_CRYPTO_VERSION}")
install(
FILES "${CMAKE_CURRENT_BINARY_DIR}/cmake/TF-PSA-CryptoConfig.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/cmake/TF-PSA-CryptoConfigVersion.cmake"
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/TF-PSA-Crypto")
export(
EXPORT TF-PSA-CryptoTargets
NAMESPACE TF-PSA-Crypto::
FILE "cmake/TF-PSA-CryptoTargets.cmake")
install(
EXPORT TF-PSA-CryptoTargets
NAMESPACE TF-PSA-Crypto::
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/TF-PSA-Crypto"
FILE "TF-PSA-CryptoTargets.cmake")
if(CMAKE_VERSION VERSION_GREATER 3.15 OR CMAKE_VERSION VERSION_EQUAL 3.15)
# Do not export the package by default
cmake_policy(SET CMP0090 NEW)
# Make this package visible to the system
export(PACKAGE TF-PSA-Crypto)
endif()
endif()
+95
View File
@@ -0,0 +1,95 @@
Contributing
============
We gratefully accept bug reports and contributions from the community. All PRs are reviewed by the project team / community, and may need some modifications to
be accepted.
Quick Checklist for PR contributors
-----------------------------------
More details on all of these points may be found in the sections below.
- [Sign-off](#license-and-copyright): all commits must be signed off.
- [Tests](#tests): please ensure the PR includes adequate tests.
- [Changelog](#documentation): if needed, please provide a changelog entry.
- [Backports](#long-term-support-branches): provide a backport if needed (it's fine to wait until the main PR is accepted).
Coding Standards
----------------
- Contributions should include tests, as mentioned in the [Tests](#tests) and [Continuous Integration](#continuous-integration-tests) sections. Please check that your contribution passes basic tests before submission, and check the CI results after making a pull request.
- The code should be written in a clean and readable style, and must follow [our coding standards](https://mbed-tls.readthedocs.io/en/latest/kb/development/mbedtls-coding-standards/).
- The code should be written in a portable generic way, that will benefit the whole community, and not only your own needs.
- The code should be secure, and will be reviewed from a security point of view as well.
Making a Contribution
---------------------
1. [Check for open issues](https://github.com/Mbed-TLS/TF-PSA-Crypto/issues) or [start a discussion](https://lists.trustedfirmware.org/mailman3/lists/mbed-tls.lists.trustedfirmware.org) around a feature idea or a bug.
1. Fork the [TF-PSA-Crypto repository on GitHub](https://github.com/Mbed-TLS/TF-PSA-Crypto) to start making your changes. As a general rule, you should use the ["development" branch](https://github.com/Mbed-TLS/TF-PSA-Crypto/tree/development) as a basis.
1. Write a test which shows that the bug was fixed or that the feature works as expected.
1. Send a pull request (PR) and work with us until it gets merged and published. Contributions may need some modifications, so a few rounds of review and fixing may be necessary. See our [review process guidelines](https://mbed-tls.readthedocs.io/en/latest/reviews/review-for-contributors/).
1. For quick merging, the contribution should be short, and concentrated on a single feature or topic. The larger the contribution is, the longer it would take to review it and merge it.
Backwards Compatibility
-----------------------
The project aims to minimise the impact on users upgrading to newer versions of the library and it should not be necessary for a user to make any changes to their own code to work with a newer version of the library. Unless the user has made an active decision to use newer features, a newer generation of the library or a change has been necessary due to a security issue or other significant software defect, no modifications to their own code should be necessary. To achieve this, API compatibility is maintained between different versions of TF-PSA-Crypto on the main development branch and in LTS (Long Term Support) branches, as described in [BRANCHES.md](BRANCHES.md).
To minimise such disruption to users, where a change to the interface is required, all changes to the ABI or API, even on the main development branch where new features are added, need to be justifiable by either being a significant enhancement, new feature or bug fix which is best resolved by an interface change. If there is an API change, the contribution, if accepted, will be merged only when there is a major release.
No changes are permitted to the definition of functions in the public interface which will change the API. Instead the interface can only be changed by its extension. Where changes to an existing interface are necessary, functions in the public interface which need to be changed are marked as 'deprecated'. If there is a strong reason to replace an existing function with one that has a slightly different interface (different prototype, or different documented behavior), create a new function with a new name with the desired interface. Keep the old function, but mark it as deprecated.
Periodically, the library will remove deprecated functions from the library which will be a breaking change in the API, but such changes will be made only in a planned, structured way that gives sufficient notice to users of the library.
Long Term Support Branches
--------------------------
TF-PSA-Crypto aim to provide LTS (Long Term Support) branches, which are maintained continuously for a given period. The release date of the first 1.x LTS is yet to be determined. The LTS branches are provided to allow users of the library to have a maintained, stable version of the library which contains only security fixes and fixes for other defects, without encountering additional features or API extensions which may introduce issues or change the code size or RAM usage, which can be significant considerations on some platforms. To allow users to take advantage of the LTS branches, these branches maintain backwards compatibility for both the public API and ABI.
When backporting to these branches please observe the following rules:
1. Any change to the library which changes the API or ABI cannot be backported.
1. All bug fixes that correct a defect that is also present in an LTS branch must be backported to that LTS branch. If a bug fix introduces a change to the API such as a new function, the fix should be reworked to avoid the API change. API changes without very strong justification are unlikely to be accepted.
1. If a contribution is a new feature or enhancement, no backporting is required. Exceptions to this may be additional test cases or quality improvements such as changes to build or test scripts.
It would be highly appreciated if contributions are backported to LTS branches in addition to the [development branch](https://github.com/Mbed-TLS/TF-PSA-Crypto/tree/development) by contributors.
The list of maintained branches can be found in the [Current Branches section
of BRANCHES.md](BRANCHES.md#current-branches).
Tests
-----
As mentioned, tests that show the correctness of the feature or bug fix should be added to the pull request, if no such tests exist.
TF-PSA-Crypto includes a comprehensive set of test suites in the `tests/` directory that are dynamically generated to produce the actual test source files (e.g. `test_suite_psa_crypto.c`). These files are generated from a `function file` (e.g. `suites/test_suite_psa_crypto.function`) and a `data file` (e.g. `suites/test_suite_psa_crypto.data`). The function file contains the test functions. The data file contains the test cases, specified as parameters that will be passed to the test function.
[A Knowledge Base article describing how to add additional tests is available on the Mbed TLS website](https://mbed-tls.readthedocs.io/en/latest/kb/development/test_suites/).
A test script `tests/scripts/basic-build-test.sh` is available to show test coverage of the library. New code contributions should provide a similar level of code coverage to that which already exists for the library.
Sample applications, if needed, should be modified as well.
Continuous Integration Tests
----------------------------
Once a PR has been made, the Continuous Integration (CI) tests are triggered and run. You should follow the result of the CI tests, and fix failures.
Documentation
-------------
TF-PSA-Crypto is well documented, but if you think documentation is needed, speak out!
1. All interfaces should be documented through Doxygen. New APIs should introduce Doxygen documentation.
1. Complex parts in the code should include comments.
1. If needed, a Readme file is advised.
1. If a [Knowledge Base (KB)](https://mbed-tls.readthedocs.io/en/latest/kb/) article should be added, write this as a comment in the PR description.
1. A [ChangeLog](https://github.com/Mbed-TLS/TF-PSA-Crypto/blob/development/ChangeLog.d/00README.md) entry should be added for this contribution.
License and Copyright
---------------------
Unless specifically indicated otherwise in a file, TF-PSA-Crypto files are provided under a dual [Apache-2.0](https://spdx.org/licenses/Apache-2.0.html) OR [GPL-2.0-or-later](https://spdx.org/licenses/GPL-2.0-or-later.html) license. See the [LICENSE](LICENSE) file for the full text of these licenses. This means that users may choose which of these licenses they take the code under.
Contributors must accept that their contributions are made under both the Apache-2.0 AND [GPL-2.0-or-later](https://spdx.org/licenses/GPL-2.0-or-later.html) licenses.
All new files should include the standard SPDX license identifier where possible, i.e. "SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later".
The copyright on contributions is retained by the original authors of the code. Where possible for new files, this should be noted in a comment at the top of the file in the form: "Copyright The Mbed TLS Contributors".
When contributing code to us, the committer and all authors are required to make the submission under the terms of the [Developer Certificate of Origin](dco.txt), confirming that the code submitted can (legally) become part of the project, and is submitted under both the Apache-2.0 AND GPL-2.0-or-later licenses.
This is done by including the standard Git `Signed-off-by:` line in every commit message. If more than one person contributed to the commit, they should also add their own `Signed-off-by:` line.
+653
View File
@@ -0,0 +1,653 @@
= TF-PSA-Crypto 1.1.0 branch released 2026-03-31
Removals
* The undocumented ability to load persistent keys outside the user key ID
range has been removed. (This does not affect
MBEDTLS_PSA_CRYPTO_BUILTIN_KEYS.)
* The headers no longer define 'inline' as a macro. This was done on Arm
Compiler 5 and MSVC. The compiler versions that needed this definition are
no longer supported since TF-PSA-Crypto 1.0.
Features
* The automatic computation of MBEDTLS_PSA_STATIC_KEY_SLOT_BUFFER_SIZE has
been improved to take into account the following key types:
asymmetric keys, ciphers, AEADs, CMAC and HMAC.
* mbedtls_pk_write_pubkey_psa() is introduced to allow exporting the public
key from a PK context in a format that can easily be imported into PSA.
* Implement SHAKE (PSA_ALG_SHAKE128, PSA_ALG_SHAKE256).
* The device for reading entropy on platforms without a dedicated system
call can now be configured with MBEDTLS_PLATFORM_DEV_RANDOM or
mbedtls_platform_dev_random.
* Applications can use the new functions psa_random_reseed() to
request an immediate reseed of the PSA random generator, or
psa_random_deplete() to force a reseed on the next random generator call.
* Applications can call psa_random_set_prediction_resistance() to toggle
prediction resistance in the PSA random generator.
Security
* The default device for reading entropy on platforms without a dedicated
system call is now /dev/random instead of /dev/urandom. This is safer
on Linux in case the application runs early after the kernel boots,
but may block needlessly on Linux <= 5.6. Reported by supers1ngular
(BayLibre).
* Fix missing validation of the peer's key in key agreement operations using
PSA_ALG_FFDH: low-order elements were not rejected as they should be. This
is a problem for protocols using FFDH that expect contributory behaviour,
that is, where neither party should be able to force the shared secret
into a small set. Reported independently by Eva Crystal (0xiviel) and
+ another reporter.
* Add tag length validation in mbedtls_ccm_finish() to prevent
out-of-bounds reads and mitigate potential application buffer
overflows where applications relied on the library to enforce
tag length constraints.
Reported by Eva Crystal (0xiviel).
* Fix a buffer overflow in psa_export_public_key() for FFDH keys when the
output buffer is too small. Found by Haruto Kimura (Stella).
* If an application called psa_crypto_init() then fork() and continued to
use cryptography APIs (possibly indirectly, e.g. for TLS), the random
generator states were duplicated. Fix this by forcing a RNG reseed in
the child process. CVE-2026-25835
* Applications running in environments where the application state is
cloned (for example due to resuming a frozen system state multiple
times, or due to cloning a virtual machine image) should arrange to
reseed the random generator using one of the new functions
psa_random_reseed() or psa_random_deplete(). CVE-2026-25835
Bugfix
* Appease GCC 14.3's array bounds checker by inserting checks in mbedtls_xor
that bail before the byte-at-a-time loop when the array size is a constant
(using MBEDTLS_HAS_BUILTIN) and an exact multiple of the larger loop size.
* CMake now installs headers to `CMAKE_INSTALL_INCLUDEDIR` instead of the
hard-coded `include` directory.
* Fix CMake package version that was inconsistent with the product version.
Fixes #553.
* Fix CMake failure on Windows because of a native directory separator.
Fixes Mbed-TLS/mbedtls#10502.
* Partially fix a performance regression in RSA operations introduced by a
security fix in 1.0, by improving the performance of RSA private key
operations when MBEDTLS_RSA_NO_CRT is disabled, which is the default.
* Fix compilation errors in `aesce.c` in some Visual Studio builds.
Fixes #548.
* Interruptible operations (ECDH key agreement, ECC key generation) were not
actually interruptible (always completed in one go) in builds with ECDSA
disabled.
* Built-in SHA3 was included in the build even when SHA3 had a PSA
accelerator. Fix this. Fixes #542.
* Fix a bug that caused GCM tag calculations to fail, so that data was
correctly encrypted but could not be authenticated. The bug was only
observed with GCC 10.0 to 14.2 inclusive, when compiling with -O3, and
running without AESNI or AESCE.
Fixes #665.
* Fix a build failure with dietlibc.
* Some functions in PK were using large buffers (around 2KB in the default
configuration) on the stack, which was a problem in environments with a
small stack. Those buffers are now allocated on the heap, except in
configurations where ECC is the only supported key type in PK, making PK
still independent of the heap in such configurations (if the ECC driver
itself is not using the heap). Fixes #476.
Changes
* ChaCha20 size and performance: add a Neon implementation of ChaCha20 for
Thumb2 and 32 and 64-bit Arm, for Armv7 onwards. At default settings,
this improves performance by around 2x to 2.7x on Aarch64.
* Add a new function, mbedtls_pk_get_key_type(), which returns the PSA
key type corresponding to the type of the key represented by the
given PK object.
* Running the unit tests now requires a heap (possibly from
MBEDTLS_MEMORY_BUFFER_ALLOC_C). They now use less stack (almost
5000 bytes less).
* Static assertions in the library (`MBEDTLS_STATIC_ASSERT`) are now
always enabled, using indirect methods in pre-C11 compilers. This change
also fixes warnings in pedantic mode with GCC or Clang on some platforms.
* Tweak the detection of Unix-like platforms, which makes more system
interfaces (timing, threading) available on Haiku, QNX and Midipix.
* On MinGW, always use a standard-compliant printf function family.
* Non-driver files have been moved out of `drivers/builtin/src` into three
new directories at the root of the repository:
- `extras`: modules implemented on top of the PSA Cryptography API, or
providing functionality beyond it (for example, the LMS stateful hash
implementation currently).
- `platform`: modules implementing the platform abstraction layer.
- `utilities`: utility modules used by the built-in drivers, the PSA
Cryptography API implementation, modules in `extras`, and potentially
by security protocols such as TLS.
* A new directory `dispatch` has been added at the root of the repository
to eventually host all code that dispatches cryptographic operations to
drivers, such as `psa_crypto_driver_wrappers_no_static.c`. For the time
being, it only contains `psa_crypto_driver_wrappers_no_static.h`.
= TF-PSA-Crypto 1.0.0 branch released 2025-10-15
API changes
* The experimental functions psa_generate_key_ext() and
psa_key_derivation_output_key_ext() have been replaced by
psa_generate_key_custom() and psa_key_derivation_output_key_custom().
They have almost exactly the same interface, but the variable-length
data is passed in a separate parameter instead of a flexible array
member. This resolves a build failure under C++ compilers that do not
support flexible array members (a C99 feature not adopted by C++).
Fixes #9020.
* The PSA and Mbed TLS error spaces are now unified. mbedtls_xxx()
functions can now return PSA_ERROR_xxx values.
This will not affect most applications since the error values are
between -32767 and -1 as before.
* Remove MBEDTLS_PK_RSA_ALT from the PK module.
* MBEDTLS_ERR_PK_SIG_LEN_MISMATCH is no longer a distinct error code.
A valid signature with trailing garbage is now reported as an invalid
signature with all algorithms.
* All API functions now use the PSA random generator psa_generate_random()
internally. As a consequence, functions no longer take RNG parameters.
Please refer to the migration guide at :
docs/4.0-migration-guide.md.
* Privatize the functions mbedtls_ecc_group_to_psa and
mbedtls_ecc_group_from_psa.
* Remove the functions mbedtls_ecc_group_to_psa() and
mbedtls_ecc_group_from_psa(), which are no longer meaningful since
ECC groups are no longer exposed directly in the API.
* mbedtls_pk_verify_ext() ignores the options parameter when an
MBEDTLS_PK_RSASSA_PSS context type is used. The function assumes that
salt length is any and that the hash algorithm used for message, encoding
and MGF1 is the same. An error will be returned if any of these assumptions
is false.
* Align the mbedtls_nist_kw_wrap() and mbedtls_nist_kw_unwrap() functions
with the PSA Crypto API. The functions mbedtls_nist_kw_wrap() and
mbedtls_nist_kw_unwrap() now take a PSA key identifier instead of a
plain-text key via a custom context.
* Remove mbedtls_pk_encrypt() and mbedtls_pk_decrypt(). Convert the
key to PSA and use the PSA functions instead, see the migration guide for
details.
* Change MBEDTLS_ERR_ECP_IN_PROGRESS to be an alias of
PSA_OPERATION_INCOMPLETE and MBEDTLS_ERR_RSA_VERIFY_FAILED to be an alias
of PSA_ERROR_INVALID_SIGNATURE.
* Rename mbedtls_pk_setup_opaque to mbedtls_pk_wrap_psa.
* The custom entropy collector callback mbedtls_hardware_poll()
(enabled by MBEDTLS_ENTROPY_HARDWARE_ALT) has been replaced by a
new callback mbedtls_platform_get_entropy() with different parameters
(enabled by MBEDTLS_PSA_DRIVER_GET_ENTROPY). See the new function's
documentation and “Custom entropy collector” in the migration guide.
* To build the library with only a nonvolatile seed and no actual entropy
source, you now need to enable the new option
MBEDTLS_ENTROPY_NO_SOURCES_OK.
* Due to the entropy configuration changes, if you write a configuration file
from scratch, the default entropy source MBEDTLS_PSA_BUILTIN_GET_ENTROPY
now needs to be enabled explicitly.
* The configuration options MBEDTLS_CTR_DRBG_RESEED_INTERVAL and
MBEDTLS_HMAC_DRBG_RESEED_INTERVAL have been replaced by a unified
setting of MBEDTLS_PSA_RNG_RESEED_INTERVAL.
* The configuration option MBEDTLS_ENTROPY_FORCE_SHA256 has been removed.
MBEDTLS_PSA_CRYPTO_RNG_HASH can now be used to select the entropy
module's hashing algorithm.
* The mutex functions provided by platforms where MBEDTLS_THREADING_ALT is
enabled have changed in minor ways:
- The type of mutex objects provided by the platform functions is
now called mbedtls_platform_mutex_t, distinct from the API type
mbedtls_threading_mutex_t.
- The mutex_init function now returns an error code.
- Mutex functions other than mutex_init can now assume that the mutex
has been successfully initialized.
* The Random Number Generator configuration options have been refactored.
The following options have been removed:
MBEDTLS_ENTROPY_C, MBEDTLS_ENTROPY_FORCE_SHA256,
MBEDTLS_ENTROPY_MAX_GATHER, MBEDTLS_ENTROPY_MAX_SOURCES,
MBEDTLS_CTR_DRBG_ENTROPY_LEN, MBEDTLS_CTR_DRBG_MAX_INPUT,
MBEDTLS_CTR_DRBG_MAX_REQUEST, MBEDTLS_CTR_DRBG_MAX_SEED_INPUT,
MBEDTLS_CTR_DRBG_USE_128_BIT_KEY, MBEDTLS_HMAC_DRBG_MAX_INPUT,
MBEDTLS_HMAC_DRBG_MAX_REQUEST, MBEDTLS_HMAC_DRBG_MAX_SEED_INPUT and
MBEDTLS_PSA_HMAC_DRBG_MD_TYPE.
The following options have been introduced:
MBEDTLS_PSA_CRYPTO_RNG_HASH and MBEDTLS_PSA_CRYPTO_RNG_STRENGTH.
See "Random number generation configuration" in the migration guide for
more information.
* The following PK interfaces are now private and should no longer be used.
mbedtls_pk_type_t
mbedtls_pk_debug_type
mbedtls_pk_debug_item
MBEDTLS_PK_DEBUG_MAX_ITEMS
mbedtls_pk_info_from_type()
mbedtls_pk_setup()
mbedtls_pk_get_len()
mbedtls_pk_can_do()
mbedtls_pk_can_do_ext()
mbedtls_pk_debug()
mbedtls_pk_get_name()
mbedtls_pk_get_type()
mbedtls_pk_rsa()
mbedtls_pk_ec()
mbedtls_pk_parse_subpubkey()
mbedtls_pk_write_pubkey()
mbedtls_pk_verify_new()
* The hmac parameter of the mbedtls_md_setup() function must now always be
set to 0 as HMAC is no longer supported by MD. To use HMAC, please use
the psa_mac_ API.
* Make the following error codes aliases of their PSA equivalents, where
xxx is a module, e.g. ASN1 or PK.
MBEDTLS_ERR_xxx_BAD_INPUT[_DATA] -> PSA_ERROR_INVALID_ARGUMENT
MBEDTLS_ERR_xxx_ALLOC_FAILED -> PSA_ERROR_INSUFFICIENT_MEMORY
MBEDTLS_ERR_xxx_[AUTH/VERIFY]_FAILED -> PSA_ERROR_INVALID_SIGNATURE
MBEDTLS_ERR_xxx_BUFFER_TOO_SMALL -> PSA_ERROR_BUFFER_TOO_SMALL
MBEDTLS_ERR_xxx_OUTPUT_TOO_LARGE -> PSA_ERROR_BUFFER_TOO_SMALL
MBEDTLS_ERR_xxx_INVALID_PADDING -> PSA_ERROR_INVALID_PADDING
* A PK context no longer associates specific algorithms with the key, except
when wrapping a PSA key. In particular, after mbedtls_pk_copy_from_psa() or
mbedtls_pk_copy_public_from_psa() on an RSA key, the functions
mbedtls_pk_get_psa_attributes(), mbedtls_pk_sign() and mbedtls_pk_verify()
will use PKCS#1v1.5 signature or encryption, regardless of the original
key's policy.
Default behavior changes
* In a PSA-client-only build (i.e. MBEDTLS_PSA_CRYPTO_CLIENT &&
!MBEDTLS_PSA_CRYPTO_C), do not automatically enable local crypto when the
corresponding PSA mechanism is enabled, since the server provides the
crypto. Fixes #9126.
* The PK module now always uses the PSA subsystem
to perform cryptographic operations, with a few exceptions documented
in docs/architecture/psa-migration/psa-limitations.md. This
corresponds to the behavior of Mbed TLS 3.x when
MBEDTLS_USE_PSA_CRYPTO is enabled. In effect, MBEDTLS_USE_PSA_CRYPTO
is now always enabled.
* psa_crypto_init() must be called before performing any cryptographic
operation, including indirect requests such as parsing a key or
certificate or starting a TLS handshake.
* The `PSA_WANT_XXX` symbols as defined in
tf-psa-crypto/include/psa/crypto_config.h are now always used in the
configuration of the cryptographic mechanisms exposed by the PSA API.
This corresponds to the configuration behavior of Mbed TLS 3.x when
MBEDTLS_PSA_CRYPTO_CONFIG is enabled. In effect, MBEDTLS_PSA_CRYPTO_CONFIG
is now always enabled and the configuration option has been removed.
Requirement changes
* Implementations of MBEDTLS_THREADING_ALT must now provide condition
variables in addition to mutexes.
Removals
* Drop support for crypto alt interface. Removes MBEDTLS_XXX_ALT options
at the module and function level for crypto mechanisms only. The remaining
alt interfaces for platform, threading and timing are unchanged.
Fixes #8149.
* Drop support for VIA Padlock. Removes MBEDTLS_PADLOCK_C.
Fixes #5903.
* Remove many MBEDTLS_ERR_xxx error codes, superseded by PSA_ERROR_xxx.
See the 4.0 migration guide for details.
* Support for dynamic secure elements (i.e. MBEDTLS_PSA_CRYPTO_SE_C) was
already marked as deprecated and it has been removed.
* Removed the MBEDTLS_PSA_INJECT_ENTROPY configuration option from
crypto_config.h. The functionality that this option was enabling will be
reintroduced as part of the work on issue #8150.
* MBEDTLS_NO_PLATFORM_ENTROPY and the previously deprecated
MBEDTLS_ENTROPY_HARDWARE_ALT are removed. See the documentation of
MBEDTLS_PLATFORM_GET_ENTROPY_ALT for a description on how the entropy
module gathers entropy data.
* MBEDTLS_ENTROPY_MIN_HARDWARE is also removed following the removal of
MBEDTLS_ENTROPY_HARDWARE_ALT.
* TF-PSA-Crypto does not provide an OID API. A subset of the OID
interfaces of Mbed TLS 3.x are now in the X.509 library in
Mbed TLS 4.x.
* Removed the MBEDTLS_SHA3_C configuration option from crypto_config.h.
SHA3 can now be configured with the PSA_WANT_SHA3_* options.
* The library no longer offers interfaces to look up values by OID
or OID by enum values. The compilation option MBEDTLS_OID_C no longer
exists. OID tables are included in the build automatically as needed.
OIDs that are not relevant to TF-PSA-Crypto have been removed.
* Remove the function mbedtls_asn1_get_mpi() from the public interface.
It is replaced by mbedtls_asn1_get_integer().
* Remove mbedtls_asn1_write_mpi() from the public API. This has been replaced
by mbedtls_asn1_write_integer(), which does not use the legacy mbedtls_mpi
type.
* Remove the legacy HKDF module (mbedtls_hkdf_xxx enabled by
MBEDTLS_HKDF_C). Use PSA instead (psa_key_derivation_xxx with
PSA_ALG_HKDF, enabled by PSA_WANT_ALG_HKDF).
* Remove mbedtls_asn1_free_named_data(). Use
mbedtls_asn1_free_named_data_list() or
mbedtls_asn1_free_named_data_list_shallow() instead.
* The options MBEDTLS_NO_PLATFORM_ENTROPY,
MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES, MBEDTLS_ENTROPY_HARDWARE_ALT and
MBEDTLS_ENTROPY_MIN_HARDWARE have been removed. Entropy sources are
now controlled by MBEDTLS_PSA_BUILTIN_GET_ENTROPY and
MBEDTLS_PSA_DRIVER_GET_ENTROPY. See “Entropy configuration” in the
migration guide for more information.
* MBEDTLS_PLATFORM_GET_ENTROPY_ALT, introduced in TF-PSA-Crypto 1.0.0-beta,
has been removed in favor of MBEDTLS_PSA_DRIVER_GET_ENTROPY.
* Remove the PKCS12 module, which provided the ability to read keys
encrypted with PKCS#5 v1.5 PBES1 with a DES-based cipher.
* Removed the `psa_pake_set_password_key()` function to comply
with the PSA API 1.2 PAKE extension.
* Removed the `psa_pake_get_implicit_key()` function. Removed to comply
with PSA API 1.2 PAKE extension.
* Support for EC curves secp224r1, secp224k1, secp192k1 and secp192r1 is
removed.
* mbedtls_pk_rsassa_pss_options has been removed from the interface.
* The configuration options MBEDTLS_MD5_C, MBEDTLS_RIPEMD160_C,
MBEDTLS_SHA1_C, MBEDTLS_SHA224_C, MBEDTLS_SHA256_C, MBEDTLS_SHA384_C and
MBEDTLS_SHA512_C have been removed. Support for hash algorithms can now
only be enabled through the hash-related `PSA_WANT_XXX` symbols. See
psa-transition.md for more information.
* The configuration options MBEDTLS_AES_C, MBEDTLS_ARIA_C,
MBEDTLS_CAMELLIA_C, MBEDTLS_CCM_C, MBEDTLS_CHACHA20_C,
MBEDTLS_CHACHAPOLY_C, MBEDTLS_CIPHER_C, MBEDTLS_CIPHER_MODE_CBC,
MBEDTLS_CIPHER_MODE_CFB, MBEDTLS_CIPHER_MODE_CTR, MBEDTLS_CIPHER_MODE_OFB,
MBEDTLS_CIPHER_MODE_XTS, MBEDTLS_CIPHER_NULL_CIPHER,
MBEDTLS_CIPHER_PADDING_PKCS7, MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS,
MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN, MBEDTLS_CIPHER_PADDING_ZEROS,
MBEDTLS_CMAC_C, MBEDTLS_DES_C MBEDTLS_GCM_C and MBEDTLS_POLY1305_C have
been removed. Support for ciphers and AEAD algorithms can now only be
enabled through the cipher and AEAD related `PSA_WANT_XXX` symbols. The
only padding mode now supported in CBC cipher mode is PKCS7. See
psa-transition.md for more information.
* The configuration options MBEDTLS_GENPRIME, MBEDTLS_PKCS1_V15,
MBEDTLS_PKCS1_V21 and MBEDTLS_RSA_C have been removed. Support for
RSA algorithms can now only be enabled through the RSA-related
`PSA_WANT_XXX` symbols. See psa-transition.md for more information.
* The configuration options MBEDTLS_ECDH_C, MBEDTLS_ECDSA_C,
MBEDTLS_ECDSA_DETERMINISTIC, MBEDTLS_ECJPAKE_C, MBEDTLS_ECP_C,
MBEDTLS_ECP_DP_BP256R1_ENABLED, MBEDTLS_ECP_DP_BP384R1_ENABLED,
MBEDTLS_ECP_DP_BP512R1_ENABLED, MBEDTLS_ECP_DP_CURVE25519_ENABLED,
MBEDTLS_ECP_DP_CURVE448_ENABLED, MBEDTLS_ECP_DP_SECP192K1_ENABLED,
MBEDTLS_ECP_DP_SECP192R1_ENABLED, MBEDTLS_ECP_DP_SECP224R1_ENABLED,
MBEDTLS_ECP_DP_SECP256K1_ENABLED, MBEDTLS_ECP_DP_SECP256R1_ENABLED,
MBEDTLS_ECP_DP_SECP384R1_ENABLED, MBEDTLS_ECP_DP_SECP521R1_ENABLE have
been removed. Support for algorithms based on elliptic curves can now
only be enabled through the elliptic-curve-related `PSA_WANT_XXX` symbols.
See psa-transition.md for more information.
* The configuration option MBEDTLS_BIGNUM_C has been removed. Support for
big number calculations is now enabled internally only when required by
enabled asymmetric cryptographic algorithms.
* Removed the ability to customize psa_can_do_hash() and
psa_can_do_cipher(), which allowed hash or cipher operations to be
performed through a legacy implementation when PSA is not yet fully
initialized.
* The following options have been removed as
they are deprecated:
PSA_WANT_KEY_TYPE_ECC_KEY_PAIR
PSA_WANT_KEY_TYPE_RSA_KEY_PAIR
MBEDTLS_PSA_BUILTIN_KEY_TYPE_RSA_KEY_PAIR
MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR
MBEDTLS_PSA_ACCEL_KEY_TYPE_RSA_KEY_PAIR
MBEDTLS_PSA_ACCEL_KEY_TYPE_ECC_KEY_PAIR
MBEDTLS_SHA256_USE_A64_CRYPTO_IF_PRESENT
MBEDTLS_SHA256_USE_A64_CRYPTO_ONLY
* Deprecated PSA key handle related functions and macros are removed:
psa_open_key() and psa_close_key() functions, PSA_KEY_HANDLE_INIT
macro and psa_key_handle_t type.
* Deprecated PSA custom Diffie-Hellman group support functions and macros
are removed: psa_get_key_domain_parameters() and
psa_set_key_domain_parameters() functions, PSA_DH_FAMILY_CUSTOM and
PSA_KEY_DOMAIN_PARAMETERS_SIZE macros.
* The following functions have been removed from the MD module:
mbedtls_md_list()
mbedtls_md_info_from_string()
mbedtls_md_get_name()
mbedtls_md_info_from_ctx()
mbedtls_md_file()
mbedtls_md_hmac_starts()
mbedtls_md_hmac_update()
mbedtls_md_hmac_finish()
mbedtls_md_hmac_reset()
mbedtls_md_hmac()
To use HMAC, please use the psa_mac_ API. Looking up hash algorithms by
name is no longer supported.
* Removed DES (including 3DES)
Features
* Added new configuration option MBEDTLS_PSA_STATIC_KEY_SLOTS, which
uses static storage for keys, enabling malloc-less use of key slots.
The size of each buffer is given by the option
MBEDTLS_PSA_STATIC_KEY_SLOT_BUFFER_SIZE. By default it accommodates the
largest PSA key enabled in the build.
* Add an interruptible version of generate key to the PSA interface.
See psa_generate_key_iop_setup() and related functions.
* Add an interruptible version of key agreement to the PSA interface.
See psa_key_agreement_iop_setup() and related functions.
* Add a new psa_key_agreement() PSA API to perform key agreement and return
an identifier for the newly created key.
* When the new compilation option MBEDTLS_PSA_KEY_STORE_DYNAMIC is enabled,
the number of volatile PSA keys is virtually unlimited, at the expense
of increased code size. This option is off by default, but enabled in
the default mbedtls_config.h. Fixes #9216.
* Add an interruptible version of export public-key to the PSA interface.
See psa_export_public_key_iop_setup() and related functions.
* MD module can now perform PSA dispatching also when
`MBEDTLS_PSA_CRYPTO_CLIENT && !MBEDTLS_PSA_CRYPTO_C`, even though this
configuration is not officially supported. This requires that a
PSA Crypto provider library which:
* supports the required `PSA_WANT_ALG_xxx` and
* implements `psa_can_do_hash()` on the client interface
is linked against Mbed TLS and that `psa_crypto_init()` is called before
performing any PSA call.
* Add a program (which_aes) that uses an internal function to print out
the current implementation of AES, i.e. software, AESCE, AESNI assembly,
or AESNI intrinsics.
* To supply a platform-specific entropy source, define the compilation option
MBEDTLS_PLATFORM_GET_ENTROPY_ALT and provide the callback function
mbedtls_platform_get_entropy_alt(). This function should typically access
a TRNG ("true hardware random generator") device on bare-metal platforms,
or call an operating system function to obtain cryptographic-quality random
data. Mbed TLS requires that a minimum of 32 bytes (not configurable) are
returned from this function for a successful entropy gathering round.
* The new function mbedtls_asn1_get_integer() parses an integer into a byte
array. It replaces mbedtls_asn1_get_mpi().
* Add a new function mbedtls_asn1_write_integer() that encodes an arbitrary
precision integer into ASN.1 DER format. This function replaces
mbedtls_asn1_write_mpi(), which has been made internal-only.
* Introduce macros and functions for getting the current version of
TF-PSA-Crypto at build time and at runtime. These can be accessed
by including "tf-psa-crypto/version.h".
* Helper symbol MBEDTLS_PK_ALG_ECDSA is added to the public "mbedtls/pk.h"
header file. It exposes the ECDSA variant used by the PK module.
* The threading platform abstraction now exposes condition variables
in addition to mutexes.
* Function mbedtls_pk_can_do_psa() is added to allow testing PK context
capabilities against a specified algorithm and usage.
* Users can set the macro TF_PSA_CRYPTO_CONFIG_VERSION in the TF-PSA-Crypto
config file to maximize backward compatibility in case of future changes
to how the config file is interpreted. TF-PSA-Crypto will maintain
backward compatibility on functional matters (except at major version
changes, e.g. from 1.x.y to 2.0), but the config version may influence
other aspect such as optimisations, or experimental options.
Security
* Fix a buffer underrun in mbedtls_pk_write_key_der() when
called on an opaque key, MBEDTLS_USE_PSA_CRYPTO is enabled,
and the output buffer is smaller than the actual output.
Fix a related buffer underrun in mbedtls_pk_write_key_pem()
when called on an opaque RSA key, MBEDTLS_USE_PSA_CRYPTO is enabled
and MBEDTLS_MPI_MAX_SIZE is smaller than needed for a 4096-bit RSA key.
CVE-2024-49195
* Unlike previously documented, enabling MBEDTLS_PSA_HMAC_DRBG_MD_TYPE does
not cause the PSA subsystem to use HMAC_DRBG: it uses HMAC_DRBG only when
MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG and MBEDTLS_CTR_DRBG_C are disabled.
CVE-2024-45157
* Fix a stack buffer overflow in mbedtls_ecdsa_der_to_raw() and
mbedtls_ecdsa_raw_to_der() when the bits parameter is larger than the
largest supported curve. In some configurations with PSA disabled,
all values of bits are affected. This never happens in internal library
calls, but can affect applications that call these functions directly.
CVE-2024-45158
* Zeroize a temporary heap buffer used in psa_key_derivation_output_key()
when deriving an ECC key pair.
* Zeroize temporary heap buffers used in PSA operations.
* Fix a buffer overread in mbedtls_lms_import_public_key() when the input is
less than 3 bytes. Reported by Linh Le and Ngan Nguyen from Calif.
CVE-2025-49601
* Fix a vulnerability in LMS verification through which an adversary could
get an invalid signature accepted if they could cause a hash accelerator
to fail. Found and reported by Linh Le and Ngan Nguyen from Calif.
CVE-2025-49600
* On x86/amd64 platforms, with some compilers, when the library is
compiled with support for both AESNI and software AES and AESNI is
available in hardware, an adversary with fine control over which
threads make progress in a multithreaded program could force software
AES to be used for some time when the program starts. This could allow
the adversary to conduct timing attacks and potentially recover the
key. In particular, this attacker model may be possible against an SGX
enclave.
The same vulnerability affects GCM acceleration, which could allow
a similarly powerful adversary to craft GCM forgeries.
CVE-2025-52496
* Fix a bug in mbedtls_asn1_store_named_data() where it would sometimes leave
an item in the output list in an inconsistent state with val.p == NULL but
val.len > 0. Functions using the structure after that, including
mbedtls_asn1_store_named_data() itself would then dereference a NULL
pointer. Applications that do not call this function are not affected.
Found by Linh Le and Ngan Nguyen from Calif.
CVE-2025-48965
* Fix an integer underflow that could occur when parsing malformed PEM
keys, which could be used by an attacker capable of feeding encrypted
PEM keys to a user. This could cause a crash or information disclosure.
Found and reported by Linh Le and Ngan Nguyen from Calif.
CVE-2025-52497
* Fix a timing side channel in the implementation of PKCS#7 padding
which would allow an attacker who can request decryption of arbitrary
ciphertexts to recover the plaintext through a timing oracle attack.
Reported by Ka Lok Wu from Stony Brook University and Doria Tang from
The Chinese University of Hong Kong.
CVE-2025-49087
* Fix a timing side channel in CBC-PKCS7 decryption that could
allow an attacker who can submit chosen ciphertexts to recover
some plaintexts through a timing-based padding oracle attack.
Credits to Beat Heeb from Oberon microsystems AG. CVE-2025-59438
* Fix a local timing side-channel in modular inversion and GCD that was
exploitable in RSA key generation and other RSA operations (see the full
advisory for details), allowing a local attacker to fully recover the
private key. This can be exploited on some Arm-v9 CPUs by an unprivileged
attacker running code on the same core (SSBleed), or when Trustzone-M is
used, by the non-secure side abusing timer interrupts (M-Step), and
probably in other similar settings as well. Found and reported
independently by: SSBleed: Chang Liu (Tsinghua University) and Trevor E.
Carlson (National University of Singapore); M-Step: Cristiano Rodrigues
(University of Minho), Marton Bognar (DistriNet, KU Leuven), Sandro Pinto
(University of Minho), Jo Van Bulck (DistriNet, KU Leuven). CVE-2025-54764
Bugfix
* MBEDTLS_ASN1_PARSE_C and MBEDTLS_ASN1_WRITE_C are now automatically enabled
as soon as MBEDTLS_RSA_C is enabled. Fixes #9041.
* Fix interference between PSA volatile keys and built-in keys
when MBEDTLS_PSA_CRYPTO_BUILTIN_KEYS is enabled and
MBEDTLS_PSA_KEY_SLOT_COUNT is more than 4096.
* Fix missing constraints on the AES-NI inline assembly which is used on
GCC-like compilers when building AES for generic x86_64 targets. This
may have resulted in incorrect code with some compilers, depending on
optimizations. Fixes #9819.
* Fix rare concurrent access bug where attempting to operate on a
non-existent key while concurrently creating a new key could potentially
corrupt the key store.
* Fix invalid JSON schemas for driver descriptions used by
generate_driver_wrappers.py.
* Fix the build when MBEDTLS_PSA_CRYPTO_CONFIG is enabled and the built-in
CMAC is enabled, but no built-in unauthenticated cipher is enabled.
Fixes #9209.
* Fix issue of redefinition warning messages for _GNU_SOURCE in
entropy_poll.c and sha_256.c. There was a build warning during
building for linux platform.
Resolves #9026
* Fix unintended performance regression when using short RSA public keys.
Fixes #9232.
* Fix error handling when creating a key in a dynamic secure element
(feature enabled by MBEDTLS_PSA_CRYPTO_SE_C). In a low memory condition,
the creation could return PSA_SUCCESS but using or destroying the key
would not work. Fixes #8537.
* Fix redefinition warnings when SECP192R1 and/or SECP192K1 are disabled.
Fixes #9029.
* Fix undefined behaviour (incrementing a NULL pointer by zero length) when
passing in zero length additional data to multipart AEAD.
* Document and enforce the limitation of mbedtls_psa_register_se_key()
to persistent keys. Resolves #9253.
* Fix a memory leak that could occur when failing to process an RSA
key through some PSA functions due to low memory conditions.
* Fix a compilation warning in pk.c when PSA is enabled and RSA is disabled.
* Fix psa_cipher_decrypt() with CCM* rejecting messages less than 3 bytes
long. Credit to Cryptofuzz. Fixes #9314.
* Fix undefined behavior in some cases when mbedtls_psa_raw_to_der() or
mbedtls_psa_der_to_raw() is called with bits=0.
* When MBEDTLS_PSA_CRYPTO_C was disabled and MBEDTLS_ECDSA_C enabled,
some code was defining 0-size arrays, resulting in compilation errors.
Fixed by disabling the offending code in configurations without PSA
Crypto, where it never worked. Fixes #9311.
* Remove Everest Visual Studio 2010 compatibility headers, which could
shadow standard CRT headers inttypes.h and stdbool.h with incomplete
implementatios if placed on the include path.
* Fix issue where psa_key_derivation_input_integer() is not detecting
bad state after an operation has been aborted.
* Fix failures of PSA multipart or interruptible operations when the
library or the application is built with a compiler where
"union foo x = {0}" does not initialize non-default members of the
union, such as GCC 15 and some versions of Clang 18. This affected MAC
multipart operations, MAC-based key derivation operations, interruptible
signature, interruptible verification, and potentially other operations
when using third-party drivers. This also affected one-shot MAC
operations using the built-in implementation. Fixes #9814.
* On entry to PSA driver entry points that set up a multipart operation
("xxx_setup"), the operation object is supposed to be all-bits-zero.
This was sometimes not the case when an operation object is reused,
or with compilers where "union foo x = {0}" does not initialize
non-default members of the union. The PSA core now ensures that this
guarantee is met in all cases. Fixes #9975.
* Resolved build issue with C++ projects using TF-PSA-Crypto when compiling
with the MSVC toolset v142 and earlier. Fixes mbedtls issue #7087.
* Silence spurious -Wunterminated-string-initialization warnings introduced
by GCC 15. Fixes #9944.
* Fix a sloppy check in LMS public key import, which could lead to accepting
keys with a different LMS or LM-OTS types on some platforms. Specifically,
this could happen on platforms where enum types are smaller than 32 bits
and compiler optimization is enabled. Found and reported by Linh Le and
Ngan Nguyen from Calif.
* Fix a race condition on x86/amd64 platforms in AESNI support detection
that could lead to using software AES in some threads at the very
beginning of a multithreaded program. Reported by Solar Designer.
Fixes #9840.
* Fix mbedtls_base64_decode() on inputs that did not have the correct
number of trailing equal signs, or had 4*k+1 digits. They were accepted
as long as they had at most two trailing equal signs. They are now
rejected. Furthermore, before, on inputs with too few equal signs, the
function reported the correct size in *olen when it returned
MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL, but truncated the output to the
last multiple of 3 bytes.
* When calling mbedtls_asn1_write_raw_buffer() with NULL, 0 as the last two
arguments, undefined behaviour would be triggered, in the form of a call to
memcpy(..., NULL, 0). This was harmless in practice, but could trigger
complains from sanitizers or static analyzers.
* Fix occasional CMake parallel build failure when building both the
static and shared tfpsacrypto libraries. Fixes #286.
* PAKE returns PSA_ERROR_INVALID_SIGNATURE instead of PSA_ERROR_DATA_INVALID
when the signature in Schnorr NIZKP is invalid.
Changes
* Cryptography and platform configuration options have been migrated
from the Mbed TLS library configuration file mbedtls_config.h to
crypto_config.h that is now the TF-PSA-Crypto configuration file.
The reference and test custom configuration files respectively in
configs/ and tests/configs/ have been updated accordingly.
To migrate custom Mbed TLS configurations where
MBEDTLS_PSA_CRYPTO_CONFIG is disabled, you should first adapt them
to the PSA configuration scheme based on PSA_WANT_XXX symbols
(see psa-conditional-inclusion-c.md for more information).
To migrate custom Mbed TLS configurations where
MBEDTLS_PSA_CRYPTO_CONFIG is enabled, you should migrate the
cryptographic and platform configuration options from mbedtls_config.h
to crypto_config.h (see the 4.0 configuration guide at
docs/4.0-migration-guide/configuration.md which includes
configuration details and examples).
* Improve performance of PSA key generation with ECC keys: it no longer
computes the public key (which was immediately discarded). Fixes #9732.
* Make the file p256-m.h internal, it is no longer installed or documented.
* Added the `key_confirmation` field to the PAKE cipher suite to conform to
PSA API 1.2 PAKE extension
* Added the `psa_pake_cs_get_key_confirmation()` function which retrieves
the value from a cipher suite, the `psa_pake_cs_set_key_confirmation()`
function which declares the value for a cipher suite
* Now the functionality of `psa_pake_set_password_key()` is implemented in
`psa_pake_setup()` function, as per the PSA API 1.2 PAKE extension.
* Changed the `PSA_ALG_JPAKE` macro to accommodate the hash algorithm
parameter, to be conformant to the PSA API 1.2 PAKE extension
* Added the `PSA_ALG_IS_JPAKE` macro to test whether a given algorithm is
JPAKE
* All tf-psa-crypto private headers were moved to a private subdirectory
* Implemented the `psa_pake_get_shared_key()` function, compliant with the
PSA API 1.2 PAKE extension, replacement for `psa_pake_get_implicit_key()`
= Mbed TLS 3.6.0 branch released 2024-03-28
Please refer to the Mbed TLS changelog, available at
https://github.com/Mbed-TLS/mbedtls/blob/mbedtls-3.6.0/ChangeLog
+90
View File
@@ -0,0 +1,90 @@
# Pending changelog entry directory
This directory contains changelog entries that have not yet been merged
to the changelog file ([`../ChangeLog`](../ChangeLog)).
## What requires a changelog entry?
Write a changelog entry if there is a user-visible change. This includes:
* Bug fixes in the library or in sample programs: fixing a security hole,
fixing broken behavior, fixing the build in some configuration or on some
platform, etc.
* New features in the library, new sample programs, or new platform support.
* Changes in existing behavior. These should be rare. Changes in features
that are documented as experimental may or may not be announced, depending
on the extent of the change and how widely we expect the feature to be used.
We generally don't include changelog entries for:
* Documentation improvements.
* Performance improvements, unless they are particularly significant.
* Changes to parts of the code base that users don't interact with directly,
such as test code and test data.
* Fixes for compiler warnings. Releases typically contain a number of fixes
of this kind, so we will only mention them in the Changelog if they are
particularly significant.
Looking at older changelog entries is good practice for how to write a
changelog entry, but not for deciding whether to write one.
## Changelog entry file format
A changelog entry file must have the extension `*.txt` and must have the
following format:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Security
* Change description.
* Another change description.
Features
* Yet another change description. This is a long change description that
spans multiple lines.
* Yet again another change description.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The permitted changelog entry categories are as follows:
<!-- Keep this synchronized with STANDARD_CATEGORIES in assemble_changelog.py! -->
API changes
Default behavior changes
Requirement changes
New deprecations
Removals
Features
Security
Bugfix
Changes
Use “Changes” for anything that doesn't fit in the other categories.
## How to write a changelog entry
Each entry starts with three spaces, an asterisk and a space. Continuation
lines start with 5 spaces. Lines wrap at 79 characters.
Write full English sentences with proper capitalization and punctuation. Use
the present tense. Use the imperative where applicable. For example: “Fix a
bug in mbedtls_xxx() ….”
Include GitHub issue numbers where relevant. Use the format “#1234” for a
TF-PSA-Crypto issue. Add other external references such as CVE numbers where
applicable.
Credit bug reporters where applicable.
**Explain why, not how**. Remember that the audience is the users of the
library, not its developers. In particular, for a bug fix, explain the
consequences of the bug, not how the bug was fixed. For a new feature, explain
why one might be interested in the feature. For an API change or a deprecation,
explain how to update existing applications.
See [existing entries](../ChangeLog) for examples.
## How `ChangeLog` is updated
Run [`../scripts/assemble_changelog.py`](../scripts/assemble_changelog.py)
from a Git working copy
to move the entries from files in `ChangeLog.d` to the main `ChangeLog` file.
+4
View File
@@ -0,0 +1,4 @@
Site: localhost
BuildName: Mbed TLS-test
CoverageCommand: /usr/bin/gcov
MemoryCheckCommand: /usr/bin/valgrind
+552
View File
@@ -0,0 +1,552 @@
TF-PSA-Crypto files are provided under a dual [Apache-2.0](https://spdx.org/licenses/Apache-2.0.html)
OR [GPL-2.0-or-later](https://spdx.org/licenses/GPL-2.0-or-later.html) license.
This means that users may choose which of these licenses they take the code
under.
The full text of each of these licenses is given below.
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
===============================================================================
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.
+388
View File
@@ -0,0 +1,388 @@
README for TF-PSA-Crypto
========================
The TF-PSA-Crypto repository provides an implementation of the
[PSA Cryptography API version 1.2](https://arm-software.github.io/psa-api/crypto/1.2/),
with the limitation that the implementation of the [PAKE extension](https://arm-software.github.io/psa-api/crypto/1.2/ext-pake/)
still has minor non-compliances, such as returned error codes.
The PSA Cryptography API implementation is organized around the
[PSA Cryptography driver interface](docs/proposed/psa-driver-interface.md)
aiming to ease the support of cryptographic accelerators and processors.
PSA Cryptography API
---------------------
The [PSA Cryptography API](https://arm-software.github.io/psa-api/crypto/)
provides access to a set of cryptographic primitives. It has a dual purpose.
First, it can be used in a PSA-compliant platform to build services, such as
secure boot, secure storage and secure communication. Second, it can also be
used independently of other PSA components on any platform.
The design goals of the PSA Cryptography API include:
* The API distinguishes caller memory from internal memory, which allows the
library to be implemented in an isolated space for additional security.
Library calls can be implemented as direct function calls if isolation is not
desired, and as remote procedure calls if isolation is desired.
* The structure of internal data is hidden to the application, which allows
substituting alternative implementations at build time or run time, for example,
in order to take advantage of hardware accelerators.
* All access to the keys happens through key identifiers, which allows support
for external cryptoprocessors that is transparent to applications.
* The interface to algorithms is generic, favoring algorithm agility.
* The interface is designed to be easy to use and hard to accidentally misuse.
We welcomes feedback on the design of the API. If you think something could be
improved, please open an issue on our Github repository. Alternatively, if you
prefer to provide your feedback privately, please email us at
[`mbed-crypto@arm.com`](mailto:mbed-crypto@arm.com). All feedback received by
email is treated confidentially.
### PSA Cryptography API implementation in TF-PSA-Crypto
TF-PSA-Crypto includes an implementation of the PSA Cryptography API. It covers
most, but not all algorithms.
### PSA Cryptography driver interface
TF-PSA-Crypto supports drivers for cryptographic accelerators, secure elements
and random generators. This is work in progress. Please note that the driver
interfaces are not fully stable yet and may change without notice. We intend to
preserve backward compatibility for application code (using the PSA Cryptography API),
but the code of the drivers may have to change in future minor releases of TF-PSA-Crypto.
Please see the [PSA driver example and guide](docs/psa-driver-example-and-guide.md)
for information on writing a driver.
Configuration
-------------
The TF-PSA-Crypto repository should build out of the box on most systems. Its
configuration is based on C preprocessor macros defined in
`include/psa/crypto_config.h`.
These configuration options are organized into seven groups:
1. Cryptographic mechanism selection (PSA API): PSA_WANT_xxx macros that
specify which parts of the PSA Cryptography API the user wants to enable,
e.g. cryptographic algorithms, key types, elliptic curves.
1. Platform abstraction layer: Options to port the library to different platforms.
1. General and test configuration options: Options that are test-specific or
not related to a particular part of the library.
1. Cryptographic mechanism selection (extended API): Options to enable
cryptographic mechanisms beyond the current PSA Cryptography API, such as LMS
or key wrapping.
1. Data format support: Options to enable support for various data formats,
such as ASN.1 or PEM.
1. PSA core: Options to configure components other than cryptographic mechanisms,
such as key management and random number generation.
1. Built-in drivers: Options to configure non-functional aspects of built-in
cryptographic mechanisms such as performance/size trade-offs.
The file `include/psa/crypto_config.h` can be edited manually, or in a more
programmatic way using the Python script `scripts/config.py` (use `--help` for
usage instructions).
We provide some non-standard configurations focused on specific use cases in the
`configs/` directory. You can read more about those in `configs/README.txt`.
Documentation
-------------
Documentation for the PSA Cryptography API is available [on GitHub](https://arm-software.github.io/psa-api/crypto/).
To generate a local copy of the library documentation in HTML format:
1. Make sure that [Doxygen](http://www.doxygen.nl/) is installed.
1. Run `cmake -B /path/to/build_dir /path/to/TF-PSA-Crypto/source`
1. Run `cmake --build /path/to/build_dir --target tfpsacrypto-apidoc`
1. Open one of the main generated HTML files:
* `apidoc/index.html`
* `apidoc/modules.html` or `apidoc/topics.html`
Compiling
---------
The build system is CMake.
The CMake build system creates one library: libtfpsacrypto.
### Tool versions
You need the following tools to build the library from the main branch with the
provided CMake files. TF-PSA-Crypto minimum tool version requirements are set
based on the versions shipped in the latest or penultimate (depending on the
release cadence) long-term support releases of major Linux distributions,
namely at time of writing: Ubuntu 22.04, RHEL 9, and SLES 15 SP4.
* A C99 toolchain (compiler, linker, archiver). We actively test with GCC 5.4,
Clang 3.8 and Arm Compiler 6.21. More recent versions should work. Slightly
older versions may work.
* Python 3.8 or later to generate some source files (see below), the test
code, and to generate sample programs.
* CMake 3.20.2 or later.
* A build system like Make or Ninja for which CMake can generate build files.
* Microsoft Visual Studio 2019 or later (if using Visual Studio).
* Doxygen 1.8.14 or later.
### Git usage
The supported branches (see [`BRANCHES.md`](BRANCHES.md)) use a [Git submodule](https://git-scm.com/book/en/v2/Git-Tools-Submodules#_cloning_submodules),
[framework](https://github.com/TF-PSA-Crypto/mbedtls-framework).
Release tags also use Git submodules.
After cloning or checking out a branch or tag, run:
```
git submodule update --init
```
to initialize and update the submodule before building.
However, the official source release tarballs (e.g. [tf-psa-crypto-1.0.0.tar.bz2](https://github.com/Mbed-TLS/TF-PSA-Crypto/releases/download/tf-psa-crypto-1.0.0/tf-psa-crypto-1.0.0.tar.bz2))
include the content of the submodule.
### Generated source files in the development branch
The source code of TF-PSA-Crypto includes some files that are automatically
generated by scripts and whose content depends only on the TF-PSA-Crypto source,
not on the platform or on the library configuration. These files are not included
in the development branch of TF-PSA-Crypto, but the generated files are included
in official releases. This section explains how to generate the missing files in
the development branch.
The following tools are required:
* Python 3 and some Python packages, for some library source files, sample programs
and test data. To install the necessary packages, run:
```
python3 -m pip install --user -r scripts/basic.requirements.txt
```
Depending on your Python installation, you may need to invoke `python` instead
of `python3`. To install the packages system-wide or in a virtual environment,
omit the `--user` option.
* A C compiler for the host platform, for some test data.
The scripts that generate the configuration-independent files will look for a
host C compiler in the following places (in order of preference):
1. The `HOSTCC` environment variable. This can be used if `CC` is pointing to a
cross-compiler.
1. The `CC` environment variable.
1. An executable called `cc` in the current path.
Note: If you have multiple toolchains installed, it is recommended to set `CC`
or `HOSTCC` to the intended host compiler before generating the files.
Any of the following methods are available to generate the configuration-independent
files:
* On non-Windows systems, when not cross-compiling, CMake generates the required
files automatically.
* Run `framework/scripts/make_generated_files.py` to generate all the
configuration-independent files.
### CMake
In order to build the source using CMake in a separate directory (recommended),
just enter at the command line:
mkdir /path/to/build_dir && cd /path/to/build_dir
cmake /path/to/tf/psa/crypto/source
cmake --build .
In order to run the tests, enter:
ctest
The test suites need Python to be built. If you don't have Python installed,
you'll want to disable the test suites with:
cmake -DENABLE_TESTING=Off /path/to/tf/psa/crypto/source
To configure CMake for building shared libraries, use:
cmake -DUSE_SHARED_TF_PSA_CRYPTO_LIBRARY=On /path/to/tf/psa/crypto/source
There are many different build modes available within the CMake build system.
Most of them are available for gcc and clang, though some are compiler-specific:
- `Release`. This generates the default code without any unnecessary
information in the binary files.
- `Debug`. This generates debug information and disables optimization of the code.
- `ASan`. This instruments the code with AddressSanitizer to check for memory
errors. (This includes LeakSanitizer, with recent version of gcc and clang.)
(With recent version of clang, this mode also instruments the code with
UndefinedSanitizer to check for undefined behaviour.)
- `ASanDbg`. Same as ASan but slower, with debug information and better stack
traces.
- `MemSan`. This instruments the code with MemorySanitizer to check for
uninitialised memory reads. Experimental, needs recent clang on Linux/x86\_64.
- `MemSanDbg`. Same as MemSan but slower, with debug information, better stack
traces and origin tracking.
- `Check`. This activates the compiler warnings that depend on optimization and
treats all warnings as errors.
- `TSan`. This instruments the code with ThreadSanitizer to detect data races
and other threading-related concurrency issues at runtime.
- `TSanDbg`. Same as TSan but slower, with debug information, better stack
traces and origin tracking.
Switching build modes in CMake is simple. For debug mode, enter at the command
line:
cmake -D CMAKE_BUILD_TYPE=Debug /path/to/tf/psa/crypto/source
To list other available CMake options, use:
cmake -LH
Note that, with CMake, you can't adjust the compiler or its flags after the
initial invocation of cmake. This means that `CC=your_cc make` and `make
CC=your_cc` will *not* work (similarly with `CFLAGS` and other variables).
These variables need to be adjusted when invoking cmake for the first time,
for example:
CC=your_cc cmake /path/to/tf/psa/crypto/source
If you already invoked cmake and want to change those settings, you need to
invoke the configuration phase of CMake again with the new settings.
Note that it is possible to build in-place, use:
cmake .
cmake --build .
Regarding variables, also note that if you set CFLAGS when invoking cmake,
your value of CFLAGS doesn't override the content provided by CMake (depending
on the build mode as seen above), it's merely prepended to it.
#### Consuming TF-PSA-Crypto
TF-PSA-Crypto provides a CMake package configuration file for consumption as a
dependency in other CMake projects. You can load its CMake library target with:
find_package(TF-PSA-Crypto)
You can help CMake find the package:
- By setting the variable `TF-PSA-Crypto_DIR` to `${YOUR_TF_PSA_CRYPTO_BUILD_DIR}/cmake`,
as shown in `programs/test/cmake_package/CMakeLists.txt`, or
- By adding the TF-PSA-Crypto installation prefix to `CMAKE_PREFIX_PATH`,
as shown in `programs/test/cmake_package_install/CMakeLists.txt`.
After a successful `find_package(TF-PSA-Crypto)`, the target `TF-PSA-Crypto::tfpsacrypto`
is available.
You can then use it directly through `target_link_libraries()`:
add_executable(xyz)
target_link_libraries(xyz PUBLIC TF-PSA-Crypto::tfpsacrypto)
This will link the TF-PSA-Crypto library to your library or application, and
add its include directories to your target (transitively, in the case of
`PUBLIC` or `INTERFACE` link libraries).
#### TF-PSA-Crypto as a subproject
The TF-PSA-Crypto repository supports being built as a CMake subproject. One
can use `add_subdirectory()` from a parent CMake project to include
TF-PSA-Crypto as a subproject.
### Microsoft Visual Studio
The TF-PSA-Crypto library can be built with Microsoft Visual Studio Community
suitably installed as a CMake project. For a general documentation about
CMake projects in Visual Studio, please refer to its documentation.
The following instructions have been tested on Microsoft Visual Studio Community
2019 Version 16.11.26. The TF-PSA-Crypto library and its tests build out of the
box with:
* Visual Studio Community installed with the default "Desktop development with C++"
and "Python development" workloads.
* Python libraries needed for code and test generation installed as defined
in basic.requirements.txt. Refer to the Visual Studio documentation of Python
environments.
* When cloning the TF-PSA-Crypto repository in Visual Studio, a
CMakeSettings.json is created at the root of the repository. In that file, add
the line `"environments": [ {"CC" : "cl"} ]` to the configuration. That way
when building the library and its tests, a CC environment variable is set with
value "cl". This is needed by Python scripts that generate test cases. The
CMakeSettings.json file can be edited in Visual Studio by following
Project > CMake Settings for TF-PSA-Crypto > Edit JSON.
* If necessary (it may have been done automatically when updating
CMakeSettings.json), generate the CMake cache: Project > Generate Cache
* Build the library: Build > Build All
* The test suites can then be run: Test > Run CTests for TF-PSA-Crypto
Example programs
----------------
We've included example programs for different features and uses in
[`programs/`](programs/README.md). Please note that the goal of these sample
programs is to demonstrate specific features of the library, and the code may
need to be adapted to build a real-world application.
Tests
-----
The TF-PSA-Crypto repository includes an elaborate test suite in `tests/` that
initially requires Python to generate the tests files
(e.g. `test_suite_psa_crypto.c`). These files are generated from a
`function file` (e.g. `suites/test_suite_psa_crypto.function`) and a
`data file` (e.g. `suites/test_suite_psa_crypto.data`). The `function file`
contains the test functions. The `data file` contains the test cases, specified
as parameters that will be passed to the test function.
Porting TF-PSA-Crypto
---------------------
TF-PSA-Crypto can be ported to many different architectures, OS's and platforms.
Before starting a port, you may find the following Knowledge Base articles useful:
- [Porting Mbed TLS to a new environment or OS](https://mbed-tls.readthedocs.io/en/latest/kb/how-to/how-do-i-port-mbed-tls-to-a-new-environment-OS/)
- [What external dependencies does Mbed TLS rely on?](https://mbed-tls.readthedocs.io/en/latest/kb/development/what-external-dependencies-does-mbedtls-rely-on/)
- [How do I configure Mbed TLS](https://mbed-tls.readthedocs.io/en/latest/kb/compiling-and-building/how-do-i-configure-mbedtls/)
TF-PSA-Crypto is mostly written in portable C99; however, it has a few platform
requirements that go beyond the standard, but are met by most modern architectures:
- Bytes must be 8 bits.
- All-bits-zero must be a valid representation of a null pointer.
- Signed integers must be represented using two's complement.
- `int` and `size_t` must be at least 32 bits wide.
- The types `uint8_t`, `uint16_t`, `uint32_t` and their signed equivalents must be available.
- Mixed-endian platforms are not supported.
- SIZE_MAX must be at least as big as INT_MAX and UINT_MAX.
License
-------
Unless specifically indicated otherwise in a file, TF-PSA-Crypto files are provided
under a dual [Apache-2.0](https://spdx.org/licenses/Apache-2.0.html) OR
[GPL-2.0-or-later](https://spdx.org/licenses/GPL-2.0-or-later.html) license.
See the [LICENSE](LICENSE) file for the full text of these licenses.
### Third-party code included in TF-PSA-Crypto
This project contains code from other projects. This code is located within the
`drivers/` directory. The original license text is included within project
subdirectories, where it differs from the normal Mbed TLS license, and/or in
source files. The projects are listed below:
* `drivers/everest/`: Files stem from [Project Everest](https://project-everest.github.io/)
and are distributed under the Apache 2.0 license.
* `drivers/p256-m/p256-m/`: Files have been taken from the [p256-m](https://github.com/mpg/p256-m)
repository. The code in the original repository is distributed under the
Apache 2.0 license. It is distributed in TF-PSA-Crypto under a dual Apache-2.0
OR GPL-2.0-or-later license with permission from the author.
Contributing
------------
We gratefully accept bug reports and contributions from the community. Please
see the [contributing guidelines](CONTRIBUTING.md) for details on how to do this.
Contact
-------
* To report a security vulnerability in TF-PSA-Crypto, please email <mbed-tls-security@lists.trustedfirmware.org>. For more information, see [`SECURITY.md`](SECURITY.md).
* To report a bug or request a feature in TF-PSA-Crypto, please [file an issue on GitHub](https://github.com/Mbed-TLS/TF-PSA-Crypto/issues/new/choose).
* Please see [`SUPPORT.md`](SUPPORT.md) for other channels for discussion and
support about TF-PSA-Crypto.
+146
View File
@@ -0,0 +1,146 @@
## Reporting Vulnerabilities
If you think you have found a security vulnerability in TF-PSA-Crypto, then
please send an email to the security team at
<mbed-tls-security@lists.trustedfirmware.org>.
## Security Incident Handling Process
Our security process is detailed in our
[security
center](https://developer.trustedfirmware.org/w/mbed-tls/security-center/).
Its primary goal is to ensure fixes are ready to be deployed when the issue
goes public.
## Maintained branches
Only the maintained branches, as listed in [`BRANCHES.md`](BRANCHES.md),
get security fixes.
Users are urged to always use the latest version of a maintained branch.
## Threat model
We classify attacks based on the capabilities of the attacker.
### Remote attacks
In this section, we consider an attacker who can observe and modify data sent
over the network. This includes observing the content and timing of individual
packets, as well as suppressing or delaying legitimate messages, and injecting
messages.
The TF-PSA-Crypto library aims to fully protect against remote attacks. More
specifically, it aims to enable network protocol implementations that use it to
perform cryptographic operations, as well as applications based on such network
protocol implementations, to provide full protection against remote attacks.
**Warning!** Block ciphers do not yet achieve full protection against attackers
who can measure the timing of packets with sufficient precision. For details
and workarounds see the [Block Ciphers](#block-ciphers) section.
### Local attacks
In this section, we consider an attacker who can run software on the same
machine. The attacker has insufficient privileges to directly access the
TF-PSA-Crypto library assets such as memory and files.
#### Timing attacks
The attacker is able to observe the timing of instructions executed by
the TF-PSA-Crypto library by leveraging shared hardware that both the
TF-PSA-Crypto library and the attacker have access to. Typical attack vectors
include cache timings, memory bus contention and branch prediction.
TF-PSA-Crypto provides limited protection against timing attacks. The cost of
protecting against timing attacks widely varies depending on the granularity of
the measurements and the noise present. Therefore the protection in
TF-PSA-Crypto is limited. We are only aiming to provide protection against
**publicly documented attack techniques**.
As attacks keep improving, so does TF-PSA-Crypto's protection. TF-PSA-Crypto is
moving towards a model of fully timing-invariant code, but has not reached this
point yet.
**Remark:** Timing information can be observed over the network or through
physical side channels as well. Remote and physical timing attacks are covered
in the [Remote attacks](remote-attacks) and [Physical
attacks](physical-attacks) sections respectively.
**Warning!** Block ciphers do not yet achieve full protection. For
details and workarounds see the [Block Ciphers](#block-ciphers) section.
#### Local non-timing side channels
The attacker code running on the platform has access to some sensor capable of
picking up information on the physical state of the hardware while the
TF-PSA-Crypto library is running. This could for example be an analogue-to-digital
converter on the platform that is located unfortunately enough to pick up the
CPU noise.
TF-PSA-Crypto doesn't make any security guarantees against local non-timing-based
side channel attacks. If local non-timing attacks are present in a use case or
a user application's threat model, they need to be mitigated by the platform.
#### Local fault injection attacks
Software running on the same hardware can affect the physical state of the
device and introduce faults.
TF-PSA-Crypto doesn't make any security guarantees against local fault injection
attacks. If local fault injection attacks are present in a use case or a user
application's threat model, they need to be mitigated by the platform.
### Physical attacks
In this section, we consider an attacker who has access to physical information
about the hardware the TF-PSA-Crypto library is running on and/or can alter the
physical state of the hardware (e.g. power analysis, radio emissions or fault
injection).
TF-PSA-Crypto doesn't make any security guarantees against physical attacks. If
physical attacks are present in a use case or a user application's threat
model, they need to be mitigated by physical countermeasures.
### Caveats
#### Out-of-scope countermeasures
TF-PSA-Crypto has evolved organically and a well defined threat model hasn't
always been present. Therefore, TF-PSA-Crypto might have countermeasures against
attacks outside the above defined threat model.
The presence of such countermeasures don't mean that TF-PSA-Crypto provides
protection against a class of attacks outside of the above described threat
model. Neither does it mean that the failure of such a countermeasure is
considered a vulnerability.
#### Block ciphers
Currently there are four block ciphers in TF-PSA-Crypto: AES, CAMELLIA, ARIA and
DES. The pure software implementation of these block ciphers uses lookup
tables, which are vulnerable to timing attacks.
These timing attacks can be physical, local or depending on network latency
even remote. The attacks can result in key recovery.
**Workarounds:**
- Turn on hardware acceleration for AES. This is supported only on selected
architectures and currently only available for AES. See configuration options
`TF_PSA_CRYPTO_AESCE_C` and `TF_PSA_CRYPTO_AESNI_C` for details.
- Add a secure alternative implementation (typically hardware acceleration) for
the vulnerable cipher. See the [PSA Cryptography Driver Interface](
docs/proposed/psa-driver-interface.md) for more information.
- Use cryptographic mechanisms that are not based on block ciphers. In
particular, for authenticated encryption, use ChaCha20/Poly1305 instead of
block cipher modes. For random generation, use HMAC\_DRBG instead of CTR\_DRBG.
#### Everest
The HACL* implementation of X25519 taken from the Everest project only protects
against remote timing attacks. (See their [Security
Policy](https://github.com/hacl-star/hacl-star/blob/main/SECURITY.md).)
The Everest variant is only used when `MBEDTLS_ECDH_VARIANT_EVEREST_ENABLED`
configuration option is defined. This option is off by default.
+16
View File
@@ -0,0 +1,16 @@
## Documentation
Here are some useful sources of information about TF-PSA-Crypto:
- API documentation, see the [Documentation section of the
README](README.md#documentation);
- the `docs` directory in the source tree;
- [Use PSA](https://mbed-tls.readthedocs.io/en/latest/getting_started/psa/);
- the [Mbed TLS Knowledge Base](https://mbed-tls.readthedocs.io/en/latest/kb/);
- the [Mbed TLS mailing-list
archives](https://lists.trustedfirmware.org/archives/list/mbed-tls@lists.trustedfirmware.org/).
## Asking Questions
If you can't find your answer in the above sources, please use the [Mbed TLS
mailing list](https://lists.trustedfirmware.org/mailman3/lists/mbed-tls.lists.trustedfirmware.org).
+1
View File
@@ -0,0 +1 @@
TF-PSA-CryptoConfig.cmake
@@ -0,0 +1,3 @@
@PACKAGE_INIT@
include("${CMAKE_CURRENT_LIST_DIR}/TF-PSA-CryptoTargets.cmake")
+20
View File
@@ -0,0 +1,20 @@
This directory contains example configuration files.
The examples are generally focused on a particular usage case (eg, support for
a restricted number of cryptographic mechanisms) and aim at minimizing resource
usage for this target. They can be used as a basis for custom configurations.
These files are complete replacements for the default crypto_config.h. To use
one of them, you can pick one of the following methods:
1. Replace the default file include/psa/crypto_config.h with the chosen one.
2. Use the TF_PSA_CRYPTO_CONFIG_FILE CMake option. For example, to build
out-of-tree with the crypto-config-ccm-aes-sha256.h configuration file:
cmake -DTF_PSA_CRYPTO_CONFIG_FILE="configs/crypto-config-ccm-aes-sha256.h" \
-B build-ccmonly
cmake --build build-ccmonly
The second method also works if you want to keep your custom configuration
file outside the TF-PSA-Crypto tree.
@@ -0,0 +1,28 @@
/**
* \file configs/crypto-config-ccm-aes-sha256.h
*
* \brief PSA crypto configuration with only symmetric cryptography: CCM-AES,
* SHA-256 and key derivation (uses HMAC).
*/
/*
* Copyright The Mbed TLS Contributors
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
*/
#ifndef PSA_CRYPTO_CONFIG_H
#define PSA_CRYPTO_CONFIG_H
#define PSA_WANT_ALG_CCM 1
#define PSA_WANT_ALG_SHA_256 1
#define PSA_WANT_ALG_TLS12_PRF 1
#define PSA_WANT_ALG_TLS12_PSK_TO_MS 1
#define PSA_WANT_KEY_TYPE_DERIVE 1
#define PSA_WANT_KEY_TYPE_AES 1
#define PSA_WANT_KEY_TYPE_RAW_DATA 1
#define MBEDTLS_PSA_CRYPTO_C
#define MBEDTLS_CTR_DRBG_C
#define MBEDTLS_PSA_BUILTIN_GET_ENTROPY
#endif /* PSA_CRYPTO_CONFIG_H */
@@ -0,0 +1,87 @@
/**
* \file crypto-config-symmetric-only.h
*
* \brief Crypto configuration without any asymmetric cryptography.
*/
/*
* Copyright The Mbed TLS Contributors
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
*/
/**
* To be used in conjunction with configs/config-symmetric-only.h. */
#ifndef PSA_CRYPTO_CONFIG_H
#define PSA_CRYPTO_CONFIG_H
#define PSA_WANT_ALG_CBC_NO_PADDING 1
#define PSA_WANT_ALG_CBC_PKCS7 1
#define PSA_WANT_ALG_CCM 1
#define PSA_WANT_ALG_CCM_STAR_NO_TAG 1
#define PSA_WANT_ALG_CFB 1
#define PSA_WANT_ALG_CHACHA20_POLY1305 1
#define PSA_WANT_ALG_CMAC 1
#define PSA_WANT_ALG_CTR 1
#define PSA_WANT_ALG_ECB_NO_PADDING 1
#define PSA_WANT_ALG_GCM 1
#define PSA_WANT_ALG_HKDF 1
#define PSA_WANT_ALG_HKDF_EXTRACT 1
#define PSA_WANT_ALG_HKDF_EXPAND 1
#define PSA_WANT_ALG_HMAC 1
#define PSA_WANT_ALG_MD5 1
#define PSA_WANT_ALG_OFB 1
#define PSA_WANT_ALG_RIPEMD160 1
#define PSA_WANT_ALG_SHA_1 1
#define PSA_WANT_ALG_STREAM_CIPHER 1
#define PSA_WANT_ALG_SHA_224 1
#define PSA_WANT_ALG_SHA_256 1
#define PSA_WANT_ALG_SHA_384 1
#define PSA_WANT_ALG_SHA_512 1
#define PSA_WANT_ALG_SHA3_224 1
#define PSA_WANT_ALG_SHA3_256 1
#define PSA_WANT_ALG_SHA3_384 1
#define PSA_WANT_ALG_SHA3_512 1
#define PSA_WANT_ALG_TLS12_ECJPAKE_TO_PMS 1
#define PSA_WANT_ALG_TLS12_PRF 1
#define PSA_WANT_ALG_TLS12_PSK_TO_MS 1
/* XTS is not yet supported via the PSA API in Mbed TLS. */
//#define PSA_WANT_ALG_XTS 1
#define PSA_WANT_KEY_TYPE_AES 1
#define PSA_WANT_KEY_TYPE_ARIA 1
#define PSA_WANT_KEY_TYPE_CAMELLIA 1
#define PSA_WANT_KEY_TYPE_CHACHA20 1
#define PSA_WANT_KEY_TYPE_HMAC 1
#define MBEDTLS_SELF_TEST
#define MBEDTLS_PSA_CRYPTO_C
/* System support */
//#define MBEDTLS_HAVE_ASM
#define MBEDTLS_HAVE_TIME
#define MBEDTLS_HAVE_TIME_DATE
#define MBEDTLS_FS_IO
#define MBEDTLS_ENTROPY_NV_SEED
/* Mbed TLS modules */
#define MBEDTLS_ASN1_PARSE_C
#define MBEDTLS_ASN1_WRITE_C
#define MBEDTLS_BASE64_C
#define MBEDTLS_CTR_DRBG_C
#define MBEDTLS_ERROR_C
#define MBEDTLS_HMAC_DRBG_C
#define MBEDTLS_NIST_KW_C
#define MBEDTLS_PEM_PARSE_C
#define MBEDTLS_PEM_WRITE_C
#define MBEDTLS_PKCS5_C
#define MBEDTLS_PLATFORM_C
#define MBEDTLS_PSA_BUILTIN_GET_ENTROPY
#define MBEDTLS_PSA_CRYPTO_STORAGE_C
#define MBEDTLS_PSA_ITS_FILE_C
//#define MBEDTLS_THREADING_C
#endif /* PSA_CRYPTO_CONFIG_H */
+22
View File
@@ -0,0 +1,22 @@
Summary
-------
The file:
* crypto_config_profile_medium.h
is copyright The Mbed TLS Contributors, and is distributed under the license normally
used by Mbed TLS: a dual Apache 2.0 or GPLv2-or-later license.
Background
----------
The file crypto_config_profile_medium.h was derived from the two files crypto_config_profile_medium.h and tfm_mbedcrypto_config_profile_medium.h taken from the TF-M source code here:
https://git.trustedfirmware.org/TF-M/trusted-firmware-m.git/tree/lib/ext/mbedcrypto/mbedcrypto_config
Initially, it was derived according to the Mbed TLS configuration file split that occurred as part of the Mbed TLS repository split, see https://github.com/Mbed-TLS/mbedtls/blob/development/docs/proposed/config-split.md. It then evolved further during the rework of the cryptographic options for version 1.0 of the library, see https://github.com/Mbed-TLS/TF-PSA-Crypto/blob/development/docs/architecture/0e-plans.md.
In TF-M, the two original files are distributed under a 3-Clause BSD license, as noted at the top of the files.
In Mbed TLS, with permission from the TF-M project, crypto_config_profile_medium.h is distributed under a dual [Apache-2.0](https://spdx.org/licenses/Apache-2.0.html) OR [GPL-2.0-or-later](https://spdx.org/licenses/GPL-2.0-or-later.html) license, with copyright assigned to The Mbed TLS Contributors.
@@ -0,0 +1,620 @@
/*
* Copyright (c) 2018-2023, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
/**
* \file psa/crypto_config.h
* \brief PSA crypto configuration options (set of defines)
*
*/
#ifndef PROFILE_M_PSA_CRYPTO_CONFIG_H
#define PROFILE_M_PSA_CRYPTO_CONFIG_H
/**
* \name SECTION: SECTION Cryptographic mechanism selection (PSA API)
*
* This section sets PSA API settings.
* \{
*/
/*
* CBC-MAC is not yet supported via the PSA API in Mbed TLS.
*/
//#define PSA_WANT_ALG_CBC_MAC 1
//#define PSA_WANT_ALG_CBC_NO_PADDING 1
//#define PSA_WANT_ALG_CBC_PKCS7 1
#define PSA_WANT_ALG_CCM 1
//#define PSA_WANT_ALG_CCM_STAR_NO_TAG 1
//#define PSA_WANT_ALG_CMAC 1
//#define PSA_WANT_ALG_CFB 1
//#define PSA_WANT_ALG_CHACHA20_POLY1305 1
//#define PSA_WANT_ALG_CTR 1
//#define PSA_WANT_ALG_DETERMINISTIC_ECDSA 1
//#define PSA_WANT_ALG_ECB_NO_PADDING 1
#define PSA_WANT_ALG_ECDH 1
//#define PSA_WANT_ALG_FFDH 1
#define PSA_WANT_ALG_ECDSA 1
//#define PSA_WANT_ALG_JPAKE 1
//#define PSA_WANT_ALG_GCM 1
#define PSA_WANT_ALG_HKDF 1
//#define PSA_WANT_ALG_HKDF_EXTRACT 1
//#define PSA_WANT_ALG_HKDF_EXPAND 1
#define PSA_WANT_ALG_HMAC 1
//#define PSA_WANT_ALG_MD5 1
//#define PSA_WANT_ALG_OFB 1
//#define PSA_WANT_ALG_PBKDF2_HMAC 1
//#define PSA_WANT_ALG_PBKDF2_AES_CMAC_PRF_128 1
//#define PSA_WANT_ALG_RIPEMD160 1
//#define PSA_WANT_ALG_RSA_OAEP 1
//#define PSA_WANT_ALG_RSA_PKCS1V15_CRYPT 1
//#define PSA_WANT_ALG_RSA_PKCS1V15_SIGN 1
//#define PSA_WANT_ALG_RSA_PSS 1
//#define PSA_WANT_ALG_SHA_1 1
#define PSA_WANT_ALG_SHA_224 1
#define PSA_WANT_ALG_SHA_256 1
//#define PSA_WANT_ALG_SHA_384 1
//#define PSA_WANT_ALG_SHA_512 1
//#define PSA_WANT_ALG_SHA3_224 1
//#define PSA_WANT_ALG_SHA3_256 1
//#define PSA_WANT_ALG_SHA3_384 1
//#define PSA_WANT_ALG_SHA3_512 1
//#define PSA_WANT_ALG_STREAM_CIPHER 1
#define PSA_WANT_ALG_TLS12_PRF 1
#define PSA_WANT_ALG_TLS12_PSK_TO_MS 1
//#define PSA_WANT_ALG_TLS12_ECJPAKE_TO_PMS 1
//#define PSA_WANT_ECC_BRAINPOOL_P_R1_256 1
//#define PSA_WANT_ECC_BRAINPOOL_P_R1_384 1
//#define PSA_WANT_ECC_BRAINPOOL_P_R1_512 1
//#define PSA_WANT_ECC_MONTGOMERY_255 1
//#define PSA_WANT_ECC_MONTGOMERY_448 1
//#define PSA_WANT_ECC_SECP_K1_256 1
/* For secp256r1, consider enabling #MBEDTLS_PSA_P256M_DRIVER_ENABLED
* (see the description in psa/cypto_config.h for details). */
#define PSA_WANT_ECC_SECP_R1_256 1
//#define PSA_WANT_ECC_SECP_R1_384 1
//#define PSA_WANT_ECC_SECP_R1_521 1
//#define PSA_WANT_DH_RFC7919_2048 1
//#define PSA_WANT_DH_RFC7919_3072 1
//#define PSA_WANT_DH_RFC7919_4096 1
//#define PSA_WANT_DH_RFC7919_6144 1
//#define PSA_WANT_DH_RFC7919_8192 1
#define PSA_WANT_KEY_TYPE_DERIVE 1
//#define PSA_WANT_KEY_TYPE_PASSWORD 1
//#define PSA_WANT_KEY_TYPE_PASSWORD_HASH 1
#define PSA_WANT_KEY_TYPE_HMAC 1
#define PSA_WANT_KEY_TYPE_AES 1
//#define PSA_WANT_KEY_TYPE_ARIA 1
//#define PSA_WANT_KEY_TYPE_CAMELLIA 1
//#define PSA_WANT_KEY_TYPE_CHACHA20 1
#define PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY 1
//#define PSA_WANT_KEY_TYPE_DH_PUBLIC_KEY 1
#define PSA_WANT_KEY_TYPE_RAW_DATA 1
//#define PSA_WANT_KEY_TYPE_RSA_PUBLIC_KEY 1
/*
* The following symbols extend and deprecate the legacy
* PSA_WANT_KEY_TYPE_xxx_KEY_PAIR ones. They include the usage of that key in
* the name's suffix. "_USE" is the most generic and it can be used to describe
* a generic suport, whereas other ones add more features on top of that and
* they are more specific.
*/
#define PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_BASIC 1
#define PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_IMPORT 1
#define PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_EXPORT 1
#define PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_GENERATE 1
//#define PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_DERIVE 1
//#define PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_BASIC 1
//#define PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_IMPORT 1
//#define PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_EXPORT 1
//#define PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_GENERATE 1
//#define PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_DERIVE 1 /* Not supported */
//#define PSA_WANT_KEY_TYPE_DH_KEY_PAIR_BASIC 1
//#define PSA_WANT_KEY_TYPE_DH_KEY_PAIR_IMPORT 1
//#define PSA_WANT_KEY_TYPE_DH_KEY_PAIR_EXPORT 1
//#define PSA_WANT_KEY_TYPE_DH_KEY_PAIR_GENERATE 1
//#define PSA_WANT_KEY_TYPE_DH_KEY_PAIR_DERIVE 1 /* Not supported */
/** \} name SECTION Cryptographic mechanism selection (PSA API) */
/**
* \name SECTION: Platform abstraction layer
*
* This section sets platform specific settings.
* \{
*/
/**
* \def MBEDTLS_MEMORY_BUFFER_ALLOC_C
*
* Enable the buffer allocator implementation that makes use of a (stack)
* based buffer to 'allocate' dynamic memory. (replaces calloc() and free()
* calls)
*
* Module: platform/memory_buffer_alloc.c
*
* Requires: MBEDTLS_PLATFORM_C
* MBEDTLS_PLATFORM_MEMORY (to use it within Mbed TLS)
*
* Enable this module to enable the buffer memory allocator.
*/
#define MBEDTLS_MEMORY_BUFFER_ALLOC_C
/**
* \def MBEDTLS_PLATFORM_C
*
* Enable the platform abstraction layer that allows you to re-assign
* functions like calloc(), free(), snprintf(), printf(), fprintf(), exit().
*
* Enabling MBEDTLS_PLATFORM_C enables to use of MBEDTLS_PLATFORM_XXX_ALT
* or MBEDTLS_PLATFORM_XXX_MACRO directives, allowing the functions mentioned
* above to be specified at runtime or compile time respectively.
*
* \note This abstraction layer must be enabled on Windows (including MSYS2)
* as other modules rely on it for a fixed snprintf implementation.
*
* Module: platform/platform.c
* Caller: Most other .c files
*
* This module enables abstraction of common (libc) functions.
*/
#define MBEDTLS_PLATFORM_C
/**
* \def MBEDTLS_PLATFORM_MEMORY
*
* Enable the memory allocation layer.
*
* By default Mbed TLS uses the system-provided calloc() and free().
* This allows different allocators (self-implemented or provided) to be
* provided to the platform abstraction layer.
*
* Enabling #MBEDTLS_PLATFORM_MEMORY without the
* MBEDTLS_PLATFORM_{FREE,CALLOC}_MACROs will provide
* "mbedtls_platform_set_calloc_free()" allowing you to set an alternative calloc() and
* free() function pointer at runtime.
*
* Enabling #MBEDTLS_PLATFORM_MEMORY and specifying
* MBEDTLS_PLATFORM_{CALLOC,FREE}_MACROs will allow you to specify the
* alternate function at compile time.
*
* An overview of how the value of mbedtls_calloc is determined:
*
* - if !MBEDTLS_PLATFORM_MEMORY
* - mbedtls_calloc = calloc
* - if MBEDTLS_PLATFORM_MEMORY
* - if (MBEDTLS_PLATFORM_CALLOC_MACRO && MBEDTLS_PLATFORM_FREE_MACRO):
* - mbedtls_calloc = MBEDTLS_PLATFORM_CALLOC_MACRO
* - if !(MBEDTLS_PLATFORM_CALLOC_MACRO && MBEDTLS_PLATFORM_FREE_MACRO):
* - Dynamic setup via mbedtls_platform_set_calloc_free is now possible with a default value MBEDTLS_PLATFORM_STD_CALLOC.
* - How is MBEDTLS_PLATFORM_STD_CALLOC handled?
* - if MBEDTLS_PLATFORM_NO_STD_FUNCTIONS:
* - MBEDTLS_PLATFORM_STD_CALLOC is not set to anything;
* - MBEDTLS_PLATFORM_STD_MEM_HDR can be included if present;
* - if !MBEDTLS_PLATFORM_NO_STD_FUNCTIONS:
* - if MBEDTLS_PLATFORM_STD_CALLOC is present:
* - User-defined MBEDTLS_PLATFORM_STD_CALLOC is respected;
* - if !MBEDTLS_PLATFORM_STD_CALLOC:
* - MBEDTLS_PLATFORM_STD_CALLOC = calloc
*
* - At this point the presence of MBEDTLS_PLATFORM_STD_CALLOC is checked.
* - if !MBEDTLS_PLATFORM_STD_CALLOC
* - MBEDTLS_PLATFORM_STD_CALLOC = uninitialized_calloc
*
* - mbedtls_calloc = MBEDTLS_PLATFORM_STD_CALLOC.
*
* Defining MBEDTLS_PLATFORM_CALLOC_MACRO and #MBEDTLS_PLATFORM_STD_CALLOC at the same time is not possible.
* MBEDTLS_PLATFORM_CALLOC_MACRO and MBEDTLS_PLATFORM_FREE_MACRO must both be defined or undefined at the same time.
* #MBEDTLS_PLATFORM_STD_CALLOC and #MBEDTLS_PLATFORM_STD_FREE do not have to be defined at the same time, as, if they are used,
* dynamic setup of these functions is possible. See the tree above to see how are they handled in all cases.
* An uninitialized #MBEDTLS_PLATFORM_STD_CALLOC always fails, returning a null pointer.
* An uninitialized #MBEDTLS_PLATFORM_STD_FREE does not do anything.
*
* Requires: MBEDTLS_PLATFORM_C
*
* Enable this layer to allow use of alternative memory allocators.
*/
#define MBEDTLS_PLATFORM_MEMORY
/**
* \def MBEDTLS_PLATFORM_NO_STD_FUNCTIONS
*
* Do not assign standard functions in the platform layer (e.g. calloc() to
* MBEDTLS_PLATFORM_STD_CALLOC and printf() to MBEDTLS_PLATFORM_STD_PRINTF)
*
* This makes sure there are no linking errors on platforms that do not support
* these functions. You will HAVE to provide alternatives, either at runtime
* via the platform_set_xxx() functions or at compile time by setting
* the MBEDTLS_PLATFORM_STD_XXX defines, or enabling a
* MBEDTLS_PLATFORM_XXX_MACRO.
*
* Requires: MBEDTLS_PLATFORM_C
*
* Uncomment to prevent default assignment of standard functions in the
* platform layer.
*/
#define MBEDTLS_PLATFORM_NO_STD_FUNCTIONS
#define MBEDTLS_PLATFORM_PRINTF_ALT
/* To use the following function macros, MBEDTLS_PLATFORM_C must be enabled. */
/* MBEDTLS_PLATFORM_XXX_MACRO and MBEDTLS_PLATFORM_XXX_ALT cannot both be defined */
#include <stdio.h>
#define MBEDTLS_PLATFORM_SNPRINTF_MACRO snprintf
#define MBEDTLS_PLATFORM_STD_EXIT_FAILURE EXIT_FAILURE
#define MBEDTLS_PLATFORM_STD_EXIT_SUCCESS EXIT_SUCCESS
#define MBEDTLS_PLATFORM_STD_MEM_HDR <stdlib.h>
/** \} name SECTION: Platform abstraction layer */
/**
* \name SECTION: PSA core
*
* This section sets PSA specific settings.
* \{
*/
/**
* \def MBEDTLS_CTR_DRBG_C
*
* Enable the CTR_DRBG AES-based random generator.
* The CTR_DRBG generator uses AES-256 by default.
* To use AES-128 instead, set #MBEDTLS_PSA_CRYPTO_RNG_STRENGTH to 128.
*
* AES support can either be achieved through built-in AES or PSA. Built-in is
* the default option when present otherwise PSA is used.
*
* Module: drivers/builtin/src/ctr_drbg.c
*
* Requires: MBEDTLS_PSA_CRYPTO_C, PSA_WANT_KEY_TYPE_AES and
* PSA_WANT_ALG_ECB_NO_PADDING
*
* This module provides the CTR_DRBG AES random number generator.
*/
#define MBEDTLS_CTR_DRBG_C
/**
* \def MBEDTLS_ENTROPY_NV_SEED
*
* Enable the non-volatile (NV) seed file-based entropy source.
* (Also enables the NV seed read/write functions in the platform layer)
*
* This is crucial (if not required) on systems that do not have a
* cryptographic entropy source (in hardware or kernel) available.
*
* Requires: MBEDTLS_PSA_CRYPTO_C,
* !MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG
* MBEDTLS_PLATFORM_C
*
* \note The read/write functions that are used by the entropy source are
* determined in the platform layer, and can be modified at runtime and/or
* compile-time depending on the flags (MBEDTLS_PLATFORM_NV_SEED_*) used.
*
* \note If you use the default implementation functions that read a seedfile
* with regular fopen(), please make sure you make a seedfile with the
* proper name (defined in MBEDTLS_PLATFORM_STD_NV_SEED_FILE) and at
* least MBEDTLS_ENTROPY_BLOCK_SIZE bytes in size that can be read from
* and written to or you will get an entropy source error! The default
* implementation will only use the first MBEDTLS_ENTROPY_BLOCK_SIZE
* bytes from the file.
*
* \note The entropy collector will write to the seed file before entropy is
* given to an external source, to update it.
*/
#define MBEDTLS_ENTROPY_NV_SEED
/**
* \def MBEDTLS_PSA_CRYPTO_C
*
* Enable the Platform Security Architecture cryptography API.
*
* Module: core/psa_crypto.c
*
* Requires: one of the following:
* - MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG
* - MBEDTLS_CTR_DRBG_C
* - MBEDTLS_HMAC_DRBG_C
*
* If MBEDTLS_CTR_DRBG_C or MBEDTLS_HMAC_DRBG_C is used as the PSA
* random generator, then either PSA_WANT_ALG_SHA_256 or
* PSA_WANT_ALG_SHA_512 must be enabled for the entropy module.
*
* \note The PSA crypto subsystem prioritizes DRBG mechanisms as follows:
* - #MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG, if enabled
* - CTR_DRBG (AES), seeded by the entropy module, if
* #MBEDTLS_CTR_DRBG_C is enabled
* - HMAC_DRBG, seeded by the entropy module, if
* #MBEDTLS_HMAC_DRBG_C is enabled
*
* A future version may reevaluate the prioritization of DRBG mechanisms.
*/
#define MBEDTLS_PSA_CRYPTO_C
/**
* \def MBEDTLS_PSA_CRYPTO_SPM
*
* When MBEDTLS_PSA_CRYPTO_SPM is defined, the code is built for SPM (Secure
* Partition Manager) integration which separates the code into two parts: a
* NSPE (Non-Secure Process Environment) and an SPE (Secure Process
* Environment).
*
* If you enable this option, your build environment must include a header
* file `"crypto_spe.h"` (either in the `psa` subdirectory of the Mbed TLS
* header files, or in another directory on the compiler's include search
* path). Alternatively, your platform may customize the header
* `psa/crypto_platform.h`, in which case it can skip or replace the
* inclusion of `"crypto_spe.h"`.
*
* Module: core/psa_crypto.c
* Requires: MBEDTLS_PSA_CRYPTO_C
*
*/
#define MBEDTLS_PSA_CRYPTO_SPM
/**
* \def MBEDTLS_PSA_CRYPTO_STORAGE_C
*
* Enable the Platform Security Architecture persistent key storage.
*
* Module: core/psa_crypto_storage.c
*
* Requires: MBEDTLS_PSA_CRYPTO_C,
* either MBEDTLS_PSA_ITS_FILE_C or a native implementation of
* the PSA ITS interface
*/
#define MBEDTLS_PSA_CRYPTO_STORAGE_C
/**
* \def MBEDTLS_PSA_DRIVER_GET_ENTROPY
*
* Requires: MBEDTLS_PSA_CRYPTO_C, !MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG
*
* Enable the custom entropy callback mbedtls_platform_get_entropy()
* (declared in mbedtls/platform.h). You need to provide this callback
* if you need an entropy source and the built-in entropy callback
* provided by #MBEDTLS_PSA_BUILTIN_GET_ENTROPY does not work on your platform.
*
* Enabling both #MBEDTLS_PSA_BUILTIN_GET_ENTROPY and
* #MBEDTLS_PSA_DRIVER_GET_ENTROPY is currently not supported.
*
* You do not need any entropy source in the following circumstances:
*
* - If your platform has a fast cryptographic-quality random generator, and
* you enable #MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG and provide a random generator
* callback instead.
* - If your platform has no source of entropy at all, and you enable
* #MBEDTLS_ENTROPY_NV_SEED and provide a seed in nonvolatile memory
* during the provisioning of the device.
* - If you build the library with no random generator.
* Builds with no random generator are not officially supported yet, except
* client-only builds (#MBEDTLS_PSA_CRYPTO_CLIENT enabled and
* #MBEDTLS_PSA_CRYPTO_C disabled).
*/
//#define MBEDTLS_PSA_DRIVER_GET_ENTROPY
/**
* \def MBEDTLS_PSA_CRYPTO_RNG_STRENGTH
*
* Minimum security strength (in bits) of the PSA RNG.
*
* \note Valid values: 128 or default of 256.
*/
#define MBEDTLS_PSA_CRYPTO_RNG_STRENGTH 128
/** \} name SECTION: PSA core */
/**
* \name SECTION: Builtin drivers
*
* This section sets driver specific settings.
* \{
*/
/**
* \def MBEDTLS_AES_ROM_TABLES
*
* Use precomputed AES tables stored in ROM.
*
* Uncomment this macro to use precomputed AES tables stored in ROM.
* Comment this macro to generate AES tables in RAM at runtime.
*
* Tradeoff: Using precomputed ROM tables reduces RAM usage by ~8kb
* (or ~2kb if \c MBEDTLS_AES_FEWER_TABLES is used) and reduces the
* initialization time before the first AES operation can be performed.
* It comes at the cost of additional ~8kb ROM use (resp. ~2kb if \c
* MBEDTLS_AES_FEWER_TABLES below is used), and potentially degraded
* performance if ROM access is slower than RAM access.
*
* This option is independent of \c MBEDTLS_AES_FEWER_TABLES.
*/
#define MBEDTLS_AES_ROM_TABLES
/**
* \def MBEDTLS_AES_FEWER_TABLES
*
* Use less ROM/RAM for AES tables.
*
* Uncommenting this macro omits 75% of the AES tables from
* ROM / RAM (depending on the value of \c MBEDTLS_AES_ROM_TABLES)
* by computing their values on the fly during operations
* (the tables are entry-wise rotations of one another).
*
* Tradeoff: Uncommenting this reduces the RAM / ROM footprint
* by ~6kb but at the cost of more arithmetic operations during
* runtime. Specifically, one has to compare 4 accesses within
* different tables to 4 accesses with additional arithmetic
* operations within the same table. The performance gain/loss
* depends on the system and memory details.
*
* This option is independent of \c MBEDTLS_AES_ROM_TABLES.
*/
#define MBEDTLS_AES_FEWER_TABLES
/**
* \def MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH
*
* Use only 128-bit keys in AES operations to save ROM.
*
* Uncomment this macro to remove support for AES operations that use 192-
* or 256-bit keys.
*
* Uncommenting this macro reduces the size of AES code by ~300 bytes
* on v8-M/Thumb2.
*
* Module: drivers/builtin/src/aes.c
*
* Requires: The AES built-in implementation
*/
#define MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH
/**
* \def MBEDTLS_ECP_NIST_OPTIM
*
* Enable specific 'modulo p' routines for each NIST prime.
* Depending on the prime and architecture, makes operations 4 to 8 times
* faster on the corresponding curve.
*
* Comment this macro to disable NIST curves optimisation.
*/
#define MBEDTLS_ECP_NIST_OPTIM
/**
* \def MBEDTLS_HAVE_ASM
*
* The compiler has support for asm().
*
* Requires support for asm() in compiler.
*
* Used in:
* drivers/builtin/src/aesni.h
* drivers/builtin/src/aria.c
* drivers/builtin/src/bn_mul.h
* utilities/constant_time.c
*
* Required by:
* MBEDTLS_AESCE_C
* MBEDTLS_AESNI_C (on some platforms)
*
* Comment to disable the use of assembly code.
*/
#define MBEDTLS_HAVE_ASM
/**
* Uncomment to enable p256-m. This is an alternative implementation of
* key generation, ECDH and (randomized) ECDSA on the curve SECP256R1.
* Compared to the default implementation:
*
* - p256-m has a much smaller code size and RAM footprint.
* - p256-m is only available via the PSA API. This includes the pk module.
* - p256-m does not support deterministic ECDSA, EC-JPAKE, custom protocols
* over the core arithmetic, or deterministic derivation of keys.
*
* We recommend enabling this option if your application uses the PSA API
* and the only elliptic curve support it needs is ECDH and ECDSA over
* SECP256R1.
*
* If you enable this option, you do not need to enable any ECC-related
* MBEDTLS_xxx option. You do need to separately request support for the
* cryptographic mechanisms through the PSA API:
* - #MBEDTLS_PSA_CRYPTO_C for PSA-based configuration;
* - #PSA_WANT_ECC_SECP_R1_256;
* - #PSA_WANT_ALG_ECDH and/or #PSA_WANT_ALG_ECDSA as needed;
* - #PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY, #PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_BASIC,
* #PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_IMPORT,
* #PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_EXPORT and/or
* #PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_GENERATE as needed.
*
* \note To benefit from the smaller code size of p256-m, make sure that you
* do not enable any ECC-related option not supported by p256-m: this
* would cause the built-in ECC implementation to be built as well, in
* order to provide the required option.
* Make sure #PSA_WANT_ALG_DETERMINISTIC_ECDSA, #PSA_WANT_ALG_JPAKE and
* #PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_DERIVE, and curves other than
* SECP256R1 are disabled as they are not supported by this driver.
* Also, avoid defining #MBEDTLS_PK_PARSE_EC_COMPRESSED or
* #MBEDTLS_PK_PARSE_EC_EXTENDED as those currently require a subset of
* the built-in ECC implementation, see docs/driver-only-builds.md.
*/
#define MBEDTLS_PSA_P256M_DRIVER_ENABLED
/**
* \def MBEDTLS_SHA256_SMALLER
*
* Enable an implementation of SHA-256 that has lower ROM footprint but also
* lower performance.
*
* The default implementation is meant to be a reasonable compromise between
* performance and size. This version optimizes more aggressively for size at
* the expense of performance. Eg on Cortex-M4 it reduces the size of
* mbedtls_sha256_process() from ~2KB to ~0.5KB for a performance hit of about
* 30%.
*
* Uncomment to enable the smaller implementation of SHA256.
*/
#define MBEDTLS_SHA256_SMALLER
/* ECP options */
#define MBEDTLS_ECP_FIXED_POINT_OPTIM 0 /**< Disable fixed-point speed-up */
/** \} name SECTION: Builtin drivers */
/***********************************************************/
/* Tweak the configuration to remove dependencies on TF-M. */
/***********************************************************/
/* MBEDTLS_PSA_CRYPTO_SPM needs third-party files, so disable it. */
#undef MBEDTLS_PSA_CRYPTO_SPM
/* Disable buffer-based memory allocator. This isn't strictly required,
* but using the native allocator is faster and works better with
* memory management analysis frameworks such as ASan. */
#undef MBEDTLS_MEMORY_BUFFER_ALLOC_C
// This macro is enabled in TFM Medium but is disabled here because it is
// incompatible with baremetal builds in Mbed TLS.
#undef MBEDTLS_PSA_CRYPTO_STORAGE_C
// This macro is enabled in TFM Medium but is disabled here because it is
// incompatible with baremetal builds in Mbed TLS.
#undef MBEDTLS_ENTROPY_NV_SEED
// This macro is disabled in TFM Medium but enabled in integrations with
// supported hardware. Enable it because we need an entropy source in our
// test builds.
#define MBEDTLS_PSA_DRIVER_GET_ENTROPY
// These platform-related TF-M settings are not useful here.
#undef MBEDTLS_PLATFORM_NO_STD_FUNCTIONS
#undef MBEDTLS_PLATFORM_STD_MEM_HDR
#undef MBEDTLS_PLATFORM_SNPRINTF_MACRO
#undef MBEDTLS_PLATFORM_PRINTF_ALT
#undef MBEDTLS_PLATFORM_STD_EXIT_SUCCESS
#undef MBEDTLS_PLATFORM_STD_EXIT_FAILURE
/***********************************************************************
* Local changes to crypto config below this delimiter
**********************************************************************/
// We expect TF-M to pick this up soon
#define MBEDTLS_BLOCK_CIPHER_NO_DECRYPT
#if CRYPTO_NV_SEED
#include "tfm_mbedcrypto_config_extra_nv_seed.h"
#endif /* CRYPTO_NV_SEED */
#if !defined(CRYPTO_HW_ACCELERATOR) && defined(MBEDTLS_ENTROPY_NV_SEED)
#include "mbedtls_entropy_nv_seed_config.h"
#endif
#ifdef CRYPTO_HW_ACCELERATOR
#include "crypto_accelerator_config.h"
#endif
#endif /* PROFILE_M_PSA_CRYPTO_CONFIG_H */
+7
View File
@@ -0,0 +1,7 @@
###START_GENERATED_FILES###
# /psa_crypto_driver_wrappers.h
# /psa_crypto_driver_wrappers_no_static.c
# /tf_psa_crypto_config_check_before.h
# /tf_psa_crypto_config_check_final.h
# /tf_psa_crypto_config_check_user.h
###END_GENERATED_FILES###
+215
View File
@@ -0,0 +1,215 @@
file(GLOB src_crypto "${CMAKE_CURRENT_SOURCE_DIR}/*.c")
# The generated file `psa_crypto_driver_wrappers_no_static.c` may exist in the
# source tree and therefore be picked up by the glob above. Remove it from
# `src_crypto` if present, then append it using a relative path. This ensures
# that the build system prefers the file from the build tree over the one in
# the source tree.
list(FIND src_crypto
"${CMAKE_CURRENT_SOURCE_DIR}/psa_crypto_driver_wrappers_no_static.c"
_idx)
if(NOT _idx EQUAL -1)
list(REMOVE_AT src_crypto ${_idx})
endif()
list(APPEND src_crypto psa_crypto_driver_wrappers_no_static.c)
if(GEN_FILES)
add_custom_command(
OUTPUT
${CMAKE_CURRENT_BINARY_DIR}/psa_crypto_driver_wrappers.h
${CMAKE_CURRENT_BINARY_DIR}/psa_crypto_driver_wrappers_no_static.c
COMMAND
${TF_PSA_CRYPTO_PYTHON_EXECUTABLE}
${PROJECT_SOURCE_DIR}/scripts/generate_driver_wrappers.py
${CMAKE_CURRENT_BINARY_DIR}
DEPENDS
${PROJECT_SOURCE_DIR}/scripts/generate_driver_wrappers.py
${PROJECT_SOURCE_DIR}/scripts/data_files/driver_templates/psa_crypto_driver_wrappers.h.jinja
${PROJECT_SOURCE_DIR}/scripts/data_files/driver_templates/psa_crypto_driver_wrappers_no_static.c.jinja
)
execute_process(
COMMAND
${TF_PSA_CRYPTO_PYTHON_EXECUTABLE}
${PROJECT_SOURCE_DIR}/scripts/generate_config_checks.py
--list-for-cmake "${CMAKE_CURRENT_BINARY_DIR}"
WORKING_DIRECTORY
${PROJECT_SOURCE_DIR}
OUTPUT_VARIABLE
TF_PSA_CRYPTO_GENERATED_CONFIG_CHECKS_HEADERS)
add_custom_command(
OUTPUT ${TF_PSA_CRYPTO_GENERATED_CONFIG_CHECKS_HEADERS}
COMMAND
${TF_PSA_CRYPTO_PYTHON_EXECUTABLE}
${PROJECT_SOURCE_DIR}/scripts/generate_config_checks.py
${CMAKE_CURRENT_BINARY_DIR}
DEPENDS
${PROJECT_SOURCE_DIR}/scripts/generate_config_checks.py
${TF_PSA_CRYPTO_FRAMEWORK_DIR}/scripts/mbedtls_framework/config_checks_generator.py
)
add_custom_target(
${TF_PSA_CRYPTO_TARGET_PREFIX}libtfpsacrypto_generated_files_target
DEPENDS
"${CMAKE_CURRENT_BINARY_DIR}/psa_crypto_driver_wrappers.h"
"${CMAKE_CURRENT_BINARY_DIR}/psa_crypto_driver_wrappers_no_static.c"
${TF_PSA_CRYPTO_GENERATED_CONFIG_CHECKS_HEADERS}
)
# List generated headers as sources explicitly. Normally CMake finds
# headers by tracing include directives, but if that happens before the
# generated headers are generated, this process doesn't find them.
list(APPEND src_crypto
"${CMAKE_CURRENT_BINARY_DIR}/psa_crypto_driver_wrappers.h"
${TF_PSA_CRYPTO_GENERATED_CONFIG_CHECKS_HEADERS}
)
endif(GEN_FILES)
if(CMAKE_COMPILER_IS_GNUCC)
set(LIBS_C_FLAGS -Wmissing-declarations -Wmissing-prototypes)
endif(CMAKE_COMPILER_IS_GNUCC)
if(CMAKE_COMPILER_IS_CLANG)
# Removed -Wdocumentation as it creates lots of noise
# from FreeRTOS header files
set(LIBS_C_FLAGS -Wmissing-declarations -Wmissing-prototypes -Wno-documentation-deprecated-sync -Wunreachable-code)
endif(CMAKE_COMPILER_IS_CLANG)
if(CMAKE_COMPILER_IS_MSVC)
option(MSVC_STATIC_RUNTIME "Build the libraries with /MT compiler flag" OFF)
if(MSVC_STATIC_RUNTIME)
foreach(flag_var
CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE
CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO
CMAKE_C_FLAGS_CHECK)
string(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}")
endforeach(flag_var)
endif()
endif()
if(CMAKE_C_COMPILER_ID MATCHES "AppleClang")
set(CMAKE_C_ARCHIVE_CREATE "<CMAKE_AR> Scr <TARGET> <LINK_FLAGS> <OBJECTS>")
set(CMAKE_C_ARCHIVE_FINISH "<CMAKE_RANLIB> -no_warning_for_no_symbols -c <TARGET>")
endif()
if(CMAKE_CXX_COMPILER_ID MATCHES "AppleClang")
set(CMAKE_CXX_ARCHIVE_CREATE "<CMAKE_AR> Scr <TARGET> <LINK_FLAGS> <OBJECTS>")
set(CMAKE_CXX_ARCHIVE_FINISH "<CMAKE_RANLIB> -no_warning_for_no_symbols -c <TARGET>")
endif()
if(WIN32)
set(libs ${libs} ws2_32 bcrypt)
endif(WIN32)
if(LINK_WITH_PTHREAD)
set(libs ${libs} ${CMAKE_THREAD_LIBS_INIT})
endif()
if(LINK_WITH_TRUSTED_STORAGE)
set(libs ${libs} trusted_storage)
endif()
if (NOT USE_STATIC_TF_PSA_CRYPTO_LIBRARY AND NOT USE_SHARED_TF_PSA_CRYPTO_LIBRARY)
message(FATAL_ERROR "Need to choose static or shared TF-PSA-Crypto build!")
endif(NOT USE_STATIC_TF_PSA_CRYPTO_LIBRARY AND NOT USE_SHARED_TF_PSA_CRYPTO_LIBRARY)
set(tfpsacrypto_target "${TF_PSA_CRYPTO_TARGET_PREFIX}tfpsacrypto")
if (USE_STATIC_TF_PSA_CRYPTO_LIBRARY)
set(tfpsacrypto_static_target ${tfpsacrypto_target})
endif()
set(target_libraries ${tfpsacrypto_target})
if(USE_STATIC_TF_PSA_CRYPTO_LIBRARY AND USE_SHARED_TF_PSA_CRYPTO_LIBRARY)
string(APPEND tfpsacrypto_static_target "_static")
list(APPEND target_libraries ${tfpsacrypto_static_target})
endif()
if(USE_STATIC_TF_PSA_CRYPTO_LIBRARY)
set(target_objects "")
foreach(driver_target ${TF_PSA_CRYPTO_DRIVER_STATIC_TARGETS})
list(APPEND target_objects "$<TARGET_OBJECTS:${driver_target}>")
endforeach()
foreach(objlib_target ${TF_PSA_CRYPTO_OBJLIB_STATIC_TARGETS})
list(APPEND target_objects "$<TARGET_OBJECTS:${objlib_target}>")
endforeach()
add_library(${tfpsacrypto_static_target} STATIC
${src_crypto}
${target_objects})
tf_psa_crypto_set_base_compile_options(${tfpsacrypto_static_target})
tf_psa_crypto_set_extra_compile_options(${tfpsacrypto_static_target})
set_target_properties(${tfpsacrypto_static_target} PROPERTIES OUTPUT_NAME tfpsacrypto)
target_link_libraries(${tfpsacrypto_static_target} PUBLIC ${libs} ${builtin_static_target} ${everest_static_target} ${p256m_static_target})
if(GEN_FILES)
add_dependencies(${tfpsacrypto_static_target}
${TF_PSA_CRYPTO_TARGET_PREFIX}libtfpsacrypto_generated_files_target)
endif()
endif(USE_STATIC_TF_PSA_CRYPTO_LIBRARY)
if(USE_SHARED_TF_PSA_CRYPTO_LIBRARY)
set(CMAKE_LIBRARY_PATH ${CMAKE_CURRENT_BINARY_DIR})
set(target_objects "")
foreach(driver_target ${TF_PSA_CRYPTO_DRIVER_TARGETS})
list(APPEND target_objects "$<TARGET_OBJECTS:${driver_target}>")
endforeach()
foreach(objlib_target ${TF_PSA_CRYPTO_OBJLIB_TARGETS})
list(APPEND target_objects "$<TARGET_OBJECTS:${objlib_target}>")
endforeach()
add_library(${tfpsacrypto_target} SHARED
${src_crypto}
${target_objects})
tf_psa_crypto_set_base_compile_options(${tfpsacrypto_target})
tf_psa_crypto_set_extra_compile_options(${tfpsacrypto_target})
set_target_properties(${tfpsacrypto_target} PROPERTIES VERSION ${TF_PSA_CRYPTO_VERSION} SOVERSION ${TF_PSA_CRYPTO_SOVERSION})
target_link_libraries(${tfpsacrypto_target} PUBLIC ${libs})
if(GEN_FILES)
add_dependencies(${tfpsacrypto_target}
${TF_PSA_CRYPTO_TARGET_PREFIX}libtfpsacrypto_generated_files_target)
endif()
endif(USE_SHARED_TF_PSA_CRYPTO_LIBRARY)
foreach(target IN LISTS target_libraries)
add_library(TF-PSA-Crypto::${target} ALIAS ${target}) # add_subdirectory support
target_include_directories(${target}
# Add the build-tree include directory before the source-tree one
# so that generated headers in the build tree take precedence.
PUBLIC $<BUILD_INTERFACE:${PROJECT_BINARY_DIR}/include/>
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include/>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
PRIVATE ${TF_PSA_CRYPTO_PRIVATE_INCLUDE_DIRS}
# Needed to include psa_crypto_driver_wrappers.h
${CMAKE_CURRENT_BINARY_DIR})
foreach(driver_target ${TF_PSA_CRYPTO_DRIVER_TARGETS})
get_target_property(public_includes ${driver_target} INTERFACE_INCLUDE_DIRECTORIES)
foreach(dir IN LISTS public_includes)
target_include_directories(${target} PUBLIC $<BUILD_INTERFACE:${dir}>)
endforeach()
endforeach()
if(TF_PSA_CRYPTO_TEST_DRIVER)
# Note: "tests/include/test" exists solely to provide access to
# "mbedtls/build_info.h". That header is an alias of
# "tf-psa-crypto/build_info.h".
#
# It is included in framework headers and C modules because those
# components are also used in the Mbed TLS context.
target_include_directories(${target}
PRIVATE ${TF_PSA_CRYPTO_FRAMEWORK_DIR}/tests/include
${PROJECT_SOURCE_DIR}/tests/include/test)
endif()
tf_psa_crypto_set_config_files_compile_definitions(${target})
install(
TARGETS ${target}
EXPORT MbedTLSTargets
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ)
install(
TARGETS ${target}
EXPORT TF-PSA-CryptoTargets
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ)
endforeach(target)
+687
View File
@@ -0,0 +1,687 @@
/**
* \file alignment.h
*
* \brief Utility code for dealing with unaligned memory accesses
*/
/*
* Copyright The Mbed TLS Contributors
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
*/
#ifndef TF_PSA_CRYPTO_ALIGNMENT_H
#define TF_PSA_CRYPTO_ALIGNMENT_H
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#if !defined(MBEDTLS_ALIGNMENT_DISABLE_EFFICENT_UNALIGNED_ACCESS) //no-check-names
/*
* Define MBEDTLS_EFFICIENT_UNALIGNED_ACCESS for architectures where unaligned memory
* accesses are known to be efficient.
*
* All functions defined here will behave correctly regardless, but might be less
* efficient when this is not defined.
*/
#if defined(__ARM_FEATURE_UNALIGNED) \
|| defined(MBEDTLS_ARCH_IS_X86) || defined(MBEDTLS_ARCH_IS_X64) \
|| defined(MBEDTLS_PLATFORM_IS_WINDOWS_ON_ARM64)
/*
* __ARM_FEATURE_UNALIGNED is defined where appropriate by armcc, gcc 7, clang 9
* (and later versions) for Arm v7 and later; all x86 platforms should have
* efficient unaligned access.
*
* https://learn.microsoft.com/en-us/cpp/build/arm64-windows-abi-conventions?view=msvc-170#alignment
* specifies that on Windows-on-Arm64, unaligned access is safe (except for uncached
* device memory).
*/
#define MBEDTLS_EFFICIENT_UNALIGNED_ACCESS
#endif /* __ARM_FEATURE_UNALIGNED || MBEDTLS_ARCH_IS_X86 || MBEDTLS_ARCH_IS_X64 ||
* MBEDTLS_PLATFORM_IS_WINDOWS_ON_ARM64 */
#endif /* MBEDTLS_ALIGNMENT_DISABLE_EFFICENT_UNALIGNED_ACCESS */ //no-check-names
#if defined(__IAR_SYSTEMS_ICC__) && \
(defined(MBEDTLS_ARCH_IS_ARM64) || defined(MBEDTLS_ARCH_IS_ARM32) \
|| defined(__ICCRX__) || defined(__ICCRL78__) || defined(__ICCRISCV__))
#pragma language=save
#pragma language=extended
#define MBEDTLS_POP_IAR_LANGUAGE_PRAGMA
/* IAR recommend this technique for accessing unaligned data in
* https://www.iar.com/knowledge/support/technical-notes/compiler/accessing-unaligned-data
* This results in a single load / store instruction (if unaligned access is supported).
* According to that document, this is only supported on certain architectures.
*/
#define UINT_UNALIGNED
typedef uint16_t __packed mbedtls_uint16_unaligned_t;
typedef uint32_t __packed mbedtls_uint32_unaligned_t;
typedef uint64_t __packed mbedtls_uint64_unaligned_t;
#elif defined(MBEDTLS_COMPILER_IS_GCC) && (MBEDTLS_GCC_VERSION >= 40504) && \
((MBEDTLS_GCC_VERSION < 60300) || (!defined(MBEDTLS_EFFICIENT_UNALIGNED_ACCESS)))
/*
* gcc may generate a branch to memcpy for calls like `memcpy(dest, src, 4)` rather than
* generating some LDR or LDRB instructions (similar for stores).
*
* This is architecture dependent: x86-64 seems fine even with old gcc; 32-bit Arm
* is affected. To keep it simple, we enable for all architectures.
*
* For versions of gcc < 5.4.0 this issue always happens.
* For gcc < 6.3.0, this issue happens at -O0
* For all versions, this issue happens iff unaligned access is not supported.
*
* For gcc 4.x, this implementation will generate byte-by-byte loads even if unaligned access is
* supported, which is correct but not optimal.
*
* For performance (and code size, in some cases), we want to avoid the branch and just generate
* some inline load/store instructions since the access is small and constant-size.
*
* The manual states:
* "The packed attribute specifies that a variable or structure field should have the smallest
* possible alignment—one byte for a variable"
* https://gcc.gnu.org/onlinedocs/gcc-4.5.4/gcc/Variable-Attributes.html
*
* Previous implementations used __attribute__((__aligned__(1)), but had issues with a gcc bug:
* https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94662
*
* Tested with several versions of GCC from 4.5.0 up to 13.2.0
* We don't enable for older than 4.5.0 as this has not been tested.
*/
#define UINT_UNALIGNED_STRUCT
typedef struct {
uint16_t x;
} __attribute__((packed, may_alias)) mbedtls_uint16_unaligned_t;
typedef struct {
uint32_t x;
} __attribute__((packed, may_alias)) mbedtls_uint32_unaligned_t;
typedef struct {
uint64_t x;
} __attribute__((packed, may_alias)) mbedtls_uint64_unaligned_t;
#endif
/*
* We try to force mbedtls_(get|put)_unaligned_uintXX to be always inline, because this results
* in code that is both smaller and faster. IAR and gcc both benefit from this when optimising
* for size.
*/
/**
* Read the unsigned 16 bits integer from the given address, which need not
* be aligned.
*
* \param p pointer to 2 bytes of data
* \return Data at the given address
*/
#if defined(__IAR_SYSTEMS_ICC__)
#pragma inline = forced
#elif defined(__GNUC__)
__attribute__((always_inline))
#endif
static inline uint16_t mbedtls_get_unaligned_uint16(const void *p)
{
uint16_t r;
#if defined(UINT_UNALIGNED)
mbedtls_uint16_unaligned_t *p16 = (mbedtls_uint16_unaligned_t *) p;
r = *p16;
#elif defined(UINT_UNALIGNED_STRUCT)
mbedtls_uint16_unaligned_t *p16 = (mbedtls_uint16_unaligned_t *) p;
r = p16->x;
#else
memcpy(&r, p, sizeof(r));
#endif
return r;
}
/**
* Write the unsigned 16 bits integer to the given address, which need not
* be aligned.
*
* \param p pointer to 2 bytes of data
* \param x data to write
*/
#if defined(__IAR_SYSTEMS_ICC__)
#pragma inline = forced
#elif defined(__GNUC__)
__attribute__((always_inline))
#endif
static inline void mbedtls_put_unaligned_uint16(void *p, uint16_t x)
{
#if defined(UINT_UNALIGNED)
mbedtls_uint16_unaligned_t *p16 = (mbedtls_uint16_unaligned_t *) p;
*p16 = x;
#elif defined(UINT_UNALIGNED_STRUCT)
mbedtls_uint16_unaligned_t *p16 = (mbedtls_uint16_unaligned_t *) p;
p16->x = x;
#else
memcpy(p, &x, sizeof(x));
#endif
}
/**
* Read the unsigned 32 bits integer from the given address, which need not
* be aligned.
*
* \param p pointer to 4 bytes of data
* \return Data at the given address
*/
#if defined(__IAR_SYSTEMS_ICC__)
#pragma inline = forced
#elif defined(__GNUC__)
__attribute__((always_inline))
#endif
static inline uint32_t mbedtls_get_unaligned_uint32(const void *p)
{
uint32_t r;
#if defined(UINT_UNALIGNED)
mbedtls_uint32_unaligned_t *p32 = (mbedtls_uint32_unaligned_t *) p;
r = *p32;
#elif defined(UINT_UNALIGNED_STRUCT)
mbedtls_uint32_unaligned_t *p32 = (mbedtls_uint32_unaligned_t *) p;
r = p32->x;
#else
memcpy(&r, p, sizeof(r));
#endif
return r;
}
/**
* Write the unsigned 32 bits integer to the given address, which need not
* be aligned.
*
* \param p pointer to 4 bytes of data
* \param x data to write
*/
#if defined(__IAR_SYSTEMS_ICC__)
#pragma inline = forced
#elif defined(__GNUC__)
__attribute__((always_inline))
#endif
static inline void mbedtls_put_unaligned_uint32(void *p, uint32_t x)
{
#if defined(UINT_UNALIGNED)
mbedtls_uint32_unaligned_t *p32 = (mbedtls_uint32_unaligned_t *) p;
*p32 = x;
#elif defined(UINT_UNALIGNED_STRUCT)
mbedtls_uint32_unaligned_t *p32 = (mbedtls_uint32_unaligned_t *) p;
p32->x = x;
#else
memcpy(p, &x, sizeof(x));
#endif
}
/**
* Read the unsigned 64 bits integer from the given address, which need not
* be aligned.
*
* \param p pointer to 8 bytes of data
* \return Data at the given address
*/
#if defined(__IAR_SYSTEMS_ICC__)
#pragma inline = forced
#elif defined(__GNUC__)
__attribute__((always_inline))
#endif
static inline uint64_t mbedtls_get_unaligned_uint64(const void *p)
{
uint64_t r;
#if defined(UINT_UNALIGNED)
mbedtls_uint64_unaligned_t *p64 = (mbedtls_uint64_unaligned_t *) p;
r = *p64;
#elif defined(UINT_UNALIGNED_STRUCT)
mbedtls_uint64_unaligned_t *p64 = (mbedtls_uint64_unaligned_t *) p;
r = p64->x;
#else
memcpy(&r, p, sizeof(r));
#endif
return r;
}
/**
* Write the unsigned 64 bits integer to the given address, which need not
* be aligned.
*
* \param p pointer to 8 bytes of data
* \param x data to write
*/
#if defined(__IAR_SYSTEMS_ICC__)
#pragma inline = forced
#elif defined(__GNUC__)
__attribute__((always_inline))
#endif
static inline void mbedtls_put_unaligned_uint64(void *p, uint64_t x)
{
#if defined(UINT_UNALIGNED)
mbedtls_uint64_unaligned_t *p64 = (mbedtls_uint64_unaligned_t *) p;
*p64 = x;
#elif defined(UINT_UNALIGNED_STRUCT)
mbedtls_uint64_unaligned_t *p64 = (mbedtls_uint64_unaligned_t *) p;
p64->x = x;
#else
memcpy(p, &x, sizeof(x));
#endif
}
#if defined(MBEDTLS_POP_IAR_LANGUAGE_PRAGMA)
#pragma language=restore
#endif
/** Byte Reading Macros
*
* Given a multi-byte integer \p x, MBEDTLS_BYTE_n retrieves the n-th
* byte from x, where byte 0 is the least significant byte.
*/
#define MBEDTLS_BYTE_0(x) ((uint8_t) ((x) & 0xff))
#define MBEDTLS_BYTE_1(x) ((uint8_t) (((x) >> 8) & 0xff))
#define MBEDTLS_BYTE_2(x) ((uint8_t) (((x) >> 16) & 0xff))
#define MBEDTLS_BYTE_3(x) ((uint8_t) (((x) >> 24) & 0xff))
#define MBEDTLS_BYTE_4(x) ((uint8_t) (((x) >> 32) & 0xff))
#define MBEDTLS_BYTE_5(x) ((uint8_t) (((x) >> 40) & 0xff))
#define MBEDTLS_BYTE_6(x) ((uint8_t) (((x) >> 48) & 0xff))
#define MBEDTLS_BYTE_7(x) ((uint8_t) (((x) >> 56) & 0xff))
/*
* Detect GCC built-in byteswap routines
*/
#if defined(__GNUC__)
#if MBEDTLS_GCC_VERSION >= 40800
#define MBEDTLS_BSWAP16 __builtin_bswap16
#endif
#if MBEDTLS_GCC_VERSION >= 40300
#define MBEDTLS_BSWAP32 __builtin_bswap32
#define MBEDTLS_BSWAP64 __builtin_bswap64
#endif
#endif /* defined(__GNUC__) */
/*
* Detect Clang built-in byteswap routines
*/
#if defined(__clang__) && defined(__has_builtin)
#if __has_builtin(__builtin_bswap16) && !defined(MBEDTLS_BSWAP16)
#define MBEDTLS_BSWAP16 __builtin_bswap16
#endif /* __has_builtin(__builtin_bswap16) */
#if __has_builtin(__builtin_bswap32) && !defined(MBEDTLS_BSWAP32)
#define MBEDTLS_BSWAP32 __builtin_bswap32
#endif /* __has_builtin(__builtin_bswap32) */
#if __has_builtin(__builtin_bswap64) && !defined(MBEDTLS_BSWAP64)
#define MBEDTLS_BSWAP64 __builtin_bswap64
#endif /* __has_builtin(__builtin_bswap64) */
#endif /* defined(__clang__) && defined(__has_builtin) */
/*
* Detect MSVC built-in byteswap routines
*/
#if defined(_MSC_VER)
#if !defined(MBEDTLS_BSWAP16)
#define MBEDTLS_BSWAP16 _byteswap_ushort
#endif
#if !defined(MBEDTLS_BSWAP32)
#define MBEDTLS_BSWAP32 _byteswap_ulong
#endif
#if !defined(MBEDTLS_BSWAP64)
#define MBEDTLS_BSWAP64 _byteswap_uint64
#endif
#endif /* defined(_MSC_VER) */
/* Detect armcc built-in byteswap routine */
#if defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 410000) && !defined(MBEDTLS_BSWAP32)
#if defined(__ARM_ACLE) /* ARM Compiler 6 - earlier versions don't need a header */
#include <arm_acle.h>
#endif
#define MBEDTLS_BSWAP32 __rev
#endif
/* Detect IAR built-in byteswap routine */
#if defined(__IAR_SYSTEMS_ICC__)
#if defined(__ARM_ACLE)
#include <arm_acle.h>
#define MBEDTLS_BSWAP16(x) ((uint16_t) __rev16((uint32_t) (x)))
#define MBEDTLS_BSWAP32 __rev
#define MBEDTLS_BSWAP64 __revll
#endif
#endif
/*
* Where compiler built-ins are not present, fall back to C code that the
* compiler may be able to detect and transform into the relevant bswap or
* similar instruction.
*/
#if !defined(MBEDTLS_BSWAP16)
static inline uint16_t mbedtls_bswap16(uint16_t x)
{
return
(x & 0x00ff) << 8 |
(x & 0xff00) >> 8;
}
#define MBEDTLS_BSWAP16 mbedtls_bswap16
#endif /* !defined(MBEDTLS_BSWAP16) */
#if !defined(MBEDTLS_BSWAP32)
static inline uint32_t mbedtls_bswap32(uint32_t x)
{
return
(x & 0x000000ff) << 24 |
(x & 0x0000ff00) << 8 |
(x & 0x00ff0000) >> 8 |
(x & 0xff000000) >> 24;
}
#define MBEDTLS_BSWAP32 mbedtls_bswap32
#endif /* !defined(MBEDTLS_BSWAP32) */
#if !defined(MBEDTLS_BSWAP64)
static inline uint64_t mbedtls_bswap64(uint64_t x)
{
return
(x & 0x00000000000000ffULL) << 56 |
(x & 0x000000000000ff00ULL) << 40 |
(x & 0x0000000000ff0000ULL) << 24 |
(x & 0x00000000ff000000ULL) << 8 |
(x & 0x000000ff00000000ULL) >> 8 |
(x & 0x0000ff0000000000ULL) >> 24 |
(x & 0x00ff000000000000ULL) >> 40 |
(x & 0xff00000000000000ULL) >> 56;
}
#define MBEDTLS_BSWAP64 mbedtls_bswap64
#endif /* !defined(MBEDTLS_BSWAP64) */
#if !defined(__BYTE_ORDER__)
#if defined(__LITTLE_ENDIAN__)
/* IAR defines __xxx_ENDIAN__, but not __BYTE_ORDER__ */
#define MBEDTLS_IS_BIG_ENDIAN 0
#elif defined(__BIG_ENDIAN__)
#define MBEDTLS_IS_BIG_ENDIAN 1
#else
static const uint16_t mbedtls_byte_order_detector = { 0x100 };
#define MBEDTLS_IS_BIG_ENDIAN (*((unsigned char *) (&mbedtls_byte_order_detector)) == 0x01)
#endif
#else
#if (__BYTE_ORDER__) == (__ORDER_BIG_ENDIAN__)
#define MBEDTLS_IS_BIG_ENDIAN 1
#else
#define MBEDTLS_IS_BIG_ENDIAN 0
#endif
#endif /* !defined(__BYTE_ORDER__) */
/**
* Get the unsigned 32 bits integer corresponding to four bytes in
* big-endian order (MSB first).
*
* \param data Base address of the memory to get the four bytes from.
* \param offset Offset from \p data of the first and most significant
* byte of the four bytes to build the 32 bits unsigned
* integer from.
*/
#define MBEDTLS_GET_UINT32_BE(data, offset) \
((MBEDTLS_IS_BIG_ENDIAN) \
? mbedtls_get_unaligned_uint32((data) + (offset)) \
: MBEDTLS_BSWAP32(mbedtls_get_unaligned_uint32((data) + (offset))) \
)
/**
* Put in memory a 32 bits unsigned integer in big-endian order.
*
* \param n 32 bits unsigned integer to put in memory.
* \param data Base address of the memory where to put the 32
* bits unsigned integer in.
* \param offset Offset from \p data where to put the most significant
* byte of the 32 bits unsigned integer \p n.
*/
#define MBEDTLS_PUT_UINT32_BE(n, data, offset) \
{ \
if (MBEDTLS_IS_BIG_ENDIAN) \
{ \
mbedtls_put_unaligned_uint32((data) + (offset), (uint32_t) (n)); \
} \
else \
{ \
mbedtls_put_unaligned_uint32((data) + (offset), MBEDTLS_BSWAP32((uint32_t) (n))); \
} \
}
/**
* Get the unsigned 32 bits integer corresponding to four bytes in
* little-endian order (LSB first).
*
* \param data Base address of the memory to get the four bytes from.
* \param offset Offset from \p data of the first and least significant
* byte of the four bytes to build the 32 bits unsigned
* integer from.
*/
#define MBEDTLS_GET_UINT32_LE(data, offset) \
((MBEDTLS_IS_BIG_ENDIAN) \
? MBEDTLS_BSWAP32(mbedtls_get_unaligned_uint32((data) + (offset))) \
: mbedtls_get_unaligned_uint32((data) + (offset)) \
)
/**
* Put in memory a 32 bits unsigned integer in little-endian order.
*
* \param n 32 bits unsigned integer to put in memory.
* \param data Base address of the memory where to put the 32
* bits unsigned integer in.
* \param offset Offset from \p data where to put the least significant
* byte of the 32 bits unsigned integer \p n.
*/
#define MBEDTLS_PUT_UINT32_LE(n, data, offset) \
{ \
if (MBEDTLS_IS_BIG_ENDIAN) \
{ \
mbedtls_put_unaligned_uint32((data) + (offset), MBEDTLS_BSWAP32((uint32_t) (n))); \
} \
else \
{ \
mbedtls_put_unaligned_uint32((data) + (offset), ((uint32_t) (n))); \
} \
}
/**
* Get the unsigned 16 bits integer corresponding to two bytes in
* little-endian order (LSB first).
*
* \param data Base address of the memory to get the two bytes from.
* \param offset Offset from \p data of the first and least significant
* byte of the two bytes to build the 16 bits unsigned
* integer from.
*/
#define MBEDTLS_GET_UINT16_LE(data, offset) \
((MBEDTLS_IS_BIG_ENDIAN) \
? MBEDTLS_BSWAP16(mbedtls_get_unaligned_uint16((data) + (offset))) \
: mbedtls_get_unaligned_uint16((data) + (offset)) \
)
/**
* Put in memory a 16 bits unsigned integer in little-endian order.
*
* \param n 16 bits unsigned integer to put in memory.
* \param data Base address of the memory where to put the 16
* bits unsigned integer in.
* \param offset Offset from \p data where to put the least significant
* byte of the 16 bits unsigned integer \p n.
*/
#define MBEDTLS_PUT_UINT16_LE(n, data, offset) \
{ \
if (MBEDTLS_IS_BIG_ENDIAN) \
{ \
mbedtls_put_unaligned_uint16((data) + (offset), MBEDTLS_BSWAP16((uint16_t) (n))); \
} \
else \
{ \
mbedtls_put_unaligned_uint16((data) + (offset), (uint16_t) (n)); \
} \
}
/**
* Get the unsigned 16 bits integer corresponding to two bytes in
* big-endian order (MSB first).
*
* \param data Base address of the memory to get the two bytes from.
* \param offset Offset from \p data of the first and most significant
* byte of the two bytes to build the 16 bits unsigned
* integer from.
*/
#define MBEDTLS_GET_UINT16_BE(data, offset) \
((MBEDTLS_IS_BIG_ENDIAN) \
? mbedtls_get_unaligned_uint16((data) + (offset)) \
: MBEDTLS_BSWAP16(mbedtls_get_unaligned_uint16((data) + (offset))) \
)
/**
* Put in memory a 16 bits unsigned integer in big-endian order.
*
* \param n 16 bits unsigned integer to put in memory.
* \param data Base address of the memory where to put the 16
* bits unsigned integer in.
* \param offset Offset from \p data where to put the most significant
* byte of the 16 bits unsigned integer \p n.
*/
#define MBEDTLS_PUT_UINT16_BE(n, data, offset) \
{ \
if (MBEDTLS_IS_BIG_ENDIAN) \
{ \
mbedtls_put_unaligned_uint16((data) + (offset), (uint16_t) (n)); \
} \
else \
{ \
mbedtls_put_unaligned_uint16((data) + (offset), MBEDTLS_BSWAP16((uint16_t) (n))); \
} \
}
/**
* Get the unsigned 24 bits integer corresponding to three bytes in
* big-endian order (MSB first).
*
* \param data Base address of the memory to get the three bytes from.
* \param offset Offset from \p data of the first and most significant
* byte of the three bytes to build the 24 bits unsigned
* integer from.
*/
#define MBEDTLS_GET_UINT24_BE(data, offset) \
( \
((uint32_t) (data)[(offset)] << 16) \
| ((uint32_t) (data)[(offset) + 1] << 8) \
| ((uint32_t) (data)[(offset) + 2]) \
)
/**
* Put in memory a 24 bits unsigned integer in big-endian order.
*
* \param n 24 bits unsigned integer to put in memory.
* \param data Base address of the memory where to put the 24
* bits unsigned integer in.
* \param offset Offset from \p data where to put the most significant
* byte of the 24 bits unsigned integer \p n.
*/
#define MBEDTLS_PUT_UINT24_BE(n, data, offset) \
{ \
(data)[(offset)] = MBEDTLS_BYTE_2(n); \
(data)[(offset) + 1] = MBEDTLS_BYTE_1(n); \
(data)[(offset) + 2] = MBEDTLS_BYTE_0(n); \
}
/**
* Get the unsigned 24 bits integer corresponding to three bytes in
* little-endian order (LSB first).
*
* \param data Base address of the memory to get the three bytes from.
* \param offset Offset from \p data of the first and least significant
* byte of the three bytes to build the 24 bits unsigned
* integer from.
*/
#define MBEDTLS_GET_UINT24_LE(data, offset) \
( \
((uint32_t) (data)[(offset)]) \
| ((uint32_t) (data)[(offset) + 1] << 8) \
| ((uint32_t) (data)[(offset) + 2] << 16) \
)
/**
* Put in memory a 24 bits unsigned integer in little-endian order.
*
* \param n 24 bits unsigned integer to put in memory.
* \param data Base address of the memory where to put the 24
* bits unsigned integer in.
* \param offset Offset from \p data where to put the least significant
* byte of the 24 bits unsigned integer \p n.
*/
#define MBEDTLS_PUT_UINT24_LE(n, data, offset) \
{ \
(data)[(offset)] = MBEDTLS_BYTE_0(n); \
(data)[(offset) + 1] = MBEDTLS_BYTE_1(n); \
(data)[(offset) + 2] = MBEDTLS_BYTE_2(n); \
}
/**
* Get the unsigned 64 bits integer corresponding to eight bytes in
* big-endian order (MSB first).
*
* \param data Base address of the memory to get the eight bytes from.
* \param offset Offset from \p data of the first and most significant
* byte of the eight bytes to build the 64 bits unsigned
* integer from.
*/
#define MBEDTLS_GET_UINT64_BE(data, offset) \
((MBEDTLS_IS_BIG_ENDIAN) \
? mbedtls_get_unaligned_uint64((data) + (offset)) \
: MBEDTLS_BSWAP64(mbedtls_get_unaligned_uint64((data) + (offset))) \
)
/**
* Put in memory a 64 bits unsigned integer in big-endian order.
*
* \param n 64 bits unsigned integer to put in memory.
* \param data Base address of the memory where to put the 64
* bits unsigned integer in.
* \param offset Offset from \p data where to put the most significant
* byte of the 64 bits unsigned integer \p n.
*/
#define MBEDTLS_PUT_UINT64_BE(n, data, offset) \
{ \
if (MBEDTLS_IS_BIG_ENDIAN) \
{ \
mbedtls_put_unaligned_uint64((data) + (offset), (uint64_t) (n)); \
} \
else \
{ \
mbedtls_put_unaligned_uint64((data) + (offset), MBEDTLS_BSWAP64((uint64_t) (n))); \
} \
}
/**
* Get the unsigned 64 bits integer corresponding to eight bytes in
* little-endian order (LSB first).
*
* \param data Base address of the memory to get the eight bytes from.
* \param offset Offset from \p data of the first and least significant
* byte of the eight bytes to build the 64 bits unsigned
* integer from.
*/
#define MBEDTLS_GET_UINT64_LE(data, offset) \
((MBEDTLS_IS_BIG_ENDIAN) \
? MBEDTLS_BSWAP64(mbedtls_get_unaligned_uint64((data) + (offset))) \
: mbedtls_get_unaligned_uint64((data) + (offset)) \
)
/**
* Put in memory a 64 bits unsigned integer in little-endian order.
*
* \param n 64 bits unsigned integer to put in memory.
* \param data Base address of the memory where to put the 64
* bits unsigned integer in.
* \param offset Offset from \p data where to put the least significant
* byte of the 64 bits unsigned integer \p n.
*/
#define MBEDTLS_PUT_UINT64_LE(n, data, offset) \
{ \
if (MBEDTLS_IS_BIG_ENDIAN) \
{ \
mbedtls_put_unaligned_uint64((data) + (offset), MBEDTLS_BSWAP64((uint64_t) (n))); \
} \
else \
{ \
mbedtls_put_unaligned_uint64((data) + (offset), (uint64_t) (n)); \
} \
}
#endif /* TF_PSA_CRYPTO_ALIGNMENT_H */
+111
View File
@@ -0,0 +1,111 @@
/**
* \file check_crypto_config.h
*
* \brief Consistency checks for PSA configuration options
*/
/*
* Copyright The Mbed TLS Contributors
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
*/
/*
* It is recommended to include this file from your crypto_config.h
* in order to catch dependency issues early.
*/
#ifndef TF_PSA_CRYPTO_CHECK_CRYPTO_CONFIG_H
#define TF_PSA_CRYPTO_CHECK_CRYPTO_CONFIG_H
#if defined(PSA_WANT_ALG_CCM) && \
!(defined(PSA_WANT_KEY_TYPE_AES) || \
defined(PSA_WANT_KEY_TYPE_CAMELLIA))
#error "PSA_WANT_ALG_CCM defined, but not all prerequisites"
#endif
#if defined(PSA_WANT_ALG_CMAC) && \
!(defined(PSA_WANT_KEY_TYPE_AES) || \
defined(PSA_WANT_KEY_TYPE_CAMELLIA))
#error "PSA_WANT_ALG_CMAC defined, but not all prerequisites"
#endif
#if defined(PSA_WANT_ALG_DETERMINISTIC_ECDSA) && \
!(defined(PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_BASIC) || \
defined(PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY))
#error "PSA_WANT_ALG_DETERMINISTIC_ECDSA defined, but not all prerequisites"
#endif
#if defined(PSA_WANT_ALG_ECDSA) && \
!(defined(PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_BASIC) || \
defined(PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY))
#error "PSA_WANT_ALG_ECDSA defined, but not all prerequisites"
#endif
#if defined(PSA_WANT_ALG_GCM) && \
!(defined(PSA_WANT_KEY_TYPE_AES) || \
defined(PSA_WANT_KEY_TYPE_CAMELLIA))
#error "PSA_WANT_ALG_GCM defined, but not all prerequisites"
#endif
#if defined(PSA_WANT_ALG_RSA_PKCS1V15_CRYPT) && \
!(defined(PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_BASIC) || \
defined(PSA_WANT_KEY_TYPE_RSA_PUBLIC_KEY))
#error "PSA_WANT_ALG_RSA_PKCS1V15_CRYPT defined, but not all prerequisites"
#endif
#if defined(PSA_WANT_ALG_RSA_PKCS1V15_SIGN) && \
!(defined(PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_BASIC) || \
defined(PSA_WANT_KEY_TYPE_RSA_PUBLIC_KEY))
#error "PSA_WANT_ALG_RSA_PKCS1V15_SIGN defined, but not all prerequisites"
#endif
#if defined(PSA_WANT_ALG_RSA_OAEP) && \
!(defined(PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_BASIC) || \
defined(PSA_WANT_KEY_TYPE_RSA_PUBLIC_KEY))
#error "PSA_WANT_ALG_RSA_OAEP defined, but not all prerequisites"
#endif
#if defined(PSA_WANT_ALG_RSA_PSS) && \
!(defined(PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_BASIC) || \
defined(PSA_WANT_KEY_TYPE_RSA_PUBLIC_KEY))
#error "PSA_WANT_ALG_RSA_PSS defined, but not all prerequisites"
#endif
#if (defined(PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_BASIC) || \
defined(PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_IMPORT) || \
defined(PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_EXPORT) || \
defined(PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_GENERATE) || \
defined(PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_DERIVE)) && \
!defined(PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY)
#error "PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_xxx defined, but not all prerequisites"
#endif
#if (defined(PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_BASIC) || \
defined(PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_IMPORT) || \
defined(PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_EXPORT) || \
defined(PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_GENERATE)) && \
!defined(PSA_WANT_KEY_TYPE_RSA_PUBLIC_KEY)
#error "PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_xxx defined, but not all prerequisites"
#endif
#if (defined(PSA_WANT_KEY_TYPE_DH_KEY_PAIR_BASIC) || \
defined(PSA_WANT_KEY_TYPE_DH_KEY_PAIR_IMPORT) || \
defined(PSA_WANT_KEY_TYPE_DH_KEY_PAIR_EXPORT) || \
defined(PSA_WANT_KEY_TYPE_DH_KEY_PAIR_GENERATE)) && \
!defined(PSA_WANT_KEY_TYPE_DH_PUBLIC_KEY)
#error "PSA_WANT_KEY_TYPE_DH_KEY_PAIR_xxx defined, but not all prerequisites"
#endif
#if defined(PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_DERIVE)
#error "PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_DERIVE defined, but feature is not supported"
#endif
#if defined(PSA_WANT_KEY_TYPE_DH_KEY_PAIR_DERIVE)
#error "PSA_WANT_KEY_TYPE_DH_KEY_PAIR_DERIVE defined, but feature is not supported"
#endif
#if defined(PSA_WANT_ALG_TLS12_ECJPAKE_TO_PMS) && \
!defined(PSA_WANT_ALG_SHA_256)
#error "PSA_WANT_ALG_TLS12_ECJPAKE_TO_PMS defined, but not all prerequisites"
#endif
#endif /* TF_PSA_CRYPTO_CHECK_CRYPTO_CONFIG_H */
+57
View File
@@ -0,0 +1,57 @@
# Helper code for library/Makefile in Mbed TLS.
# This file is only meant to be included by library/Makefile in Mbed TLS and
# is unlikely to work in another context.
ifeq (,$(BUILDING_LIBTESTDRIVER1))
# List the generated files from crypto that are needed in the build,
# because we don't have the list in a consumable form.
TF_PSA_CRYPTO_LIBRARY_GENERATED_FILES := \
$(TF_PSA_CRYPTO_CORE_PATH)/psa_crypto_driver_wrappers.h \
$(TF_PSA_CRYPTO_CORE_PATH)/psa_crypto_driver_wrappers_no_static.c \
$(TF_PSA_CRYPTO_CORE_PATH)/tf_psa_crypto_config_check_before.h \
$(TF_PSA_CRYPTO_CORE_PATH)/tf_psa_crypto_config_check_final.h \
$(TF_PSA_CRYPTO_CORE_PATH)/tf_psa_crypto_config_check_user.h
GENERATED_WRAPPER_FILES = \
$(TF_PSA_CRYPTO_CORE_PATH)/psa_crypto_driver_wrappers.h \
$(TF_PSA_CRYPTO_CORE_PATH)/psa_crypto_driver_wrappers_no_static.c
$(GENERATED_WRAPPER_FILES): ../tf-psa-crypto/scripts/generate_driver_wrappers.py
$(GENERATED_WRAPPER_FILES): ../tf-psa-crypto/scripts/data_files/driver_templates/psa_crypto_driver_wrappers.h.jinja
$(GENERATED_WRAPPER_FILES): ../tf-psa-crypto/scripts/data_files/driver_templates/psa_crypto_driver_wrappers_no_static.c.jinja
$(GENERATED_WRAPPER_FILES):
echo " Gen $(GENERATED_WRAPPER_FILES)"
$(PYTHON) ../tf-psa-crypto/scripts/generate_driver_wrappers.py $(TF_PSA_CRYPTO_CORE_PATH)
$(TF_PSA_CRYPTO_CORE_PATH)/psa_crypto.o:$(TF_PSA_CRYPTO_CORE_PATH)/psa_crypto_driver_wrappers.h
TF_PSA_CRYPTO_GENERATED_CONFIG_CHECK_FILES = $(shell $(PYTHON) \
$(TF_PSA_CRYPTO_CORE_PATH)/../scripts/generate_config_checks.py \
--list $(TF_PSA_CRYPTO_CORE_PATH))
$(TF_PSA_CRYPTO_GENERATED_CONFIG_CHECK_FILES): $(gen_file_dep) \
$(TF_PSA_CRYPTO_CORE_PATH)/../scripts/generate_config_checks.py \
../framework/scripts/mbedtls_framework/config_checks_generator.py
$(TF_PSA_CRYPTO_GENERATED_CONFIG_CHECK_FILES):
echo " Gen $(TF_PSA_CRYPTO_GENERATED_CONFIG_CHECK_FILES)"
$(PYTHON) $(TF_PSA_CRYPTO_CORE_PATH)/../scripts/generate_config_checks.py
$(TF_PSA_CRYPTO_CORE_PATH)/tf_psa_crypto_config.o: $(TF_PSA_CRYPTO_GENERATED_CONFIG_CHECK_FILES)
else # BUILDING_LIBTESTDRIVER1 empty?
# When building libtestdriver1, assume that the generated files are present
# and up-to-date. This way, we don't need the file generation scripts to
# work in the libtestdriver1 tree, where they might not find all the data
# files that they need.
TF_PSA_CRYPTO_LIBRARY_GENERATED_FILES :=
endif # BUILDING_LIBTESTDRIVER1 empty?
TF_PSA_CRYPTO_LIBRARY_OBJS := $(patsubst %.c, %.o,$(wildcard \
$(TF_PSA_CRYPTO_CORE_PATH)/*.c \
$(TF_PSA_CRYPTO_DRIVERS_BUILTIN_SRC_PATH)/*.c \
$(TF_PSA_CRYPTO_PATH)/dispatch/*.c \
$(TF_PSA_CRYPTO_PATH)/extras/*.c \
$(TF_PSA_CRYPTO_PATH)/platform/*.c \
$(TF_PSA_CRYPTO_PATH)/utilities/*.c))
TF_PSA_CRYPTO_LIBRARY_GENERATED_OBJS = $(TF_PSA_CRYPTO_CORE_PATH)/psa_crypto_driver_wrappers_no_static.o
TF_PSA_CRYPTO_LIBRARY_OBJS := $(filter-out $(TF_PSA_CRYPTO_LIBRARY_GENERATED_OBJS),$(TF_PSA_CRYPTO_LIBRARY_OBJS))
TF_PSA_CRYPTO_LIBRARY_OBJS += $(TF_PSA_CRYPTO_LIBRARY_GENERATED_OBJS)
TF_PSA_CRYPTO_LIBRARY_OBJS+=$(THIRDPARTY_CRYPTO_OBJECTS)
File diff suppressed because it is too large Load Diff
+22
View File
@@ -0,0 +1,22 @@
/*
* PSA crypto client code
*/
/*
* Copyright The Mbed TLS Contributors
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
*/
#include "tf_psa_crypto_common.h"
#include "psa/crypto.h"
#if defined(MBEDTLS_PSA_CRYPTO_CLIENT)
#include <string.h>
#include "mbedtls/platform.h"
void psa_reset_key_attributes(psa_key_attributes_t *attributes)
{
memset(attributes, 0, sizeof(*attributes));
}
#endif /* MBEDTLS_PSA_CRYPTO_CLIENT */
+972
View File
@@ -0,0 +1,972 @@
/*
* PSA crypto core internal interfaces
*/
/*
* Copyright The Mbed TLS Contributors
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
*/
#ifndef TF_PSA_CRYPTO_PSA_CRYPTO_CORE_H
#define TF_PSA_CRYPTO_PSA_CRYPTO_CORE_H
#include "tf-psa-crypto/build_info.h"
#include "psa/crypto.h"
#if defined(MBEDTLS_THREADING_C)
#include "mbedtls/threading.h"
#endif
typedef enum {
PSA_SLOT_EMPTY = 0,
PSA_SLOT_FILLING,
PSA_SLOT_FULL,
PSA_SLOT_PENDING_DELETION,
} psa_key_slot_state_t;
/** The data structure representing a key slot, containing key material
* and metadata for one key.
*/
typedef struct {
/* This field is accessed in a lot of places. Putting it first
* reduces the code size. */
psa_key_attributes_t attr;
/*
* The current state of the key slot, as described in
* docs/architecture/psa-thread-safety/psa-thread-safety.md.
*
* Library functions can modify the state of a key slot by calling
* psa_key_slot_state_transition.
*
* The state variable is used to help determine whether library functions
* which operate on the slot succeed. For example, psa_finish_key_creation,
* which transfers the state of a slot from PSA_SLOT_FILLING to
* PSA_SLOT_FULL, must fail with error code PSA_ERROR_CORRUPTION_DETECTED
* if the state of the slot is not PSA_SLOT_FILLING.
*
* Library functions which traverse the array of key slots only consider
* slots that are in a suitable state for the function.
* For example, psa_get_and_lock_key_slot_in_memory, which finds a slot
* containing a given key ID, will only check slots whose state variable is
* PSA_SLOT_FULL.
*/
psa_key_slot_state_t state;
#if defined(MBEDTLS_PSA_KEY_STORE_DYNAMIC)
/* The index of the slice containing this slot.
* This field must be filled if the slot contains a key
* (including keys being created or destroyed), and can be either
* filled or 0 when the slot is free.
*
* In most cases, the slice index can be deduced from the key identifer.
* We keep it in a separate field for robustness (it reduces the chance
* that a coding mistake in the key store will result in accessing the
* wrong slice), and also so that it's available even on code paths
* during creation or destruction where the key identifier might not be
* filled in.
* */
uint8_t slice_index;
#endif /* MBEDTLS_PSA_KEY_STORE_DYNAMIC */
union {
struct {
/* The index of the next slot in the free list for this
* slice, relative * to the next array element.
*
* That is, 0 means the next slot, 1 means the next slot
* but one, etc. -1 would mean the slot itself. -2 means
* the previous slot, etc.
*
* If this is beyond the array length, the free list ends with the
* current element.
*
* The reason for this strange encoding is that 0 means the next
* element. This way, when we allocate a slice and initialize it
* to all-zero, the slice is ready for use, with a free list that
* consists of all the slots in order.
*/
int32_t next_free_relative_to_next;
} free;
struct {
/*
* Number of functions registered as reading the material in the key slot.
*
* Library functions must not write directly to registered_readers
*
* A function must call psa_register_read(slot) before reading
* the current contents of the slot for an operation.
* They then must call psa_unregister_read(slot) once they have
* finished reading the current contents of the slot. If the key
* slot mutex is not held (when mutexes are enabled), this call
* must be done via a call to
* psa_unregister_read_under_mutex(slot).
* A function must call psa_key_slot_has_readers(slot) to check if
* the slot is in use for reading.
*
* This counter is used to prevent resetting the key slot while
* the library may access it. For example, such control is needed
* in the following scenarios:
* . In case of key slot starvation, all key slots contain the
* description of a key, and the library asks for the
* description of a persistent key not present in the
* key slots, the key slots currently accessed by the
* library cannot be reclaimed to free a key slot to load
* the persistent key.
* . In case of a multi-threaded application where one thread
* asks to close or purge or destroy a key while it is in use
* by the library through another thread. */
size_t registered_readers;
} occupied;
} var;
/* Dynamically allocated key data buffer.
* Format as specified in psa_export_key(). */
struct key_data {
#if defined(MBEDTLS_PSA_STATIC_KEY_SLOTS)
uint8_t data[MBEDTLS_PSA_STATIC_KEY_SLOT_BUFFER_SIZE];
#else
uint8_t *data;
#endif
size_t bytes;
} key;
} psa_key_slot_t;
#if defined(MBEDTLS_THREADING_C)
/** Perform a mutex operation and return immediately upon failure.
*
* Returns PSA_ERROR_SERVICE_FAILURE if the operation fails
* and status was PSA_SUCCESS.
*
* Assumptions:
* psa_status_t status exists.
* f is a mutex operation which returns 0 upon success.
*/
#define PSA_THREADING_CHK_RET(f) \
do \
{ \
if ((f) != 0) { \
if (status == PSA_SUCCESS) { \
return PSA_ERROR_SERVICE_FAILURE; \
} \
return status; \
} \
} while (0);
/** Perform a mutex operation and goto exit on failure.
*
* Sets status to PSA_ERROR_SERVICE_FAILURE if status was PSA_SUCCESS.
*
* Assumptions:
* psa_status_t status exists.
* Label exit: exists.
* f is a mutex operation which returns 0 upon success.
*/
#define PSA_THREADING_CHK_GOTO_EXIT(f) \
do \
{ \
if ((f) != 0) { \
if (status == PSA_SUCCESS) { \
status = PSA_ERROR_SERVICE_FAILURE; \
} \
goto exit; \
} \
} while (0);
#endif
/** Test whether a key slot has any registered readers.
* If multi-threading is enabled, the caller must hold the
* global key slot mutex.
*
* \param[in] slot The key slot to test.
*
* \return 1 if the slot has any registered readers, 0 otherwise.
*/
static inline int psa_key_slot_has_readers(const psa_key_slot_t *slot)
{
return slot->var.occupied.registered_readers > 0;
}
/** Completely wipe a slot in memory, including its policy.
*
* Persistent storage is not affected.
* Sets the slot's state to PSA_SLOT_EMPTY.
* If multi-threading is enabled, the caller must hold the
* global key slot mutex.
*
* \param[in,out] slot The key slot to wipe.
*
* \retval #PSA_SUCCESS
* The slot has been successfully wiped.
* \retval #PSA_ERROR_CORRUPTION_DETECTED
* The slot's state was PSA_SLOT_FULL or PSA_SLOT_PENDING_DELETION, and
* the amount of registered readers was not equal to 1. Or,
* the slot's state was PSA_SLOT_EMPTY. Or,
* the slot's state was PSA_SLOT_FILLING, and the amount
* of registered readers was not equal to 0.
*/
psa_status_t psa_wipe_key_slot(psa_key_slot_t *slot);
/** Try to allocate a buffer to an empty key slot.
*
* \param[in,out] slot Key slot to attach buffer to.
* \param[in] buffer_length Requested size of the buffer.
*
* \retval #PSA_SUCCESS
* The buffer has been successfully allocated.
* \retval #PSA_ERROR_INSUFFICIENT_MEMORY
* Not enough memory was available for allocation.
* \retval #PSA_ERROR_ALREADY_EXISTS
* Trying to allocate a buffer to a non-empty key slot.
*/
psa_status_t psa_allocate_buffer_to_slot(psa_key_slot_t *slot,
size_t buffer_length);
/** Wipe key data from a slot. Preserves metadata such as the policy. */
psa_status_t psa_remove_key_data_from_memory(psa_key_slot_t *slot);
/** Copy key data (in export format) into an empty key slot.
*
* This function assumes that the slot does not contain
* any key material yet. On failure, the slot content is unchanged.
*
* \param[in,out] slot Key slot to copy the key into.
* \param[in] data Buffer containing the key material.
* \param data_length Size of the key buffer.
*
* \retval #PSA_SUCCESS
* The key has been copied successfully.
* \retval #PSA_ERROR_INSUFFICIENT_MEMORY
* Not enough memory was available for allocation of the
* copy buffer.
* \retval #PSA_ERROR_ALREADY_EXISTS
* There was other key material already present in the slot.
*/
psa_status_t psa_copy_key_material_into_slot(psa_key_slot_t *slot,
const uint8_t *data,
size_t data_length);
/** Convert an Mbed TLS error code to a PSA error code
*
* \note This function is provided solely for the convenience of
* Mbed TLS and may be removed at any time without notice.
*
* \param ret An Mbed TLS-thrown error code
*
* \return The corresponding PSA error code
*/
psa_status_t mbedtls_to_psa_error(int ret);
/** Whether PSA is ready for a cipher operation.
*
* This is a legacy concept inherited from "driver-only" work in Mbed TLS 3.x.
* The block_cipher module uses this to determine whether to call a legacy
* module directly. This is necessary in some builds involving drivers, where
* the PSA RNG is powered by CTR_DRBG, but AES is not accelerated. This is
* an implementation kludge that should be fixed.
* https://github.com/Mbed-TLS/TF-PSA-Crypto/issues/469
*/
int psa_is_ready_for_cipher(void);
/** Import a key in binary format.
*
* \note The signature of this function is that of a PSA driver
* import_key entry point. This function behaves as an import_key
* entry point as defined in the PSA driver interface specification for
* transparent drivers.
*
* \param[in] attributes The attributes for the key to import.
* \param[in] data The buffer containing the key data in import
* format.
* \param[in] data_length Size of the \p data buffer in bytes.
* \param[out] key_buffer The buffer to contain the key data in output
* format upon successful return.
* \param[in] key_buffer_size Size of the \p key_buffer buffer in bytes. This
* size is greater or equal to \p data_length.
* \param[out] key_buffer_length The length of the data written in \p
* key_buffer in bytes.
* \param[out] bits The key size in number of bits.
*
* \retval #PSA_SUCCESS The key was imported successfully.
* \retval #PSA_ERROR_INVALID_ARGUMENT
* The key data is not correctly formatted.
* \retval #PSA_ERROR_NOT_SUPPORTED \emptydescription
* \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription
* \retval #PSA_ERROR_CORRUPTION_DETECTED \emptydescription
*/
psa_status_t psa_import_key_into_slot(
const psa_key_attributes_t *attributes,
const uint8_t *data, size_t data_length,
uint8_t *key_buffer, size_t key_buffer_size,
size_t *key_buffer_length, size_t *bits);
/** Export a key in binary format
*
* \note The signature of this function is that of a PSA driver export_key
* entry point. This function behaves as an export_key entry point as
* defined in the PSA driver interface specification.
*
* \param[in] attributes The attributes for the key to export.
* \param[in] key_buffer Material or context of the key to export.
* \param[in] key_buffer_size Size of the \p key_buffer buffer in bytes.
* \param[out] data Buffer where the key data is to be written.
* \param[in] data_size Size of the \p data buffer in bytes.
* \param[out] data_length On success, the number of bytes written in
* \p data
*
* \retval #PSA_SUCCESS The key was exported successfully.
* \retval #PSA_ERROR_NOT_SUPPORTED \emptydescription
* \retval #PSA_ERROR_COMMUNICATION_FAILURE \emptydescription
* \retval #PSA_ERROR_HARDWARE_FAILURE \emptydescription
* \retval #PSA_ERROR_CORRUPTION_DETECTED \emptydescription
* \retval #PSA_ERROR_STORAGE_FAILURE \emptydescription
* \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription
*/
psa_status_t psa_export_key_internal(
const psa_key_attributes_t *attributes,
const uint8_t *key_buffer, size_t key_buffer_size,
uint8_t *data, size_t data_size, size_t *data_length);
/** Export a public key or the public part of a key pair in binary format.
*
* \note The signature of this function is that of a PSA driver
* export_public_key entry point. This function behaves as an
* export_public_key entry point as defined in the PSA driver interface
* specification.
*
* \param[in] attributes The attributes for the key to export.
* \param[in] key_buffer Material or context of the key to export.
* \param[in] key_buffer_size Size of the \p key_buffer buffer in bytes.
* \param[out] data Buffer where the key data is to be written.
* \param[in] data_size Size of the \p data buffer in bytes.
* \param[out] data_length On success, the number of bytes written in
* \p data
*
* \retval #PSA_SUCCESS The public key was exported successfully.
* \retval #PSA_ERROR_NOT_SUPPORTED \emptydescription
* \retval #PSA_ERROR_COMMUNICATION_FAILURE \emptydescription
* \retval #PSA_ERROR_HARDWARE_FAILURE \emptydescription
* \retval #PSA_ERROR_CORRUPTION_DETECTED \emptydescription
* \retval #PSA_ERROR_STORAGE_FAILURE \emptydescription
* \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription
*/
psa_status_t psa_export_public_key_internal(
const psa_key_attributes_t *attributes,
const uint8_t *key_buffer, size_t key_buffer_size,
uint8_t *data, size_t data_size, size_t *data_length);
/** Whether a key custom production parameters structure is the default.
*
* Calls to a key generation driver with non-default custom production parameters
* require a driver supporting custom production parameters.
*
* \param[in] custom The key custom production parameters to check.
* \param custom_data_length Size of the associated variable-length data
* in bytes.
*/
int psa_custom_key_parameters_are_default(
const psa_custom_key_parameters_t *custom,
size_t custom_data_length);
/**
* \brief Generate a key.
*
* \note The signature of the function is that of a PSA driver generate_key
* entry point.
*
* \param[in] attributes The attributes for the key to generate.
* \param[in] custom Custom parameters for the key generation.
* \param[in] custom_data Variable-length data associated with \c custom.
* \param custom_data_length Length of `custom_data` in bytes.
* \param[out] key_buffer Buffer where the key data is to be written.
* \param[in] key_buffer_size Size of \p key_buffer in bytes.
* \param[out] key_buffer_length On success, the number of bytes written in
* \p key_buffer.
*
* \retval #PSA_SUCCESS
* The key was generated successfully.
* \retval #PSA_ERROR_INVALID_ARGUMENT \emptydescription
* \retval #PSA_ERROR_NOT_SUPPORTED
* Key size in bits or type not supported.
* \retval #PSA_ERROR_BUFFER_TOO_SMALL
* The size of \p key_buffer is too small.
*/
psa_status_t psa_generate_key_internal(const psa_key_attributes_t *attributes,
const psa_custom_key_parameters_t *custom,
const uint8_t *custom_data,
size_t custom_data_length,
uint8_t *key_buffer,
size_t key_buffer_size,
size_t *key_buffer_length);
/** Sign a message with a private key. For hash-and-sign algorithms,
* this includes the hashing step.
*
* \note The signature of this function is that of a PSA driver
* sign_message entry point. This function behaves as a sign_message
* entry point as defined in the PSA driver interface specification for
* transparent drivers.
*
* \note This function will call the driver for psa_sign_hash
* and go through driver dispatch again.
*
* \param[in] attributes The attributes of the key to use for the
* operation.
* \param[in] key_buffer The buffer containing the key context.
* \param[in] key_buffer_size Size of the \p key_buffer buffer in bytes.
* \param[in] alg A signature algorithm that is compatible with
* the type of the key.
* \param[in] input The input message to sign.
* \param[in] input_length Size of the \p input buffer in bytes.
* \param[out] signature Buffer where the signature is to be written.
* \param[in] signature_size Size of the \p signature buffer in bytes.
* \param[out] signature_length On success, the number of bytes
* that make up the returned signature value.
*
* \retval #PSA_SUCCESS \emptydescription
* \retval #PSA_ERROR_BUFFER_TOO_SMALL
* The size of the \p signature buffer is too small. You can
* determine a sufficient buffer size by calling
* #PSA_SIGN_OUTPUT_SIZE(\c key_type, \c key_bits, \p alg)
* where \c key_type and \c key_bits are the type and bit-size
* respectively of the key.
* \retval #PSA_ERROR_NOT_SUPPORTED \emptydescription
* \retval #PSA_ERROR_INVALID_ARGUMENT \emptydescription
* \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription
* \retval #PSA_ERROR_CORRUPTION_DETECTED \emptydescription
* \retval #PSA_ERROR_INSUFFICIENT_ENTROPY \emptydescription
*/
psa_status_t psa_sign_message_builtin(
const psa_key_attributes_t *attributes,
const uint8_t *key_buffer, size_t key_buffer_size,
psa_algorithm_t alg, const uint8_t *input, size_t input_length,
uint8_t *signature, size_t signature_size, size_t *signature_length);
/** Verify the signature of a message with a public key, using
* a hash-and-sign verification algorithm.
*
* \note The signature of this function is that of a PSA driver
* verify_message entry point. This function behaves as a verify_message
* entry point as defined in the PSA driver interface specification for
* transparent drivers.
*
* \note This function will call the driver for psa_verify_hash
* and go through driver dispatch again.
*
* \param[in] attributes The attributes of the key to use for the
* operation.
* \param[in] key_buffer The buffer containing the key context.
* \param[in] key_buffer_size Size of the \p key_buffer buffer in bytes.
* \param[in] alg A signature algorithm that is compatible with
* the type of the key.
* \param[in] input The message whose signature is to be verified.
* \param[in] input_length Size of the \p input buffer in bytes.
* \param[in] signature Buffer containing the signature to verify.
* \param[in] signature_length Size of the \p signature buffer in bytes.
*
* \retval #PSA_SUCCESS
* The signature is valid.
* \retval #PSA_ERROR_INVALID_SIGNATURE
* The calculation was performed successfully, but the passed
* signature is not a valid signature.
* \retval #PSA_ERROR_NOT_SUPPORTED \emptydescription
* \retval #PSA_ERROR_INVALID_ARGUMENT \emptydescription
* \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription
*/
psa_status_t psa_verify_message_builtin(
const psa_key_attributes_t *attributes,
const uint8_t *key_buffer, size_t key_buffer_size,
psa_algorithm_t alg, const uint8_t *input, size_t input_length,
const uint8_t *signature, size_t signature_length);
/** Sign an already-calculated hash with a private key.
*
* \note The signature of this function is that of a PSA driver
* sign_hash entry point. This function behaves as a sign_hash
* entry point as defined in the PSA driver interface specification for
* transparent drivers.
*
* \param[in] attributes The attributes of the key to use for the
* operation.
* \param[in] key_buffer The buffer containing the key context.
* \param[in] key_buffer_size Size of the \p key_buffer buffer in bytes.
* \param[in] alg A signature algorithm that is compatible with
* the type of the key.
* \param[in] hash The hash or message to sign.
* \param[in] hash_length Size of the \p hash buffer in bytes.
* \param[out] signature Buffer where the signature is to be written.
* \param[in] signature_size Size of the \p signature buffer in bytes.
* \param[out] signature_length On success, the number of bytes
* that make up the returned signature value.
*
* \retval #PSA_SUCCESS \emptydescription
* \retval #PSA_ERROR_BUFFER_TOO_SMALL
* The size of the \p signature buffer is too small. You can
* determine a sufficient buffer size by calling
* #PSA_SIGN_OUTPUT_SIZE(\c key_type, \c key_bits, \p alg)
* where \c key_type and \c key_bits are the type and bit-size
* respectively of the key.
* \retval #PSA_ERROR_NOT_SUPPORTED \emptydescription
* \retval #PSA_ERROR_INVALID_ARGUMENT \emptydescription
* \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription
* \retval #PSA_ERROR_CORRUPTION_DETECTED \emptydescription
* \retval #PSA_ERROR_INSUFFICIENT_ENTROPY \emptydescription
*/
psa_status_t psa_sign_hash_builtin(
const psa_key_attributes_t *attributes,
const uint8_t *key_buffer, size_t key_buffer_size,
psa_algorithm_t alg, const uint8_t *hash, size_t hash_length,
uint8_t *signature, size_t signature_size, size_t *signature_length);
/**
* \brief Verify the signature a hash or short message using a public key.
*
* \note The signature of this function is that of a PSA driver
* verify_hash entry point. This function behaves as a verify_hash
* entry point as defined in the PSA driver interface specification for
* transparent drivers.
*
* \param[in] attributes The attributes of the key to use for the
* operation.
* \param[in] key_buffer The buffer containing the key context.
* \param[in] key_buffer_size Size of the \p key_buffer buffer in bytes.
* \param[in] alg A signature algorithm that is compatible with
* the type of the key.
* \param[in] hash The hash or message whose signature is to be
* verified.
* \param[in] hash_length Size of the \p hash buffer in bytes.
* \param[in] signature Buffer containing the signature to verify.
* \param[in] signature_length Size of the \p signature buffer in bytes.
*
* \retval #PSA_SUCCESS
* The signature is valid.
* \retval #PSA_ERROR_INVALID_SIGNATURE
* The calculation was performed successfully, but the passed
* signature is not a valid signature.
* \retval #PSA_ERROR_NOT_SUPPORTED \emptydescription
* \retval #PSA_ERROR_INVALID_ARGUMENT \emptydescription
* \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription
*/
psa_status_t psa_verify_hash_builtin(
const psa_key_attributes_t *attributes,
const uint8_t *key_buffer, size_t key_buffer_size,
psa_algorithm_t alg, const uint8_t *hash, size_t hash_length,
const uint8_t *signature, size_t signature_length);
/**
* \brief Validate the key bit size for unstructured keys.
*
* \note Check that the bit size is acceptable for a given key type for
* unstructured keys.
*
* \param[in] type The key type
* \param[in] bits The number of bits of the key
*
* \retval #PSA_SUCCESS
* The key type and size are valid.
* \retval #PSA_ERROR_INVALID_ARGUMENT
* The size in bits of the key is not valid.
* \retval #PSA_ERROR_NOT_SUPPORTED
* The type and/or the size in bits of the key or the combination of
* the two is not supported.
*/
psa_status_t psa_validate_unstructured_key_bit_size(psa_key_type_t type,
size_t bits);
/** Perform a key agreement and return the raw shared secret, using
built-in raw key agreement functions.
*
* \note The signature of this function is that of a PSA driver
* key_agreement entry point. This function behaves as a key_agreement
* entry point as defined in the PSA driver interface specification for
* transparent drivers.
*
* \param[in] attributes The attributes of the key to use for the
* operation.
* \param[in] key_buffer The buffer containing the private key
* context.
* \param[in] key_buffer_size Size of the \p key_buffer buffer in
* bytes.
* \param[in] alg A key agreement algorithm that is
* compatible with the type of the key.
* \param[in] peer_key The buffer containing the key context
* of the peer's public key.
* \param[in] peer_key_length Size of the \p peer_key buffer in
* bytes.
* \param[out] shared_secret The buffer to which the shared secret
* is to be written.
* \param[in] shared_secret_size Size of the \p shared_secret buffer in
* bytes.
* \param[out] shared_secret_length On success, the number of bytes that make
* up the returned shared secret.
* \retval #PSA_SUCCESS
* Success. Shared secret successfully calculated.
* \retval #PSA_ERROR_INVALID_HANDLE \emptydescription
* \retval #PSA_ERROR_NOT_PERMITTED \emptydescription
* \retval #PSA_ERROR_INVALID_ARGUMENT
* \p alg is not a key agreement algorithm, or
* \p private_key is not compatible with \p alg,
* or \p peer_key is not valid for \p alg or not compatible with
* \p private_key.
* \retval #PSA_ERROR_BUFFER_TOO_SMALL
* \p shared_secret_size is too small
* \retval #PSA_ERROR_NOT_SUPPORTED
* \p alg is not a supported key agreement algorithm.
* \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription
* \retval #PSA_ERROR_COMMUNICATION_FAILURE \emptydescription
* \retval #PSA_ERROR_HARDWARE_FAILURE \emptydescription
* \retval #PSA_ERROR_CORRUPTION_DETECTED \emptydescription
* \retval #PSA_ERROR_STORAGE_FAILURE \emptydescription
* \retval #PSA_ERROR_BAD_STATE \emptydescription
*/
psa_status_t psa_key_agreement_raw_builtin(
const psa_key_attributes_t *attributes,
const uint8_t *key_buffer,
size_t key_buffer_size,
psa_algorithm_t alg,
const uint8_t *peer_key,
size_t peer_key_length,
uint8_t *shared_secret,
size_t shared_secret_size,
size_t *shared_secret_length);
/**
* \brief Set the maximum number of ops allowed to be executed by an
* interruptible function in a single call.
*
* \note The signature of this function is that of a PSA driver
* interruptible_set_max_ops entry point. This function behaves as an
* interruptible_set_max_ops entry point as defined in the PSA driver
* interface specification for transparent drivers.
*
* \param[in] max_ops The maximum number of ops to be executed in a
* single call, this can be a number from 0 to
* #PSA_INTERRUPTIBLE_MAX_OPS_UNLIMITED, where 0
* is obviously the least amount of work done per
* call.
*/
void mbedtls_psa_interruptible_set_max_ops(uint32_t max_ops);
/**
* \brief Get the maximum number of ops allowed to be executed by an
* interruptible function in a single call.
*
* \note The signature of this function is that of a PSA driver
* interruptible_get_max_ops entry point. This function behaves as an
* interruptible_get_max_ops entry point as defined in the PSA driver
* interface specification for transparent drivers.
*
* \return Maximum number of ops allowed to be executed
* by an interruptible function in a single call.
*/
uint32_t mbedtls_psa_interruptible_get_max_ops(void);
/**
* \brief Get the number of ops that a hash signing operation has taken for the
* previous call. If no call or work has taken place, this will return
* zero.
*
* \note The signature of this function is that of a PSA driver
* sign_hash_get_num_ops entry point. This function behaves as an
* sign_hash_get_num_ops entry point as defined in the PSA driver
* interface specification for transparent drivers.
*
* \param operation The \c
* mbedtls_psa_sign_hash_interruptible_operation_t
* to use. This must be initialized first.
*
* \return Number of ops that were completed
* in the last call to \c
* mbedtls_psa_sign_hash_complete().
*/
uint32_t mbedtls_psa_sign_hash_get_num_ops(
const mbedtls_psa_sign_hash_interruptible_operation_t *operation);
/**
* \brief Get the number of ops that a hash verification operation has taken for
* the previous call. If no call or work has taken place, this will
* return zero.
*
* \note The signature of this function is that of a PSA driver
* verify_hash_get_num_ops entry point. This function behaves as an
* verify_hash_get_num_ops entry point as defined in the PSA driver
* interface specification for transparent drivers.
*
* \param operation The \c
* mbedtls_psa_verify_hash_interruptible_operation_t
* to use. This must be initialized first.
*
* \return Number of ops that were completed
* in the last call to \c
* mbedtls_psa_verify_hash_complete().
*/
uint32_t mbedtls_psa_verify_hash_get_num_ops(
const mbedtls_psa_verify_hash_interruptible_operation_t *operation);
/**
* \brief Start signing a hash or short message with a private key, in an
* interruptible manner.
*
* \note The signature of this function is that of a PSA driver
* sign_hash_start entry point. This function behaves as a
* sign_hash_start entry point as defined in the PSA driver interface
* specification for transparent drivers.
*
* \param[in] operation The \c
* mbedtls_psa_sign_hash_interruptible_operation_t
* to use. This must be initialized first.
* \param[in] attributes The attributes of the key to use for the
* operation.
* \param[in] key_buffer The buffer containing the key context.
* \param[in] key_buffer_size Size of the \p key_buffer buffer in bytes.
* \param[in] alg A signature algorithm that is compatible with
* the type of the key.
* \param[in] hash The hash or message to sign.
* \param hash_length Size of the \p hash buffer in bytes.
*
* \retval #PSA_SUCCESS
* The operation started successfully - call \c psa_sign_hash_complete()
* with the same context to complete the operation
* \retval #PSA_ERROR_INVALID_ARGUMENT
* An unsupported, incorrectly formatted or incorrect type of key was
* used.
* \retval #PSA_ERROR_NOT_SUPPORTED Either no internal interruptible operations
* are currently supported, or the key type is currently unsupported.
* \retval #PSA_ERROR_INSUFFICIENT_MEMORY
* There was insufficient memory to load the key representation.
*/
psa_status_t mbedtls_psa_sign_hash_start(
mbedtls_psa_sign_hash_interruptible_operation_t *operation,
const psa_key_attributes_t *attributes, const uint8_t *key_buffer,
size_t key_buffer_size, psa_algorithm_t alg,
const uint8_t *hash, size_t hash_length);
/**
* \brief Continue and eventually complete the action of signing a hash or
* short message with a private key, in an interruptible manner.
*
* \note The signature of this function is that of a PSA driver
* sign_hash_complete entry point. This function behaves as a
* sign_hash_complete entry point as defined in the PSA driver interface
* specification for transparent drivers.
*
* \param[in] operation The \c
* mbedtls_psa_sign_hash_interruptible_operation_t
* to use. This must be initialized first.
*
* \param[out] signature Buffer where the signature is to be written.
* \param signature_size Size of the \p signature buffer in bytes. This
* must be appropriate for the selected
* algorithm and key.
* \param[out] signature_length On success, the number of bytes that make up
* the returned signature value.
*
* \retval #PSA_SUCCESS
* Operation completed successfully
*
* \retval #PSA_OPERATION_INCOMPLETE
* Operation was interrupted due to the setting of \c
* psa_interruptible_set_max_ops(), there is still work to be done,
* please call this function again with the same operation object.
*
* \retval #PSA_ERROR_BUFFER_TOO_SMALL
* The size of the \p signature buffer is too small. You can
* determine a sufficient buffer size by calling
* #PSA_SIGN_OUTPUT_SIZE(\c key_type, \c key_bits, \p alg)
* where \c key_type and \c key_bits are the type and bit-size
* respectively of \p key.
*
* \retval #PSA_ERROR_NOT_SUPPORTED \emptydescription
* \retval #PSA_ERROR_INVALID_ARGUMENT \emptydescription
* \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription
* \retval #PSA_ERROR_CORRUPTION_DETECTED \emptydescription
* \retval #PSA_ERROR_INSUFFICIENT_ENTROPY \emptydescription
*/
psa_status_t mbedtls_psa_sign_hash_complete(
mbedtls_psa_sign_hash_interruptible_operation_t *operation,
uint8_t *signature, size_t signature_size,
size_t *signature_length);
/**
* \brief Abort a sign hash operation.
*
* \note The signature of this function is that of a PSA driver sign_hash_abort
* entry point. This function behaves as a sign_hash_abort entry point as
* defined in the PSA driver interface specification for transparent
* drivers.
*
* \param[in] operation The \c
* mbedtls_psa_sign_hash_interruptible_operation_t
* to abort.
*
* \retval #PSA_SUCCESS
* The operation was aborted successfully.
*/
psa_status_t mbedtls_psa_sign_hash_abort(
mbedtls_psa_sign_hash_interruptible_operation_t *operation);
/**
* \brief Start reading and verifying a hash or short message, in an
* interruptible manner.
*
* \note The signature of this function is that of a PSA driver
* verify_hash_start entry point. This function behaves as a
* verify_hash_start entry point as defined in the PSA driver interface
* specification for transparent drivers.
*
* \param[in] operation The \c
* mbedtls_psa_verify_hash_interruptible_operation_t
* to use. This must be initialized first.
* \param[in] attributes The attributes of the key to use for the
* operation.
* \param[in] key_buffer The buffer containing the key context.
* \param[in] key_buffer_size Size of the \p key_buffer buffer in bytes.
* \param[in] alg A signature algorithm that is compatible with
* the type of the key.
* \param[in] hash The hash whose signature is to be verified.
* \param hash_length Size of the \p hash buffer in bytes.
* \param[in] signature Buffer containing the signature to verify.
* \param signature_length Size of the \p signature buffer in bytes.
*
* \retval #PSA_SUCCESS
* The operation started successfully - call \c psa_sign_hash_complete()
* with the same context to complete the operation
* \retval #PSA_ERROR_INVALID_ARGUMENT
* An unsupported or incorrect type of key was used.
* \retval #PSA_ERROR_NOT_SUPPORTED
* Either no internal interruptible operations are currently supported,
* or the key type is currently unsupported.
* \retval #PSA_ERROR_INSUFFICIENT_MEMORY
* There was insufficient memory either to load the key representation,
* or to prepare the operation.
*/
psa_status_t mbedtls_psa_verify_hash_start(
mbedtls_psa_verify_hash_interruptible_operation_t *operation,
const psa_key_attributes_t *attributes,
const uint8_t *key_buffer, size_t key_buffer_size,
psa_algorithm_t alg,
const uint8_t *hash, size_t hash_length,
const uint8_t *signature, size_t signature_length);
/**
* \brief Continue and eventually complete the action of signing a hash or
* short message with a private key, in an interruptible manner.
*
* \note The signature of this function is that of a PSA driver
* sign_hash_complete entry point. This function behaves as a
* sign_hash_complete entry point as defined in the PSA driver interface
* specification for transparent drivers.
*
* \param[in] operation The \c
* mbedtls_psa_sign_hash_interruptible_operation_t
* to use. This must be initialized first.
*
* \retval #PSA_SUCCESS
* Operation completed successfully, and the passed signature is valid.
*
* \retval #PSA_OPERATION_INCOMPLETE
* Operation was interrupted due to the setting of \c
* psa_interruptible_set_max_ops(), there is still work to be done,
* please call this function again with the same operation object.
*
* \retval #PSA_ERROR_INVALID_SIGNATURE
* The calculation was performed successfully, but the passed
* signature is not a valid signature.
*
* \retval #PSA_ERROR_NOT_SUPPORTED \emptydescription
* \retval #PSA_ERROR_INVALID_ARGUMENT \emptydescription
* \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription
*/
psa_status_t mbedtls_psa_verify_hash_complete(
mbedtls_psa_verify_hash_interruptible_operation_t *operation);
/**
* \brief Abort a verify signed hash operation.
*
* \note The signature of this function is that of a PSA driver
* verify_hash_abort entry point. This function behaves as a
* verify_hash_abort entry point as defined in the PSA driver interface
* specification for transparent drivers.
*
* \param[in] operation The \c
* mbedtls_psa_verify_hash_interruptible_operation_t
* to abort.
*
* \retval #PSA_SUCCESS
* The operation was aborted successfully.
*/
psa_status_t mbedtls_psa_verify_hash_abort(
mbedtls_psa_verify_hash_interruptible_operation_t *operation);
typedef struct psa_crypto_local_input_s {
uint8_t *buffer;
size_t length;
} psa_crypto_local_input_t;
#define PSA_CRYPTO_LOCAL_INPUT_INIT ((psa_crypto_local_input_t) { NULL, 0 })
/** Allocate a local copy of an input buffer and copy the contents into it.
*
* \param[in] input Pointer to input buffer.
* \param[in] input_len Length of the input buffer.
* \param[out] local_input Pointer to a psa_crypto_local_input_t struct
* containing a local input copy.
* \return #PSA_SUCCESS, if the buffer was successfully
* copied.
* \return #PSA_ERROR_INSUFFICIENT_MEMORY, if a copy of
* the buffer cannot be allocated.
*/
psa_status_t psa_crypto_local_input_alloc(const uint8_t *input, size_t input_len,
psa_crypto_local_input_t *local_input);
/** Free a local copy of an input buffer.
*
* \param[in] local_input Pointer to a psa_crypto_local_input_t struct
* populated by a previous call to
* psa_crypto_local_input_alloc().
*/
void psa_crypto_local_input_free(psa_crypto_local_input_t *local_input);
typedef struct psa_crypto_local_output_s {
uint8_t *original;
uint8_t *buffer;
size_t length;
} psa_crypto_local_output_t;
#define PSA_CRYPTO_LOCAL_OUTPUT_INIT ((psa_crypto_local_output_t) { NULL, NULL, 0 })
/** Allocate a local copy of an output buffer.
*
* \note This does not copy any data from the original
* output buffer but only allocates a buffer
* whose contents will be copied back to the
* original in a future call to
* psa_crypto_local_output_free().
*
* \param[in] output Pointer to output buffer.
* \param[in] output_len Length of the output buffer.
* \param[out] local_output Pointer to a psa_crypto_local_output_t struct to
* populate with the local output copy.
* \return #PSA_SUCCESS, if the buffer was successfully
* copied.
* \return #PSA_ERROR_INSUFFICIENT_MEMORY, if a copy of
* the buffer cannot be allocated.
*/
psa_status_t psa_crypto_local_output_alloc(uint8_t *output, size_t output_len,
psa_crypto_local_output_t *local_output);
/** Copy from a local copy of an output buffer back to the original, then
* free the local copy.
*
* \param[in] local_output Pointer to a psa_crypto_local_output_t struct
* populated by a previous call to
* psa_crypto_local_output_alloc().
* \return #PSA_SUCCESS, if the local output was
* successfully copied back to the original.
* \return #PSA_ERROR_CORRUPTION_DETECTED, if the output
* could not be copied back to the original.
*/
psa_status_t psa_crypto_local_output_free(psa_crypto_local_output_t *local_output);
#endif /* TF_PSA_CRYPTO_PSA_CRYPTO_CORE_H */
@@ -0,0 +1,52 @@
/**
* \file psa_crypto_core_common.h
*
* \brief Utility macros for internal use in the PSA cryptography core.
*/
/*
* Copyright The Mbed TLS Contributors
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
*/
#ifndef TF_PSA_CRYPTO_PSA_CRYPTO_CORE_COMMON_H
#define TF_PSA_CRYPTO_PSA_CRYPTO_CORE_COMMON_H
/** Return an offset into a buffer.
*
* This is just the addition of an offset to a pointer, except that this
* function also accepts an offset of 0 into a buffer whose pointer is null.
* (`p + n` has undefined behavior when `p` is null, even when `n == 0`.
* A null pointer is a valid buffer pointer when the size is 0, for example
* as the result of `malloc(0)` on some platforms.)
*
* \param p Pointer to a buffer of at least n bytes.
* This may be \p NULL if \p n is zero.
* \param n An offset in bytes.
* \return Pointer to offset \p n in the buffer \p p.
* Note that this is only a valid pointer if the size of the
* buffer is at least \p n + 1.
*/
static inline unsigned char *psa_crypto_buffer_offset(
unsigned char *p, size_t n)
{
return p == NULL ? NULL : p + n;
}
/** Return an offset into a read-only buffer.
*
* Similar to mbedtls_buffer_offset(), but for const pointers.
*
* \param p Pointer to a buffer of at least n bytes.
* This may be \p NULL if \p n is zero.
* \param n An offset in bytes.
* \return Pointer to offset \p n in the buffer \p p.
* Note that this is only a valid pointer if the size of the
* buffer is at least \p n + 1.
*/
static inline const unsigned char *psa_crypto_buffer_offset_const(
const unsigned char *p, size_t n)
{
return p == NULL ? NULL : p + n;
}
#endif /* TF_PSA_CRYPTO_PSA_CRYPTO_CORE_COMMON_H */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,249 @@
/*
* Functions to delegate cryptographic operations to an available
* and appropriate accelerator.
* Warning: This file is now auto-generated.
*/
/* Copyright The Mbed TLS Contributors
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
*/
/* BEGIN-common headers */
#include "tf_psa_crypto_common.h"
#include "psa_crypto_aead.h"
#include "psa_crypto_cipher.h"
#include "psa_crypto_core.h"
#include "psa_crypto_driver_wrappers_no_static.h"
#include "psa_crypto_hash.h"
#include "psa_crypto_mac.h"
#include "psa_crypto_pake.h"
#include "psa_crypto_rsa.h"
#if defined(TF_PSA_CRYPTO_PQCP_MLDSA_ENABLED)
#include "psa_crypto_mldsa.h"
#endif
#include "mbedtls/platform.h"
/* END-common headers */
#if defined(MBEDTLS_PSA_CRYPTO_C)
/* BEGIN-driver headers */
/* Headers for mbedtls_test opaque driver */
#if defined(PSA_CRYPTO_DRIVER_TEST)
#include "test/drivers/test_driver.h"
#endif
/* Headers for mbedtls_test transparent driver */
#if defined(PSA_CRYPTO_DRIVER_TEST)
#include "test/drivers/test_driver.h"
#endif
/* Headers for p256 transparent driver */
#if defined(MBEDTLS_PSA_P256M_DRIVER_ENABLED)
#include "../drivers/p256-m/p256-m_driver_entrypoints.h"
#endif
/* Headers for esp_ecdsa opaque driver */
#if defined(ESP_ECDSA_DRIVER_ENABLED)
#include "../../../port/psa_driver/include/psa_crypto_driver_esp_ecdsa.h"
#endif
/* END-driver headers */
/* Auto-generated values depending on which drivers are registered.
* ID 0 is reserved for unallocated operations.
* ID 1 is reserved for the Mbed TLS software driver. */
/* BEGIN-driver id definition */
#define PSA_CRYPTO_MBED_TLS_DRIVER_ID (1)
#define MBEDTLS_TEST_OPAQUE_DRIVER_ID (2)
#define MBEDTLS_TEST_TRANSPARENT_DRIVER_ID (3)
#define P256_TRANSPARENT_DRIVER_ID (4)
/* END-driver id */
/* BEGIN-Common Macro definitions */
/* END-Common Macro definitions */
/** Get the key buffer size required to store the key material of a key
* associated with an opaque driver.
*
* \param[in] attributes The key attributes.
* \param[out] key_buffer_size Minimum buffer size to contain the key material
*
* \retval #PSA_SUCCESS
* The minimum size for a buffer to contain the key material has been
* returned successfully.
* \retval #PSA_ERROR_NOT_SUPPORTED
* The type and/or the size in bits of the key or the combination of
* the two is not supported.
* \retval #PSA_ERROR_INVALID_ARGUMENT
* The key is declared with a lifetime not known to us.
*/
psa_status_t psa_driver_wrapper_get_key_buffer_size(
const psa_key_attributes_t *attributes,
size_t *key_buffer_size )
{
psa_key_location_t location = PSA_KEY_LIFETIME_GET_LOCATION( psa_get_key_lifetime(attributes) );
psa_key_type_t key_type = psa_get_key_type(attributes);
size_t key_bits = psa_get_key_bits(attributes);
*key_buffer_size = 0;
switch( location )
{
#if defined(PSA_CRYPTO_DRIVER_TEST)
case PSA_CRYPTO_TEST_DRIVER_LOCATION:
#if defined(MBEDTLS_PSA_CRYPTO_BUILTIN_KEYS)
/* Emulate property 'builtin_key_size' */
if( psa_key_id_is_builtin(
MBEDTLS_SVC_KEY_ID_GET_KEY_ID(
psa_get_key_id( attributes ) ) ) )
{
*key_buffer_size = sizeof( psa_drv_slot_number_t );
return( PSA_SUCCESS );
}
#endif /* MBEDTLS_PSA_CRYPTO_BUILTIN_KEYS */
*key_buffer_size = mbedtls_test_opaque_size_function( key_type,
key_bits );
return( ( *key_buffer_size != 0 ) ?
PSA_SUCCESS : PSA_ERROR_NOT_SUPPORTED );
#endif /* PSA_CRYPTO_DRIVER_TEST */
default:
(void)key_type;
(void)key_bits;
return( PSA_ERROR_INVALID_ARGUMENT );
}
}
psa_status_t psa_driver_wrapper_export_public_key(
const psa_key_attributes_t *attributes,
const uint8_t *key_buffer, size_t key_buffer_size,
uint8_t *data, size_t data_size, size_t *data_length )
{
psa_status_t status = PSA_ERROR_INVALID_ARGUMENT;
psa_key_location_t location = PSA_KEY_LIFETIME_GET_LOCATION(
psa_get_key_lifetime( attributes ) );
switch( location )
{
case PSA_KEY_LOCATION_LOCAL_STORAGE:
/* Key is stored in the slot in export representation, so
* cycle through all known transparent accelerators */
#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT)
#if (defined(PSA_CRYPTO_DRIVER_TEST) )
status = mbedtls_test_transparent_export_public_key
(attributes,
key_buffer,
key_buffer_size,
data,
data_size,
data_length
);
if( status != PSA_ERROR_NOT_SUPPORTED )
return( status );
#endif
#if (defined(MBEDTLS_PSA_P256M_DRIVER_ENABLED) )
status = p256_transparent_export_public_key
(attributes,
key_buffer,
key_buffer_size,
data,
data_size,
data_length
);
if( status != PSA_ERROR_NOT_SUPPORTED )
return( status );
#endif
#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */
/* Fell through, meaning no accelerator supports this operation */
return( psa_export_public_key_internal( attributes,
key_buffer,
key_buffer_size,
data,
data_size,
data_length ) );
/* Add cases for opaque driver here */
#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT)
#if (defined(PSA_CRYPTO_DRIVER_TEST) )
case 0x7fffff:
return( mbedtls_test_opaque_export_public_key
(attributes,
key_buffer,
key_buffer_size,
data,
data_size,
data_length
));
#endif
#if defined(ESP_ECDSA_DRIVER_ENABLED) && defined(ESP_ECDSA_SIGN_DRIVER_ENABLED)
case PSA_KEY_LOCATION_ESP_ECDSA:
if( PSA_KEY_TYPE_IS_ECC( psa_get_key_type(attributes) ) &&
PSA_ALG_IS_ECDSA( psa_get_key_algorithm(attributes) ) &&
PSA_KEY_TYPE_ECC_GET_FAMILY(psa_get_key_type(attributes)) == PSA_ECC_FAMILY_SECP_R1)
{
return ( esp_ecdsa_opaque_export_public_key(
attributes,
key_buffer,
key_buffer_size,
data,
data_size,
data_length ) );
}
return PSA_ERROR_INVALID_ARGUMENT;
#endif /* defined(ESP_ECDSA_DRIVER_ENABLED) && defined(ESP_ECDSA_SIGN_DRIVER_ENABLED) */
#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */
default:
/* Key is declared with a lifetime not known to us */
return( status );
}
}
psa_status_t psa_driver_wrapper_get_builtin_key(
psa_drv_slot_number_t slot_number,
psa_key_attributes_t *attributes,
uint8_t *key_buffer, size_t key_buffer_size, size_t *key_buffer_length )
{
psa_key_location_t location = PSA_KEY_LIFETIME_GET_LOCATION( psa_get_key_lifetime(attributes) );
switch( location )
{
#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT)
#if (defined(PSA_CRYPTO_DRIVER_TEST) )
case 0x7fffff:
return( mbedtls_test_opaque_get_builtin_key
(slot_number,
attributes,
key_buffer,
key_buffer_size,
key_buffer_length
));
#endif
#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */
default:
(void) slot_number;
(void) key_buffer;
(void) key_buffer_size;
(void) key_buffer_length;
return( PSA_ERROR_DOES_NOT_EXIST );
}
}
#endif /* MBEDTLS_PSA_CRYPTO_C */
+85
View File
@@ -0,0 +1,85 @@
/**
* \file psa_crypto_invasive.h
*
* \brief PSA cryptography module: invasive interfaces for test only.
*
* The interfaces in this file are intended for testing purposes only.
* They MUST NOT be made available to clients over IPC in integrations
* with isolation, and they SHOULD NOT be made available in library
* integrations except when building the library for testing.
*/
/*
* Copyright The Mbed TLS Contributors
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
*/
#ifndef TF_PSA_CRYPTO_PSA_CRYPTO_INVASIVE_H
#define TF_PSA_CRYPTO_PSA_CRYPTO_INVASIVE_H
#include "tf-psa-crypto/build_info.h"
#include "psa/crypto.h"
#include "tf_psa_crypto_common.h"
#include "mbedtls/private/entropy.h"
#if !defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG)
/** \brief Configure entropy sources.
*
* This function may only be called before a call to psa_crypto_init(),
* or after a call to mbedtls_psa_crypto_free() and before any
* subsequent call to psa_crypto_init().
*
* This function is only intended for test purposes. The functionality
* it provides is also useful for system integrators, but
* system integrators should configure entropy drivers instead of
* breaking through to the Mbed TLS API.
*
* \param entropy_init Function to initialize the entropy context
* and set up the desired entropy sources.
* It is called by psa_crypto_init().
* By default this is mbedtls_entropy_init().
* This function cannot report failures directly.
* To indicate a failure, set the entropy context
* to a state where mbedtls_entropy_func() will
* return an error.
* \param entropy_free Function to free the entropy context
* and associated resources.
* It is called by mbedtls_psa_crypto_free().
* By default this is mbedtls_entropy_free().
*
* \retval #PSA_SUCCESS
* Success.
* \retval #PSA_ERROR_NOT_PERMITTED
* The caller does not have the permission to configure
* entropy sources.
* \retval #PSA_ERROR_BAD_STATE
* The library has already been initialized.
*/
psa_status_t mbedtls_psa_crypto_configure_entropy_sources(
void (* entropy_init)(mbedtls_entropy_context *ctx),
void (* entropy_free)(mbedtls_entropy_context *ctx));
#endif /* !defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) */
#if defined(MBEDTLS_TEST_HOOKS) && defined(MBEDTLS_PSA_CRYPTO_C)
psa_status_t psa_mac_key_can_do(
psa_algorithm_t algorithm,
psa_key_type_t key_type);
psa_status_t psa_crypto_copy_input(const uint8_t *input, size_t input_len,
uint8_t *input_copy, size_t input_copy_len);
psa_status_t psa_crypto_copy_output(const uint8_t *output_copy, size_t output_copy_len,
uint8_t *output, size_t output_len);
/*
* Test hooks to use for memory unpoisoning/poisoning in copy functions.
*/
extern void (*psa_input_pre_copy_hook)(const uint8_t *input, size_t input_len);
extern void (*psa_input_post_copy_hook)(const uint8_t *input, size_t input_len);
extern void (*psa_output_pre_copy_hook)(const uint8_t *output, size_t output_len);
extern void (*psa_output_post_copy_hook)(const uint8_t *output, size_t output_len);
#endif /* MBEDTLS_TEST_HOOKS && MBEDTLS_PSA_CRYPTO_C */
#endif /* TF_PSA_CRYPTO_PSA_CRYPTO_INVASIVE_H */
+131
View File
@@ -0,0 +1,131 @@
/** \file psa_crypto_its.h
* \brief Interface of trusted storage that crypto is built on.
*/
/*
* Copyright The Mbed TLS Contributors
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
*/
#ifndef TF_PSA_CRYPTO_PSA_CRYPTO_ITS_H
#define TF_PSA_CRYPTO_PSA_CRYPTO_ITS_H
#include <stddef.h>
#include <stdint.h>
#include <psa/crypto_types.h>
#include <psa/crypto_values.h>
#ifdef __cplusplus
extern "C" {
#endif
/** \brief Flags used when creating a data entry
*/
typedef uint32_t psa_storage_create_flags_t;
/** \brief A type for UIDs used for identifying data
*/
typedef uint64_t psa_storage_uid_t;
#define PSA_STORAGE_FLAG_NONE 0 /**< No flags to pass */
#define PSA_STORAGE_FLAG_WRITE_ONCE (1 << 0) /**< The data associated with the uid will not be able to be modified or deleted. Intended to be used to set bits in `psa_storage_create_flags_t`*/
/**
* \brief A container for metadata associated with a specific uid
*/
struct psa_storage_info_t {
uint32_t size; /**< The size of the data associated with a uid **/
psa_storage_create_flags_t flags; /**< The flags set when the uid was created **/
};
/** Flag indicating that \ref psa_storage_create and \ref psa_storage_set_extended are supported */
#define PSA_STORAGE_SUPPORT_SET_EXTENDED (1 << 0)
#define PSA_ITS_API_VERSION_MAJOR 1 /**< The major version number of the PSA ITS API. It will be incremented on significant updates that may include breaking changes */
#define PSA_ITS_API_VERSION_MINOR 1 /**< The minor version number of the PSA ITS API. It will be incremented in small updates that are unlikely to include breaking changes */
/**
* \brief create a new or modify an existing uid/value pair
*
* \param[in] uid the identifier for the data
* \param[in] data_length The size in bytes of the data in `p_data`
* \param[in] p_data A buffer containing the data
* \param[in] create_flags The flags that the data will be stored with
*
* \return A status indicating the success/failure of the operation
*
* \retval #PSA_SUCCESS The operation completed successfully
* \retval #PSA_ERROR_NOT_PERMITTED The operation failed because the provided `uid` value was already created with PSA_STORAGE_FLAG_WRITE_ONCE
* \retval #PSA_ERROR_NOT_SUPPORTED The operation failed because one or more of the flags provided in `create_flags` is not supported or is not valid
* \retval #PSA_ERROR_INSUFFICIENT_STORAGE The operation failed because there was insufficient space on the storage medium
* \retval #PSA_ERROR_STORAGE_FAILURE The operation failed because the physical storage has failed (Fatal error)
* \retval #PSA_ERROR_INVALID_ARGUMENT The operation failed because one of the provided pointers(`p_data`)
* is invalid, for example is `NULL` or references memory the caller cannot access
*/
psa_status_t psa_its_set(psa_storage_uid_t uid,
uint32_t data_length,
const void *p_data,
psa_storage_create_flags_t create_flags);
/**
* \brief Retrieve the value associated with a provided uid
*
* \param[in] uid The uid value
* \param[in] data_offset The starting offset of the data requested
* \param[in] data_length the amount of data requested (and the minimum allocated size of the `p_data` buffer)
* \param[out] p_data The buffer where the data will be placed upon successful completion
* \param[out] p_data_length The amount of data returned in the p_data buffer
*
*
* \return A status indicating the success/failure of the operation
*
* \retval #PSA_SUCCESS The operation completed successfully
* \retval #PSA_ERROR_DOES_NOT_EXIST The operation failed because the provided `uid` value was not found in the storage
* \retval #PSA_ERROR_STORAGE_FAILURE The operation failed because the physical storage has failed (Fatal error)
* \retval #PSA_ERROR_DATA_CORRUPT The operation failed because stored data has been corrupted
* \retval #PSA_ERROR_INVALID_ARGUMENT The operation failed because one of the provided pointers(`p_data`, `p_data_length`)
* is invalid. For example is `NULL` or references memory the caller cannot access.
* In addition, this can also happen if an invalid offset was provided.
*/
psa_status_t psa_its_get(psa_storage_uid_t uid,
uint32_t data_offset,
uint32_t data_length,
void *p_data,
size_t *p_data_length);
/**
* \brief Retrieve the metadata about the provided uid
*
* \param[in] uid The uid value
* \param[out] p_info A pointer to the `psa_storage_info_t` struct that will be populated with the metadata
*
* \return A status indicating the success/failure of the operation
*
* \retval #PSA_SUCCESS The operation completed successfully
* \retval #PSA_ERROR_DOES_NOT_EXIST The operation failed because the provided uid value was not found in the storage
* \retval #PSA_ERROR_DATA_CORRUPT The operation failed because stored data has been corrupted
* \retval #PSA_ERROR_INVALID_ARGUMENT The operation failed because one of the provided pointers(`p_info`)
* is invalid, for example is `NULL` or references memory the caller cannot access
*/
psa_status_t psa_its_get_info(psa_storage_uid_t uid,
struct psa_storage_info_t *p_info);
/**
* \brief Remove the provided key and its associated data from the storage
*
* \param[in] uid The uid value
*
* \return A status indicating the success/failure of the operation
*
* \retval #PSA_SUCCESS The operation completed successfully
* \retval #PSA_ERROR_DOES_NOT_EXIST The operation failed because the provided key value was not found in the storage
* \retval #PSA_ERROR_NOT_PERMITTED The operation failed because the provided key value was created with PSA_STORAGE_FLAG_WRITE_ONCE
* \retval #PSA_ERROR_STORAGE_FAILURE The operation failed because the physical storage has failed (Fatal error)
*/
psa_status_t psa_its_remove(psa_storage_uid_t uid);
#ifdef __cplusplus
}
#endif
#endif /* TF_PSA_CRYPTO_PSA_CRYPTO_ITS_H */
+168
View File
@@ -0,0 +1,168 @@
/*
* PSA crypto random generator.
*/
/*
* Copyright The Mbed TLS Contributors
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
*/
#include "tf_psa_crypto_common.h"
#if defined(MBEDTLS_PSA_CRYPTO_C) && !defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG)
#include "psa_crypto_core.h"
#include "psa_crypto_random.h"
#include "psa_crypto_random_impl.h"
#include "threading_internal.h"
#if defined(MBEDTLS_PLATFORM_IS_UNIXLIKE)
/* For getpid(), for fork protection */
#include <unistd.h>
#if defined(MBEDTLS_HAVE_TIME)
#include <mbedtls/platform_time.h>
#else
/* For gettimeofday(), for fork protection without actual entropy */
#include <sys/time.h>
#endif
#endif
void psa_random_internal_init(mbedtls_psa_random_context_t *rng)
{
/* Set default configuration if
* mbedtls_psa_crypto_configure_entropy_sources() hasn't been called. */
if (rng->entropy_init == NULL) {
rng->entropy_init = mbedtls_entropy_init;
}
if (rng->entropy_free == NULL) {
rng->entropy_free = mbedtls_entropy_free;
}
rng->entropy_init(&rng->entropy);
mbedtls_psa_drbg_init(&rng->drbg);
}
void psa_random_internal_free(mbedtls_psa_random_context_t *rng)
{
mbedtls_psa_drbg_free(&rng->drbg);
rng->entropy_free(&rng->entropy);
}
psa_status_t psa_random_internal_seed(mbedtls_psa_random_context_t *rng)
{
const unsigned char drbg_seed[] = "PSA";
int ret = mbedtls_psa_drbg_seed(&rng->drbg, &rng->entropy,
drbg_seed, sizeof(drbg_seed) - 1);
#if defined(MBEDTLS_PLATFORM_IS_UNIXLIKE)
rng->pid = getpid();
#endif
return mbedtls_to_psa_error(ret);
}
#if defined(MBEDTLS_PLATFORM_IS_UNIXLIKE)
static psa_status_t psa_random_internal_reseed_child(
mbedtls_psa_random_context_t *rng,
intmax_t pid)
{
/* Reseeding from actual entropy gives the child a unique RNG state
* which the parent process cannot predict, and wipes the
* parent's RNG state from the child.
*
* However, in some library configurations, there is no actual
* entropy source, only a nonvolatile seed (MBEDTLS_ENTROPY_NV_SEED
* enabled and no actual entropy source enabled). In such a
* configuration, the reseed operation is deterministic and
* always injects the same content, so with the DRBG reseed
* process alone, for example, two child processes forked in
* close sequence would end up with the same RNG state.
* To avoid this, we use a personalization string that has a high
* likelihood of being unique. This way, the child has a unique state.
* The parent can predict the child's RNG state until the next time
* it reseeds or generates some random output, but that's
* unavoidable in the absence of actual entropy.
*/
struct {
/* Using the PID mostly guarantees that each child gets a
* unique state. */
/* Use intmax_t, not pid_t, because some Unix-like platforms
* don't define pid_t, or more likely nowadays they define
* pid_t but only with certain platform macros which might not
* be the exact ones we use. In practice, this only costs
* a couple of instructions to pass and compare two words
* rather than one.
*/
intmax_t pid;
/* In case an old child had died and its PID is reused for
* a new child of the same process, also include the time. */
#if defined(MBEDTLS_HAVE_TIME)
mbedtls_ms_time_t now;
#else
struct timeval now;
#endif
} perso;
memset(&perso, 0, sizeof(perso));
perso.pid = pid;
#if defined(MBEDTLS_HAVE_TIME)
perso.now = mbedtls_ms_time();
#else
/* We don't have mbedtls_ms_time(), but the platform has getpid().
* Use gettimeofday(), which is a classic Unix function. Modern POSIX
* has stopped requiring gettimeofday() (in favor of clock_gettime()),
* but this is fallback code for restricted configurations, so it's
* more likely to be used on embedded platforms that only have a subset
* of Unix APIs and are more likely to have the classic gettimeofday(). */
if (gettimeofday(&perso.now, NULL) == -1) {
return PSA_ERROR_INSUFFICIENT_ENTROPY;
}
#endif
int ret = mbedtls_psa_drbg_reseed(&rng->drbg,
(unsigned char *) &perso, sizeof(perso));
return mbedtls_to_psa_error(ret);
}
#endif /* MBEDTLS_PLATFORM_IS_UNIXLIKE */
psa_status_t psa_random_internal_generate(
mbedtls_psa_random_context_t *rng,
uint8_t *output, size_t output_size)
{
#if defined(MBEDTLS_PLATFORM_IS_UNIXLIKE)
intmax_t pid = getpid();
if (pid != rng->pid) {
/* This is a (grand...)child of the original process, but
* we inherited the RNG state from our parent. We must reseed! */
#if defined(MBEDTLS_THREADING_C)
mbedtls_mutex_lock(&mbedtls_threading_psa_rngdata_mutex);
#endif /* defined(MBEDTLS_THREADING_C) */
psa_status_t status = psa_random_internal_reseed_child(rng, pid);
if (status == PSA_SUCCESS) {
rng->pid = pid;
}
#if defined(MBEDTLS_THREADING_C)
mbedtls_mutex_unlock(&mbedtls_threading_psa_rngdata_mutex);
#endif /* defined(MBEDTLS_THREADING_C) */
if (status != PSA_SUCCESS) {
return status;
}
}
#endif /* MBEDTLS_PLATFORM_IS_UNIXLIKE */
while (output_size > 0) {
size_t request_size =
(output_size > MBEDTLS_PSA_RANDOM_MAX_REQUEST ?
MBEDTLS_PSA_RANDOM_MAX_REQUEST :
output_size);
#if defined(MBEDTLS_CTR_DRBG_C)
int ret = mbedtls_ctr_drbg_random(&rng->drbg, output, request_size);
#elif defined(MBEDTLS_HMAC_DRBG_C)
int ret = mbedtls_hmac_drbg_random(&rng->drbg, output, request_size);
#endif /* !MBEDTLS_CTR_DRBG_C && !MBEDTLS_HMAC_DRBG_C */
if (ret != 0) {
return mbedtls_to_psa_error(ret);
}
output_size -= request_size;
output += request_size;
}
return PSA_SUCCESS;
}
#endif /* MBEDTLS_PSA_CRYPTO_C && !MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
+72
View File
@@ -0,0 +1,72 @@
/*
* PSA crypto random generator internal functions.
*/
/*
* Copyright The Mbed TLS Contributors
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
*/
#ifndef TF_PSA_CRYPTO_PSA_CRYPTO_RANDOM_H
#define TF_PSA_CRYPTO_PSA_CRYPTO_RANDOM_H
#include "tf_psa_crypto_common.h"
#if !defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG)
#include <psa/crypto.h>
#include "psa_crypto_random_impl.h"
/** Initialize the PSA random generator.
*
* \param[out] rng The random generator context to initialize.
*/
void psa_random_internal_init(mbedtls_psa_random_context_t *rng);
/** Deinitialize the PSA random generator.
*
* \param[in,out] rng The random generator context to deinitialize.
*/
void psa_random_internal_free(mbedtls_psa_random_context_t *rng);
/** Seed the PSA random generator.
*
* \note This function is not thread-safe.
*
* \param[in,out] rng The random generator context to seed.
*
* \retval #PSA_SUCCESS
* Success.
* \retval #PSA_ERROR_INSUFFICIENT_ENTROPY
* The entropy source failed.
*/
psa_status_t psa_random_internal_seed(mbedtls_psa_random_context_t *rng);
/**
* \brief Generate random bytes. Like psa_generate_random(), but for use
* inside the library.
*
* This function is thread-safe.
*
* \warning This function **can** fail! Callers MUST check the return status
* and MUST NOT use the content of the output buffer if the return
* status is not #PSA_SUCCESS.
*
* \param[in,out] rng The random generator context to seed.
* \param[out] output Output buffer for the generated data.
* \param output_size Number of bytes to generate and output.
*
* \retval #PSA_SUCCESS
* Success.
* \retval #PSA_ERROR_INSUFFICIENT_ENTROPY
* The random generator needed to reseed, and the entropy
* source failed.
* \retval #PSA_ERROR_HARDWARE_FAILURE
* A hardware accelerator failed.
*/
psa_status_t psa_random_internal_generate(
mbedtls_psa_random_context_t *rng,
uint8_t *output, size_t output_size);
#endif /* !defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) */
#endif /* TF_PSA_CRYPTO_PSA_CRYPTO_RANDOM_H */
+215
View File
@@ -0,0 +1,215 @@
/** \file psa_crypto_random_impl.h
*
* \brief PSA crypto random generator implementation abstraction.
*/
/*
* Copyright The Mbed TLS Contributors
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
*/
#ifndef TF_PSA_CRYPTO_PSA_CRYPTO_RANDOM_IMPL_H
#define TF_PSA_CRYPTO_PSA_CRYPTO_RANDOM_IMPL_H
#include "mbedtls/psa_util.h"
#if defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG)
typedef mbedtls_psa_external_random_context_t mbedtls_psa_random_context_t;
#else /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
#include "mbedtls/private/entropy.h"
#include "mbedtls/private/error_common.h"
#if !defined(PSA_WANT_ALG_SHA_256)
MBEDTLS_STATIC_ASSERT(MBEDTLS_PSA_CRYPTO_RNG_HASH != PSA_ALG_SHA_256,
"SHA_256 used as the hash for the random generator, but not enabled");
#endif
#if !defined(PSA_WANT_ALG_SHA_512)
MBEDTLS_STATIC_ASSERT(MBEDTLS_PSA_CRYPTO_RNG_HASH != PSA_ALG_SHA_512,
"SHA_512 used as the hash for the random generator, but not enabled");
#endif
MBEDTLS_STATIC_ASSERT((MBEDTLS_PSA_CRYPTO_RNG_HASH == PSA_ALG_SHA_256) || \
(MBEDTLS_PSA_CRYPTO_RNG_HASH == PSA_ALG_SHA_512),
"Invalid hashing algorithm for MBEDTLS_PSA_CRYPTO_RNG_HASH");
MBEDTLS_STATIC_ASSERT(PSA_BYTES_TO_BITS(PSA_HASH_LENGTH(
MBEDTLS_PSA_CRYPTO_RNG_HASH))
>= MBEDTLS_PSA_CRYPTO_RNG_STRENGTH,
"The hash size (in bits) of MBEDTLS_PSA_CRYPTO_RNG_HASH must be at least MBEDTLS_PSA_CRYPTO_RNG_STRENGTH");
/* Choose a DRBG based on configuration and availability */
#if defined(MBEDTLS_CTR_DRBG_C)
#include "mbedtls/private/ctr_drbg.h"
#if (MBEDTLS_PSA_CRYPTO_RNG_STRENGTH > 128) && \
defined(MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH)
#error "CTR_DRBG cannot meet the configured RNG strength using only 128-bit AES keys."
#endif
#if MBEDTLS_PSA_CRYPTO_RNG_STRENGTH > PSA_BYTES_TO_BITS(MBEDTLS_CTR_DRBG_KEYSIZE)
#error "The CTR_DRBG key size (in bits) must be at least MBEDTLS_PSA_CRYPTO_RNG_STRENGTH"
#endif
#undef MBEDTLS_PSA_HMAC_DRBG_MD_TYPE
#elif defined(MBEDTLS_HMAC_DRBG_C)
#include "mbedtls/private/hmac_drbg.h"
#define MBEDTLS_PSA_HMAC_DRBG_MD_TYPE MBEDTLS_ENTROPY_MD
#else /* !MBEDTLS_CTR_DRBG_C && !MBEDTLS_HMAC_DRBG_C*/
#error "No DRBG module available for the psa_crypto module."
#endif /* !MBEDTLS_CTR_DRBG_C && !MBEDTLS_HMAC_DRBG_C*/
/* The maximum number of bytes that mbedtls_psa_get_random() is expected to return. */
#if defined(MBEDTLS_CTR_DRBG_C)
#define MBEDTLS_PSA_RANDOM_MAX_REQUEST MBEDTLS_CTR_DRBG_MAX_REQUEST
#elif defined(MBEDTLS_HMAC_DRBG_C)
#define MBEDTLS_PSA_RANDOM_MAX_REQUEST MBEDTLS_HMAC_DRBG_MAX_REQUEST
#endif
#if defined(MBEDTLS_CTR_DRBG_C)
typedef mbedtls_ctr_drbg_context mbedtls_psa_drbg_context_t;
#elif defined(MBEDTLS_HMAC_DRBG_C)
typedef mbedtls_hmac_drbg_context mbedtls_psa_drbg_context_t;
#endif /* !MBEDTLS_CTR_DRBG_C && !MBEDTLS_HMAC_DRBG_C */
typedef struct {
void (* entropy_init)(mbedtls_entropy_context *ctx);
void (* entropy_free)(mbedtls_entropy_context *ctx);
mbedtls_entropy_context entropy;
mbedtls_psa_drbg_context_t drbg;
#if defined(MBEDTLS_PLATFORM_IS_UNIXLIKE)
/* Fork protection: normally pid = getpid(). If the value changes,
* we are in a (grand)*child of the original process, so reseed
* the RNG to ensure that the child and the original process have
* distinct RNG states. See psa_random_internal_generate().
*
* The type is intmax_t, not pid_t, for portability reasons:
* pid_t is defined in `unistd.h`, but on some platforms, it may
* only be defined if a certain compatibility level is requested
* by defining a macro such as _POSIX_C_SOURCE or _XOPEN_SOURCE.
* The macro needs to be defined before any system header, which
* may be hard to do in some C files that include this header
* (e.g. test suites). So we sidestep this complication, at the
* cost of possibly a few more instructions to compare pid values.
*/
intmax_t pid;
#endif
} mbedtls_psa_random_context_t;
/** Initialize the PSA DRBG.
*
* \param p_rng Pointer to the Mbed TLS DRBG state.
*/
static inline void mbedtls_psa_drbg_init(mbedtls_psa_drbg_context_t *p_rng)
{
#if defined(MBEDTLS_CTR_DRBG_C)
mbedtls_ctr_drbg_init(p_rng);
#elif defined(MBEDTLS_HMAC_DRBG_C)
mbedtls_hmac_drbg_init(p_rng);
#endif
}
/** Deinitialize the PSA DRBG.
*
* \param p_rng Pointer to the Mbed TLS DRBG state.
*/
static inline void mbedtls_psa_drbg_free(mbedtls_psa_drbg_context_t *p_rng)
{
#if defined(MBEDTLS_CTR_DRBG_C)
mbedtls_ctr_drbg_free(p_rng);
#elif defined(MBEDTLS_HMAC_DRBG_C)
mbedtls_hmac_drbg_free(p_rng);
#endif
}
/** Seed the PSA DRBG.
*
* \param drbg_ctx The DRBG context to seed.
* It must be initialized but not active.
* \param entropy An entropy context to read the seed from.
* \param custom The personalization string.
* This can be \c NULL, in which case the personalization
* string is empty regardless of the value of \p len.
* \param len The length of the personalization string.
*
* \return \c 0 on success.
* \return An Mbed TLS error code (\c MBEDTLS_ERR_xxx) on failure.
*/
static inline int mbedtls_psa_drbg_seed(mbedtls_psa_drbg_context_t *drbg_ctx,
mbedtls_entropy_context *entropy,
const unsigned char *custom, size_t len)
{
#if defined(MBEDTLS_CTR_DRBG_C)
return mbedtls_ctr_drbg_seed(drbg_ctx, mbedtls_entropy_func, entropy, custom, len);
#elif defined(MBEDTLS_HMAC_DRBG_C)
const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type(MBEDTLS_PSA_HMAC_DRBG_MD_TYPE);
return mbedtls_hmac_drbg_seed(drbg_ctx, md_info, mbedtls_entropy_func, entropy, custom, len);
#endif /* MBEDTLS_HMAC_DRBG_C */
}
/** Reseed the PSA DRBG.
*
* \param drbg_ctx The DRBG context to reseed.
* It must be active.
* \param additional Additional data to inject.
* \param len The length of \p additional in bytes.
* This can be 0 to simply reseed from the entropy source.
*
* \return \c 0 on success.
* \return An Mbed TLS error code (\c MBEDTLS_ERR_xxx) on failure.
*/
static inline int mbedtls_psa_drbg_reseed(mbedtls_psa_drbg_context_t *drbg_ctx,
const unsigned char *additional,
size_t len)
{
#if defined(MBEDTLS_CTR_DRBG_C)
return mbedtls_ctr_drbg_reseed(drbg_ctx, additional, len);
#elif defined(MBEDTLS_HMAC_DRBG_C)
return mbedtls_hmac_drbg_reseed(drbg_ctx, additional, len);
#endif
}
/** Deplete the PSA DRBG, i.e. cause it to reseed the next time it is used.
*
* \note This function is not thread-safe.
*
* \param drbg_ctx The DRBG context to deplete.
* It must be active.
*/
static inline void mbedtls_psa_drbg_deplete(mbedtls_psa_drbg_context_t *drbg_ctx)
{
drbg_ctx->reseed_counter = drbg_ctx->reseed_interval;
}
#if MBEDTLS_ENTROPY_TRUE_SOURCES > 0
/** Set prediction resistance in the PSA DRBG.
*
* \note This function is not thread-safe.
*
* \param drbg_ctx The DRBG context to reconfigure.
* It must be active.
* \param enabled \c 1 to enable, or \c 0 to disable.
*/
static inline void mbedtls_psa_drbg_set_prediction_resistance(
mbedtls_psa_drbg_context_t *drbg_ctx,
unsigned enabled)
{
#if defined(MBEDTLS_CTR_DRBG_C)
mbedtls_ctr_drbg_set_prediction_resistance(drbg_ctx, enabled);
#elif defined(MBEDTLS_HMAC_DRBG_C)
mbedtls_hmac_drbg_set_prediction_resistance(drbg_ctx, enabled);
#endif
}
#endif /* MBEDTLS_ENTROPY_TRUE_SOURCES > 0 */
#endif /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
#endif /* TF_PSA_CRYPTO_PSA_CRYPTO_RANDOM_IMPL_H */
@@ -0,0 +1,998 @@
/*
* PSA crypto layer on top of Mbed TLS crypto
*/
/*
* Copyright The Mbed TLS Contributors
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
*/
#include "tf_psa_crypto_common.h"
#if defined(MBEDTLS_PSA_CRYPTO_C)
#include "psa/crypto.h"
#include "psa_crypto_core.h"
#include "psa_crypto_driver_wrappers_no_static.h"
#include "psa_crypto_slot_management.h"
#include "psa_crypto_storage.h"
#include <stdlib.h>
#include <string.h>
#include "mbedtls/platform.h"
#if defined(MBEDTLS_THREADING_C)
#include "mbedtls/threading.h"
#include "threading_internal.h"
#endif
/* Make sure we have distinct ranges of key identifiers for distinct
* purposes. */
MBEDTLS_STATIC_ASSERT(PSA_KEY_ID_USER_MIN < PSA_KEY_ID_USER_MAX,
"Empty user key ID range");
MBEDTLS_STATIC_ASSERT(PSA_KEY_ID_VENDOR_MIN < PSA_KEY_ID_VENDOR_MAX,
"Empty vendor key ID range");
MBEDTLS_STATIC_ASSERT(MBEDTLS_PSA_KEY_ID_BUILTIN_MIN <= MBEDTLS_PSA_KEY_ID_BUILTIN_MAX,
"Empty builtin key ID range");
MBEDTLS_STATIC_ASSERT(PSA_KEY_ID_VOLATILE_MIN <= PSA_KEY_ID_VOLATILE_MAX,
"Empty volatile key ID range");
MBEDTLS_STATIC_ASSERT(PSA_KEY_ID_USER_MAX < PSA_KEY_ID_VENDOR_MIN ||
PSA_KEY_ID_VENDOR_MAX < PSA_KEY_ID_USER_MIN,
"Overlap between user key IDs and vendor key IDs");
MBEDTLS_STATIC_ASSERT(PSA_KEY_ID_VENDOR_MIN <= MBEDTLS_PSA_KEY_ID_BUILTIN_MIN &&
MBEDTLS_PSA_KEY_ID_BUILTIN_MAX <= PSA_KEY_ID_VENDOR_MAX,
"Builtin key identifiers are not in the vendor range");
MBEDTLS_STATIC_ASSERT(PSA_KEY_ID_VENDOR_MIN <= PSA_KEY_ID_VOLATILE_MIN &&
PSA_KEY_ID_VOLATILE_MAX <= PSA_KEY_ID_VENDOR_MAX,
"Volatile key identifiers are not in the vendor range");
MBEDTLS_STATIC_ASSERT(PSA_KEY_ID_VOLATILE_MAX < MBEDTLS_PSA_KEY_ID_BUILTIN_MIN ||
MBEDTLS_PSA_KEY_ID_BUILTIN_MAX < PSA_KEY_ID_VOLATILE_MIN,
"Overlap between builtin key IDs and volatile key IDs");
#if defined(MBEDTLS_PSA_KEY_STORE_DYNAMIC)
/* Dynamic key store.
*
* The key store consists of multiple slices.
*
* The volatile keys are stored in variable-sized tables called slices.
* Slices are allocated on demand and deallocated when possible.
* The size of slices increases exponentially, so the average overhead
* (number of slots that are allocated but not used) is roughly
* proportional to the number of keys (with a factor that grows
* when the key store is fragmented).
*
* One slice is dedicated to the cache of persistent and built-in keys.
* For simplicity, they are separated from volatile keys. This cache
* slice has a fixed size and has the slice index KEY_SLOT_CACHE_SLICE_INDEX,
* located after the slices for volatile keys.
*/
/* Size of the last slice containing the cache of persistent and built-in keys. */
#define PERSISTENT_KEY_CACHE_COUNT MBEDTLS_PSA_KEY_SLOT_COUNT
/* Volatile keys are stored in slices 0 through
* (KEY_SLOT_VOLATILE_SLICE_COUNT - 1) inclusive.
* Each slice is twice the size of the previous slice.
* Volatile key identifiers encode the slice number as follows:
* bits 30..31: 0b10 (mandated by the PSA Crypto specification).
* bits 25..29: slice index (0...KEY_SLOT_VOLATILE_SLICE_COUNT-1)
* bits 0..24: slot index in slice
*/
#define KEY_ID_SLOT_INDEX_WIDTH 25u
#define KEY_ID_SLICE_INDEX_WIDTH 5u
#define KEY_SLOT_VOLATILE_SLICE_BASE_LENGTH 16u
#define KEY_SLOT_VOLATILE_SLICE_COUNT 22u
#define KEY_SLICE_COUNT (KEY_SLOT_VOLATILE_SLICE_COUNT + 1u)
#define KEY_SLOT_CACHE_SLICE_INDEX KEY_SLOT_VOLATILE_SLICE_COUNT
/* Check that the length of the largest slice (calculated as
* KEY_SLICE_LENGTH_MAX below) does not overflow size_t. We use
* an indirect method in case the calculation of KEY_SLICE_LENGTH_MAX
* itself overflows uintmax_t: if (BASE_LENGTH << c)
* overflows size_t then BASE_LENGTH > SIZE_MAX >> c.
*/
#if (KEY_SLOT_VOLATILE_SLICE_BASE_LENGTH > \
SIZE_MAX >> (KEY_SLOT_VOLATILE_SLICE_COUNT - 1))
#error "Maximum slice length overflows size_t"
#endif
#if KEY_ID_SLICE_INDEX_WIDTH + KEY_ID_SLOT_INDEX_WIDTH > 30
#error "Not enough room in volatile key IDs for slice index and slot index"
#endif
#if KEY_SLOT_VOLATILE_SLICE_COUNT > (1 << KEY_ID_SLICE_INDEX_WIDTH)
#error "Too many slices to fit the slice index in a volatile key ID"
#endif
#define KEY_SLICE_LENGTH_MAX \
(KEY_SLOT_VOLATILE_SLICE_BASE_LENGTH << (KEY_SLOT_VOLATILE_SLICE_COUNT - 1))
#if KEY_SLICE_LENGTH_MAX > 1 << KEY_ID_SLOT_INDEX_WIDTH
#error "Not enough room in volatile key IDs for a slot index in the largest slice"
#endif
#if KEY_ID_SLICE_INDEX_WIDTH > 8
#error "Slice index does not fit in uint8_t for psa_key_slot_t::slice_index"
#endif
/* Calculate the volatile key id to use for a given slot.
* This function assumes valid parameter values. */
static psa_key_id_t volatile_key_id_of_index(size_t slice_idx,
size_t slot_idx)
{
/* We assert above that the slice and slot indexes fit in separate
* bit-fields inside psa_key_id_t, which is a 32-bit type per the
* PSA Cryptography specification. */
return (psa_key_id_t) (0x40000000u |
(slice_idx << KEY_ID_SLOT_INDEX_WIDTH) |
slot_idx);
}
/* Calculate the slice containing the given volatile key.
* This function assumes valid parameter values. */
static size_t slice_index_of_volatile_key_id(psa_key_id_t key_id)
{
size_t mask = (1LU << KEY_ID_SLICE_INDEX_WIDTH) - 1;
return (key_id >> KEY_ID_SLOT_INDEX_WIDTH) & mask;
}
/* Calculate the index of the slot containing the given volatile key.
* This function assumes valid parameter values. */
static size_t slot_index_of_volatile_key_id(psa_key_id_t key_id)
{
return key_id & ((1LU << KEY_ID_SLOT_INDEX_WIDTH) - 1);
}
/* In global_data.first_free_slot_index, use this special value to
* indicate that the slice is full. */
#define FREE_SLOT_INDEX_NONE ((size_t) -1)
#if defined(MBEDTLS_TEST_HOOKS)
size_t psa_key_slot_volatile_slice_count(void)
{
return KEY_SLOT_VOLATILE_SLICE_COUNT;
}
#endif
#else /* MBEDTLS_PSA_KEY_STORE_DYNAMIC */
/* Static key store.
*
* All the keys (volatile or persistent) are in a single slice.
* We only use slices as a concept to allow some differences between
* static and dynamic key store management to be buried in auxiliary
* functions.
*/
#define PERSISTENT_KEY_CACHE_COUNT MBEDTLS_PSA_KEY_SLOT_COUNT
#define KEY_SLICE_COUNT 1u
#define KEY_SLOT_CACHE_SLICE_INDEX 0
#endif /* MBEDTLS_PSA_KEY_STORE_DYNAMIC */
typedef struct {
#if defined(MBEDTLS_PSA_KEY_STORE_DYNAMIC)
psa_key_slot_t *key_slices[KEY_SLICE_COUNT];
size_t first_free_slot_index[KEY_SLOT_VOLATILE_SLICE_COUNT];
#else /* MBEDTLS_PSA_KEY_STORE_DYNAMIC */
psa_key_slot_t key_slots[MBEDTLS_PSA_KEY_SLOT_COUNT];
#endif /* MBEDTLS_PSA_KEY_STORE_DYNAMIC */
uint8_t key_slots_initialized;
} psa_global_data_t;
static psa_global_data_t global_data;
static uint8_t psa_get_key_slots_initialized(void)
{
uint8_t initialized;
#if defined(MBEDTLS_THREADING_C)
mbedtls_mutex_lock(&mbedtls_threading_psa_globaldata_mutex);
#endif /* defined(MBEDTLS_THREADING_C) */
initialized = global_data.key_slots_initialized;
#if defined(MBEDTLS_THREADING_C)
mbedtls_mutex_unlock(&mbedtls_threading_psa_globaldata_mutex);
#endif /* defined(MBEDTLS_THREADING_C) */
return initialized;
}
/** The length of the given slice in the key slot table.
*
* \param slice_idx The slice number. It must satisfy
* 0 <= slice_idx < KEY_SLICE_COUNT.
*
* \return The number of elements in the given slice.
*/
static inline size_t key_slice_length(size_t slice_idx);
/** Get a pointer to the slot where the given volatile key is located.
*
* \param key_id The key identifier. It must be a valid volatile key
* identifier.
* \return A pointer to the only slot that the given key
* can be in. Note that the slot may be empty or
* contain a different key.
*/
static inline psa_key_slot_t *get_volatile_key_slot(psa_key_id_t key_id);
/** Get a pointer to an entry in the persistent key cache.
*
* \param slot_idx The index in the table. It must satisfy
* 0 <= slot_idx < PERSISTENT_KEY_CACHE_COUNT.
* \return A pointer to the slot containing the given
* persistent key cache entry.
*/
static inline psa_key_slot_t *get_persistent_key_slot(size_t slot_idx);
/** Get a pointer to a slot given by slice and index.
*
* \param slice_idx The slice number. It must satisfy
* 0 <= slice_idx < KEY_SLICE_COUNT.
* \param slot_idx An index in the given slice. It must satisfy
* 0 <= slot_idx < key_slice_length(slice_idx).
*
* \return A pointer to the given slot.
*/
static inline psa_key_slot_t *get_key_slot(size_t slice_idx, size_t slot_idx);
#if defined(MBEDTLS_PSA_KEY_STORE_DYNAMIC)
#if defined(MBEDTLS_TEST_HOOKS)
size_t (*mbedtls_test_hook_psa_volatile_key_slice_length)(size_t slice_idx) = NULL;
#endif
static inline size_t key_slice_length(size_t slice_idx)
{
if (slice_idx == KEY_SLOT_CACHE_SLICE_INDEX) {
return PERSISTENT_KEY_CACHE_COUNT;
} else {
#if defined(MBEDTLS_TEST_HOOKS)
if (mbedtls_test_hook_psa_volatile_key_slice_length != NULL) {
return mbedtls_test_hook_psa_volatile_key_slice_length(slice_idx);
}
#endif
return KEY_SLOT_VOLATILE_SLICE_BASE_LENGTH << slice_idx;
}
}
static inline psa_key_slot_t *get_volatile_key_slot(psa_key_id_t key_id)
{
size_t slice_idx = slice_index_of_volatile_key_id(key_id);
if (slice_idx >= KEY_SLOT_VOLATILE_SLICE_COUNT) {
return NULL;
}
size_t slot_idx = slot_index_of_volatile_key_id(key_id);
if (slot_idx >= key_slice_length(slice_idx)) {
return NULL;
}
psa_key_slot_t *slice = global_data.key_slices[slice_idx];
if (slice == NULL) {
return NULL;
}
return &slice[slot_idx];
}
static inline psa_key_slot_t *get_persistent_key_slot(size_t slot_idx)
{
return &global_data.key_slices[KEY_SLOT_CACHE_SLICE_INDEX][slot_idx];
}
static inline psa_key_slot_t *get_key_slot(size_t slice_idx, size_t slot_idx)
{
return &global_data.key_slices[slice_idx][slot_idx];
}
#else /* MBEDTLS_PSA_KEY_STORE_DYNAMIC */
static inline size_t key_slice_length(size_t slice_idx)
{
(void) slice_idx;
return ARRAY_LENGTH(global_data.key_slots);
}
static inline psa_key_slot_t *get_volatile_key_slot(psa_key_id_t key_id)
{
MBEDTLS_STATIC_ASSERT(ARRAY_LENGTH(global_data.key_slots) <=
PSA_KEY_ID_VOLATILE_MAX - PSA_KEY_ID_VOLATILE_MIN + 1,
"The key slot array is larger than the volatile key ID range");
return &global_data.key_slots[key_id - PSA_KEY_ID_VOLATILE_MIN];
}
static inline psa_key_slot_t *get_persistent_key_slot(size_t slot_idx)
{
return &global_data.key_slots[slot_idx];
}
static inline psa_key_slot_t *get_key_slot(size_t slice_idx, size_t slot_idx)
{
(void) slice_idx;
return &global_data.key_slots[slot_idx];
}
#endif /* MBEDTLS_PSA_KEY_STORE_DYNAMIC */
/** Get the description in memory of a key given its identifier and lock it.
*
* The descriptions of volatile keys and loaded persistent keys are
* stored in key slots. This function returns a pointer to the key slot
* containing the description of a key given its identifier.
*
* The function searches the key slots containing the description of the key
* with \p key identifier. The function does only read accesses to the key
* slots. The function does not load any persistent key thus does not access
* any storage.
*
* For volatile key identifiers, only one key slot is queried as a volatile
* key with identifier key_id can only be stored in slot of index
* ( key_id - #PSA_KEY_ID_VOLATILE_MIN ).
*
* On success, the function locks the key slot. It is the responsibility of
* the caller to unlock the key slot when it does not access it anymore.
*
* If multi-threading is enabled, the caller must hold the
* global key slot mutex.
*
* \param key Key identifier to query.
* \param[out] p_slot On success, `*p_slot` contains a pointer to the
* key slot containing the description of the key
* identified by \p key.
*
* \retval #PSA_SUCCESS
* The pointer to the key slot containing the description of the key
* identified by \p key was returned.
* \retval #PSA_ERROR_INVALID_HANDLE
* \p key is not a valid key identifier.
* \retval #PSA_ERROR_DOES_NOT_EXIST
* There is no key with key identifier \p key in the key slots.
*/
static psa_status_t psa_get_and_lock_key_slot_in_memory(
mbedtls_svc_key_id_t key, psa_key_slot_t **p_slot)
{
psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
psa_key_id_t key_id = MBEDTLS_SVC_KEY_ID_GET_KEY_ID(key);
size_t slot_idx;
psa_key_slot_t *slot = NULL;
if (psa_key_id_is_volatile(key_id)) {
slot = get_volatile_key_slot(key_id);
/* Check if both the PSA key identifier key_id and the owner
* identifier of key match those of the key slot. */
if (slot != NULL &&
slot->state == PSA_SLOT_FULL &&
mbedtls_svc_key_id_equal(key, slot->attr.id)) {
status = PSA_SUCCESS;
} else {
status = PSA_ERROR_DOES_NOT_EXIST;
}
} else if (psa_key_id_is_user(key_id) || psa_key_id_is_builtin(key_id)) {
for (slot_idx = 0; slot_idx < PERSISTENT_KEY_CACHE_COUNT; slot_idx++) {
slot = get_persistent_key_slot(slot_idx);
/* Only consider slots which are in a full state. */
if ((slot->state == PSA_SLOT_FULL) &&
(mbedtls_svc_key_id_equal(key, slot->attr.id))) {
break;
}
}
status = (slot_idx < MBEDTLS_PSA_KEY_SLOT_COUNT) ?
PSA_SUCCESS : PSA_ERROR_DOES_NOT_EXIST;
} else {
return PSA_ERROR_INVALID_HANDLE;
}
if (status == PSA_SUCCESS) {
status = psa_register_read(slot);
if (status == PSA_SUCCESS) {
*p_slot = slot;
}
}
return status;
}
psa_status_t psa_initialize_key_slots(void)
{
#if defined(MBEDTLS_PSA_KEY_STORE_DYNAMIC)
global_data.key_slices[KEY_SLOT_CACHE_SLICE_INDEX] =
mbedtls_calloc(PERSISTENT_KEY_CACHE_COUNT,
sizeof(*global_data.key_slices[KEY_SLOT_CACHE_SLICE_INDEX]));
if (global_data.key_slices[KEY_SLOT_CACHE_SLICE_INDEX] == NULL) {
return PSA_ERROR_INSUFFICIENT_MEMORY;
}
#else /* MBEDTLS_PSA_KEY_STORE_DYNAMIC */
/* Nothing to do: program startup and psa_wipe_all_key_slots() both
* guarantee that the key slots are initialized to all-zero, which
* means that all the key slots are in a valid, empty state. The global
* data mutex is already held when calling this function, so no need to
* lock it here, to set the flag. */
#endif /* MBEDTLS_PSA_KEY_STORE_DYNAMIC */
global_data.key_slots_initialized = 1;
return PSA_SUCCESS;
}
void psa_wipe_all_key_slots(void)
{
for (size_t slice_idx = 0; slice_idx < KEY_SLICE_COUNT; slice_idx++) {
#if defined(MBEDTLS_PSA_KEY_STORE_DYNAMIC)
if (global_data.key_slices[slice_idx] == NULL) {
continue;
}
#endif /* MBEDTLS_PSA_KEY_STORE_DYNAMIC */
for (size_t slot_idx = 0; slot_idx < key_slice_length(slice_idx); slot_idx++) {
psa_key_slot_t *slot = get_key_slot(slice_idx, slot_idx);
#if defined(MBEDTLS_PSA_KEY_STORE_DYNAMIC)
/* When MBEDTLS_PSA_KEY_STORE_DYNAMIC is disabled, calling
* psa_wipe_key_slot() on an unused slot is useless, but it
* happens to work (because we flip the state to PENDING_DELETION).
*
* When MBEDTLS_PSA_KEY_STORE_DYNAMIC is enabled,
* psa_wipe_key_slot() needs to have a valid slice_index
* field, but that value might not be correct in a
* free slot, so we must not call it.
*
* Bypass the call to psa_wipe_key_slot() if the slot is empty,
* but only if MBEDTLS_PSA_KEY_STORE_DYNAMIC is enabled, to save
* a few bytes of code size otherwise.
*/
if (slot->state == PSA_SLOT_EMPTY) {
continue;
}
#endif
slot->var.occupied.registered_readers = 1;
slot->state = PSA_SLOT_PENDING_DELETION;
(void) psa_wipe_key_slot(slot);
}
#if defined(MBEDTLS_PSA_KEY_STORE_DYNAMIC)
mbedtls_free(global_data.key_slices[slice_idx]);
global_data.key_slices[slice_idx] = NULL;
#endif /* MBEDTLS_PSA_KEY_STORE_DYNAMIC */
}
#if defined(MBEDTLS_PSA_KEY_STORE_DYNAMIC)
for (size_t slice_idx = 0; slice_idx < KEY_SLOT_VOLATILE_SLICE_COUNT; slice_idx++) {
global_data.first_free_slot_index[slice_idx] = 0;
}
#endif /* MBEDTLS_PSA_KEY_STORE_DYNAMIC */
/* The global data mutex is already held when calling this function. */
global_data.key_slots_initialized = 0;
}
#if defined(MBEDTLS_PSA_KEY_STORE_DYNAMIC)
static psa_status_t psa_allocate_volatile_key_slot(psa_key_id_t *key_id,
psa_key_slot_t **p_slot)
{
size_t slice_idx;
for (slice_idx = 0; slice_idx < KEY_SLOT_VOLATILE_SLICE_COUNT; slice_idx++) {
if (global_data.first_free_slot_index[slice_idx] != FREE_SLOT_INDEX_NONE) {
break;
}
}
if (slice_idx == KEY_SLOT_VOLATILE_SLICE_COUNT) {
return PSA_ERROR_INSUFFICIENT_MEMORY;
}
if (global_data.key_slices[slice_idx] == NULL) {
global_data.key_slices[slice_idx] =
mbedtls_calloc(key_slice_length(slice_idx),
sizeof(psa_key_slot_t));
if (global_data.key_slices[slice_idx] == NULL) {
return PSA_ERROR_INSUFFICIENT_MEMORY;
}
}
psa_key_slot_t *slice = global_data.key_slices[slice_idx];
size_t slot_idx = global_data.first_free_slot_index[slice_idx];
*key_id = volatile_key_id_of_index(slice_idx, slot_idx);
psa_key_slot_t *slot = &slice[slot_idx];
size_t next_free = slot_idx + 1 + slot->var.free.next_free_relative_to_next;
if (next_free >= key_slice_length(slice_idx)) {
next_free = FREE_SLOT_INDEX_NONE;
}
global_data.first_free_slot_index[slice_idx] = next_free;
/* The .next_free field is not meaningful when the slot is not free,
* so give it the same content as freshly initialized memory. */
slot->var.free.next_free_relative_to_next = 0;
psa_status_t status = psa_key_slot_state_transition(slot,
PSA_SLOT_EMPTY,
PSA_SLOT_FILLING);
if (status != PSA_SUCCESS) {
/* The only reason for failure is if the slot state was not empty.
* This indicates that something has gone horribly wrong.
* In this case, we leave the slot out of the free list, and stop
* modifying it. This minimizes any further corruption. The slot
* is a memory leak, but that's a lesser evil. */
return status;
}
*p_slot = slot;
/* We assert at compile time that the slice index fits in uint8_t. */
slot->slice_index = (uint8_t) slice_idx;
return PSA_SUCCESS;
}
psa_status_t psa_free_key_slot(size_t slice_idx,
psa_key_slot_t *slot)
{
if (slice_idx == KEY_SLOT_CACHE_SLICE_INDEX) {
/* This is a cache entry. We don't maintain a free list, so
* there's nothing to do. */
return PSA_SUCCESS;
}
if (slice_idx >= KEY_SLOT_VOLATILE_SLICE_COUNT) {
return PSA_ERROR_CORRUPTION_DETECTED;
}
psa_key_slot_t *slice = global_data.key_slices[slice_idx];
psa_key_slot_t *slice_end = slice + key_slice_length(slice_idx);
if (slot < slice || slot >= slice_end) {
/* The slot isn't actually in the slice! We can't detect that
* condition for sure, because the pointer comparison itself is
* undefined behavior in that case. That same condition makes the
* subtraction to calculate the slot index also UB.
* Give up now to avoid causing further corruption.
*/
return PSA_ERROR_CORRUPTION_DETECTED;
}
size_t slot_idx = slot - slice;
size_t next_free = global_data.first_free_slot_index[slice_idx];
if (next_free >= key_slice_length(slice_idx)) {
/* The slot was full. The newly freed slot thus becomes the
* end of the free list. */
next_free = key_slice_length(slice_idx);
}
global_data.first_free_slot_index[slice_idx] = slot_idx;
slot->var.free.next_free_relative_to_next =
(int32_t) next_free - (int32_t) slot_idx - 1;
return PSA_SUCCESS;
}
#endif /* MBEDTLS_PSA_KEY_STORE_DYNAMIC */
psa_status_t psa_reserve_free_key_slot(psa_key_id_t *volatile_key_id,
psa_key_slot_t **p_slot)
{
psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
size_t slot_idx;
psa_key_slot_t *selected_slot, *unused_persistent_key_slot;
if (!psa_get_key_slots_initialized()) {
status = PSA_ERROR_BAD_STATE;
goto error;
}
#if defined(MBEDTLS_PSA_KEY_STORE_DYNAMIC)
if (volatile_key_id != NULL) {
return psa_allocate_volatile_key_slot(volatile_key_id, p_slot);
}
#endif /* MBEDTLS_PSA_KEY_STORE_DYNAMIC */
/* With a dynamic key store, allocate an entry in the cache slice,
* applicable only to non-volatile keys that get cached in RAM.
* With a static key store, allocate an entry in the sole slice,
* applicable to all keys. */
selected_slot = unused_persistent_key_slot = NULL;
for (slot_idx = 0; slot_idx < PERSISTENT_KEY_CACHE_COUNT; slot_idx++) {
psa_key_slot_t *slot = get_key_slot(KEY_SLOT_CACHE_SLICE_INDEX, slot_idx);
if (slot->state == PSA_SLOT_EMPTY) {
selected_slot = slot;
break;
}
if ((unused_persistent_key_slot == NULL) &&
(slot->state == PSA_SLOT_FULL) &&
(!psa_key_slot_has_readers(slot)) &&
(!PSA_KEY_LIFETIME_IS_VOLATILE(slot->attr.lifetime))) {
unused_persistent_key_slot = slot;
}
}
/*
* If there is no unused key slot and there is at least one unlocked key
* slot containing the description of a persistent key, recycle the first
* such key slot we encountered. If we later need to operate on the
* persistent key we are evicting now, we will reload its description from
* storage.
*/
if ((selected_slot == NULL) &&
(unused_persistent_key_slot != NULL)) {
selected_slot = unused_persistent_key_slot;
psa_register_read(selected_slot);
status = psa_wipe_key_slot(selected_slot);
if (status != PSA_SUCCESS) {
goto error;
}
}
if (selected_slot != NULL) {
status = psa_key_slot_state_transition(selected_slot, PSA_SLOT_EMPTY,
PSA_SLOT_FILLING);
if (status != PSA_SUCCESS) {
goto error;
}
#if defined(MBEDTLS_PSA_KEY_STORE_DYNAMIC)
selected_slot->slice_index = KEY_SLOT_CACHE_SLICE_INDEX;
#endif /* MBEDTLS_PSA_KEY_STORE_DYNAMIC */
#if !defined(MBEDTLS_PSA_KEY_STORE_DYNAMIC)
if (volatile_key_id != NULL) {
/* Refresh slot_idx, for when the slot is not the original
* selected_slot but rather unused_persistent_key_slot. */
slot_idx = selected_slot - global_data.key_slots;
*volatile_key_id = PSA_KEY_ID_VOLATILE_MIN + (psa_key_id_t) slot_idx;
}
#endif
*p_slot = selected_slot;
return PSA_SUCCESS;
}
status = PSA_ERROR_INSUFFICIENT_MEMORY;
error:
*p_slot = NULL;
return status;
}
#if defined(MBEDTLS_PSA_CRYPTO_STORAGE_C)
static psa_status_t psa_load_persistent_key_into_slot(psa_key_slot_t *slot)
{
psa_status_t status = PSA_SUCCESS;
uint8_t *key_data = NULL;
size_t key_data_length = 0;
if (!psa_key_id_is_user(MBEDTLS_SVC_KEY_ID_GET_KEY_ID(slot->attr.id))) {
return PSA_ERROR_DOES_NOT_EXIST;
}
status = psa_load_persistent_key(&slot->attr,
&key_data, &key_data_length);
if (status != PSA_SUCCESS) {
goto exit;
}
status = psa_copy_key_material_into_slot(slot, key_data, key_data_length);
if (status != PSA_SUCCESS) {
goto exit;
}
exit:
psa_free_persistent_key_data(key_data, key_data_length);
return status;
}
#endif /* MBEDTLS_PSA_CRYPTO_STORAGE_C */
#if defined(MBEDTLS_PSA_CRYPTO_BUILTIN_KEYS)
static psa_status_t psa_load_builtin_key_into_slot(psa_key_slot_t *slot)
{
psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
psa_key_lifetime_t lifetime = PSA_KEY_LIFETIME_VOLATILE;
psa_drv_slot_number_t slot_number = 0;
size_t key_buffer_size = 0;
size_t key_buffer_length = 0;
if (!psa_key_id_is_builtin(
MBEDTLS_SVC_KEY_ID_GET_KEY_ID(slot->attr.id))) {
return PSA_ERROR_DOES_NOT_EXIST;
}
/* Check the platform function to see whether this key actually exists */
status = mbedtls_psa_platform_get_builtin_key(
slot->attr.id, &lifetime, &slot_number);
if (status != PSA_SUCCESS) {
return status;
}
/* Set required key attributes to ensure get_builtin_key can retrieve the
* full attributes. */
psa_set_key_id(&attributes, slot->attr.id);
psa_set_key_lifetime(&attributes, lifetime);
/* Get the full key attributes from the driver in order to be able to
* calculate the required buffer size. */
status = psa_driver_wrapper_get_builtin_key(
slot_number, &attributes,
NULL, 0, NULL);
if (status != PSA_ERROR_BUFFER_TOO_SMALL) {
/* Builtin keys cannot be defined by the attributes alone */
if (status == PSA_SUCCESS) {
status = PSA_ERROR_CORRUPTION_DETECTED;
}
return status;
}
/* If the key should exist according to the platform, then ask the driver
* what its expected size is. */
status = psa_driver_wrapper_get_key_buffer_size(&attributes,
&key_buffer_size);
if (status != PSA_SUCCESS) {
return status;
}
/* Allocate a buffer of the required size and load the builtin key directly
* into the (now properly sized) slot buffer. */
status = psa_allocate_buffer_to_slot(slot, key_buffer_size);
if (status != PSA_SUCCESS) {
return status;
}
status = psa_driver_wrapper_get_builtin_key(
slot_number, &attributes,
slot->key.data, slot->key.bytes, &key_buffer_length);
if (status != PSA_SUCCESS) {
goto exit;
}
/* Copy actual key length and core attributes into the slot on success */
slot->key.bytes = key_buffer_length;
slot->attr = attributes;
exit:
if (status != PSA_SUCCESS) {
psa_remove_key_data_from_memory(slot);
}
return status;
}
#endif /* MBEDTLS_PSA_CRYPTO_BUILTIN_KEYS */
psa_status_t psa_get_and_lock_key_slot(mbedtls_svc_key_id_t key,
psa_key_slot_t **p_slot)
{
psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
*p_slot = NULL;
if (!psa_get_key_slots_initialized()) {
return PSA_ERROR_BAD_STATE;
}
#if defined(MBEDTLS_THREADING_C)
/* We need to set status as success, otherwise CORRUPTION_DETECTED
* would be returned if the lock fails. */
status = PSA_SUCCESS;
/* If the key is persistent and not loaded, we cannot unlock the mutex
* between checking if the key is loaded and setting the slot as FULL,
* as otherwise another thread may load and then destroy the key
* in the meantime. */
PSA_THREADING_CHK_RET(mbedtls_mutex_lock(
&mbedtls_threading_key_slot_mutex));
#endif
/*
* On success, the pointer to the slot is passed directly to the caller
* thus no need to unlock the key slot here.
*/
status = psa_get_and_lock_key_slot_in_memory(key, p_slot);
if (status != PSA_ERROR_DOES_NOT_EXIST) {
#if defined(MBEDTLS_THREADING_C)
PSA_THREADING_CHK_RET(mbedtls_mutex_unlock(
&mbedtls_threading_key_slot_mutex));
#endif
return status;
}
/* Loading keys from storage requires support for such a mechanism */
#if defined(MBEDTLS_PSA_CRYPTO_STORAGE_C) || \
defined(MBEDTLS_PSA_CRYPTO_BUILTIN_KEYS)
status = psa_reserve_free_key_slot(NULL, p_slot);
if (status != PSA_SUCCESS) {
#if defined(MBEDTLS_THREADING_C)
PSA_THREADING_CHK_RET(mbedtls_mutex_unlock(
&mbedtls_threading_key_slot_mutex));
#endif
return status;
}
(*p_slot)->attr.id = key;
(*p_slot)->attr.lifetime = PSA_KEY_LIFETIME_PERSISTENT;
status = PSA_ERROR_DOES_NOT_EXIST;
#if defined(MBEDTLS_PSA_CRYPTO_BUILTIN_KEYS)
/* Load keys in the 'builtin' range through their own interface */
status = psa_load_builtin_key_into_slot(*p_slot);
#endif /* MBEDTLS_PSA_CRYPTO_BUILTIN_KEYS */
#if defined(MBEDTLS_PSA_CRYPTO_STORAGE_C)
if (status == PSA_ERROR_DOES_NOT_EXIST) {
status = psa_load_persistent_key_into_slot(*p_slot);
}
#endif /* defined(MBEDTLS_PSA_CRYPTO_STORAGE_C) */
if (status != PSA_SUCCESS) {
psa_wipe_key_slot(*p_slot);
/* If the key does not exist, we need to return
* PSA_ERROR_INVALID_HANDLE. */
if (status == PSA_ERROR_DOES_NOT_EXIST) {
status = PSA_ERROR_INVALID_HANDLE;
}
} else {
/* Add implicit usage flags. */
psa_extend_key_usage_flags(&(*p_slot)->attr.policy.usage);
psa_key_slot_state_transition((*p_slot), PSA_SLOT_FILLING,
PSA_SLOT_FULL);
status = psa_register_read(*p_slot);
}
#else /* MBEDTLS_PSA_CRYPTO_STORAGE_C || MBEDTLS_PSA_CRYPTO_BUILTIN_KEYS */
status = PSA_ERROR_INVALID_HANDLE;
#endif /* MBEDTLS_PSA_CRYPTO_STORAGE_C || MBEDTLS_PSA_CRYPTO_BUILTIN_KEYS */
if (status != PSA_SUCCESS) {
*p_slot = NULL;
}
#if defined(MBEDTLS_THREADING_C)
PSA_THREADING_CHK_RET(mbedtls_mutex_unlock(
&mbedtls_threading_key_slot_mutex));
#endif
return status;
}
psa_status_t psa_unregister_read(psa_key_slot_t *slot)
{
if (slot == NULL) {
return PSA_SUCCESS;
}
if ((slot->state != PSA_SLOT_FULL) &&
(slot->state != PSA_SLOT_PENDING_DELETION)) {
return PSA_ERROR_CORRUPTION_DETECTED;
}
/* If we are the last reader and the slot is marked for deletion,
* we must wipe the slot here. */
if ((slot->state == PSA_SLOT_PENDING_DELETION) &&
(slot->var.occupied.registered_readers == 1)) {
return psa_wipe_key_slot(slot);
}
if (psa_key_slot_has_readers(slot)) {
slot->var.occupied.registered_readers--;
return PSA_SUCCESS;
}
/*
* As the return error code may not be handled in case of multiple errors,
* do our best to report if there are no registered readers. Assert with
* MBEDTLS_TEST_HOOK_TEST_ASSERT that there are registered readers:
* if the MBEDTLS_TEST_HOOKS configuration option is enabled and
* the function is called as part of the execution of a test suite, the
* execution of the test suite is stopped in error if the assertion fails.
*/
MBEDTLS_TEST_HOOK_TEST_ASSERT(psa_key_slot_has_readers(slot));
return PSA_ERROR_CORRUPTION_DETECTED;
}
psa_status_t psa_unregister_read_under_mutex(psa_key_slot_t *slot)
{
psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
#if defined(MBEDTLS_THREADING_C)
/* We need to set status as success, otherwise CORRUPTION_DETECTED
* would be returned if the lock fails. */
status = PSA_SUCCESS;
PSA_THREADING_CHK_RET(mbedtls_mutex_lock(
&mbedtls_threading_key_slot_mutex));
#endif
status = psa_unregister_read(slot);
#if defined(MBEDTLS_THREADING_C)
PSA_THREADING_CHK_RET(mbedtls_mutex_unlock(
&mbedtls_threading_key_slot_mutex));
#endif
return status;
}
psa_status_t psa_validate_key_persistence(psa_key_lifetime_t lifetime)
{
if (PSA_KEY_LIFETIME_IS_VOLATILE(lifetime)) {
/* Volatile keys are always supported */
return PSA_SUCCESS;
} else {
/* Persistent keys require storage support */
#if defined(MBEDTLS_PSA_CRYPTO_STORAGE_C)
if (PSA_KEY_LIFETIME_IS_READ_ONLY(lifetime)) {
return PSA_ERROR_INVALID_ARGUMENT;
} else {
return PSA_SUCCESS;
}
#else /* MBEDTLS_PSA_CRYPTO_STORAGE_C */
return PSA_ERROR_NOT_SUPPORTED;
#endif /* !MBEDTLS_PSA_CRYPTO_STORAGE_C */
}
}
psa_status_t psa_purge_key(mbedtls_svc_key_id_t key)
{
psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
psa_key_slot_t *slot;
#if defined(MBEDTLS_THREADING_C)
/* We need to set status as success, otherwise CORRUPTION_DETECTED
* would be returned if the lock fails. */
status = PSA_SUCCESS;
PSA_THREADING_CHK_RET(mbedtls_mutex_lock(
&mbedtls_threading_key_slot_mutex));
#endif
status = psa_get_and_lock_key_slot_in_memory(key, &slot);
if (status != PSA_SUCCESS) {
#if defined(MBEDTLS_THREADING_C)
PSA_THREADING_CHK_RET(mbedtls_mutex_unlock(
&mbedtls_threading_key_slot_mutex));
#endif
return status;
}
if ((!PSA_KEY_LIFETIME_IS_VOLATILE(slot->attr.lifetime)) &&
(slot->var.occupied.registered_readers == 1)) {
status = psa_wipe_key_slot(slot);
} else {
status = psa_unregister_read(slot);
}
#if defined(MBEDTLS_THREADING_C)
PSA_THREADING_CHK_RET(mbedtls_mutex_unlock(
&mbedtls_threading_key_slot_mutex));
#endif
return status;
}
void mbedtls_psa_get_stats(mbedtls_psa_stats_t *stats)
{
memset(stats, 0, sizeof(*stats));
for (size_t slice_idx = 0; slice_idx < KEY_SLICE_COUNT; slice_idx++) {
#if defined(MBEDTLS_PSA_KEY_STORE_DYNAMIC)
if (global_data.key_slices[slice_idx] == NULL) {
continue;
}
#endif /* MBEDTLS_PSA_KEY_STORE_DYNAMIC */
for (size_t slot_idx = 0; slot_idx < key_slice_length(slice_idx); slot_idx++) {
const psa_key_slot_t *slot = get_key_slot(slice_idx, slot_idx);
if (slot->state == PSA_SLOT_EMPTY) {
++stats->empty_slots;
continue;
}
if (psa_key_slot_has_readers(slot)) {
++stats->locked_slots;
}
if (PSA_KEY_LIFETIME_IS_VOLATILE(slot->attr.lifetime)) {
++stats->volatile_slots;
} else {
psa_key_id_t id = MBEDTLS_SVC_KEY_ID_GET_KEY_ID(slot->attr.id);
++stats->persistent_slots;
if (id > stats->max_open_internal_key_id) {
stats->max_open_internal_key_id = id;
}
}
if (PSA_KEY_LIFETIME_GET_LOCATION(slot->attr.lifetime) !=
PSA_KEY_LOCATION_LOCAL_STORAGE) {
psa_key_id_t id = MBEDTLS_SVC_KEY_ID_GET_KEY_ID(slot->attr.id);
++stats->external_slots;
if (id > stats->max_open_external_key_id) {
stats->max_open_external_key_id = id;
}
}
}
}
}
#endif /* MBEDTLS_PSA_CRYPTO_C */
@@ -0,0 +1,330 @@
/*
* PSA crypto layer on top of Mbed TLS crypto
*/
/*
* Copyright The Mbed TLS Contributors
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
*/
#ifndef TF_PSA_CRYPTO_PSA_CRYPTO_SLOT_MANAGEMENT_H
#define TF_PSA_CRYPTO_PSA_CRYPTO_SLOT_MANAGEMENT_H
#include "psa/crypto.h"
#include "psa_crypto_core.h"
/** Range of volatile key identifiers.
*
* The first #MBEDTLS_PSA_KEY_SLOT_COUNT identifiers of the implementation
* range of key identifiers are reserved for volatile key identifiers.
*
* If \c id is a a volatile key identifier, #PSA_KEY_ID_VOLATILE_MIN - \c id
* indicates the key slot containing the volatile key definition. See
* psa_crypto_slot_management.c for details.
*/
/** The minimum value for a volatile key identifier.
*/
#define PSA_KEY_ID_VOLATILE_MIN PSA_KEY_ID_VENDOR_MIN
/** The maximum value for a volatile key identifier.
*/
#if defined(MBEDTLS_PSA_KEY_STORE_DYNAMIC)
#define PSA_KEY_ID_VOLATILE_MAX (MBEDTLS_PSA_KEY_ID_BUILTIN_MIN - 1)
#else /* MBEDTLS_PSA_KEY_STORE_DYNAMIC */
#define PSA_KEY_ID_VOLATILE_MAX \
(PSA_KEY_ID_VOLATILE_MIN + MBEDTLS_PSA_KEY_SLOT_COUNT - 1)
#endif /* MBEDTLS_PSA_KEY_STORE_DYNAMIC */
/** Test whether a key identifier is a volatile key identifier.
*
* \param key_id Key identifier to test.
*
* \retval 1
* The key identifier is a volatile key identifier.
* \retval 0
* The key identifier is not a volatile key identifier.
*/
static inline int psa_key_id_is_volatile(psa_key_id_t key_id)
{
return (key_id >= PSA_KEY_ID_VOLATILE_MIN) &&
(key_id <= PSA_KEY_ID_VOLATILE_MAX);
}
/** Get the description of a key given its identifier and lock it.
*
* The descriptions of volatile keys and loaded persistent keys are stored in
* key slots. This function returns a pointer to the key slot containing the
* description of a key given its identifier.
*
* In case of a persistent key, the function loads the description of the key
* into a key slot if not already done.
*
* On success, the returned key slot has been registered for reading.
* It is the responsibility of the caller to call psa_unregister_read(slot)
* when they have finished reading the contents of the slot.
*
* On failure, `*p_slot` is set to NULL. This ensures that it is always valid
* to call psa_unregister_read on the returned slot.
*
* \param key Key identifier to query.
* \param[out] p_slot On success, `*p_slot` contains a pointer to the
* key slot containing the description of the key
* identified by \p key.
*
* \retval #PSA_SUCCESS
* \p *p_slot contains a pointer to the key slot containing the
* description of the key identified by \p key.
* The key slot counter has been incremented.
* \retval #PSA_ERROR_BAD_STATE
* The library has not been initialized.
* \retval #PSA_ERROR_INVALID_HANDLE
* \p key is not a valid key identifier.
* \retval #PSA_ERROR_INSUFFICIENT_MEMORY
* \p key is a persistent key identifier. The implementation does not
* have sufficient resources to load the persistent key. This can be
* due to a lack of empty key slot, or available memory.
* \retval #PSA_ERROR_DOES_NOT_EXIST
* There is no key with key identifier \p key.
* \retval #PSA_ERROR_CORRUPTION_DETECTED \emptydescription
* \retval #PSA_ERROR_STORAGE_FAILURE \emptydescription
* \retval #PSA_ERROR_DATA_CORRUPT \emptydescription
*/
psa_status_t psa_get_and_lock_key_slot(mbedtls_svc_key_id_t key,
psa_key_slot_t **p_slot);
/** Initialize the key slot structures.
*
* \retval #PSA_SUCCESS
* Currently this function always succeeds.
*/
psa_status_t psa_initialize_key_slots(void);
#if defined(MBEDTLS_TEST_HOOKS) && defined(MBEDTLS_PSA_KEY_STORE_DYNAMIC)
/* Allow test code to customize the key slice length. We use this in tests
* that exhaust the key store to reach a full key store in reasonable time
* and memory.
*
* The length of each slice must be between 1 and
* (1 << KEY_ID_SLOT_INDEX_WIDTH) inclusive.
*
* The length for a given slice index must not change while
* the key store is initialized.
*/
extern size_t (*mbedtls_test_hook_psa_volatile_key_slice_length)(
size_t slice_idx);
/* The number of volatile key slices. */
size_t psa_key_slot_volatile_slice_count(void);
#endif
/** Delete all data from key slots in memory.
* This function is not thread safe, it wipes every key slot regardless of
* state and reader count. It should only be called when no slot is in use.
*
* This does not affect persistent storage. */
void psa_wipe_all_key_slots(void);
/** Find a free key slot and reserve it to be filled with a key.
*
* This function finds a key slot that is free,
* sets its state to PSA_SLOT_FILLING and then returns the slot.
*
* On success, the key slot's state is PSA_SLOT_FILLING.
* It is the responsibility of the caller to change the slot's state to
* PSA_SLOT_EMPTY/FULL once key creation has finished.
*
* If multi-threading is enabled, the caller must hold the
* global key slot mutex.
*
* \param[out] volatile_key_id - If null, reserve a cache slot for
* a persistent or built-in key.
* - If non-null, allocate a slot for
* a volatile key. On success,
* \p *volatile_key_id is the
* identifier corresponding to the
* returned slot. It is the caller's
* responsibility to set this key identifier
* in the attributes.
* \param[out] p_slot On success, a pointer to the slot.
*
* \retval #PSA_SUCCESS \emptydescription
* \retval #PSA_ERROR_INSUFFICIENT_MEMORY
* There were no free key slots.
* When #MBEDTLS_PSA_KEY_STORE_DYNAMIC is enabled, there was not
* enough memory to allocate more slots.
* \retval #PSA_ERROR_BAD_STATE \emptydescription
* \retval #PSA_ERROR_CORRUPTION_DETECTED
* This function attempted to operate on a key slot which was in an
* unexpected state.
*/
psa_status_t psa_reserve_free_key_slot(psa_key_id_t *volatile_key_id,
psa_key_slot_t **p_slot);
#if defined(MBEDTLS_PSA_KEY_STORE_DYNAMIC)
/** Return a key slot to the free list.
*
* Call this function when a slot obtained from psa_reserve_free_key_slot()
* is no longer in use.
*
* If multi-threading is enabled, the caller must hold the
* global key slot mutex.
*
* \param slice_idx The slice containing the slot.
* This is `slot->slice_index` when the slot
* is obtained from psa_reserve_free_key_slot().
* \param slot The key slot.
*
* \retval #PSA_SUCCESS \emptydescription
* \retval #PSA_ERROR_CORRUPTION_DETECTED
* This function attempted to operate on a key slot which was in an
* unexpected state.
*/
psa_status_t psa_free_key_slot(size_t slice_idx,
psa_key_slot_t *slot);
#endif /* MBEDTLS_PSA_KEY_STORE_DYNAMIC */
/** Change the state of a key slot.
*
* This function changes the state of the key slot from expected_state to
* new state. If the state of the slot was not expected_state, the state is
* unchanged.
*
* If multi-threading is enabled, the caller must hold the
* global key slot mutex.
*
* \param[in] slot The key slot.
* \param[in] expected_state The current state of the slot.
* \param[in] new_state The new state of the slot.
*
* \retval #PSA_SUCCESS
The key slot's state variable is new_state.
* \retval #PSA_ERROR_CORRUPTION_DETECTED
* The slot's state was not expected_state.
*/
static inline psa_status_t psa_key_slot_state_transition(
psa_key_slot_t *slot, psa_key_slot_state_t expected_state,
psa_key_slot_state_t new_state)
{
if (slot->state != expected_state) {
return PSA_ERROR_CORRUPTION_DETECTED;
}
slot->state = new_state;
return PSA_SUCCESS;
}
/** Register as a reader of a key slot.
*
* This function increments the key slot registered reader counter by one.
* If multi-threading is enabled, the caller must hold the
* global key slot mutex.
*
* \param[in] slot The key slot.
*
* \retval #PSA_SUCCESS
The key slot registered reader counter was incremented.
* \retval #PSA_ERROR_CORRUPTION_DETECTED
* The reader counter already reached its maximum value and was not
* increased, or the slot's state was not PSA_SLOT_FULL.
*/
static inline psa_status_t psa_register_read(psa_key_slot_t *slot)
{
if ((slot->state != PSA_SLOT_FULL) ||
(slot->var.occupied.registered_readers >= SIZE_MAX)) {
return PSA_ERROR_CORRUPTION_DETECTED;
}
slot->var.occupied.registered_readers++;
return PSA_SUCCESS;
}
/** Unregister from reading a key slot.
*
* This function decrements the key slot registered reader counter by one.
* If the state of the slot is PSA_SLOT_PENDING_DELETION,
* and there is only one registered reader (the caller),
* this function will call psa_wipe_key_slot().
* If multi-threading is enabled, the caller must hold the
* global key slot mutex.
*
* \note To ease the handling of errors in retrieving a key slot
* a NULL input pointer is valid, and the function returns
* successfully without doing anything in that case.
*
* \param[in] slot The key slot.
* \retval #PSA_SUCCESS
* \p slot is NULL or the key slot reader counter has been
* decremented (and potentially wiped) successfully.
* \retval #PSA_ERROR_CORRUPTION_DETECTED
* The slot's state was neither PSA_SLOT_FULL nor
* PSA_SLOT_PENDING_DELETION.
* Or a wipe was attempted and the slot's state was not
* PSA_SLOT_PENDING_DELETION.
* Or registered_readers was equal to 0.
*/
psa_status_t psa_unregister_read(psa_key_slot_t *slot);
/** Wrap a call to psa_unregister_read in the global key slot mutex.
*
* If threading is disabled, this simply calls psa_unregister_read.
*
* \note To ease the handling of errors in retrieving a key slot
* a NULL input pointer is valid, and the function returns
* successfully without doing anything in that case.
*
* \param[in] slot The key slot.
* \retval #PSA_SUCCESS
* \p slot is NULL or the key slot reader counter has been
* decremented (and potentially wiped) successfully.
* \retval #PSA_ERROR_CORRUPTION_DETECTED
* The slot's state was neither PSA_SLOT_FULL nor
* PSA_SLOT_PENDING_DELETION.
* Or a wipe was attempted and the slot's state was not
* PSA_SLOT_PENDING_DELETION.
* Or registered_readers was equal to 0.
*/
psa_status_t psa_unregister_read_under_mutex(psa_key_slot_t *slot);
/** Test whether a lifetime designates a key in an external cryptoprocessor.
*
* \param lifetime The lifetime to test.
*
* \retval 1
* The lifetime designates an external key. There should be a
* registered driver for this lifetime, otherwise the key cannot
* be created or manipulated.
* \retval 0
* The lifetime designates a key that is volatile or in internal
* storage.
*/
static inline int psa_key_lifetime_is_external(psa_key_lifetime_t lifetime)
{
return PSA_KEY_LIFETIME_GET_LOCATION(lifetime)
!= PSA_KEY_LOCATION_LOCAL_STORAGE;
}
/** Validate the persistence of a key.
*
* \param[in] lifetime The key lifetime attribute.
*
* \retval #PSA_SUCCESS \emptydescription
* \retval #PSA_ERROR_NOT_SUPPORTED The key is persistent but persistent keys
* are not supported.
*/
psa_status_t psa_validate_key_persistence(psa_key_lifetime_t lifetime);
/** Test whether a key identifier belongs to the user key range.
*
* \param key_id Key identifier to test.
*
* \retval 1
* The key identifier is a user key identifier.
* \retval 0
* The key identifier is not a user key identifier.
*/
static inline int psa_key_id_is_user(psa_key_id_t key_id)
{
return (key_id >= PSA_KEY_ID_USER_MIN) &&
(key_id <= PSA_KEY_ID_USER_MAX);
}
#endif /* TF_PSA_CRYPTO_PSA_CRYPTO_SLOT_MANAGEMENT_H */
+400
View File
@@ -0,0 +1,400 @@
/*
* PSA persistent key storage
*/
/*
* Copyright The Mbed TLS Contributors
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
*/
#include "tf_psa_crypto_common.h"
#if defined(MBEDTLS_PSA_CRYPTO_STORAGE_C)
#include <stdlib.h>
#include <string.h>
#include "psa/crypto.h"
#include "psa_crypto_storage.h"
#include "mbedtls/platform_util.h"
#if defined(MBEDTLS_PSA_ITS_FILE_C)
#include "psa_crypto_its.h"
#else /* Native ITS implementation */
#include "psa/error.h"
#include "psa/internal_trusted_storage.h"
#endif
#include "mbedtls/platform.h"
/****************************************************************/
/* Key storage */
/****************************************************************/
/* Determine a file name (ITS file identifier) for the given key identifier.
* The file name must be distinct from any file that is used for a purpose
* other than storing a key. Currently, the only such file is the random seed
* file whose name is PSA_CRYPTO_ITS_RANDOM_SEED_UID and whose value is
* 0xFFFFFF52. */
static psa_storage_uid_t psa_its_identifier_of_slot(mbedtls_svc_key_id_t key)
{
#if defined(MBEDTLS_PSA_CRYPTO_KEY_ID_ENCODES_OWNER)
/* Encode the owner in the upper 32 bits. This means that if
* owner values are nonzero (as they are on a PSA platform),
* no key file will ever have a value less than 0x100000000, so
* the whole range 0..0xffffffff is available for non-key files. */
uint32_t unsigned_owner_id = MBEDTLS_SVC_KEY_ID_GET_OWNER_ID(key);
return ((uint64_t) unsigned_owner_id << 32) |
MBEDTLS_SVC_KEY_ID_GET_KEY_ID(key);
#else
/* Use the key id directly as a file name.
* psa_is_key_id_valid() in psa_crypto_slot_management.c
* is responsible for ensuring that key identifiers do not have a
* value that is reserved for non-key files. */
return key;
#endif
}
/**
* \brief Load persistent data for the given key slot number.
*
* This function reads data from a storage backend and returns the data in a
* buffer.
*
* \param key Persistent identifier of the key to be loaded. This
* should be an occupied storage location.
* \param[out] data Buffer where the data is to be written.
* \param data_size Size of the \c data buffer in bytes.
*
* \retval #PSA_SUCCESS \emptydescription
* \retval #PSA_ERROR_DATA_INVALID \emptydescription
* \retval #PSA_ERROR_DATA_CORRUPT \emptydescription
* \retval #PSA_ERROR_STORAGE_FAILURE \emptydescription
* \retval #PSA_ERROR_DOES_NOT_EXIST \emptydescription
*/
static psa_status_t psa_crypto_storage_load(
const mbedtls_svc_key_id_t key, uint8_t *data, size_t data_size)
{
psa_status_t status;
psa_storage_uid_t data_identifier = psa_its_identifier_of_slot(key);
struct psa_storage_info_t data_identifier_info;
size_t data_length = 0;
status = psa_its_get_info(data_identifier, &data_identifier_info);
if (status != PSA_SUCCESS) {
return status;
}
status = psa_its_get(data_identifier, 0, (uint32_t) data_size, data, &data_length);
if (data_size != data_length) {
return PSA_ERROR_DATA_INVALID;
}
return status;
}
int psa_is_key_present_in_storage(const mbedtls_svc_key_id_t key)
{
psa_status_t ret;
psa_storage_uid_t data_identifier = psa_its_identifier_of_slot(key);
struct psa_storage_info_t data_identifier_info;
ret = psa_its_get_info(data_identifier, &data_identifier_info);
if (ret == PSA_ERROR_DOES_NOT_EXIST) {
return 0;
}
return 1;
}
/**
* \brief Store persistent data for the given key slot number.
*
* This function stores the given data buffer to a persistent storage.
*
* \param key Persistent identifier of the key to be stored. This
* should be an unoccupied storage location.
* \param[in] data Buffer containing the data to be stored.
* \param data_length The number of bytes
* that make up the data.
*
* \retval #PSA_SUCCESS \emptydescription
* \retval #PSA_ERROR_INSUFFICIENT_STORAGE \emptydescription
* \retval #PSA_ERROR_ALREADY_EXISTS \emptydescription
* \retval #PSA_ERROR_STORAGE_FAILURE \emptydescription
* \retval #PSA_ERROR_DATA_INVALID \emptydescription
*/
static psa_status_t psa_crypto_storage_store(const mbedtls_svc_key_id_t key,
const uint8_t *data,
size_t data_length)
{
psa_status_t status;
psa_storage_uid_t data_identifier = psa_its_identifier_of_slot(key);
struct psa_storage_info_t data_identifier_info;
if (psa_is_key_present_in_storage(key) == 1) {
return PSA_ERROR_ALREADY_EXISTS;
}
status = psa_its_set(data_identifier, (uint32_t) data_length, data, 0);
if (status != PSA_SUCCESS) {
return PSA_ERROR_DATA_INVALID;
}
status = psa_its_get_info(data_identifier, &data_identifier_info);
if (status != PSA_SUCCESS) {
goto exit;
}
if (data_identifier_info.size != data_length) {
status = PSA_ERROR_DATA_INVALID;
goto exit;
}
exit:
if (status != PSA_SUCCESS) {
/* Remove the file in case we managed to create it but something
* went wrong. It's ok if the file doesn't exist. If the file exists
* but the removal fails, we're already reporting an error so there's
* nothing else we can do. */
(void) psa_its_remove(data_identifier);
}
return status;
}
psa_status_t psa_destroy_persistent_key(const mbedtls_svc_key_id_t key)
{
psa_status_t ret;
psa_storage_uid_t data_identifier = psa_its_identifier_of_slot(key);
struct psa_storage_info_t data_identifier_info;
ret = psa_its_get_info(data_identifier, &data_identifier_info);
if (ret == PSA_ERROR_DOES_NOT_EXIST) {
return PSA_SUCCESS;
}
if (psa_its_remove(data_identifier) != PSA_SUCCESS) {
return PSA_ERROR_DATA_INVALID;
}
ret = psa_its_get_info(data_identifier, &data_identifier_info);
if (ret != PSA_ERROR_DOES_NOT_EXIST) {
return PSA_ERROR_DATA_INVALID;
}
return PSA_SUCCESS;
}
/**
* \brief Get data length for given key slot number.
*
* \param key Persistent identifier whose stored data length
* is to be obtained.
* \param[out] data_length The number of bytes that make up the data.
*
* \retval #PSA_SUCCESS \emptydescription
* \retval #PSA_ERROR_STORAGE_FAILURE \emptydescription
* \retval #PSA_ERROR_DOES_NOT_EXIST \emptydescription
* \retval #PSA_ERROR_DATA_CORRUPT \emptydescription
*/
static psa_status_t psa_crypto_storage_get_data_length(
const mbedtls_svc_key_id_t key,
size_t *data_length)
{
psa_status_t status;
psa_storage_uid_t data_identifier = psa_its_identifier_of_slot(key);
struct psa_storage_info_t data_identifier_info;
status = psa_its_get_info(data_identifier, &data_identifier_info);
if (status != PSA_SUCCESS) {
return status;
}
*data_length = (size_t) data_identifier_info.size;
return PSA_SUCCESS;
}
/**
* Persistent key storage magic header.
*/
#define PSA_KEY_STORAGE_MAGIC_HEADER "PSA\0KEY"
#define PSA_KEY_STORAGE_MAGIC_HEADER_LENGTH (sizeof(PSA_KEY_STORAGE_MAGIC_HEADER))
typedef struct {
uint8_t magic[PSA_KEY_STORAGE_MAGIC_HEADER_LENGTH];
uint8_t version[4];
uint8_t lifetime[sizeof(psa_key_lifetime_t)];
uint8_t type[2];
uint8_t bits[2];
uint8_t policy[sizeof(psa_key_policy_t)];
uint8_t data_len[4];
uint8_t key_data[];
} psa_persistent_key_storage_format;
void psa_format_key_data_for_storage(const uint8_t *data,
const size_t data_length,
const psa_key_attributes_t *attr,
uint8_t *storage_data)
{
psa_persistent_key_storage_format *storage_format =
(psa_persistent_key_storage_format *) storage_data;
memcpy(storage_format->magic, PSA_KEY_STORAGE_MAGIC_HEADER,
PSA_KEY_STORAGE_MAGIC_HEADER_LENGTH);
MBEDTLS_PUT_UINT32_LE(0, storage_format->version, 0);
MBEDTLS_PUT_UINT32_LE(attr->lifetime, storage_format->lifetime, 0);
MBEDTLS_PUT_UINT16_LE((uint16_t) attr->type, storage_format->type, 0);
MBEDTLS_PUT_UINT16_LE((uint16_t) attr->bits, storage_format->bits, 0);
MBEDTLS_PUT_UINT32_LE(attr->policy.usage, storage_format->policy, 0);
MBEDTLS_PUT_UINT32_LE(attr->policy.alg, storage_format->policy, sizeof(uint32_t));
MBEDTLS_PUT_UINT32_LE(attr->policy.alg2, storage_format->policy, 2 * sizeof(uint32_t));
MBEDTLS_PUT_UINT32_LE(data_length, storage_format->data_len, 0);
memcpy(storage_format->key_data, data, data_length);
}
static psa_status_t check_magic_header(const uint8_t *data)
{
if (memcmp(data, PSA_KEY_STORAGE_MAGIC_HEADER,
PSA_KEY_STORAGE_MAGIC_HEADER_LENGTH) != 0) {
return PSA_ERROR_DATA_INVALID;
}
return PSA_SUCCESS;
}
psa_status_t psa_parse_key_data_from_storage(const uint8_t *storage_data,
size_t storage_data_length,
uint8_t **key_data,
size_t *key_data_length,
psa_key_attributes_t *attr)
{
psa_status_t status;
const psa_persistent_key_storage_format *storage_format =
(const psa_persistent_key_storage_format *) storage_data;
uint32_t version;
if (storage_data_length < sizeof(*storage_format)) {
return PSA_ERROR_DATA_INVALID;
}
status = check_magic_header(storage_data);
if (status != PSA_SUCCESS) {
return status;
}
version = MBEDTLS_GET_UINT32_LE(storage_format->version, 0);
if (version != 0) {
return PSA_ERROR_DATA_INVALID;
}
*key_data_length = MBEDTLS_GET_UINT32_LE(storage_format->data_len, 0);
if (*key_data_length > (storage_data_length - sizeof(*storage_format)) ||
*key_data_length > PSA_CRYPTO_MAX_STORAGE_SIZE) {
return PSA_ERROR_DATA_INVALID;
}
if (*key_data_length == 0) {
*key_data = NULL;
} else {
*key_data = mbedtls_calloc(1, *key_data_length);
if (*key_data == NULL) {
return PSA_ERROR_INSUFFICIENT_MEMORY;
}
memcpy(*key_data, storage_format->key_data, *key_data_length);
}
attr->lifetime = MBEDTLS_GET_UINT32_LE(storage_format->lifetime, 0);
attr->type = MBEDTLS_GET_UINT16_LE(storage_format->type, 0);
attr->bits = MBEDTLS_GET_UINT16_LE(storage_format->bits, 0);
attr->policy.usage = MBEDTLS_GET_UINT32_LE(storage_format->policy, 0);
attr->policy.alg = MBEDTLS_GET_UINT32_LE(storage_format->policy, sizeof(uint32_t));
attr->policy.alg2 = MBEDTLS_GET_UINT32_LE(storage_format->policy, 2 * sizeof(uint32_t));
return PSA_SUCCESS;
}
psa_status_t psa_save_persistent_key(const psa_key_attributes_t *attr,
const uint8_t *data,
const size_t data_length)
{
size_t storage_data_length;
uint8_t *storage_data;
psa_status_t status;
/* All keys saved to persistent storage always have a key context */
if (data == NULL || data_length == 0) {
return PSA_ERROR_INVALID_ARGUMENT;
}
if (data_length > PSA_CRYPTO_MAX_STORAGE_SIZE) {
return PSA_ERROR_INSUFFICIENT_STORAGE;
}
storage_data_length = data_length + sizeof(psa_persistent_key_storage_format);
storage_data = mbedtls_calloc(1, storage_data_length);
if (storage_data == NULL) {
return PSA_ERROR_INSUFFICIENT_MEMORY;
}
psa_format_key_data_for_storage(data, data_length, attr, storage_data);
status = psa_crypto_storage_store(attr->id,
storage_data, storage_data_length);
mbedtls_zeroize_and_free(storage_data, storage_data_length);
return status;
}
void psa_free_persistent_key_data(uint8_t *key_data, size_t key_data_length)
{
mbedtls_zeroize_and_free(key_data, key_data_length);
}
psa_status_t psa_load_persistent_key(psa_key_attributes_t *attr,
uint8_t **data,
size_t *data_length)
{
psa_status_t status = PSA_SUCCESS;
uint8_t *loaded_data;
size_t storage_data_length = 0;
mbedtls_svc_key_id_t key = attr->id;
status = psa_crypto_storage_get_data_length(key, &storage_data_length);
if (status != PSA_SUCCESS) {
return status;
}
loaded_data = mbedtls_calloc(1, storage_data_length);
if (loaded_data == NULL) {
return PSA_ERROR_INSUFFICIENT_MEMORY;
}
status = psa_crypto_storage_load(key, loaded_data, storage_data_length);
if (status != PSA_SUCCESS) {
goto exit;
}
status = psa_parse_key_data_from_storage(loaded_data, storage_data_length,
data, data_length, attr);
/* All keys saved to persistent storage always have a key context */
if (status == PSA_SUCCESS &&
(*data == NULL || *data_length == 0)) {
status = PSA_ERROR_STORAGE_FAILURE;
}
exit:
mbedtls_zeroize_and_free(loaded_data, storage_data_length);
return status;
}
/****************************************************************/
/* The end */
/****************************************************************/
#endif /* MBEDTLS_PSA_CRYPTO_STORAGE_C */
+201
View File
@@ -0,0 +1,201 @@
/**
* \file psa_crypto_storage.h
*
* \brief PSA cryptography module: Mbed TLS key storage
*/
/*
* Copyright The Mbed TLS Contributors
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
*/
#ifndef TF_PSA_CRYPTO_PSA_CRYPTO_STORAGE_H
#define TF_PSA_CRYPTO_PSA_CRYPTO_STORAGE_H
#ifdef __cplusplus
extern "C" {
#endif
#include "psa/crypto.h"
#include <stdint.h>
#include <string.h>
/* Limit the maximum key size in storage. */
#if defined(MBEDTLS_PSA_STATIC_KEY_SLOTS)
/* Reflect the maximum size for the key buffer. */
#define PSA_CRYPTO_MAX_STORAGE_SIZE (MBEDTLS_PSA_STATIC_KEY_SLOT_BUFFER_SIZE)
#else
/* Just set an upper boundary but it should have no effect since the key size
* is limited in memory. */
#define PSA_CRYPTO_MAX_STORAGE_SIZE (PSA_BITS_TO_BYTES(PSA_MAX_KEY_BITS))
#endif
/* Sanity check: a file size must fit in 32 bits. Allow a generous
* 64kB of metadata. */
#if PSA_CRYPTO_MAX_STORAGE_SIZE > 0xffff0000
#error "PSA_CRYPTO_MAX_STORAGE_SIZE > 0xffff0000"
#endif
/** The maximum permitted persistent slot number.
*
* In Mbed Crypto 0.1.0b:
* - Using the file backend, all key ids are ok except 0.
* - Using the ITS backend, all key ids are ok except 0xFFFFFF52
* (#PSA_CRYPTO_ITS_RANDOM_SEED_UID) for which the file contains the
* device's random seed (if this feature is enabled).
* - Only key ids from 1 to #MBEDTLS_PSA_KEY_SLOT_COUNT are actually used.
*
* Since we need to preserve the random seed, avoid using that key slot.
* Reserve a whole range of key slots just in case something else comes up.
*
* This limitation will probably become moot when we implement client
* separation for key storage.
*/
#define PSA_MAX_PERSISTENT_KEY_IDENTIFIER PSA_KEY_ID_VENDOR_MAX
/**
* \brief Checks if persistent data is stored for the given key slot number
*
* This function checks if any key data or metadata exists for the key slot in
* the persistent storage.
*
* \param key Persistent identifier to check.
*
* \retval 0
* No persistent data present for slot number
* \retval 1
* Persistent data present for slot number
*/
int psa_is_key_present_in_storage(const mbedtls_svc_key_id_t key);
/**
* \brief Format key data and metadata and save to a location for given key
* slot.
*
* This function formats the key data and metadata and saves it to a
* persistent storage backend. The storage location corresponding to the
* key slot must be empty, otherwise this function will fail. This function
* should be called after loading the key into an internal slot to ensure the
* persistent key is not saved into a storage location corresponding to an
* already occupied non-persistent key, as well as ensuring the key data is
* validated.
*
* Note: This function will only succeed for key buffers which are not
* empty. If passed a NULL pointer or zero-length, the function will fail
* with #PSA_ERROR_INVALID_ARGUMENT.
*
* \param[in] attr The attributes of the key to save.
* The key identifier field in the attributes
* determines the key's location.
* \param[in] data Buffer containing the key data.
* \param data_length The number of bytes that make up the key data.
*
* \retval #PSA_SUCCESS \emptydescription
* \retval #PSA_ERROR_INVALID_ARGUMENT \emptydescription
* \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription
* \retval #PSA_ERROR_INSUFFICIENT_STORAGE \emptydescription
* \retval #PSA_ERROR_STORAGE_FAILURE \emptydescription
* \retval #PSA_ERROR_ALREADY_EXISTS \emptydescription
* \retval #PSA_ERROR_DATA_INVALID \emptydescription
* \retval #PSA_ERROR_DATA_CORRUPT \emptydescription
*/
psa_status_t psa_save_persistent_key(const psa_key_attributes_t *attr,
const uint8_t *data,
const size_t data_length);
/**
* \brief Parses key data and metadata and load persistent key for given
* key slot number.
*
* This function reads from a storage backend, parses the key data and
* metadata and writes them to the appropriate output parameters.
*
* Note: This function allocates a buffer and returns a pointer to it through
* the data parameter. On successful return, the pointer is guaranteed to be
* valid and the buffer contains at least one byte of data.
* psa_free_persistent_key_data() must be called on the data buffer
* afterwards to zeroize and free this buffer.
*
* \param[in,out] attr On input, the key identifier field identifies
* the key to load. Other fields are ignored.
* On success, the attribute structure contains
* the key metadata that was loaded from storage.
* \param[out] data Pointer to an allocated key data buffer on return.
* \param[out] data_length The number of bytes that make up the key data.
*
* \retval #PSA_SUCCESS \emptydescription
* \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription
* \retval #PSA_ERROR_DATA_INVALID \emptydescription
* \retval #PSA_ERROR_DATA_CORRUPT \emptydescription
* \retval #PSA_ERROR_DOES_NOT_EXIST \emptydescription
*/
psa_status_t psa_load_persistent_key(psa_key_attributes_t *attr,
uint8_t **data,
size_t *data_length);
/**
* \brief Remove persistent data for the given key slot number.
*
* \param key Persistent identifier of the key to remove
* from persistent storage.
*
* \retval #PSA_SUCCESS
* The key was successfully removed,
* or the key did not exist.
* \retval #PSA_ERROR_DATA_INVALID \emptydescription
*/
psa_status_t psa_destroy_persistent_key(const mbedtls_svc_key_id_t key);
/**
* \brief Free the temporary buffer allocated by psa_load_persistent_key().
*
* This function must be called at some point after psa_load_persistent_key()
* to zeroize and free the memory allocated to the buffer in that function.
*
* \param key_data Buffer for the key data.
* \param key_data_length Size of the key data buffer.
*
*/
void psa_free_persistent_key_data(uint8_t *key_data, size_t key_data_length);
/**
* \brief Formats key data and metadata for persistent storage
*
* \param[in] data Buffer containing the key data.
* \param data_length Length of the key data buffer.
* \param[in] attr The core attributes of the key.
* \param[out] storage_data Output buffer for the formatted data.
*
*/
void psa_format_key_data_for_storage(const uint8_t *data,
const size_t data_length,
const psa_key_attributes_t *attr,
uint8_t *storage_data);
/**
* \brief Parses persistent storage data into key data and metadata
*
* \param[in] storage_data Buffer for the storage data.
* \param storage_data_length Length of the storage data buffer
* \param[out] key_data On output, pointer to a newly allocated buffer
* containing the key data. This must be freed
* using psa_free_persistent_key_data()
* \param[out] key_data_length Length of the key data buffer
* \param[out] attr On success, the attribute structure is filled
* with the loaded key metadata.
*
* \retval #PSA_SUCCESS \emptydescription
* \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription
* \retval #PSA_ERROR_DATA_INVALID \emptydescription
*/
psa_status_t psa_parse_key_data_from_storage(const uint8_t *storage_data,
size_t storage_data_length,
uint8_t **key_data,
size_t *key_data_length,
psa_key_attributes_t *attr);
#ifdef __cplusplus
}
#endif
#endif /* TF_PSA_CRYPTO_PSA_CRYPTO_STORAGE_H */
+254
View File
@@ -0,0 +1,254 @@
/*
* PSA ITS simulator over stdio files.
*/
/*
* Copyright The Mbed TLS Contributors
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
*/
#include "tf_psa_crypto_common.h"
#if defined(MBEDTLS_PSA_ITS_FILE_C)
#include "mbedtls/platform.h"
#if defined(_WIN32)
#include <windows.h>
#endif
#include "psa_crypto_its.h"
#include <limits.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#if !defined(PSA_ITS_STORAGE_PREFIX)
#define PSA_ITS_STORAGE_PREFIX ""
#endif
#define PSA_ITS_STORAGE_FILENAME_PATTERN "%08x%08x"
#define PSA_ITS_STORAGE_SUFFIX ".psa_its"
#define PSA_ITS_STORAGE_FILENAME_LENGTH \
(sizeof(PSA_ITS_STORAGE_PREFIX) - 1 + /*prefix without terminating 0*/ \
16 + /*UID (64-bit number in hex)*/ \
sizeof(PSA_ITS_STORAGE_SUFFIX) - 1 + /*suffix without terminating 0*/ \
1 /*terminating null byte*/)
#define PSA_ITS_STORAGE_TEMP \
PSA_ITS_STORAGE_PREFIX "tempfile" PSA_ITS_STORAGE_SUFFIX
/* The maximum value of psa_storage_info_t.size */
#define PSA_ITS_MAX_SIZE 0xffffffff
#define PSA_ITS_MAGIC_STRING "PSA\0ITS\0"
#define PSA_ITS_MAGIC_LENGTH 8
/* As rename fails on Windows if the new filepath already exists,
* use MoveFileExA with the MOVEFILE_REPLACE_EXISTING flag instead.
* Returns 0 on success, nonzero on failure. */
#if defined(_WIN32)
#define rename_replace_existing(oldpath, newpath) \
(!MoveFileExA(oldpath, newpath, MOVEFILE_REPLACE_EXISTING))
#else
#define rename_replace_existing(oldpath, newpath) rename(oldpath, newpath)
#endif
typedef struct {
uint8_t magic[PSA_ITS_MAGIC_LENGTH];
uint8_t size[sizeof(uint32_t)];
uint8_t flags[sizeof(psa_storage_create_flags_t)];
} psa_its_file_header_t;
static void psa_its_fill_filename(psa_storage_uid_t uid, char *filename)
{
/* Break up the UID into two 32-bit pieces so as not to rely on
* long long support in snprintf. */
mbedtls_snprintf(filename, PSA_ITS_STORAGE_FILENAME_LENGTH,
"%s" PSA_ITS_STORAGE_FILENAME_PATTERN "%s",
PSA_ITS_STORAGE_PREFIX,
(unsigned) (uid >> 32),
(unsigned) (uid & 0xffffffff),
PSA_ITS_STORAGE_SUFFIX);
}
static psa_status_t psa_its_read_file(psa_storage_uid_t uid,
struct psa_storage_info_t *p_info,
FILE **p_stream)
{
char filename[PSA_ITS_STORAGE_FILENAME_LENGTH];
psa_its_file_header_t header;
size_t n;
*p_stream = NULL;
psa_its_fill_filename(uid, filename);
*p_stream = fopen(filename, "rb");
if (*p_stream == NULL) {
return PSA_ERROR_DOES_NOT_EXIST;
}
/* Ensure no stdio buffering of secrets, as such buffers cannot be wiped. */
mbedtls_setbuf(*p_stream, NULL);
n = fread(&header, 1, sizeof(header), *p_stream);
if (n != sizeof(header)) {
return PSA_ERROR_DATA_CORRUPT;
}
if (memcmp(header.magic, PSA_ITS_MAGIC_STRING,
PSA_ITS_MAGIC_LENGTH) != 0) {
return PSA_ERROR_DATA_CORRUPT;
}
p_info->size = MBEDTLS_GET_UINT32_LE(header.size, 0);
p_info->flags = MBEDTLS_GET_UINT32_LE(header.flags, 0);
return PSA_SUCCESS;
}
psa_status_t psa_its_get_info(psa_storage_uid_t uid,
struct psa_storage_info_t *p_info)
{
psa_status_t status;
FILE *stream = NULL;
status = psa_its_read_file(uid, p_info, &stream);
if (stream != NULL) {
fclose(stream);
}
return status;
}
psa_status_t psa_its_get(psa_storage_uid_t uid,
uint32_t data_offset,
uint32_t data_length,
void *p_data,
size_t *p_data_length)
{
psa_status_t status;
FILE *stream = NULL;
size_t n;
struct psa_storage_info_t info;
status = psa_its_read_file(uid, &info, &stream);
if (status != PSA_SUCCESS) {
goto exit;
}
status = PSA_ERROR_INVALID_ARGUMENT;
if (data_offset + data_length < data_offset) {
goto exit;
}
#if SIZE_MAX < 0xffffffff
if (data_offset + data_length > SIZE_MAX) {
goto exit;
}
#endif
if (data_offset + data_length > info.size) {
goto exit;
}
status = PSA_ERROR_STORAGE_FAILURE;
#if LONG_MAX < 0xffffffff
while (data_offset > LONG_MAX) {
if (fseek(stream, LONG_MAX, SEEK_CUR) != 0) {
goto exit;
}
data_offset -= LONG_MAX;
}
#endif
if (fseek(stream, data_offset, SEEK_CUR) != 0) {
goto exit;
}
n = fread(p_data, 1, data_length, stream);
if (n != data_length) {
goto exit;
}
status = PSA_SUCCESS;
if (p_data_length != NULL) {
*p_data_length = n;
}
exit:
if (stream != NULL) {
fclose(stream);
}
return status;
}
psa_status_t psa_its_set(psa_storage_uid_t uid,
uint32_t data_length,
const void *p_data,
psa_storage_create_flags_t create_flags)
{
if (uid == 0) {
return PSA_ERROR_INVALID_HANDLE;
}
psa_status_t status = PSA_ERROR_STORAGE_FAILURE;
char filename[PSA_ITS_STORAGE_FILENAME_LENGTH];
FILE *stream = NULL;
psa_its_file_header_t header;
size_t n;
memcpy(header.magic, PSA_ITS_MAGIC_STRING, PSA_ITS_MAGIC_LENGTH);
MBEDTLS_PUT_UINT32_LE(data_length, header.size, 0);
MBEDTLS_PUT_UINT32_LE(create_flags, header.flags, 0);
psa_its_fill_filename(uid, filename);
stream = fopen(PSA_ITS_STORAGE_TEMP, "wb");
if (stream == NULL) {
goto exit;
}
/* Ensure no stdio buffering of secrets, as such buffers cannot be wiped. */
mbedtls_setbuf(stream, NULL);
status = PSA_ERROR_INSUFFICIENT_STORAGE;
n = fwrite(&header, 1, sizeof(header), stream);
if (n != sizeof(header)) {
goto exit;
}
if (data_length != 0) {
n = fwrite(p_data, 1, data_length, stream);
if (n != data_length) {
goto exit;
}
}
status = PSA_SUCCESS;
exit:
if (stream != NULL) {
int ret = fclose(stream);
if (status == PSA_SUCCESS && ret != 0) {
status = PSA_ERROR_INSUFFICIENT_STORAGE;
}
}
if (status == PSA_SUCCESS) {
if (rename_replace_existing(PSA_ITS_STORAGE_TEMP, filename) != 0) {
status = PSA_ERROR_STORAGE_FAILURE;
}
}
/* The temporary file may still exist, but only in failure cases where
* we're already reporting an error. So there's nothing we can do on
* failure. If the function succeeded, and in some error cases, the
* temporary file doesn't exist and so remove() is expected to fail.
* Thus we just ignore the return status of remove(). */
(void) remove(PSA_ITS_STORAGE_TEMP);
return status;
}
psa_status_t psa_its_remove(psa_storage_uid_t uid)
{
char filename[PSA_ITS_STORAGE_FILENAME_LENGTH];
FILE *stream;
psa_its_fill_filename(uid, filename);
stream = fopen(filename, "rb");
if (stream == NULL) {
return PSA_ERROR_DOES_NOT_EXIST;
}
fclose(stream);
if (remove(filename) != 0) {
return PSA_ERROR_STORAGE_FAILURE;
}
return PSA_SUCCESS;
}
#endif /* MBEDTLS_PSA_ITS_FILE_C */
+295
View File
@@ -0,0 +1,295 @@
/*
* Copyright The Mbed TLS Contributors
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
*/
#include "tf_psa_crypto_common.h"
/* This is needed for MBEDTLS_ERR_XXX macros */
#include <mbedtls/private/error_common.h>
#if defined(MBEDTLS_ASN1_WRITE_C)
#include <mbedtls/asn1write.h>
#include <psa/crypto_sizes.h>
#endif
#include <mbedtls/psa_util.h>
#if defined(MBEDTLS_PSA_CRYPTO_CLIENT)
#include <psa/crypto.h>
#include <mbedtls/private/entropy.h>
/* Wrapper function allowing the classic API to use the PSA RNG.
*
* `mbedtls_psa_get_random(MBEDTLS_PSA_RANDOM_STATE, ...)` calls
* `psa_generate_random(...)`. The state parameter is ignored since the
* PSA API doesn't support passing an explicit state.
*/
int mbedtls_psa_get_random(void *p_rng,
unsigned char *output,
size_t output_size)
{
/* This function takes a pointer to the RNG state because that's what
* classic mbedtls functions using an RNG expect. The PSA RNG manages
* its own state internally and doesn't let the caller access that state.
* So we just ignore the state parameter, and in practice we'll pass
* NULL. */
(void) p_rng;
psa_status_t status = psa_generate_random(output, output_size);
if (status == PSA_SUCCESS) {
return 0;
} else {
return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED;
}
}
#endif /* MBEDTLS_PSA_CRYPTO_CLIENT */
#if defined(PSA_HAVE_ALG_SOME_ECDSA)
/**
* \brief Convert a single raw coordinate to DER ASN.1 format. The output der
* buffer is filled backward (i.e. starting from its end).
*
* \param raw_buf Buffer containing the raw coordinate to be
* converted.
* \param raw_len Length of raw_buf in bytes. This must be > 0.
* \param der_buf_start Pointer to the beginning of the buffer which
* will be filled with the DER converted data.
* \param der_buf_end End of the buffer used to store the DER output.
*
* \return On success, the amount of data (in bytes) written to
* the DER buffer.
* \return MBEDTLS_ERR_ASN1_BUF_TOO_SMALL if the provided der
* buffer is too small to contain all the converted data.
* \return MBEDTLS_ERR_ASN1_INVALID_DATA if the input raw
* coordinate is null (i.e. all zeros).
*
* \warning Raw and der buffer must not be overlapping.
*/
static int convert_raw_to_der_single_int(const unsigned char *raw_buf, size_t raw_len,
unsigned char *der_buf_start,
unsigned char *der_buf_end)
{
unsigned char *p = der_buf_end;
int len;
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
/* ASN.1 DER encoding requires minimal length, so skip leading 0s.
* Provided input MPIs should not be 0, but as a failsafe measure, still
* detect that and return error in case. */
while (*raw_buf == 0x00) {
++raw_buf;
--raw_len;
if (raw_len == 0) {
return MBEDTLS_ERR_ASN1_INVALID_DATA;
}
}
len = (int) raw_len;
/* Copy the raw coordinate to the end of der_buf. */
if ((p - der_buf_start) < len) {
return MBEDTLS_ERR_ASN1_BUF_TOO_SMALL;
}
p -= len;
memcpy(p, raw_buf, len);
/* If MSb is 1, ASN.1 requires that we prepend a 0. */
if (*p & 0x80) {
if ((p - der_buf_start) < 1) {
return MBEDTLS_ERR_ASN1_BUF_TOO_SMALL;
}
--p;
*p = 0x00;
++len;
}
MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&p, der_buf_start, len));
MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_tag(&p, der_buf_start, MBEDTLS_ASN1_INTEGER));
return len;
}
int mbedtls_ecdsa_raw_to_der(size_t bits, const unsigned char *raw, size_t raw_len,
unsigned char *der, size_t der_size, size_t *der_len)
{
unsigned char r[PSA_BITS_TO_BYTES(PSA_VENDOR_ECC_MAX_CURVE_BITS)];
unsigned char s[PSA_BITS_TO_BYTES(PSA_VENDOR_ECC_MAX_CURVE_BITS)];
const size_t coordinate_len = PSA_BITS_TO_BYTES(bits);
size_t len = 0;
unsigned char *p = der + der_size;
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
if (bits == 0) {
return MBEDTLS_ERR_ASN1_INVALID_DATA;
}
if (raw_len != (2 * coordinate_len)) {
return MBEDTLS_ERR_ASN1_INVALID_DATA;
}
if (coordinate_len > sizeof(r)) {
return MBEDTLS_ERR_ASN1_BUF_TOO_SMALL;
}
/* Since raw and der buffers might overlap, dump r and s before starting
* the conversion. */
memcpy(r, raw, coordinate_len);
memcpy(s, raw + coordinate_len, coordinate_len);
/* der buffer will initially be written starting from its end so we pick s
* first and then r. */
ret = convert_raw_to_der_single_int(s, coordinate_len, der, p);
if (ret < 0) {
return ret;
}
p -= ret;
len += ret;
ret = convert_raw_to_der_single_int(r, coordinate_len, der, p);
if (ret < 0) {
return ret;
}
p -= ret;
len += ret;
/* Add ASN.1 header (len + tag). */
MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&p, der, len));
MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_tag(&p, der,
MBEDTLS_ASN1_CONSTRUCTED |
MBEDTLS_ASN1_SEQUENCE));
/* memmove the content of der buffer to its beginnig. */
memmove(der, p, len);
*der_len = len;
return 0;
}
/**
* \brief Convert a single integer from ASN.1 DER format to raw.
*
* \param der Buffer containing the DER integer value to be
* converted.
* \param der_len Length of the der buffer in bytes.
* \param raw Output buffer that will be filled with the
* converted data. This should be at least
* coordinate_size bytes and it must be zeroed before
* calling this function.
* \param coordinate_size Size (in bytes) of a single coordinate in raw
* format.
*
* \return On success, the amount of DER data parsed from the
* provided der buffer.
* \return MBEDTLS_ERR_ASN1_UNEXPECTED_TAG if the integer tag
* is missing in the der buffer.
* \return MBEDTLS_ERR_ASN1_LENGTH_MISMATCH if the integer
* is null (i.e. all zeros) or if the output raw buffer
* is too small to contain the converted raw value.
*
* \warning Der and raw buffers must not be overlapping.
*/
static int convert_der_to_raw_single_int(unsigned char *der, size_t der_len,
unsigned char *raw, size_t coordinate_size)
{
unsigned char *p = der;
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
size_t unpadded_len, padding_len = 0;
/* Get the length of ASN.1 element (i.e. the integer we need to parse). */
ret = mbedtls_asn1_get_tag(&p, p + der_len, &unpadded_len,
MBEDTLS_ASN1_INTEGER);
if (ret != 0) {
return ret;
}
/* It's invalid to have:
* - unpadded_len == 0.
* - MSb set without a leading 0x00 (leading 0x00 is checked below). */
if (((unpadded_len == 0) || (*p & 0x80) != 0)) {
return MBEDTLS_ERR_ASN1_INVALID_DATA;
}
/* Skip possible leading zero */
if (*p == 0x00) {
p++;
unpadded_len--;
/* It is not allowed to have more than 1 leading zero.
* Ignore the case in which unpadded_len = 0 because that's a 0 encoded
* in ASN.1 format (i.e. 020100). */
if ((unpadded_len > 0) && (*p == 0x00)) {
return MBEDTLS_ERR_ASN1_INVALID_DATA;
}
}
if (unpadded_len > coordinate_size) {
/* Parsed number is longer than the maximum expected value. */
return MBEDTLS_ERR_ASN1_INVALID_DATA;
}
padding_len = coordinate_size - unpadded_len;
/* raw buffer was already zeroed by the calling function so zero-padding
* operation is skipped here. */
memcpy(raw + padding_len, p, unpadded_len);
p += unpadded_len;
return (int) (p - der);
}
int mbedtls_ecdsa_der_to_raw(size_t bits, const unsigned char *der, size_t der_len,
unsigned char *raw, size_t raw_size, size_t *raw_len)
{
unsigned char raw_tmp[PSA_VENDOR_ECDSA_SIGNATURE_MAX_SIZE];
unsigned char *p = (unsigned char *) der;
size_t data_len;
size_t coordinate_size = PSA_BITS_TO_BYTES(bits);
int ret;
if (bits == 0) {
return MBEDTLS_ERR_ASN1_INVALID_DATA;
}
/* The output raw buffer should be at least twice the size of a raw
* coordinate in order to store r and s. */
if (raw_size < coordinate_size * 2) {
return MBEDTLS_ERR_ASN1_BUF_TOO_SMALL;
}
if (2 * coordinate_size > sizeof(raw_tmp)) {
return MBEDTLS_ERR_ASN1_BUF_TOO_SMALL;
}
/* Check that the provided input DER buffer has the right header. */
ret = mbedtls_asn1_get_tag(&p, der + der_len, &data_len,
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE);
if (ret != 0) {
return ret;
}
memset(raw_tmp, 0, 2 * coordinate_size);
/* Extract r */
ret = convert_der_to_raw_single_int(p, data_len, raw_tmp, coordinate_size);
if (ret < 0) {
return ret;
}
p += ret;
data_len -= ret;
/* Extract s */
ret = convert_der_to_raw_single_int(p, data_len, raw_tmp + coordinate_size,
coordinate_size);
if (ret < 0) {
return ret;
}
p += ret;
data_len -= ret;
/* Check that we consumed all the input der data. */
if ((size_t) (p - der) != der_len) {
return MBEDTLS_ERR_ASN1_LENGTH_MISMATCH;
}
memcpy(raw, raw_tmp, 2 * coordinate_size);
*raw_len = 2 * coordinate_size;
return 0;
}
#endif /* PSA_HAVE_ALG_SOME_ECDSA */
@@ -0,0 +1,598 @@
/**
* \file tf-psa-crypto/check_config.h
*
* \brief Consistency checks for configuration options
*
* This is an internal header. Do not include it directly.
*
* This header is included automatically by all public TF-PSA-Crypto headers
* (via tf-psa-crypto/build_info.h). Do not include it directly in a
* configuration file such as psa/crypto_config.h or #TF_PSA_CRYPTO_USER_CONFIG_FILE!
* It would run at the wrong time due to missing derived symbols.
*/
/*
* Copyright The Mbed TLS Contributors
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
*/
#ifndef TF_PSA_CRYPTO_TF_PSA_CRYPTO_CHECK_CONFIG_H
#define TF_PSA_CRYPTO_TF_PSA_CRYPTO_CHECK_CONFIG_H
/* *INDENT-OFF* */
/*
* We assume CHAR_BIT is 8 in many places. In practice, this is true on our
* target platforms, so not an issue, but let's just be extra sure.
*/
#include <limits.h>
#if CHAR_BIT != 8
#error "Mbed TLS requires a platform with 8-bit chars"
#endif
#include <stdint.h>
#if defined(__MINGW32__) || (defined(_MSC_VER) && _MSC_VER <= 1900)
#if !defined(MBEDTLS_PLATFORM_C)
#error "MBEDTLS_PLATFORM_C is required on Windows"
#endif
/* See auto-enabling SNPRINTF_ALT and VSNPRINTF_ALT
* in <tf-psa-crypto/private/crypto_adjust_config_support.h> */
#endif /* _MINGW32__ || (_MSC_VER && (_MSC_VER <= 1900)) */
#if defined(MBEDTLS_DEPRECATED_WARNING) && \
!defined(__GNUC__) && !defined(__clang__)
#error "MBEDTLS_DEPRECATED_WARNING only works with GCC and Clang"
#endif
/* Limitations on ECC key types acceleration: if we have any of `PUBLIC_KEY`,
* `KEY_PAIR_BASIC`, `KEY_PAIR_IMPORT`, `KEY_PAIR_EXPORT` then we must have
* all 4 of them.
*/
#if defined(MBEDTLS_PSA_ACCEL_KEY_TYPE_ECC_PUBLIC_KEY) || \
defined(MBEDTLS_PSA_ACCEL_KEY_TYPE_ECC_KEY_PAIR_BASIC) || \
defined(MBEDTLS_PSA_ACCEL_KEY_TYPE_ECC_KEY_PAIR_IMPORT) || \
defined(MBEDTLS_PSA_ACCEL_KEY_TYPE_ECC_KEY_PAIR_EXPORT)
#if !defined(MBEDTLS_PSA_ACCEL_KEY_TYPE_ECC_PUBLIC_KEY) || \
!defined(MBEDTLS_PSA_ACCEL_KEY_TYPE_ECC_KEY_PAIR_BASIC) || \
!defined(MBEDTLS_PSA_ACCEL_KEY_TYPE_ECC_KEY_PAIR_IMPORT) || \
!defined(MBEDTLS_PSA_ACCEL_KEY_TYPE_ECC_KEY_PAIR_EXPORT)
#error "Unsupported partial support for ECC key type acceleration, see docs/driver-only-builds.md"
#endif /* not all of public, basic, import, export */
#endif /* one of public, basic, import, export */
/* Limitations on ECC curves acceleration: partial curve acceleration is only
* supported with crypto excluding PK, X.509 or TLS.
* Note: no need to check X.509 as it depends on PK. */
#if defined(MBEDTLS_PSA_ACCEL_ECC_BRAINPOOL_P_R1_256) || \
defined(MBEDTLS_PSA_ACCEL_ECC_BRAINPOOL_P_R1_384) || \
defined(MBEDTLS_PSA_ACCEL_ECC_BRAINPOOL_P_R1_512) || \
defined(MBEDTLS_PSA_ACCEL_ECC_MONTGOMERY_255) || \
defined(MBEDTLS_PSA_ACCEL_ECC_MONTGOMERY_448) || \
defined(MBEDTLS_PSA_ACCEL_ECC_SECP_K1_256) || \
defined(MBEDTLS_PSA_ACCEL_ECC_SECP_R1_256) || \
defined(MBEDTLS_PSA_ACCEL_ECC_SECP_R1_384) || \
defined(MBEDTLS_PSA_ACCEL_ECC_SECP_R1_521)
#if defined(MBEDTLS_PSA_ECC_ACCEL_INCOMPLETE_CURVES)
#if defined(MBEDTLS_PK_C)
#error "Unsupported partial support for ECC curves acceleration, see docs/driver-only-builds.md"
#endif /* modules beyond what's supported */
#endif /* not all curves accelerated */
#endif /* some curve accelerated */
#if defined(MBEDTLS_CTR_DRBG_C) && !(defined(MBEDTLS_AES_C) || \
(defined(MBEDTLS_PSA_CRYPTO_CLIENT) && defined(PSA_WANT_KEY_TYPE_AES) && \
defined(PSA_WANT_ALG_ECB_NO_PADDING)))
#error "MBEDTLS_CTR_DRBG_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_CMAC_C) && \
( !defined(MBEDTLS_CIPHER_C ) || !defined(MBEDTLS_AES_C) )
#error "MBEDTLS_CMAC_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_BLOCK_CIPHER_NO_DECRYPT)
#if defined(PSA_WANT_ALG_CBC_NO_PADDING)
#error "MBEDTLS_BLOCK_CIPHER_NO_DECRYPT and PSA_WANT_ALG_CBC_NO_PADDING cannot be defined simultaneously"
#endif
#if defined(PSA_WANT_ALG_CBC_PKCS7)
#error "MBEDTLS_BLOCK_CIPHER_NO_DECRYPT and PSA_WANT_ALG_CBC_PKCS7 cannot be defined simultaneously"
#endif
#if defined(PSA_WANT_ALG_ECB_NO_PADDING)
#error "MBEDTLS_BLOCK_CIPHER_NO_DECRYPT and PSA_WANT_ALG_ECB_NO_PADDING cannot be defined simultaneously"
#endif
#if defined(MBEDTLS_NIST_KW_C)
#error "MBEDTLS_BLOCK_CIPHER_NO_DECRYPT and MBEDTLS_NIST_KW_C cannot be defined simultaneously"
#endif
#endif
#if defined(MBEDTLS_ECDSA_C) && \
!( defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) || \
defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED) || \
defined(MBEDTLS_ECP_DP_SECP521R1_ENABLED) || \
defined(MBEDTLS_ECP_DP_SECP256K1_ENABLED) || \
defined(MBEDTLS_ECP_DP_BP256R1_ENABLED) || \
defined(MBEDTLS_ECP_DP_BP384R1_ENABLED) || \
defined(MBEDTLS_ECP_DP_BP512R1_ENABLED) )
#error "Built-in ECDSA implementation enabled but no suitable curve"
#endif
#if defined(MBEDTLS_PK_C)
#if defined(PSA_HAVE_ALG_ECDSA_SIGN) && !defined(MBEDTLS_ASN1_WRITE_C)
#error "MBEDTLS_PK_C needs MBEDTLS_ASN1_WRITE_C for ECDSA signature"
#endif
#if defined(PSA_HAVE_ALG_ECDSA_VERIFY) && !defined(MBEDTLS_ASN1_PARSE_C)
#error "MBEDTLS_PK_C needs MBEDTLS_ASN1_PARSE_C for ECDSA verification"
#endif
#endif /* MBEDTLS_PK_C */
#if defined(MBEDTLS_ECP_RESTARTABLE) && \
!defined(MBEDTLS_ECP_C)
#error "MBEDTLS_ECP_RESTARTABLE defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_ECP_LIGHT) && ( !defined(MBEDTLS_BIGNUM_C) || ( \
!defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) && \
!defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED) && \
!defined(MBEDTLS_ECP_DP_SECP521R1_ENABLED) && \
!defined(MBEDTLS_ECP_DP_BP256R1_ENABLED) && \
!defined(MBEDTLS_ECP_DP_BP384R1_ENABLED) && \
!defined(MBEDTLS_ECP_DP_BP512R1_ENABLED) && \
!defined(MBEDTLS_ECP_DP_SECP256K1_ENABLED) && \
!defined(MBEDTLS_ECP_DP_CURVE25519_ENABLED) && \
!defined(MBEDTLS_ECP_DP_CURVE448_ENABLED) ) )
#error "Generic elliptic curve module or a subset enabled, but not all prerequisites"
#endif
#if defined(MBEDTLS_ENTROPY_C)
# if !defined(MBEDTLS_ENTROPY_HAVE_SOURCES)
/* The entropy module needs at least one entropy source, such as
* #MBEDTLS_PSA_BUILTIN_GET_ENTROPY or #MBEDTLS_PSA_DRIVER_GET_ENTROPY
* or #MBEDTLS_ENTROPY_NV_SEED.
*
* If your platform has a cryptographic-quality random generator,
* enable #MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG.
*/
# error "Entropy module enabled, but no sources"
# elif MBEDTLS_ENTROPY_TRUE_SOURCES == 0
# if !defined(MBEDTLS_ENTROPY_NO_SOURCES_OK)
/* Having only the NV seed as an entropy source weakens security.
* To indicate that this is acceptable, define
* MBEDTLS_ENTROPY_NO_SOURCES_OK. */
# error "Entropy module enabled, but no true sources"
# endif
# endif
#endif
#if defined(MBEDTLS_ENTROPY_C) && \
!(defined(PSA_WANT_ALG_SHA_512) || defined(PSA_WANT_ALG_SHA_256))
#error "Entropy module enabled but neither SHA-256 nor SHA-512 is available"
#endif
#if (MBEDTLS_PSA_CRYPTO_RNG_STRENGTH != 128) && \
(MBEDTLS_PSA_CRYPTO_RNG_STRENGTH != 256)
#error "MBEDTLS_PSA_CRYPTO_RNG_STRENGTH must be 128 or 256"
#endif
#if defined(__has_feature)
#if __has_feature(memory_sanitizer)
#define MBEDTLS_HAS_MEMSAN // #undef at the end of this paragraph
#endif
#endif
#if defined(MBEDTLS_TEST_CONSTANT_FLOW_MEMSAN) && !defined(MBEDTLS_HAS_MEMSAN)
#error "MBEDTLS_TEST_CONSTANT_FLOW_MEMSAN requires building with MemorySanitizer"
#endif
#if defined(MBEDTLS_HAS_MEMSAN) && defined(MBEDTLS_HAVE_ASM)
#error "MemorySanitizer does not support assembly implementation"
#endif
#undef MBEDTLS_HAS_MEMSAN // temporary macro defined above
#if defined(MBEDTLS_CCM_C) && \
!(defined(MBEDTLS_CCM_GCM_CAN_AES) || defined(MBEDTLS_CCM_GCM_CAN_ARIA) || \
defined(MBEDTLS_CCM_GCM_CAN_CAMELLIA))
#error "Built-in CCM implementation enabled, but not all prerequisites"
#endif
#if defined(MBEDTLS_GCM_C) && \
!(defined(MBEDTLS_CCM_GCM_CAN_AES) || defined(MBEDTLS_CCM_GCM_CAN_ARIA) || \
defined(MBEDTLS_CCM_GCM_CAN_CAMELLIA))
#error "Built-in GCM implementation enabled, but not all prerequisites"
#endif
#if defined(MBEDTLS_HMAC_DRBG_C) && !defined(MBEDTLS_MD_C)
#error "MBEDTLS_HMAC_DRBG_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_MD_C) && \
!defined(PSA_WANT_ALG_MD5) && \
!defined(PSA_WANT_ALG_RIPEMD160) && \
!defined(PSA_WANT_ALG_SHA_1) && \
!defined(PSA_WANT_ALG_SHA_224) && \
!defined(PSA_WANT_ALG_SHA_256) && \
!defined(PSA_WANT_ALG_SHA_384) && \
!defined(PSA_WANT_ALG_SHA_512) && \
!defined(PSA_WANT_ALG_SHA3_224) && \
!defined(PSA_WANT_ALG_SHA3_256) && \
!defined(PSA_WANT_ALG_SHA3_384) && \
!defined(PSA_WANT_ALG_SHA3_512)
#error "MBEDTLS_MD_C defined, but no hash algorithm"
#endif
#if defined(MBEDTLS_LMS_C) && \
! ( defined(MBEDTLS_PSA_CRYPTO_CLIENT) && defined(PSA_WANT_ALG_SHA_256) )
#error "MBEDTLS_LMS_C requires MBEDTLS_PSA_CRYPTO_C and PSA_WANT_ALG_SHA_256"
#endif
#if defined(MBEDTLS_LMS_PRIVATE) && \
( !defined(MBEDTLS_LMS_C) )
#error "MBEDTLS_LMS_PRIVATE requires MBEDTLS_LMS_C"
#endif
#if defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C) && \
( !defined(MBEDTLS_PLATFORM_C) || !defined(MBEDTLS_PLATFORM_MEMORY) )
#error "MBEDTLS_MEMORY_BUFFER_ALLOC_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_MEMORY_BACKTRACE) && !defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C)
#error "MBEDTLS_MEMORY_BACKTRACE defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_MEMORY_DEBUG) && !defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C)
#error "MBEDTLS_MEMORY_DEBUG defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PEM_PARSE_C) && !defined(MBEDTLS_BASE64_C)
#error "MBEDTLS_PEM_PARSE_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PEM_WRITE_C) && !defined(MBEDTLS_BASE64_C)
#error "MBEDTLS_PEM_WRITE_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PK_C) && \
!defined(PSA_WANT_KEY_TYPE_RSA_PUBLIC_KEY) && !defined(PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY)
#error "MBEDTLS_PK_C defined, but neither PSA_WANT_KEY_TYPE_[ECC|RSA]_PUBLIC_KEY are"
#endif
#if defined(MBEDTLS_PK_C) && !defined(MBEDTLS_PSA_CRYPTO_CLIENT)
#error "MBEDTLS_PK_C defined, but not MBEDTLS_PSA_CRYPTO_CLIENT"
#endif
#if defined(MBEDTLS_PK_PARSE_C) && \
(!defined(MBEDTLS_ASN1_PARSE_C) || \
!defined(MBEDTLS_PK_C))
#error "MBEDTLS_PK_PARSE_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PK_WRITE_C) && \
(!defined(MBEDTLS_ASN1_WRITE_C) || \
!defined(MBEDTLS_PK_C))
#error "MBEDTLS_PK_WRITE_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_EXIT_ALT) && !defined(MBEDTLS_PLATFORM_C)
#error "MBEDTLS_PLATFORM_EXIT_ALT defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_EXIT_MACRO) && !defined(MBEDTLS_PLATFORM_C)
#error "MBEDTLS_PLATFORM_EXIT_MACRO defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_EXIT_MACRO) &&\
( defined(MBEDTLS_PLATFORM_STD_EXIT) ||\
defined(MBEDTLS_PLATFORM_EXIT_ALT) )
#error "MBEDTLS_PLATFORM_EXIT_MACRO and MBEDTLS_PLATFORM_STD_EXIT/MBEDTLS_PLATFORM_EXIT_ALT cannot be defined simultaneously"
#endif
#if defined(MBEDTLS_PLATFORM_SETBUF_ALT) && !defined(MBEDTLS_PLATFORM_C)
#error "MBEDTLS_PLATFORM_SETBUF_ALT defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_SETBUF_MACRO) && !defined(MBEDTLS_PLATFORM_C)
#error "MBEDTLS_PLATFORM_SETBUF_MACRO defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_SETBUF_MACRO) &&\
( defined(MBEDTLS_PLATFORM_STD_SETBUF) ||\
defined(MBEDTLS_PLATFORM_SETBUF_ALT) )
#error "MBEDTLS_PLATFORM_SETBUF_MACRO and MBEDTLS_PLATFORM_STD_SETBUF/MBEDTLS_PLATFORM_SETBUF_ALT cannot be defined simultaneously"
#endif
#if defined(MBEDTLS_PLATFORM_TIME_ALT) &&\
( !defined(MBEDTLS_PLATFORM_C) ||\
!defined(MBEDTLS_HAVE_TIME) )
#error "MBEDTLS_PLATFORM_TIME_ALT defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_TIME_MACRO) &&\
( !defined(MBEDTLS_PLATFORM_C) ||\
!defined(MBEDTLS_HAVE_TIME) )
#error "MBEDTLS_PLATFORM_TIME_MACRO defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_MS_TIME_TYPE_MACRO) &&\
( !defined(MBEDTLS_PLATFORM_C) || !defined(MBEDTLS_HAVE_TIME) )
#error "MBEDTLS_PLATFORM_MS_TIME_TYPE_MACRO defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_MS_TIME_ALT) && \
( !defined(MBEDTLS_PLATFORM_C) || !defined(MBEDTLS_HAVE_TIME) )
#error "MBEDTLS_PLATFORM_MS_TIME_ALT defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_TIME_TYPE_MACRO) &&\
( !defined(MBEDTLS_PLATFORM_C) ||\
!defined(MBEDTLS_HAVE_TIME) )
#error "MBEDTLS_PLATFORM_TIME_TYPE_MACRO defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_TIME_MACRO) &&\
( defined(MBEDTLS_PLATFORM_STD_TIME) ||\
defined(MBEDTLS_PLATFORM_TIME_ALT) )
#error "MBEDTLS_PLATFORM_TIME_MACRO and MBEDTLS_PLATFORM_STD_TIME/MBEDTLS_PLATFORM_TIME_ALT cannot be defined simultaneously"
#endif
#if defined(MBEDTLS_PLATFORM_TIME_TYPE_MACRO) &&\
( defined(MBEDTLS_PLATFORM_STD_TIME) ||\
defined(MBEDTLS_PLATFORM_TIME_ALT) )
#error "MBEDTLS_PLATFORM_TIME_TYPE_MACRO and MBEDTLS_PLATFORM_STD_TIME/MBEDTLS_PLATFORM_TIME_ALT cannot be defined simultaneously"
#endif
#if defined(MBEDTLS_PLATFORM_FPRINTF_ALT) && !defined(MBEDTLS_PLATFORM_C)
#error "MBEDTLS_PLATFORM_FPRINTF_ALT defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_FPRINTF_MACRO) && !defined(MBEDTLS_PLATFORM_C)
#error "MBEDTLS_PLATFORM_FPRINTF_MACRO defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_FPRINTF_MACRO) &&\
( defined(MBEDTLS_PLATFORM_STD_FPRINTF) ||\
defined(MBEDTLS_PLATFORM_FPRINTF_ALT) )
#error "MBEDTLS_PLATFORM_FPRINTF_MACRO and MBEDTLS_PLATFORM_STD_FPRINTF/MBEDTLS_PLATFORM_FPRINTF_ALT cannot be defined simultaneously"
#endif
#if defined(MBEDTLS_PLATFORM_FREE_MACRO) &&\
( !defined(MBEDTLS_PLATFORM_C) || !defined(MBEDTLS_PLATFORM_MEMORY) )
#error "MBEDTLS_PLATFORM_FREE_MACRO defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_FREE_MACRO) &&\
defined(MBEDTLS_PLATFORM_STD_FREE)
#error "MBEDTLS_PLATFORM_FREE_MACRO and MBEDTLS_PLATFORM_STD_FREE cannot be defined simultaneously"
#endif
#if defined(MBEDTLS_PLATFORM_FREE_MACRO) && !defined(MBEDTLS_PLATFORM_CALLOC_MACRO)
#error "MBEDTLS_PLATFORM_CALLOC_MACRO must be defined if MBEDTLS_PLATFORM_FREE_MACRO is"
#endif
#if defined(MBEDTLS_PLATFORM_CALLOC_MACRO) &&\
( !defined(MBEDTLS_PLATFORM_C) || !defined(MBEDTLS_PLATFORM_MEMORY) )
#error "MBEDTLS_PLATFORM_CALLOC_MACRO defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_CALLOC_MACRO) &&\
defined(MBEDTLS_PLATFORM_STD_CALLOC)
#error "MBEDTLS_PLATFORM_CALLOC_MACRO and MBEDTLS_PLATFORM_STD_CALLOC cannot be defined simultaneously"
#endif
#if defined(MBEDTLS_PLATFORM_CALLOC_MACRO) && !defined(MBEDTLS_PLATFORM_FREE_MACRO)
#error "MBEDTLS_PLATFORM_FREE_MACRO must be defined if MBEDTLS_PLATFORM_CALLOC_MACRO is"
#endif
#if defined(MBEDTLS_PLATFORM_MEMORY) && !defined(MBEDTLS_PLATFORM_C)
#error "MBEDTLS_PLATFORM_MEMORY defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_PRINTF_ALT) && !defined(MBEDTLS_PLATFORM_C)
#error "MBEDTLS_PLATFORM_PRINTF_ALT defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_PRINTF_MACRO) && !defined(MBEDTLS_PLATFORM_C)
#error "MBEDTLS_PLATFORM_PRINTF_MACRO defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_PRINTF_MACRO) &&\
( defined(MBEDTLS_PLATFORM_STD_PRINTF) ||\
defined(MBEDTLS_PLATFORM_PRINTF_ALT) )
#error "MBEDTLS_PLATFORM_PRINTF_MACRO and MBEDTLS_PLATFORM_STD_PRINTF/MBEDTLS_PLATFORM_PRINTF_ALT cannot be defined simultaneously"
#endif
#if defined(MBEDTLS_PLATFORM_SNPRINTF_ALT) && !defined(MBEDTLS_PLATFORM_C)
#error "MBEDTLS_PLATFORM_SNPRINTF_ALT defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_SNPRINTF_MACRO) && !defined(MBEDTLS_PLATFORM_C)
#error "MBEDTLS_PLATFORM_SNPRINTF_MACRO defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_SNPRINTF_MACRO) &&\
( defined(MBEDTLS_PLATFORM_STD_SNPRINTF) ||\
defined(MBEDTLS_PLATFORM_SNPRINTF_ALT) )
#error "MBEDTLS_PLATFORM_SNPRINTF_MACRO and MBEDTLS_PLATFORM_STD_SNPRINTF/MBEDTLS_PLATFORM_SNPRINTF_ALT cannot be defined simultaneously"
#endif
#if defined(MBEDTLS_PLATFORM_VSNPRINTF_ALT) && !defined(MBEDTLS_PLATFORM_C)
#error "MBEDTLS_PLATFORM_VSNPRINTF_ALT defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_VSNPRINTF_MACRO) && !defined(MBEDTLS_PLATFORM_C)
#error "MBEDTLS_PLATFORM_VSNPRINTF_MACRO defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_VSNPRINTF_MACRO) &&\
( defined(MBEDTLS_PLATFORM_STD_VSNPRINTF) ||\
defined(MBEDTLS_PLATFORM_VSNPRINTF_ALT) )
#error "MBEDTLS_PLATFORM_VSNPRINTF_MACRO and MBEDTLS_PLATFORM_STD_VSNPRINTF/MBEDTLS_PLATFORM_VSNPRINTF_ALT cannot be defined simultaneously"
#endif
#if defined(MBEDTLS_PLATFORM_STD_MEM_HDR) &&\
!defined(MBEDTLS_PLATFORM_NO_STD_FUNCTIONS)
#error "MBEDTLS_PLATFORM_STD_MEM_HDR defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_STD_CALLOC) && !defined(MBEDTLS_PLATFORM_MEMORY)
#error "MBEDTLS_PLATFORM_STD_CALLOC defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_STD_FREE) && !defined(MBEDTLS_PLATFORM_MEMORY)
#error "MBEDTLS_PLATFORM_STD_FREE defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_STD_EXIT) &&\
!defined(MBEDTLS_PLATFORM_EXIT_ALT)
#error "MBEDTLS_PLATFORM_STD_EXIT defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_STD_TIME) &&\
( !defined(MBEDTLS_PLATFORM_TIME_ALT) ||\
!defined(MBEDTLS_HAVE_TIME) )
#error "MBEDTLS_PLATFORM_STD_TIME defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_STD_FPRINTF) &&\
!defined(MBEDTLS_PLATFORM_FPRINTF_ALT)
#error "MBEDTLS_PLATFORM_STD_FPRINTF defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_STD_PRINTF) &&\
!defined(MBEDTLS_PLATFORM_PRINTF_ALT)
#error "MBEDTLS_PLATFORM_STD_PRINTF defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_STD_SNPRINTF) &&\
!defined(MBEDTLS_PLATFORM_SNPRINTF_ALT)
#error "MBEDTLS_PLATFORM_STD_SNPRINTF defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_ENTROPY_NV_SEED) &&\
(!defined(MBEDTLS_PSA_CRYPTO_C) || !defined(MBEDTLS_PLATFORM_C))
#error "MBEDTLS_ENTROPY_NV_SEED defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_ENTROPY_NV_SEED) && defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG)
#error "MBEDTLS_ENTROPY_NV_SEED has no effect when MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG is enabled"
#endif
#if defined(MBEDTLS_PLATFORM_NV_SEED_ALT) &&\
!defined(MBEDTLS_ENTROPY_NV_SEED)
#error "MBEDTLS_PLATFORM_NV_SEED_ALT defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_STD_NV_SEED_READ) &&\
!defined(MBEDTLS_PLATFORM_NV_SEED_ALT)
#error "MBEDTLS_PLATFORM_STD_NV_SEED_READ defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_STD_NV_SEED_WRITE) &&\
!defined(MBEDTLS_PLATFORM_NV_SEED_ALT)
#error "MBEDTLS_PLATFORM_STD_NV_SEED_WRITE defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_NV_SEED_READ_MACRO) &&\
( defined(MBEDTLS_PLATFORM_STD_NV_SEED_READ) ||\
defined(MBEDTLS_PLATFORM_NV_SEED_ALT) )
#error "MBEDTLS_PLATFORM_NV_SEED_READ_MACRO and MBEDTLS_PLATFORM_STD_NV_SEED_READ cannot be defined simultaneously"
#endif
#if defined(MBEDTLS_PLATFORM_NV_SEED_WRITE_MACRO) &&\
( defined(MBEDTLS_PLATFORM_STD_NV_SEED_WRITE) ||\
defined(MBEDTLS_PLATFORM_NV_SEED_ALT) )
#error "MBEDTLS_PLATFORM_NV_SEED_WRITE_MACRO and MBEDTLS_PLATFORM_STD_NV_SEED_WRITE cannot be defined simultaneously"
#endif
#if defined(MBEDTLS_PSA_CRYPTO_C) && \
!(defined(MBEDTLS_CTR_DRBG_C) || defined(MBEDTLS_HMAC_DRBG_C) || \
defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG))
#error "MBEDTLS_PSA_CRYPTO_C defined, but missing RNG"
#endif
#if defined(MBEDTLS_PSA_CRYPTO_C) && defined(PSA_HAVE_SOFT_BLOCK_MODE) && \
defined(PSA_HAVE_SOFT_BLOCK_CIPHER) && !defined(MBEDTLS_CIPHER_C)
#error "MBEDTLS_PSA_CRYPTO_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PSA_CRYPTO_SPM) && !defined(MBEDTLS_PSA_CRYPTO_C)
#error "MBEDTLS_PSA_CRYPTO_SPM defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PSA_CRYPTO_STORAGE_C) && \
! defined(MBEDTLS_PSA_CRYPTO_C)
#error "MBEDTLS_PSA_CRYPTO_STORAGE_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PSA_KEY_STORE_DYNAMIC) && \
defined(MBEDTLS_PSA_STATIC_KEY_SLOTS)
#error "MBEDTLS_PSA_KEY_STORE_DYNAMIC and MBEDTLS_PSA_STATIC_KEY_SLOTS cannot be defined simultaneously"
#endif
#if defined(MBEDTLS_PSA_ITS_FILE_C) && \
!defined(MBEDTLS_FS_IO)
#error "MBEDTLS_PSA_ITS_FILE_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_SHA512_USE_A64_CRYPTO_IF_PRESENT) && \
defined(MBEDTLS_SHA512_USE_A64_CRYPTO_ONLY)
#error "Must only define one of MBEDTLS_SHA512_USE_A64_CRYPTO_*"
#endif
#if defined(MBEDTLS_SHA512_USE_A64_CRYPTO_IF_PRESENT) || \
defined(MBEDTLS_SHA512_USE_A64_CRYPTO_ONLY)
#if !defined(MBEDTLS_SHA512_C)
#error "MBEDTLS_SHA512_USE_A64_CRYPTO_* defined without the SHA-512 built-in implementation"
#endif
#endif /* MBEDTLS_SHA512_USE_A64_CRYPTO_IF_PRESENT || MBEDTLS_SHA512_USE_A64_CRYPTO_ONLY */
#if defined(MBEDTLS_SHA512_USE_A64_CRYPTO_ONLY) && !defined(__aarch64__)
#error "MBEDTLS_SHA512_USE_A64_CRYPTO_ONLY defined on non-Aarch64 system"
#endif
#if defined(MBEDTLS_SHA256_USE_ARMV8_A_CRYPTO_IF_PRESENT) && \
defined(MBEDTLS_SHA256_USE_ARMV8_A_CRYPTO_ONLY)
#error "Must only define one of MBEDTLS_SHA256_USE_ARMV8_A_CRYPTO_*"
#endif
#if defined(MBEDTLS_SHA256_USE_ARMV8_A_CRYPTO_IF_PRESENT) || \
defined(MBEDTLS_SHA256_USE_ARMV8_A_CRYPTO_ONLY)
#if !defined(MBEDTLS_SHA256_C)
#error "MBEDTLS_SHA256_USE_ARMV8_A_CRYPTO_* defined without the SHA-256 built-in implementation"
#endif
#endif
#if defined(MBEDTLS_SHA256_USE_ARMV8_A_CRYPTO_ONLY) && !defined(MBEDTLS_ARCH_IS_ARMV8_A)
#error "MBEDTLS_SHA256_USE_ARMV8_A_CRYPTO_ONLY defined on non-Armv8-A system"
#endif
#if defined(MBEDTLS_THREADING_PTHREAD)
#if !defined(MBEDTLS_THREADING_C) || defined(MBEDTLS_THREADING_IMPL)
#error "MBEDTLS_THREADING_PTHREAD defined, but not all prerequisites"
#endif
#define MBEDTLS_THREADING_IMPL // undef at the end of this paragraph
#endif
#if defined(MBEDTLS_THREADING_ALT)
#if !defined(MBEDTLS_THREADING_C) || defined(MBEDTLS_THREADING_IMPL)
#error "MBEDTLS_THREADING_ALT defined, but not all prerequisites"
#endif
#define MBEDTLS_THREADING_IMPL // undef at the end of this paragraph
#endif
#if defined(MBEDTLS_THREADING_C) && !defined(MBEDTLS_THREADING_IMPL)
#error "MBEDTLS_THREADING_C defined, single threading implementation required"
#endif
#undef MBEDTLS_THREADING_IMPL // temporary macro defined above
#if defined(MBEDTLS_HAVE_INT32) && defined(MBEDTLS_HAVE_INT64)
#error "MBEDTLS_HAVE_INT32 and MBEDTLS_HAVE_INT64 cannot be defined simultaneously"
#endif /* MBEDTLS_HAVE_INT32 && MBEDTLS_HAVE_INT64 */
#if ( defined(MBEDTLS_HAVE_INT32) || defined(MBEDTLS_HAVE_INT64) ) && \
defined(MBEDTLS_HAVE_ASM)
#error "MBEDTLS_HAVE_INT32/MBEDTLS_HAVE_INT64 and MBEDTLS_HAVE_ASM cannot be defined simultaneously"
#endif /* (MBEDTLS_HAVE_INT32 || MBEDTLS_HAVE_INT64) && MBEDTLS_HAVE_ASM */
#if (defined(PSA_WANT_ECC_SECP_R1_192) || defined(PSA_WANT_ECC_SECP_K1_192)) //no-check-names
#error "PSA_WANT_ECC_SECP_R1_192 and PSA_WANT_ECC_SECP_K1_192 are no longer supported"
#endif
/* *INDENT-ON* */
#endif /* TF_PSA_CRYPTO_TF_PSA_CRYPTO_CHECK_CONFIG_H */
+628
View File
@@ -0,0 +1,628 @@
/**
* \file tf_psa_crypto_common.h
*
* \brief Utility macros for internal use in the library.
*
* This file should be included as the first thing in all library C files.
* It must not be included by sample programs, since sample programs
* illustrate what you can do without the library sources.
* It may be included (often indirectly) by test code that isn't purely
* black-box testing.
*
* This file takes care of setting up requirements for platform headers.
* It includes the library configuration and derived macros.
* It additionally defines various utility macros and other definitions
* (but no function declarations).
*/
/*
* Copyright The Mbed TLS Contributors
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
*/
#ifndef TF_PSA_CRYPTO_TF_PSA_CRYPTO_COMMON_H
#define TF_PSA_CRYPTO_TF_PSA_CRYPTO_COMMON_H
/* Before including any system header, declare some macros to tell system
* headers what we expect of them. */
#include "tf_psa_crypto_platform_requirements.h"
/* From this point onwards, ensure we have the library configuration and
* the configuration-derived macros. */
#include "tf-psa-crypto/build_info.h"
#include "alignment.h"
#include <assert.h>
#include <stddef.h>
#include <stdint.h>
#include <stddef.h>
#if defined(__ARM_NEON)
#include <arm_neon.h>
#define MBEDTLS_HAVE_NEON_INTRINSICS
#elif defined(MBEDTLS_PLATFORM_IS_WINDOWS_ON_ARM64)
#include <arm64_neon.h>
#define MBEDTLS_HAVE_NEON_INTRINSICS
#endif
/* Decide whether we're built for a Unix-like platform.
*/
#if defined(MBEDTLS_TEST_PLATFORM_IS_NOT_UNIXLIKE) //no-check-names
/* We may be building on a Unix-like platform, but for test purposes,
* do not try to use Unix features. */
#elif defined(_WIN32)
/* If Windows platform interfaces are available, we use them, even if
* a Unix-like might also to be available. */
/* defined(_WIN32) ==> we can include <windows.h> */
#elif defined(unix) || defined(__unix) || defined(__unix__) || \
(defined(__APPLE__) && defined(__MACH__)) || \
defined(__HAIKU__) || \
defined(__midipix__) || \
/* Add other Unix-like platform indicators here ^^^^ */ 0
/* defined(MBEDTLS_PLATFORM_IS_UNIXLIKE) ==> we can include <unistd.h> */
#define MBEDTLS_PLATFORM_IS_UNIXLIKE
#endif
/** Helper to define a function as static except when building invasive tests.
*
* If a function is only used inside its own source file and should be
* declared `static` to allow the compiler to optimize for code size,
* but that function has unit tests, define it with
* ```
* MBEDTLS_STATIC_TESTABLE int mbedtls_foo(...) { ... }
* ```
* and declare it in a header in the `library/` directory with
* ```
* #if defined(MBEDTLS_TEST_HOOKS)
* int mbedtls_foo(...);
* #endif
* ```
*/
#if defined(MBEDTLS_TEST_HOOKS)
#define MBEDTLS_STATIC_TESTABLE
#else
#define MBEDTLS_STATIC_TESTABLE static
#endif
#if defined(MBEDTLS_TEST_HOOKS)
extern void (*mbedtls_test_hook_test_fail)(const char *test, int line, const char *file);
#define MBEDTLS_TEST_HOOK_TEST_ASSERT(TEST) \
do { \
if ((!(TEST)) && ((*mbedtls_test_hook_test_fail) != NULL)) \
{ \
(*mbedtls_test_hook_test_fail)( #TEST, __LINE__, __FILE__); \
} \
} while (0)
#else
#define MBEDTLS_TEST_HOOK_TEST_ASSERT(TEST)
#endif /* defined(MBEDTLS_TEST_HOOKS) */
/** \def ARRAY_LENGTH
* Return the number of elements of a static or stack array.
*
* \param array A value of array (not pointer) type.
*
* \return The number of elements of the array.
*/
/* A correct implementation of ARRAY_LENGTH, but which silently gives
* a nonsensical result if called with a pointer rather than an array. */
#define ARRAY_LENGTH_UNSAFE(array) \
(sizeof(array) / sizeof(*(array)))
#if defined(__GNUC__)
/* Test if arg and &(arg)[0] have the same type. This is true if arg is
* an array but not if it's a pointer. */
#define IS_ARRAY_NOT_POINTER(arg) \
(!__builtin_types_compatible_p(__typeof__(arg), \
__typeof__(&(arg)[0])))
/* A compile-time constant with the value 0. If `const_expr` is not a
* compile-time constant with a nonzero value, cause a compile-time error. */
#define STATIC_ASSERT_EXPR(const_expr) \
(0 && sizeof(struct { unsigned int STATIC_ASSERT : (const_expr) ? 1 : -1; }))
/* Return the scalar value `value` (possibly promoted). This is a compile-time
* constant if `value` is. `condition` must be a compile-time constant.
* If `condition` is false, arrange to cause a compile-time error. */
#define STATIC_ASSERT_THEN_RETURN(condition, value) \
(STATIC_ASSERT_EXPR(condition) ? 0 : (value))
#define ARRAY_LENGTH(array) \
(STATIC_ASSERT_THEN_RETURN(IS_ARRAY_NOT_POINTER(array), \
ARRAY_LENGTH_UNSAFE(array)))
#else
/* If we aren't sure the compiler supports our non-standard tricks,
* fall back to the unsafe implementation. */
#define ARRAY_LENGTH(array) ARRAY_LENGTH_UNSAFE(array)
#endif
#if defined(__has_builtin)
#define MBEDTLS_HAS_BUILTIN(x) __has_builtin(x)
#else
#define MBEDTLS_HAS_BUILTIN(x) 0
#endif
/** Allow library to access its structs' private members.
*
* Although structs defined in header files are publicly available,
* their members are private and should not be accessed by the user.
*/
#define MBEDTLS_ALLOW_PRIVATE_ACCESS
/**
* \brief Securely zeroize a buffer then free it.
*
* Similar to making consecutive calls to
* \c mbedtls_platform_zeroize() and \c mbedtls_free(), but has
* code size savings, and potential for optimisation in the future.
*
* Guaranteed to be a no-op if \p buf is \c NULL and \p len is 0.
*
* \param buf Buffer to be zeroized then freed.
* \param len Length of the buffer in bytes
*/
void mbedtls_zeroize_and_free(void *buf, size_t len);
/** Return an offset into a buffer.
*
* This is just the addition of an offset to a pointer, except that this
* function also accepts an offset of 0 into a buffer whose pointer is null.
* (`p + n` has undefined behavior when `p` is null, even when `n == 0`.
* A null pointer is a valid buffer pointer when the size is 0, for example
* as the result of `malloc(0)` on some platforms.)
*
* \param p Pointer to a buffer of at least n bytes.
* This may be \p NULL if \p n is zero.
* \param n An offset in bytes.
* \return Pointer to offset \p n in the buffer \p p.
* Note that this is only a valid pointer if the size of the
* buffer is at least \p n + 1.
*/
static inline unsigned char *mbedtls_buffer_offset(
unsigned char *p, size_t n)
{
return p == NULL ? NULL : p + n;
}
/** Return an offset into a read-only buffer.
*
* Similar to mbedtls_buffer_offset(), but for const pointers.
*
* \param p Pointer to a buffer of at least n bytes.
* This may be \p NULL if \p n is zero.
* \param n An offset in bytes.
* \return Pointer to offset \p n in the buffer \p p.
* Note that this is only a valid pointer if the size of the
* buffer is at least \p n + 1.
*/
static inline const unsigned char *mbedtls_buffer_offset_const(
const unsigned char *p, size_t n)
{
return p == NULL ? NULL : p + n;
}
/* Always inline mbedtls_xor() for similar reasons as mbedtls_xor_no_simd(). */
#if defined(__IAR_SYSTEMS_ICC__)
#pragma inline = forced
#elif defined(__GNUC__)
__attribute__((always_inline))
#endif
/**
* Perform a fast block XOR operation, such that
* r[i] = a[i] ^ b[i] where 0 <= i < n
*
* \param r Pointer to result (buffer of at least \p n bytes). \p r
* may be equal to either \p a or \p b, but behaviour when
* it overlaps in other ways is undefined.
* \param a Pointer to input (buffer of at least \p n bytes)
* \param b Pointer to input (buffer of at least \p n bytes)
* \param n Number of bytes to process.
*
* \note Depending on the situation, it may be faster to use either mbedtls_xor() or
* mbedtls_xor_no_simd() (these are functionally equivalent).
* If the result is used immediately after the xor operation in non-SIMD code (e.g, in
* AES-CBC), there may be additional latency to transfer the data from SIMD to scalar
* registers, and in this case, mbedtls_xor_no_simd() may be faster. In other cases where
* the result is not used immediately (e.g., in AES-CTR), mbedtls_xor() may be faster.
* For targets without SIMD support, they will behave the same.
*/
static inline void mbedtls_xor(unsigned char *r,
const unsigned char *a,
const unsigned char *b,
size_t n)
{
size_t i = 0;
#if defined(MBEDTLS_EFFICIENT_UNALIGNED_ACCESS)
#if defined(MBEDTLS_HAVE_NEON_INTRINSICS) && \
(!(defined(MBEDTLS_COMPILER_IS_GCC) && MBEDTLS_GCC_VERSION < 70300))
/* Old GCC versions generate a warning here, so disable the NEON path for these compilers */
for (; (i + 16) <= n; i += 16) {
uint8x16_t v1 = vld1q_u8(a + i);
uint8x16_t v2 = vld1q_u8(b + i);
uint8x16_t x = veorq_u8(v1, v2);
vst1q_u8(r + i, x);
}
#if defined(__IAR_SYSTEMS_ICC__)
/* This if statement helps some compilers (e.g., IAR) optimise out the byte-by-byte tail case
* where n is a constant multiple of 16.
* For other compilers (e.g. recent gcc and clang) it makes no difference if n is a compile-time
* constant, and is a very small perf regression if n is not a compile-time constant. */
if (n % 16 == 0) {
return;
}
#endif
#if defined(MBEDTLS_COMPILER_IS_GCC) && MBEDTLS_HAS_BUILTIN(__builtin_constant_p)
/* Some GCC versions (e.g. 14.3) with compile-time array bounds checking are confused
* when the byte-by-byte tail case is unused because the length is a constant multiple
* of 16. Eliminate a run-time check by only doing this for constant values. */
if (__builtin_constant_p(n) && n % 16 == 0) {
return;
}
#endif
#elif defined(MBEDTLS_ARCH_IS_X64) || defined(MBEDTLS_ARCH_IS_ARM64)
/* This codepath probably only makes sense on architectures with 64-bit registers */
for (; (i + 8) <= n; i += 8) {
uint64_t x = mbedtls_get_unaligned_uint64(a + i) ^ mbedtls_get_unaligned_uint64(b + i);
mbedtls_put_unaligned_uint64(r + i, x);
}
#if defined(__IAR_SYSTEMS_ICC__)
if (n % 8 == 0) {
return;
}
#endif
#if defined(MBEDTLS_COMPILER_IS_GCC) && MBEDTLS_HAS_BUILTIN(__builtin_constant_p)
/* Some GCC versions (e.g. 14.3) with compile-time array bounds checking are confused
* when the byte-by-byte tail case is unused because the length is a constant multiple
* of 8. Eliminate a run-time check by only doing this for constant values. */
if (__builtin_constant_p(n) && n % 8 == 0) {
return;
}
#endif
#else
for (; (i + 4) <= n; i += 4) {
uint32_t x = mbedtls_get_unaligned_uint32(a + i) ^ mbedtls_get_unaligned_uint32(b + i);
mbedtls_put_unaligned_uint32(r + i, x);
}
#if defined(__IAR_SYSTEMS_ICC__)
if (n % 4 == 0) {
return;
}
#endif
#if defined(MBEDTLS_COMPILER_IS_GCC) && MBEDTLS_HAS_BUILTIN(__builtin_constant_p)
/* Some GCC versions (e.g. 14.3) with compile-time array bounds checking are confused
* when the byte-by-byte tail case is unused because the length is a constant multiple
* of 4. Eliminate a run-time check by only doing this for constant values. */
if (__builtin_constant_p(n) && n % 4 == 0) {
return;
}
#endif
#endif
#endif
for (; i < n; i++) {
r[i] = a[i] ^ b[i];
}
}
/* Always inline mbedtls_xor_no_simd() as we see significant perf regressions when it does not get
* inlined (e.g., observed about 3x perf difference in gcm_mult_largetable with gcc 7 - 12) */
#if defined(__IAR_SYSTEMS_ICC__)
#pragma inline = forced
#elif defined(__GNUC__)
__attribute__((always_inline))
#endif
/**
* Perform a fast block XOR operation, such that
* r[i] = a[i] ^ b[i] where 0 <= i < n
*
* In some situations, this can perform better than mbedtls_xor() (e.g., it's about 5%
* better in AES-CBC).
*
* \param r Pointer to result (buffer of at least \p n bytes). \p r
* may be equal to either \p a or \p b, but behaviour when
* it overlaps in other ways is undefined.
* \param a Pointer to input (buffer of at least \p n bytes)
* \param b Pointer to input (buffer of at least \p n bytes)
* \param n Number of bytes to process.
*
* \note Depending on the situation, it may be faster to use either mbedtls_xor() or
* mbedtls_xor_no_simd() (these are functionally equivalent).
* If the result is used immediately after the xor operation in non-SIMD code (e.g, in
* AES-CBC), there may be additional latency to transfer the data from SIMD to scalar
* registers, and in this case, mbedtls_xor_no_simd() may be faster. In other cases where
* the result is not used immediately (e.g., in AES-CTR), mbedtls_xor() may be faster.
* For targets without SIMD support, they will behave the same.
*/
static inline void mbedtls_xor_no_simd(unsigned char *r,
const unsigned char *a,
const unsigned char *b,
size_t n)
{
size_t i = 0;
#if defined(MBEDTLS_EFFICIENT_UNALIGNED_ACCESS)
#if defined(MBEDTLS_ARCH_IS_X64) || defined(MBEDTLS_ARCH_IS_ARM64)
/* This codepath probably only makes sense on architectures with 64-bit registers */
for (; (i + 8) <= n; i += 8) {
uint64_t x = mbedtls_get_unaligned_uint64(a + i) ^ mbedtls_get_unaligned_uint64(b + i);
mbedtls_put_unaligned_uint64(r + i, x);
}
#if defined(__IAR_SYSTEMS_ICC__)
/* This if statement helps some compilers (e.g., IAR) optimise out the byte-by-byte tail case
* where n is a constant multiple of 8.
* For other compilers (e.g. recent gcc and clang) it makes no difference if n is a compile-time
* constant, and is a very small perf regression if n is not a compile-time constant. */
if (n % 8 == 0) {
return;
}
#endif
#else
for (; (i + 4) <= n; i += 4) {
uint32_t x = mbedtls_get_unaligned_uint32(a + i) ^ mbedtls_get_unaligned_uint32(b + i);
mbedtls_put_unaligned_uint32(r + i, x);
}
#if defined(__IAR_SYSTEMS_ICC__)
if (n % 4 == 0) {
return;
}
#endif
#endif
#endif
for (; i < n; i++) {
r[i] = a[i] ^ b[i];
}
}
/* Fix MSVC C99 compatible issue
* MSVC support __func__ from visual studio 2015( 1900 )
* Use MSVC predefine macro to avoid name check fail.
*/
#if (defined(_MSC_VER) && (_MSC_VER <= 1900))
#define /*no-check-names*/ __func__ __FUNCTION__
#endif
/* Define `asm` for compilers which don't define it. */
/* *INDENT-OFF* */
#ifndef asm
#if defined(__IAR_SYSTEMS_ICC__)
#define asm __asm
#else
#define asm __asm__
#endif
#endif
/* *INDENT-ON* */
/*
* Define the constraint used for read-only pointer operands to aarch64 asm.
*
* This is normally the usual "r", but for aarch64_32 (aka ILP32,
* as found in watchos), "p" is required to avoid warnings from clang.
*
* Note that clang does not recognise '+p' or '=p', and armclang
* does not recognise 'p' at all. Therefore, to update a pointer from
* aarch64 assembly, it is necessary to use something like:
*
* uintptr_t uptr = (uintptr_t) ptr;
* asm( "ldr x4, [%x0], #8" ... : "+r" (uptr) : : )
* ptr = (void*) uptr;
*
* Note that the "x" in "%x0" is neccessary; writing "%0" will cause warnings.
*/
#if defined(__aarch64__) && defined(MBEDTLS_HAVE_ASM)
#if UINTPTR_MAX == 0xfffffffful
/* ILP32: Specify the pointer operand slightly differently, as per #7787. */
#define MBEDTLS_ASM_AARCH64_PTR_CONSTRAINT "p"
#elif UINTPTR_MAX == 0xfffffffffffffffful
/* Normal case (64-bit pointers): use "r" as the constraint for pointer operands to asm */
#define MBEDTLS_ASM_AARCH64_PTR_CONSTRAINT "r"
#else
#error "Unrecognised pointer size for aarch64"
#endif
#endif
/** \def MBEDTLS_STATIC_ASSERT
*
* A static assert macro, equivalent to `static_assert` or `_Static_assert`
* in modern C.
*
* You can use `MBEDTLS_STATIC_ASSERT(expr, msg)` in any position where a
* declaration is permitted, both at the toplevel and within a function.
* This macro may not be used inside an expression (see #STATIC_ASSERT_EXPR,
* available on fewer platforms).
*
* \param expr An expression which must be a compile-time constant with
* an integer value. This doesn't have to be a preprocessor
* constant, for example it can use `sizeof`.
* The compilation fails if the value is 0.
* \param msg An error messsage to display if the value of \p expr is 0.
*/
#if __STDC_VERSION__ >= 202311L
/* static_assert is a keyword since C23 */
#define MBEDTLS_STATIC_ASSERT(expr, msg) static_assert(expr, msg)
#elif __STDC_VERSION__ >= 201112L
/* _Static_assert is a keyword since C11 */
#define MBEDTLS_STATIC_ASSERT(expr, msg) _Static_assert(expr, msg)
#elif defined(static_assert) && !defined(__STRICT_ANSI__)
/* If static_assert is defined as a macro, presumably from <assert.h>
* included above, then trust that it is what we expect.
* This is a common extension even before C11.
* However, don't use it if it looks like a build with `gcc -c99 -pedantic`
* or `clang -c99 -pedantic`, because they would complain about the use of
* a feature that doesn't exist in C99.
*/
#define MBEDTLS_STATIC_ASSERT(expr, msg) static_assert(expr, msg)
#elif defined(_MSC_VER)
/* MSVC has `static_assert` as a keyword (not a macro) since
* Visual Studio 2010.
*/
#define MBEDTLS_STATIC_ASSERT(expr, msg) static_assert(expr, msg)
#elif defined(__GNUC__) && \
((__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ > 4) && \
!defined(__STRICT_ANSI__)
/* _Static_assert is a keyword since GCC 4.6.
* However, don't use it if it looks like a build with `gcc -c99 -pedantic`
* or `clang -c99 -pedantic`, because they would complain about the use of
* a feature that doesn't exist in C99.
*/
#define MBEDTLS_STATIC_ASSERT(expr, msg) _Static_assert(expr, msg)
#elif defined(__COUNTER__)
/* Fall back to a hack that works in practice with non-ancient GCC-like
* compilers and MSVC, and doesn't trigger `-Wredundant-decls`.
*
* See the `#else` block below for an explanation. Here, we add another
* layer to make the declared name unique using the special preprocessor
* token `__COUNTER__`.
*/
#define MBEDTLS_STATIC_ASSERT_COUNTER(expr, counter) \
struct mbedtls_static_assert_anchor##counter { \
unsigned int STATIC_ASSERT : (expr) ? 1 : -1; \
}
#define MBEDTLS_STATIC_ASSERT_WRAP(expr, counter) \
MBEDTLS_STATIC_ASSERT_COUNTER(expr, counter)
#define MBEDTLS_STATIC_ASSERT(expr, msg) \
MBEDTLS_STATIC_ASSERT_WRAP(expr, __COUNTER__)
#else
/* Fall back to a hack that works in practice with almost all C compilers.
*
* Constraints:
* - Must be valid C99 when `expr` is a constant expression with a nonzero value.
* - Must compile without warnings on known compilers when `expr` is a
* constant expression with a nonzero value.
* - Must be valid both at file scope and inside a function.
* - Must allow multiple static assertions in the same scope.
* - Must not rely on `__LINE__` to create unique identifiers, since this
* could lead to collisions, e.g. if `MBEDTLS_STATIC_ASSERT` is used in
* a header, or if a macro expands to multiple uses of
* `MBEDTLS_STATIC_ASSERT`.
* - Should result in an error when `expr` evaluates to 0.
*
* How it works:
* - Ostensibly declare a function. This function will never be used, but
* declaring a function that won't be used is routine.
* - The function's name is in our namespace, so we just need to avoid that
* name for any other purpose.
* - Declaring the same function with the same prototype multiple times is
* also common (it triggers `gcc -Wredundant-decls`, but we handle
* non-ancient GCC separately above).
* - The function returns a pointer to an array.
* - The array size involves parsing an anonymous struct declaration.
* - The struct declaration contains a bit-field whose width is 1 if the
* assertion is true, and -1 otherwise. This is a constraint violation,
* requiring a diagnostic.
*
* Limitations:
* - If you have multiple static assertions in the same scope,
* `gcc -Wredundant-decls` complains.
* - When the assertion fails, some compilers complain about a negative
* bit-field width without displaying the problematic line, so the message
* is not visible.
*
* On Godbolt compiler explorer, the only failures I could find are:
* - CCC (Claude C Compiler) as of 2026-03-02 ignores the assertion.
* - Chibicc 2020-12-07 ignores the assertion.
* - LC3 (trunk) ignores the assertion.
* - MSVC warns about assertions, whether they pass or not:
* "warning C4116: unnamed type definition in parentheses"
* This doesn't matter because non-ancient MSVC supports __COUNTER__,
* which is covered above.
* - ppci 0.5.5 complains of a syntax error.
* - SDCC 4.5.0 (and earlier) complains if there are multiple assertions in
* the same scope, even if they pass:
* "extern definition for 'mbedtls_static_assert_anchor' mismatches with declaration."
* - x86 tendra (trunk) complains if there are multiple assertions in
* the same scope, even if they pass:
* " The types 'int ( * ( void ) ) [<exp1>]' and 'int ( * ( void ) ) [<exp2>]' are incompatible."
* - vast (trunk) complains about assertions at function scope,
* even if they pass:
* "unexpected error: failed to legalize operation 'll.func' that was explicitly marked illegal"
* This doesn't matter because it supports __COUNTER__, which is covered
* above.
*/
#define MBEDTLS_STATIC_ASSERT(expr, msg) \
extern int (*mbedtls_static_assert_anchor(void))[sizeof(struct { \
int STATIC_ASSERT : (expr) ? 1 : -1; \
})]
#endif
/* Define compiler branch hints */
#if MBEDTLS_HAS_BUILTIN(__builtin_expect)
#define MBEDTLS_LIKELY(x) __builtin_expect(!!(x), 1)
#define MBEDTLS_UNLIKELY(x) __builtin_expect(!!(x), 0)
#else
#define MBEDTLS_LIKELY(x) x
#define MBEDTLS_UNLIKELY(x) x
#endif
/* MBEDTLS_ASSUME may be used to provide additional information to the compiler
* which can result in smaller code-size. */
#if MBEDTLS_HAS_BUILTIN(__builtin_assume)
/* clang provides __builtin_assume */
#define MBEDTLS_ASSUME(x) __builtin_assume(x)
#elif MBEDTLS_HAS_BUILTIN(__builtin_unreachable)
/* gcc and IAR can use __builtin_unreachable */
#define MBEDTLS_ASSUME(x) do { if (!(x)) __builtin_unreachable(); } while (0)
#elif defined(_MSC_VER)
/* Supported by MSVC since VS 2005 */
#define MBEDTLS_ASSUME(x) __assume(x)
#else
#define MBEDTLS_ASSUME(x) do { } while (0)
#endif
/* For gcc -Os, override with -O2 for a given function.
*
* This will not affect behaviour for other optimisation settings, e.g. -O0.
*/
#if defined(MBEDTLS_COMPILER_IS_GCC) && defined(__OPTIMIZE_SIZE__)
#define MBEDTLS_OPTIMIZE_FOR_PERFORMANCE __attribute__((optimize("-O2")))
#else
#define MBEDTLS_OPTIMIZE_FOR_PERFORMANCE
#endif
/* Suppress compiler warnings for unused functions and variables. */
#if !defined(MBEDTLS_MAYBE_UNUSED) && defined(__has_attribute)
# if __has_attribute(unused)
# define MBEDTLS_MAYBE_UNUSED __attribute__((unused))
# endif
#endif
#if !defined(MBEDTLS_MAYBE_UNUSED) && defined(__GNUC__)
# define MBEDTLS_MAYBE_UNUSED __attribute__((unused))
#endif
#if !defined(MBEDTLS_MAYBE_UNUSED) && defined(__IAR_SYSTEMS_ICC__) && defined(__VER__)
/* IAR does support __attribute__((unused)), but only if the -e flag (extended language support)
* is given; the pragma always works.
* Unfortunately the pragma affects the rest of the file where it is used, but this is harmless.
* Check for version 5.2 or later - this pragma may be supported by earlier versions, but I wasn't
* able to find documentation).
*/
# if (__VER__ >= 5020000)
# define MBEDTLS_MAYBE_UNUSED _Pragma("diag_suppress=Pe177")
# endif
#endif
#if !defined(MBEDTLS_MAYBE_UNUSED) && defined(_MSC_VER)
# define MBEDTLS_MAYBE_UNUSED __pragma(warning(suppress:4189))
#endif
#if !defined(MBEDTLS_MAYBE_UNUSED)
# define MBEDTLS_MAYBE_UNUSED
#endif
/* GCC >= 15 has a warning 'unterminated-string-initialization' which complains if you initialize
* a string into an array without space for a terminating NULL character. In some places in the
* codebase this behaviour is intended, so we add the macro MBEDTLS_ATTRIBUTE_UNTERMINATED_STRING
* to suppress the warning in these places.
*/
#if defined(__has_attribute)
#if __has_attribute(nonstring)
#define MBEDTLS_HAS_ATTRIBUTE_NONSTRING
#endif /* __has_attribute(nonstring) */
#endif /* __has_attribute */
#if defined(MBEDTLS_HAS_ATTRIBUTE_NONSTRING)
#define MBEDTLS_ATTRIBUTE_UNTERMINATED_STRING __attribute__((nonstring))
#else
#define MBEDTLS_ATTRIBUTE_UNTERMINATED_STRING
#endif /* MBEDTLS_HAS_ATTRIBUTE_NONSTRING */
#endif /* TF_PSA_CRYPTO_TF_PSA_CRYPTO_COMMON_H */
+70
View File
@@ -0,0 +1,70 @@
/*
* TF-PSA-Crypto configuration checks
*/
/*
* Copyright The Mbed TLS Contributors
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
*/
/* Detect whether this is a normal build of the library, or a build of
* libtestdriver1, where all identifiers starting with normal prefixes
* have LIBTESTDRIVER1_ prepended. Do this without relying on
* any headers, since this has to happen before we include
* tf_psa_crypto/build_info.h.
*
* In the libtestdriver1 build, the next two code lines are
* `#define LIBTESTDRIVER_FOO 1` and
* `#if LIBTESTDRIVER_FOO == LIBTESTDRIVER_FOO` so the conditional is true.
* In a normal build, `LIBTESTDRIVER1_TF_PSA_CRYPTO_MARKER` remains
* undefined so the conditional is false.
*/
#define TF_PSA_CRYPTO_MARKER 1
#if LIBTESTDRIVER1_TF_PSA_CRYPTO_MARKER == TF_PSA_CRYPTO_MARKER
#define TF_PSA_CRYPTO_WE_ARE_IN_LIBTESTDRIVER1
#endif
#undef TF_PSA_CRYPTO_MARKER
/* Completely byass generated config checks in libtestdriver1, where
* they aren't useful (when building test drivers, we can bypass
* normal configuration mechanisms if we want).
* This way we don't have to make them work. Since we bypass the
* header inclusions, the build system doesn't even need to know how
* to generate files with the right names and in the right locations.
*/
#if !defined(TF_PSA_CRYPTO_WE_ARE_IN_LIBTESTDRIVER1)
/* Consistency checks on the user's configuration.
* Check that it doesn't define macros that we assume are under full
* control of the library, or options from past major versions that
* no longer have any effect.
* These headers are automatically generated. See
* framework/scripts/mbedtls_framework/config_checks_generator.py
*
* This here is the first stage, before including the user config.
*/
#include "tf_psa_crypto_config_check_before.h"
/* The second stage, after including the user config but before doing
* any subsequent adjustment, will be included by build_info.h. */
#define TF_PSA_CRYPTO_INCLUDE_AFTER_RAW_CONFIG "tf_psa_crypto_config_check_user.h"
#endif /* !defined(TF_PSA_CRYPTO_WE_ARE_IN_LIBTESTDRIVER1) */
#include <tf-psa-crypto/build_info.h>
/* Consistency checks in the configuration: check for incompatible options,
* missing options when at least one of a set needs to be enabled, etc. */
/* Manually written checks */
#include "tf_psa_crypto_check_config.h"
#if !defined(TF_PSA_CRYPTO_WE_ARE_IN_LIBTESTDRIVER1)
/* Automatically generated checks (final stage after config adjustment) */
#include "tf_psa_crypto_config_check_final.h"
#endif /* !defined(TF_PSA_CRYPTO_WE_ARE_IN_LIBTESTDRIVER1) */
/* For MBEDTLS_STATIC_ASSERT */
#include "tf_psa_crypto_common.h"
/* For PSA_HASH_LENGTH */
#include <psa/crypto_sizes.h>
/* Additional domain-specific checks */
#if defined(MBEDTLS_PSA_CRYPTO_C)
#include "psa_crypto_random_impl.h"
#endif
@@ -0,0 +1,12 @@
/* tf_psa_crypto_config_check_before.h (generated part of tf_psa_crypto_config.c). */
/* Automatically generated by generate_config_checks.py. Do not edit! */
#if !defined(TF_PSA_CRYPTO_CONFIG_CHECK_BYPASS) //no-check-names
/* *INDENT-OFF* */
/* *INDENT-ON* */
#endif /* !defined(TF_PSA_CRYPTO_CONFIG_CHECK_BYPASS) */ //no-check-names
/* End of automatically generated tf_psa_crypto_config_check_before.h */
@@ -0,0 +1,12 @@
/* tf_psa_crypto_config_check_final.h (generated part of tf_psa_crypto_config.c). */
/* Automatically generated by generate_config_checks.py. Do not edit! */
#if !defined(TF_PSA_CRYPTO_CONFIG_CHECK_BYPASS) //no-check-names
/* *INDENT-OFF* */
/* *INDENT-ON* */
#endif /* !defined(TF_PSA_CRYPTO_CONFIG_CHECK_BYPASS) */ //no-check-names
/* End of automatically generated tf_psa_crypto_config_check_final.h */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,62 @@
/**
* \file tf_psa_crypto_platform_requirements.h
*
* \brief Declare macros that tell system headers what we expect of them.
*
* This file must be included before any system header, and so in particular
* before build_info.h (which includes the user config, which may include
* system headers).
*/
/*
* Copyright The Mbed TLS Contributors
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
*/
#ifndef TF_PSA_CRYPTO_TF_PSA_CRYPTO_PLATFORM_REQUIREMENTS_H
#define TF_PSA_CRYPTO_TF_PSA_CRYPTO_PLATFORM_REQUIREMENTS_H
#ifndef __STDC_WANT_LIB_EXT1__
/* Ask for the C11 gmtime_s() and memset_s() if available */
#define __STDC_WANT_LIB_EXT1__ 1
#endif
#if !defined(_POSIX_C_SOURCE)
/* For standards-compliant access to
* clock_gettime(), gmtime_r(), ...
*/
#define _POSIX_C_SOURCE 200112L
#endif
/* With GNU libc, define all the things, even when compiling with -pedantic. */
#if !defined(_GNU_SOURCE)
#define _GNU_SOURCE
#endif
/* On NetBSD, needed to include <sys/sysctl.h>, which we do in platform_util.c
* to get sysctl() and KERN_ARND. */
#if defined(__NetBSD__) && !defined(_NETBSD_SOURCE)
#define _NETBSD_SOURCE
#endif
/* On OpenBSD, needed to make <string.h> declare explicit_bzero()
* (<strings.h> doesn't declare it). Not used on FreeBSD or NetBSD,
* but causes Glibc to complain. */
#if defined(__OpenBSD__) && !defined(_BSD_SOURCE)
#define _BSD_SOURCE
#endif
/* On Mingw-w64, force the use of a C99-compliant printf() and friends.
* This is necessary on older versions of Mingw and/or Windows runtimes
* where snprintf does not always zero-terminate the buffer, and does
* not support formats such as "%zu" for size_t and "%lld" for long long.
*
* Defining __USE_MINGW_ANSI_STDIO=0 may work and provide a small code size
* and performance benefit for some combinations of older Mingw and Windows
* versions. Do this at your own risk and make sure that least
* test_suite_platform_printf passes.
*/
#if !defined(__USE_MINGW_ANSI_STDIO)
#define __USE_MINGW_ANSI_STDIO 1
#endif
#endif /* TF_PSA_CRYPTO_TF_PSA_CRYPTO_PLATFORM_REQUIREMENTS_H */
@@ -0,0 +1,28 @@
/*
* Version information
*
* Copyright The Mbed TLS Contributors
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
*/
#include "tf_psa_crypto_common.h"
#if defined(TF_PSA_CRYPTO_VERSION)
#include "tf-psa-crypto/version.h"
unsigned int tf_psa_crypto_version_get_number(void)
{
return TF_PSA_CRYPTO_VERSION_NUMBER;
}
const char *tf_psa_crypto_version_get_string(void)
{
return TF_PSA_CRYPTO_VERSION_STRING;
}
const char *tf_psa_crypto_version_get_string_full(void)
{
return TF_PSA_CRYPTO_VERSION_STRING_FULL;
}
#endif /* TF_PSA_CRYPTO_VERSION */
+37
View File
@@ -0,0 +1,37 @@
Developer Certificate of Origin
Version 1.1
Copyright (C) 2004, 2006 The Linux Foundation and its contributors.
1 Letterman Drive
Suite D4700
San Francisco, CA, 94129
Everyone is permitted to copy and distribute verbatim copies of this
license document, but changing it is not allowed.
Developer's Certificate of Origin 1.1
By making a contribution to this project, I certify that:
(a) The contribution was created in whole or in part by me and I
have the right to submit it under the open source license
indicated in the file; or
(b) The contribution is based upon previous work that, to the best
of my knowledge, is covered under an appropriate open source
license and I have the right under that license to submit that
work with modifications, whether created in whole or in part
by me, under the same open source license (unless I am
permitted to submit under a different license), as indicated
in the file; or
(c) The contribution was provided directly to me by some other
person who certified (a), (b) or (c) and I have not modified
it.
(d) I understand and agree that this project and the contribution
are public and that a record of the contribution (including all
personal information I submit with it, including my sign-off) is
maintained indefinitely and may be redistributed consistent with
this project or the open source license(s) involved.
@@ -0,0 +1,31 @@
/*
* Function signatures for functionality that can be provided by
* cryptographic accelerators.
*/
/* Copyright The Mbed TLS Contributors
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
*/
#ifndef TF_PSA_CRYPTO_PSA_CRYPTO_DRIVER_WRAPPERS_NO_STATIC_H
#define TF_PSA_CRYPTO_PSA_CRYPTO_DRIVER_WRAPPERS_NO_STATIC_H
#include "psa/crypto.h"
#include "psa/crypto_driver_common.h"
psa_status_t psa_driver_wrapper_export_public_key(
const psa_key_attributes_t *attributes,
const uint8_t *key_buffer, size_t key_buffer_size,
uint8_t *data, size_t data_size, size_t *data_length);
psa_status_t psa_driver_wrapper_get_key_buffer_size(
const psa_key_attributes_t *attributes,
size_t *key_buffer_size);
psa_status_t psa_driver_wrapper_get_builtin_key(
psa_drv_slot_number_t slot_number,
psa_key_attributes_t *attributes,
uint8_t *key_buffer, size_t key_buffer_size, size_t *key_buffer_length);
#endif /* TF_PSA_CRYPTO_PSA_CRYPTO_DRIVER_WRAPPERS_NO_STATIC_H */
/* End of automatically generated file. */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,22 @@
This directory contains sections intended for the migration guide
from Mbed TLS 3.6 to TF-PSA-Crypto 1.0 + Mbed TLS 4.0.
The files in this document should be markdown files with the .md
extension. They should generally contain level-2 sections (## title).
The files will be consolidated into a single cohesive document or
document set shortly before the .0 releases.
The reason to have multiple files is that each strand of work can create
one file, without worrying about where to fit in the document structure.
We'll worry about the general structure once we have the content.
Furthermore, placing different strands of work in separate files will
avoid merge conflicts (as would happen e.g. if parallel strands of
work append to the same file in concurrent pull requests).
Files can be placed in the docs/4.0-migration-guide indifferently in
mbedtls or TF-PSA-Crypto, as convenient.
Documentation that is specifically about migrating from the legacy
crypto API to the PSA crypto API should be added to the existing
docs/psa-transition.md instead.
@@ -0,0 +1,36 @@
## Compile-time configuration
### Configuration file split
Whether you are using TF-PSA-Crypto as a standalone project or as part of Mbed TLS, all the configuration options that are relevant to TF-PSA-Crypto must be configured in one of its configuration files, namely:
* `TF_PSA_CRYPTO_CONFIG_FILE`, if set on the preprocessor command line;
* otherwise `<psa/crypto_config.h>`;
* additionally `TF_PSA_CRYPTO_USER_CONFIG_FILE`, if set.
The macros `MBEDTLS_PSA_CRYPTO_CONFIG_FILE` and `MBEDTLS_PSA_CRYPTO_USER_CONFIG_FILE` are no longer recognized. Use `TF_PSA_CRYPTO_CONFIG_FILE` and `TF_PSA_CRYPTO_USER_CONFIG_FILE` instead
Configuration options that are relevant to X.509 or TLS should still be set in the Mbed TLS configuration file (`MBEDTLS_CONFIG_FILE` or `<mbedtls/mbedtls_config.h>`, plus `MBEDTLS_USER_CONFIG_FILE` if it is set). However, you can define all options in the crypto configuration, and Mbed TLS will pick them up.
Generally speaking, the options that must be configured in TF-PSA-Crypto are:
* options related to platform settings;
* options related to the choice of cryptographic mechanisms included in the build;
* options related to the inner workings of cryptographic mechanisms, such as size/memory/performance compromises;
* options related to crypto-adjacent features, such as ASN.1 and Base64.
See `include/psa/crypto_config.h` in TF-PSA-Crypto and `include/mbedtls/mbedtls_config.h` in Mbed TLS for details.
Notably, `<psa/crypto_config.h>` is no longer limited to `PSA_WANT_xxx` options.
Note that many options related to cryptography have changed; this is covered in other sections of this document.
### Split of `build_info.h` and `version.h`
TF-PSA-Crypto has a header file `<tf-psa-crypto/build_info.h>` which includes the configuration file and provides the adjusted configuration macros, similar to `<mbedtls/build_info.h>` in Mbed TLS.
TF-PSA-Crypto exposes its version through `<tf-psa-crypto/version.h>`, similar to `<mbedtls/version.h>` in Mbed TLS.
### Removal of `check_config.h`
The header `mbedtls/check_config.h` is no longer present. Including it from user configuration files was already obsolete in Mbed TLS 3.x, since it enforces properties of the configuration as adjusted by `mbedtls/build_info.h`, not properties that the user configuration is expected to meet.
@@ -0,0 +1,77 @@
## Error codes
### Unified error code space
The convention still applies that functions return 0 for success and a negative value between -32767 and -1 on error. PSA functions (`psa_xxx()` or `mbedtls_psa_xxx()`) still return a `PSA_ERROR_xxx` error codes. Non-PSA functions (`mbedtls_xxx()` excluding `mbedtls_psa_xxx()`) can return either `PSA_ERROR_xxx` or `MBEDTLS_ERR_xxx` error codes.
There may be cases where an `MBEDTLS_ERR_xxx` constant has the same numerical value as a `PSA_ERROR_xxx`. In such cases, they have the same meaning: they are different names for the same error condition.
### Simplified legacy error codes
All values returned by a function to indicate an error now have a defined constant named `MBEDTLS_ERR_xxx` or `PSA_ERROR_xxx`. Functions no longer return the sum of a “low-level” and a “high-level” error code.
Generally, functions that used to return the sum of two error codes now return the low-level code. However, as before, the exact error code returned in a given scenario can change without notice unless the condition is specifically described in the function's documentation and no other condition is applicable.
As a consequence, the functions `mbedtls_low_level_strerr()` and `mbedtls_high_level_strerr()` no longer exist.
### Removed English error messages
TF-PSA-Crypto does not provide English text corresponding to error codes. The functionality provided by `mbedtls_strerror()` in `mbedtls/error.h` is still present in Mbed TLS.
### Removed error code names
Many legacy error codes have been removed in favor of PSA error codes. Generally, functions that returned a legacy error code in the table below in Mbed TLS 3.6 now return the PSA error code listed on the same row. Similarly, callbacks should apply the same changes to error code, unless there has been a relevant change to the callback's interface.
| Legacy constant (Mbed TLS 3.6) | PSA constant (TF-PSA-Crypto 1.0) |
|--------------------------------------------|----------------------------------|
| `MBEDTLS_ERR_AES_BAD_INPUT_DATA` | `PSA_ERROR_INVALID_ARGUMENT` |
| `MBEDTLS_ERR_ARIA_BAD_INPUT_DATA` | `PSA_ERROR_INVALID_ARGUMENT` |
| `MBEDTLS_ERR_ASN1_ALLOC_FAILED` | `PSA_ERROR_INSUFFICIENT_MEMORY` |
| `MBEDTLS_ERR_ASN1_BUF_TOO_SMALL` | `PSA_ERROR_BUFFER_TOO_SMALL` |
| `MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL` | `PSA_ERROR_BUFFER_TOO_SMALL` |
| `MBEDTLS_ERR_CAMELLIA_BAD_INPUT_DATA` | `PSA_ERROR_INVALID_ARGUMENT` |
| `MBEDTLS_ERR_CCM_AUTH_FAILED` | `PSA_ERROR_INVALID_SIGNATURE` |
| `MBEDTLS_ERR_CCM_BAD_INPUT_DATA` | `PSA_ERROR_INVALID_ARGUMENT` |
| `MBEDTLS_ERR_CHACHA20_BAD_INPUT_DATA` | `PSA_ERROR_INVALID_ARGUMENT` |
| `MBEDTLS_ERR_CHACHAPOLY_AUTH_FAILED` | `PSA_ERROR_INVALID_SIGNATURE` |
| `MBEDTLS_ERR_CIPHER_ALLOC_FAILED` | `PSA_ERROR_INSUFFICIENT_MEMORY` |
| `MBEDTLS_ERR_CIPHER_AUTH_FAILED` | `PSA_ERROR_INVALID_SIGNATURE` |
| `MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA` | `PSA_ERROR_INVALID_ARGUMENT` |
| `MBEDTLS_ERR_CIPHER_INVALID_PADDING` | `PSA_ERROR_INVALID_PADDING` |
| `MBEDTLS_ERR_ECP_ALLOC_FAILED` | `PSA_ERROR_INSUFFICIENT_MEMORY` |
| `MBEDTLS_ERR_ECP_BAD_INPUT_DATA` | `PSA_ERROR_INVALID_ARGUMENT` |
| `MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL` | `PSA_ERROR_BUFFER_TOO_SMALL` |
| `MBEDTLS_ERR_ECP_IN_PROGRESS` | `PSA_OPERATION_INCOMPLETE` |
| `MBEDTLS_ERR_ECP_SIG_LEN_MISMATCH` | `PSA_ERROR_INVALID_SIGNATURE` |
| `MBEDTLS_ERR_ECP_VERIFY_FAILED` | `PSA_ERROR_INVALID_SIGNATURE` |
| `MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED` | `PSA_ERROR_CORRUPTION_DETECTED` |
| `MBEDTLS_ERR_ERROR_GENERIC_ERROR` | `PSA_ERROR_GENERIC_ERROR` |
| `MBEDTLS_ERR_GCM_AUTH_FAILED` | `PSA_ERROR_INVALID_SIGNATURE` |
| `MBEDTLS_ERR_GCM_BAD_INPUT` | `PSA_ERROR_INVALID_ARGUMENT` |
| `MBEDTLS_ERR_GCM_BUFFER_TOO_SMALL` | `PSA_ERROR_BUFFER_TOO_SMALL` |
| `MBEDTLS_ERR_LMS_ALLOC_FAILED` | `PSA_ERROR_INSUFFICIENT_MEMORY` |
| `MBEDTLS_ERR_LMS_BAD_INPUT_DATA` | `PSA_ERROR_INVALID_ARGUMENT` |
| `MBEDTLS_ERR_LMS_BUFFER_TOO_SMALL` | `PSA_ERROR_BUFFER_TOO_SMALL` |
| `MBEDTLS_ERR_MD_ALLOC_FAILED` | `PSA_ERROR_INSUFFICIENT_MEMORY` |
| `MBEDTLS_ERR_MD_BAD_INPUT_DATA` | `PSA_ERROR_INVALID_ARGUMENT` |
| `MBEDTLS_ERR_MPI_ALLOC_FAILED` | `PSA_ERROR_INSUFFICIENT_MEMORY` |
| `MBEDTLS_ERR_MPI_BAD_INPUT_DATA` | `PSA_ERROR_INVALID_ARGUMENT` |
| `MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL` | `PSA_ERROR_BUFFER_TOO_SMALL` |
| `MBEDTLS_ERR_OID_NOT_FOUND` | `PSA_ERROR_NOT_SUPPORTED` |
| `MBEDTLS_ERR_PEM_ALLOC_FAILED` | `PSA_ERROR_INSUFFICIENT_MEMORY` |
| `MBEDTLS_ERR_PEM_BAD_INPUT_DATA` | `PSA_ERROR_INVALID_ARGUMENT` |
| `MBEDTLS_ERR_PK_ALLOC_FAILED` | `PSA_ERROR_INSUFFICIENT_MEMORY` |
| `MBEDTLS_ERR_PK_BAD_INPUT_DATA` | `PSA_ERROR_INVALID_ARGUMENT` |
| `MBEDTLS_ERR_PK_BUFFER_TOO_SMALL` | `PSA_ERROR_BUFFER_TOO_SMALL` |
| `MBEDTLS_ERR_PK_SIG_LEN_MISMATCH` | `PSA_ERROR_INVALID_SIGNATURE` |
| `MBEDTLS_ERR_PKCS5_BAD_INPUT_DATA` | `PSA_ERROR_INVALID_ARGUMENT` |
| `MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED` | `PSA_ERROR_NOT_SUPPORTED` |
| `MBEDTLS_ERR_PLATFORM_HW_ACCEL_FAILED` | `PSA_ERROR_HARDWARE_FAILURE` |
| `MBEDTLS_ERR_POLY1305_BAD_INPUT_DATA` | `PSA_ERROR_INVALID_ARGUMENT` |
| `MBEDTLS_ERR_RSA_BAD_INPUT_DATA` | `PSA_ERROR_INVALID_ARGUMENT` |
| `MBEDTLS_ERR_RSA_INVALID_PADDING` | `PSA_ERROR_INVALID_PADDING` |
| `MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE` | `PSA_ERROR_BUFFER_TOO_SMALL` |
| `MBEDTLS_ERR_SHA1_BAD_INPUT_DATA` | `PSA_ERROR_INVALID_ARGUMENT` |
| `MBEDTLS_ERR_SHA256_BAD_INPUT_DATA` | `PSA_ERROR_INVALID_ARGUMENT` |
| `MBEDTLS_ERR_SHA3_BAD_INPUT_DATA` | `PSA_ERROR_INVALID_ARGUMENT` |
| `MBEDTLS_ERR_SHA512_BAD_INPUT_DATA` | `PSA_ERROR_INVALID_ARGUMENT` |
@@ -0,0 +1,32 @@
## Feature removals
### Removal of self-test interfaces
TF-PSA-Crypto 1.0 does not provide a ready-made self-test interface; one may be added in a future version of the library.
If you need self-tests for compliance, you may perform them by invoking normal API functions with sample data.
As a consequence, the compilation option `MBEDTLS_SELF_TEST` does not provide direct benefits in TF-PSA-Crypto 1.0. However, it allows the sample program `programs/test/selftest.c` in Mbed TLS to run self tests of cryptographic mechanisms.
### Removed hardware support
Acceleration for VIA Padlock (`MBEDTLS_PADLOCK_C`) is no longer provided.
The deprecated and incomplete support for dynamic registration of secure element drivers (`MBEDTLS_PSA_CRYPTO_SE_C`) has been removed. Use compile-time secure element drivers instead.
See also [the removal of ALT interfaces](#removal-of-alternative-cryptographic-module-implementations).
### Removed obsolete cryptographic mechanisms
Some obsolescent cryptographic mechanisms have been removed:
* The library no longer supports DES (including 3DES). All supported block ciphers now have 128-bit blocks. As a consequence, the PKCS12 module, which provided the obsolete PBE mode for private key encryption that does not support stronger ciphers, has been removed.
* The library no longer supports elliptic curves whose size is 224 bits or less. The following curves are no longer supported: secp192r1, secp192k1, secp224k1, secp224r1. Use larger curves such as secp256r1.
### Removed obsolete PSA functions
Some PSA Crypto API functions dating back from before the 1.0 version of the API, or that were experimental, have been removed:
* `psa_open_key()`, `psa_close_key()`, and auxiliary functions and macros related to handles. Persistent keys are opened implicitly since Mbed TLS 2.25.
* `psa_set_key_domain_parameters()`, `psa_get_key_domain_parameters()` and related macros. This feature was primarily intended to support custom finite-field Diffie-Hellman (FFDH) groups, but this was never implemented. To generate an RSA key with a custom public exponent, use `psa_generate_key_custom()`, introduced in Mbed TLS 3.6.1.
* `psa_generate_key_ext()`, `psa_key_derivation_output_key_ext` and related types and macros. Use `psa_generate_key_custom()` or `psa_key_derivation_output_key_custom()` instead.
@@ -0,0 +1,162 @@
## Function prototype changes
A number of existing functions now take a different list of arguments, mostly to migrate them to the PSA API.
### Public functions no longer take a RNG callback
Functions that need randomness no longer take an RNG callback in the form of `f_rng, p_rng` arguments. Instead, they use the PSA Crypto random generator (accessible as `psa_generate_random()`). All software using the LMS or PK modules must call `psa_crypto_init()` before calling any of the functions listed here.
### RNG removal in LMS
The following function prototypes have been changed in `mbedtls/lms.h`:
```c
int mbedtls_lms_generate_private_key(mbedtls_lms_private_t *ctx, mbedtls_lms_algorithm_type_t type, mbedtls_lmots_algorithm_type_t otstype,
int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng,
const unsigned char *seed, size_t seed_size);
int mbedtls_lms_sign(mbedtls_lms_private_t *ctx,
int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng,
const unsigned char *msg, unsigned int msg_size, unsigned char *sig, size_t sig_size, size_t *sig_len);
```
to
```c
int mbedtls_lms_generate_private_key(mbedtls_lms_private_t *ctx, mbedtls_lms_algorithm_type_t type, mbedtls_lmots_algorithm_type_t otstype,
const unsigned char *seed, size_t seed_size);
int mbedtls_lms_sign(mbedtls_lms_private_t *ctx,
const unsigned char *msg, unsigned int msg_size, unsigned char *sig, size_t sig_size, size_t *sig_len);
```
### RNG removal in PK
The following function prototypes have been changed in `mbedtls/pk.h`:
```c
int mbedtls_pk_sign_restartable(mbedtls_pk_context *ctx, mbedtls_md_type_t md_alg, const unsigned char *hash, size_t hash_len, unsigned char *sig, size_t sig_size, size_t *sig_len,
int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng,
mbedtls_pk_restart_ctx *rs_ctx);
int mbedtls_pk_check_pair(const mbedtls_pk_context *pub, const mbedtls_pk_context *prv,
int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng);
int mbedtls_pk_sign(mbedtls_pk_context *ctx, mbedtls_md_type_t md_alg, const unsigned char *hash, size_t hash_len, unsigned char *sig, size_t sig_size, size_t *sig_len,
int (*f_rng)(void *, unsigned char *, size_t), void *p_rng);
int mbedtls_pk_sign_ext(mbedtls_pk_type_t pk_type, mbedtls_pk_context *ctx, mbedtls_md_type_t md_alg, const unsigned char *hash, size_t hash_len, unsigned char *sig, size_t sig_size, size_t *sig_len,
int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng);
int mbedtls_pk_parse_key(mbedtls_pk_context *ctx, const unsigned char *key, size_t keylen, const unsigned char *pwd, size_t pwdlen,
int (*f_rng)(void *, unsigned char *, size_t), void *p_rng);
int mbedtls_pk_parse_keyfile(mbedtls_pk_context *ctx, const char *path, const char *password,
int (*f_rng)(void *, unsigned char *, size_t), void *p_rng);
typedef int (*mbedtls_pk_rsa_alt_sign_func)(void *ctx,
int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng,
mbedtls_md_type_t md_alg, unsigned int hashlen, const unsigned char *hash, unsigned char *sig);
```
to
```c
int mbedtls_pk_sign_restartable(mbedtls_pk_context *ctx, mbedtls_md_type_t md_alg, const unsigned char *hash, size_t hash_len, unsigned char *sig, size_t sig_size, size_t *sig_len,
mbedtls_pk_restart_ctx *rs_ctx);
int mbedtls_pk_check_pair(const mbedtls_pk_context *pub, const mbedtls_pk_context *prv);
int mbedtls_pk_sign(mbedtls_pk_context *ctx, mbedtls_md_type_t md_alg, const unsigned char *hash, size_t hash_len, unsigned char *sig, size_t sig_size, size_t *sig_len);
int mbedtls_pk_sign_ext(mbedtls_pk_type_t pk_type, mbedtls_pk_context *ctx, mbedtls_md_type_t md_alg, const unsigned char *hash, size_t hash_len, unsigned char *sig, size_t sig_size, size_t *sig_len);
int mbedtls_pk_parse_key(mbedtls_pk_context *ctx, const unsigned char *key, size_t keylen, const unsigned char *pwd, size_t pwdlen);
int mbedtls_pk_parse_keyfile(mbedtls_pk_context *ctx, const char *path, const char *password);
typedef int (*mbedtls_pk_rsa_alt_sign_func)(void *ctx,
mbedtls_md_type_t md_alg, unsigned int hashlen, const unsigned char *hash, unsigned char *sig);
```
### Changes to NIST_KW
The NIST\_KW module remains part of TF-PSA-Crypto, since it does not have a PSA equivalent yet. However, its interface has changed, to use PSA key identifiers instead of a plaintext key via a custom context.
The following function prototypes have been changed in `mbedtls/nist_kw.h`:
```c
int mbedtls_nist_kw_wrap(mbedtls_nist_kw_context *ctx,
mbedtls_nist_kw_mode_t mode,
const unsigned char *input, size_t in_len,
unsigned char *output, size_t *out_len, size_t out_size);
int mbedtls_nist_kw_unwrap(mbedtls_nist_kw_context *ctx,
mbedtls_nist_kw_mode_t mode,
const unsigned char *input, size_t in_len,
unsigned char *output, size_t *out_len, size_t out_size);
```
to
```c
psa_status_t mbedtls_nist_kw_wrap(mbedtls_svc_key_id_t key,
mbedtls_nist_kw_mode_t mode,
const unsigned char *input, size_t input_length,
unsigned char *output, size_t output_size,
size_t *output_length);
psa_status_t mbedtls_nist_kw_unwrap(mbedtls_svc_key_id_t key,
mbedtls_nist_kw_mode_t mode,
const unsigned char *input, size_t input_length,
unsigned char *output, size_t output_size,
size_t *output_length);
```
Note that in addition to the change to keys, the last two parameters for the output buffer size and the length of the actual output have been swapped, to align the order of parameters with PSA Crypto APIs.
The type `mbedtls_nist_kw_context` and the functions `mbedtls_nist_kw_init()`, `mbedtls_nist_kw_free()` and `mbedtls_nist_kw_setkey()` have been removed, since the interface no longer involves a specific context object for NIST\_KW.
Also, the function `mbedtls_nist_kw_self_test()` has been removed. TF-PSA-Crypto 1.0 does not provide a ready-made self-test interface; one may be added in a future version of the library.
### Changes to ASN.1 functions
As a consequence of the removal of the type `mbedtls_mpi` (provided by `mbedtls/bignum.h`) from public interfaces, the ASN.1 functions to parse and write integers have changed.
The following functions have been removed from the API:
```c
// mbedtls/asn1.h
int mbedtls_asn1_get_mpi(unsigned char **p, const unsigned char *end,
mbedtls_mpi *X);
// mbedtls/asn1write.h
int mbedtls_asn1_write_mpi(unsigned char **p, const unsigned char *start,
const mbedtls_mpi *X);
```
You can use the following new functions instead:
```c
// mbedtls/asn1.h
int mbedtls_asn1_get_integer(unsigned char **p, const unsigned char *end,
unsigned char **head, size_t *length);
// mbedtls/asn1write.h
int mbedtls_asn1_write_integer(unsigned char **p,
unsigned char *start,
const unsigned char *integer,
size_t integer_length);
```
Both new functions use a big-endian byte buffer as the representation.
Note some differences in the semantics of the new parsing function:
* `mbedtls_asn1_get_integer()` rejects negative integers. (`mbedtls_asn1_get_mpi()` misparsed them, using the sign bit as a value bit).
* `mbedtls_asn1_get_integer()` does not allocate memory. It returns a pointer inside the ASN.1 representation.
@@ -0,0 +1,10 @@
## Reduced `md.h`
PSA is now the preferred interface for computing hashes and HMAC. See [“Hashes and MAC” in the PSA transition guide](psa-transition.md#hashes-and-mac) for more information.
TF-PSA-Crypto 1.x still has a header file `<mbedtls/md.h>` to facilitate the transition. Its functionality is limited to calculating hashes:
* `mbedtls_md_setup()` now requires the `hmac` parameter to be 0. Use the PSA API for HMAC calculations.
* The HMAC functions `mbedtls_md_hmac_xxx()` are no longer available.
* The metadata functions `mbedtls_md_list()`, `mbedtls_md_info_from_string()`, `mbedtls_md_get_name()` and `mbedtls_md_info_from_ctx()` have been removed. The library does not associate names to individual algorithms any longer.
* The function `mbedtls_md_file()` has been removed. To hash a file, load it into memory manually. Load it piecewise and call `mbedtls_md_update()` or `psa_hash_update()` in a loop if the file may be large.
@@ -0,0 +1,9 @@
## OID module
The compilation option `MBEDTLS_OID_C` no longer exists. OID tables are included in the build automatically as needed for parsing and writing keys and signatures.
TF-PSA-Crypto does not have interfaces to look up values by OID or OID by enum values.
Functions to convert between binary and dotted string OID representations (`mbedtls_oid_get_numeric_string()` and `mbedtls_oid_from_numeric_string()`) are still available, but they are now in the X.509 library in Mbed TLS. The header file `<mbedtls/oid.h>` is now in Mbed TLS, not in TF-PSA-Crypto.
TF-PSA-Crypto does not expose OID values through macros, the way Mbed TLS 3.x and earlier did.
@@ -0,0 +1,126 @@
## Changes to the PAKE interface
The PAKE interface in TF-PSA-Crypto 1.0 has been updated to match PSA Crypto API [1.2 Final](https://arm-software.github.io/psa-api/crypto/1.2/ext-pake/) PAKE extension, which is the same version that has been integrated into the main specification of PSA Crypto [version 1.3](https://arm-software.github.io/psa-api/crypto/1.3/).
In Mbed TLS 3.6, the PAKE interface implemented version [1.1 Beta](https://arm-software.github.io/psa-api/crypto/1.1/ext-pake/) of the PAKE extension. There has been a number of [changes between the beta and the final version](https://arm-software.github.io/psa-api/crypto/1.2/ext-pake/appendix/history.html#changes-between-beta-1-and-final) of the API. The changes that require applications to update their code are detailed in the following subsections.
Note that TF-PSA-Crypto 1.0 still only implements `PSA_ALG_JPAKE` (and only on elliptic curves, specifically only on secp256r1). Support for SPAKE2+ is likely to be added in a future version but is not there yet.
### Combine `psa_pake_set_password_key()` with `psa_pake_setup()`
The function `psa_pake_set_password_key()` has been removed. Its `key` argument is now passed to `psa_pake_setup()` which has gained a new `key` parameter.
Before:
```
status = psa_pake_setup(&operation, &cipher_suite);
if (status != PSA_SUCCESS) // error handling ommited for brevity
status = psa_pake_set_password_key(&operation, key);
if (status != PSA_SUCCESS) // error handling ommited for brevity
```
Now:
```
status = psa_pake_setup(&operation, key, &cipher_suite);
if (status != PSA_SUCCESS) // error handling ommited for brevity
```
### Move the hash algorithm parameter into the algorithm identifier
The function `psa_pake_cs_set_hash()` has been removed. Its `hash` argument is now passed to `PSA_ALG_JPAKE()` which is now a function-like macro with one parameter.
Before:
```
psa_pake_cs_set_algorithm(&cipher_suite, PSA_ALG_JPAKE);
psa_pake_cs_set_hash(&cipher_suite, PSA_ALG_SHA_256);
```
Now:
```
psa_pake_cs_set_algorithm(&cipher_suite, PSA_ALG_JPAKE(PSA_ALG_SHA_256));
```
To check if a given algorithm is J-PAKE, the new `PSA_ALG_IS_JPAKE()` macro has been added.
Before: `if (alg == PSA_ALG_JPAKE)`
Now: `if (PSA_ALG_IS_JPAKE(alg))`
The function `psa_pake_cs_get_hash()` has also been removed.
### Replace `psa_pake_get_implicit_key()` with `psa_pake_get_shared_key()`
The function `psa_pake_get_implicit_key()`, which injects the shared secret into a key derivation operation, has been removed. Its replacement is `psa_pake_get_shared_key()` which stores the shared secret in a new key. That new key can then be used as part of a key derivation operation.
Before:
```
// ommited: set up pake_op and do the PAKE key exchange
psa_algorithm_t alg = PSA_ALG_TLS12_ECJPAKE_TO_PMS; // for example
psa_key_derivation_operation_t derivation = PSA_KEY_DERIVATION_OPERATION_INIT;
status = psa_key_derivation_setup(&derivation, alg);
if (status != PSA_SUCCESS) // error handling ommited for brevity
status = psa_pake_get_implicit_key(&pake_op, &derivation);
if (status != PSA_SUCCESS) // error handling ommited for brevity
// ommited: finish key derivation (output/verify, then abort)
```
Now:
```
// ommited: set up pake_op and do the PAKE key exchange
psa_algorithm_t alg = PSA_ALG_TLS12_ECJPAKE_TO_PMS; // for example
psa_key_derivation_operation_t derivation = PSA_KEY_DERIVATION_OPERATION_INIT;
status = psa_key_derivation_setup(&derivation, alg);
if (status != PSA_SUCCESS) // error handling ommited for brevity
psa_key_id_t shared_key_id = (psa_key_id_t) 0;
psa_key_attributes_t shared_key_attributes = PSA_KEY_ATTRIBUTES_INIT;
psa_set_key_usage_flags(&shared_key_attributes, PSA_KEY_USAGE_DERIVE);
psa_set_key_algorithm(&shared_key_attributes, alg); // same as derivation
psa_set_key_type(&shared_key_attributes, PSA_KEY_TYPE_DERIVE);
status = psa_pake_get_shared_key(&pake_op,
&shared_key_attributes,
&shared_key_id);
if (status != PSA_SUCCESS) // error handling ommited for brevity
psa_reset_key_attributes(&shared_key_attributes);
status = psa_key_derivation_input_key(&derivation_op,
PSA_KEY_DERIVATION_INPUT_SECRET,
shared_key_id);
if (status != PSA_SUCCESS) // error handling ommited for brevity
// ommited: finish key derivation (output/verify, then abort)
psa_destroy_key(shared_key_id); // after key derivation is complete
```
Note that the new function is more flexible: instead of using the shared secret
only for key derivation, you can also directly use it as an HMAC key by setting
the appropriate key type and policy, for example:
```
psa_key_id_t shared_key_id = (psa_key_id_t) 0;
psa_algorithm_t alg = PSA_ALG_HMAC(PSA_ALG_SHA_256); // or other hash
psa_key_attributes_t shared_key_attributes = PSA_KEY_ATTRIBUTES_INIT;
psa_set_key_usage_flags(&shared_key_attributes, PSA_KEY_USAGE_SIGN_MESSAGE);
// or VERIFY_MESSAGE
psa_set_key_algorithm(&shared_key_attributes, alg);
psa_set_key_type(&shared_key_attributes, PSA_KEY_TYPE_HMAC);
status = psa_pake_get_shared_key(&pake_op,
&shared_key_attributes,
&shared_key_id);
if (status != PSA_SUCCESS) // error handling ommited for brevity
```
See [the specification](https://arm-software.github.io/psa-api/crypto/1.3/api/ops/pake.html#c.psa_pake_get_shared_key) for details. Note that the J-PAKE shared secret is not uniformly pseudorandom, so it can only be used for key derivation and HMAC.
@@ -0,0 +1,85 @@
## PK module
The PK module for asymmetric cryptography is still present in TF-PSA-Crypto 1.x, but with a somewhat reduced scope compared to Mbed TLS. The main goal of PK is now to parse and format key pairs and public keys. PK also retains signature functions, to facilitate the transition from previous versions. The main differences compared to Mbed TLS 3.6 and below are:
* PK objects no longer expose the underlying representation. It is now unspecified in most cases whether a PK object stores key material directly, or a PSA key identifier.
* PK objects no longer have any policy attached to them. This mostly affects RSA keys, which no longer “remember” whether they are meant to be used with PKCS#1v1.5 or PSS/OAEP.
### Changes to PK metadata
The type `mbedtls_pk_type_t` has been removed from the API. This type could convey different kinds of information, depending on where it was used:
* Information about the representation of a PK context (distinguishing between transparent and opaque objects containing the same type of key). This information is no longer exposed.
* Which signature algorithm to use (distinguishing between PKCS#1v1.5 and PSS for RSA keys), mostly for the sake of X.509. This information is now represented as `mbedtls_pk_sigalg_t`, using enum constants with tweaked names:
| Old `mbedtls_pk_type_t` name | New `mbedtls_pk_sigalg_t` name |
| ---------------------------- | ------------------------------ |
| `MBEDTLS_PK_NONE` | `MBEDTLS_PK_SIGALG_NONE` |
| `MBEDTLS_PK_RSA` | `MBEDTLS_PK_SIGALG_RSA_PKCS1V15` |
| `MBEDTLS_PK_RSASSA_PSS` | `MBEDTLS_PK_SIGALG_RSA_PSS` |
| `MBEDTLS_PK_ECDSA` or `MBEDTLS_PK_ECKEY` | `MBEDTLS_PK_SIGALG_ECDSA` |
* Policy information after parsing a key (only relevant for ECC keys marked as ECDH-only). This is now tracked internally and reflected in rejecting the key for signature or verification in `mbedtls_pk_get_psa_attributes()` and in operation functions.
<!-- Untested, see https://github.com/Mbed-TLS/TF-PSA-Crypto/issues/206 -->
As a consequence, the functions `mbedtls_pk_get_type()`, `mbedtls_pk_get_name()` and `mbedtls_pk_info_from_type()` and have been removed. The type `mbedtls_pk_info_t` is no longer part of the API.
The function `mbedtls_pk_get_len()` has also been removed. It was not very meaningful since it did not convey the length of the key representation, but the size in bytes of the representation of one number associated with the key. As before, you can use `mbedtls_pk_get_bitlen()` to get the key size in the usual cryptographic sense. The size of a formatted key representation depends on the format, and there is no API function to determine it. (For the short export formats of PSA, you can use macros such as `PSA_EXPORT_KEY_OUTPUT_SIZE()`, `PSA_EXPORT_PUBLIC_KEY_OUTPUT_SIZE()`, `PSA_EXPORT_KEY_PAIR_MAX_SIZE`, `PSA_EXPORT_PUBLIC_KEY_MAX_SIZE`.)
### Checking the capabilities of a PK context
The function `mbedtls_pk_can_do()`, based on the polysemic `mbedtls_pk_type_t`, has been removed. The function `mbedtls_pk_can_do_ext()`, based on PSA metadata, has been renamed to `mbedtls_pk_can_do_psa()`. It now supports public-key operations as well as private-key operations.
### Loss of policy information for RSA keys
The PK module no longer partially keeps track of whether an RSA key is intended for use with PKCS#1v1.5 or PKCS#1v2.1 (PSS or OAEP) algorithms. Functions that consume a PK object (`mbedtls_pk_get_psa_attributes()`, `mbedtls_pk_sign()`, `mbedtls_pk_verify()`) now always default to PKCS#1v1.5, except for PK contexts populated with `mbedtls_pk_wrap_psa()` where they use the primary algorithm in the key's policy.
Note in particular that the functions `mbedtls_pk_copy_from_psa()` and `mbedtls_pk_copy_public_from_psa()` are now equivalent to exporting and re-importing the key, losing all policy information. For example, calling `mbedtls_pk_copy_from_psa()` on a key whose policy specifies PSS as the single allowed algorithm, then calling `mbedtls_pk_sign()`, results in a PKCS#1v1.5 signature. Call `mbedtls_pk_sign_ext()` or `mbedtls_pk_verify_ext()` if you want to specify the signature algorithm explicitly.
### Removal of transparent PK contexts
It is no longer possible to directly inspect a PK context to act on its underlying RSA or ECC context. The representation of a key in PK is now always an implementation detail.
As a consequence, the functions `mbedtls_pk_setup()`, `mbedtls_pk_rsa()` and `mbedtls_pk_ec()` have been removed.
### Changes to opaque PK contexts
The library no longer supports an alternative representation of RSA keys in PK (`MBEDTLS_PK_RSA_ALT_SUPPORT` compilation option, PK context type `MBEDTLS_PK_RSA_ALT`). See [“RSA-ALT interface” in the PSA transition guide](psa-transition.md#rsa-alt-interface).
A PK object can still wrap around an PSA key, which was formerly known as “opaque” PK objects of type `MBEDTLS_PK_OPAQUE`. The function `mbedtls_pk_setup_opaque()` has been renamed to `mbedtls_pk_wrap_psa()`, to reflect the fact that the PSA key is not necessarily “opaque” in PSA terminology. The PK module now hides the distinction between “wrapping” and “non-wrapping” PK contexts as much as possible, and in particular there is no simple metadata query to distinguish “wrapping” keys like the former `mbedtls_pk_get_type()`.
### Fewer operations in PK
The functions `mbedtls_pk_encrypt()` and `mbedtls_pk_decrypt()` have been removed. Use `psa_asymmetric_encrypt()` and `psa_asymmetric_decrypt()` instead. See [“Asymmetric encryption and decryption” in the PSA transition guide](psa-transition.md#rsa-alt-interface) for more information.
If you have a key as a PK context and you wish to use it with PSA operation functions, use the functions `mbedtls_pk_get_psa_attributes()` and `mbedtls_pk_import_into_psa()` to obtain a PSA key identifier. See the documentation of these functions or [“Creating a PSA key via PK” in the PSA transition guide](psa-transition.md#creating-a-psa-key-via-pk) for more information.
### Miscellaneous changes to PK signature and verification
The `type` argument to `mbedtls_pk_sign_ext()` and `mbedtls_pk_verify_ext()` now has the type `mbedtls_pk_sigalg_t`. See [“Changes to PK metadata”](#changes-to-pk-metadata).
The function `mbedtls_pk_verify_ext()` no longer supports a custom salt length for RSA-PSS. It always allows signatures with any salt length. The PSA API offers `psa_verify_hash()` with `PSA_ALG_RSA_PSS` to enforce the most commonly used salt length.
`MBEDTLS_ERR_PK_SIG_LEN_MISMATCH` is no longer a distinct error code. A valid signature with trailing garbage is now reported as an invalid signature with all algorithms.
The PK module continues to favor deterministic ECDSA over randomized ECDSA when both are possible. This may change in the future. The new macro `MBEDTLS_PK_ALG_ECDSA(hash_alg)` indicates which variant PK favors. It is equivalent to either `PSA_ALG_DETERMINISTIC_ECDSA(hash_alg)` or `PSA_ALG_ECDSA(hash_alg)`.
### Changes in resources consumed by PK objects
The implementation of the type `mbedtls_pk_context` has changed in ways that do not directly affect functionality, but affect resource consumption and memory partitioning.
Historically, at least in the default configuration, a PK context stored all the key material in a heap-allocated object. In TF-PSA-Crypto 1.0, a PK context now contains:
* the public key, in a fixed-size buffer that is directly in the `mbedtls_pk_context` structure;
* the private key (if available), in the PSA key store.
This may change in future minor versions of TF-PSA-Crypto.
### Other miscellaneous changes in PK
Since PSA has a built-in random generator, all `(f_rng, p_rng)` arguments to PK functions have been removed.
`mbedtls_pk_debug()` and the associated types have been removed. This was intended solely for internal consumption by the debug module, and tied to internal details of the legacy representation of keys. If you need equivalent functionality in TF-PSA-Crypto, export the key.
The auxiliary functions `mbedtls_pk_parse_subpubkey()` and `mbedtls_pk_write_pubkey()` are no longer exposed. Use `mbedtls_pk_parse_public_key()` and `mbedtls_pk_write_pubkey_der()` instead.
@@ -0,0 +1,33 @@
## Private declarations
Since Mbed TLS 3.0, some things that are declared in a public header are not part of the stable application programming interface (API), but instead are considered private. Private elements may be removed or may have their semantics changed in a future minor release without notice.
### Understanding private declarations in public headers
In TF-PSA-Crypto 1.x, private elements in header files include:
* Anything appearing in a header file whose path contains `/private` (unless re-exported and documented in another non-private header).
* Structure and union fields declared with `MBEDTLS_PRIVATE(field_name)` in the source code, and appearing as `private_field_name` in the rendered documentation. (This was already the case since Mbed TLS 3.0.)
* Any preprocessor macro that is not documented with a Doxygen comment.
In the source code, Doxygen comments start with `/**` or `/*!`. If a macro only has a comment above that starts with `/*`, the macro is considered private.
In the rendered documentation, private macros appear with only an automatically rendered parameter list, value and location, but no custom text.
* Any declaration that is guarded by the preprocessor macro `MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS`.
### Usage of private declarations
Some private declarations are present in public headers for technical reasons, because they need to be visible to the compiler. Others are present for historical reasons and may be cleaned up in later versions of the library. We strongly recommend against relying on these declarations, since they may be removed or may have their semantics changed without notice.
Note that Mbed TLS 4.0 still relies on some private interfaces of TF-PSA-Crypto 1.0. We expect to remove this reliance gradually in future minor releases.
Sample programs have not been fully updated yet and some of them might still
use APIs that are no longer public. You can recognize them by the fact that they
define the macro `MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS` (or
`MBEDTLS_ALLOW_PRIVATE_ACCESS`) at the very top (before including headers). When
you see one of these two macros in a sample program, be aware it has not been
updated and parts of it do not demonstrate current practice.
We strongly recommend against defining `MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS` or
`MBEDTLS_ALLOW_PRIVATE_ACCESS` in your own application. If you do so, your code
may not compile or work with future minor releases. If there's something you
want to do that you feel can only be achieved by using one of these two macros,
please reach out on github or the mailing list.
@@ -0,0 +1,5 @@
Temporary sub-directory to avoid conflicts in private-decls.md.
Will be merged back to private-decls.md as part of
https://github.com/Mbed-TLS/TF-PSA-Crypto/issues/232
One file per header, with .md extension (and valid markdown content).
@@ -0,0 +1,96 @@
## PSA as the only cryptography API
The PSA Crypto API is now the only API for cryptographic primitives.
For general guidance on migrating to the PSA Crypto API, consult the
[PSA transition guide](../psa-transition.md). Note that most of the suggested migrations also work in the Mbed TLS 3.6 long-time support branch, provided that the library is configured suitably (`MBEDTLS_USE_PSA_CRYPTO` and `MBEDTLS_PSA_CRYPTO_CONFIG` enabled).
### Impact on application code
The PK module uses PSA for cryptographic operations. This corresponds to the behavior of Mbed TLS 3.x when `MBEDTLS_USE_PSA_CRYPTO` is enabled. In effect, `MBEDTLS_USE_PSA_CRYPTO` is now always enabled.
`psa_crypto_init()` must be called before performing any cryptographic operation.
A few functions take different parameters to migrate them to the PSA API. See “[Function prototype changes](#function-prototype-changes)”.
### No random generator instantiation
Formerly, applications using various cryptographic features needed to provide a random generator, generally by instantiating an entropy context (`mbedtls_entropy_context`) and a DRBG context (`mbedtls_ctr_drbg_context` or `mbedtls_hmac_drbg_context`). This is no longer necessary, or possible. All features that require a random generator (RNG) now use the one provided by the PSA subsystem.
Instead, applications that use random generators or keys (even public keys) need to call `psa_crypto_init()` before any cryptographic operation or key management operation.
See also [function prototype changes](#function-prototype-changes), many of which are related to the move from RNG callbacks to a global RNG.
### Impact on the library configuration
The choice of supported cryptographic mechanisms is now based on `PSA_WANT_xxx` macros instead of legacy configuration macros such as `MBEDTLS_RSA_C`, `MBEDTLS_PKCS1_V15`, etc. This corresponds to the behavior of Mbed TLS 3.x when `MBEDTLS_PSA_CRYPTO_CONFIG` is enabled. In effect, `MBEDTLS_PSA_CRYPTO_CONFIG` is now always enabled.
For information on which configuration macros are affected and their new PSA equivalent, consult the [PSA transition guide](../psa-transition.md).
See also the section [“Random number generation configuration”](#random-number-generation-configuration).
### No direct access to specific algorithms
All modules that are specific to a particular cryptographic mechanism have been removed from the API. There are a few exceptions, for some mechanisms that are not yet present in the PSA API: `mbedtls/lms.h` and `mbedtls/nist_kw.h` remain part of the API.
The high-level legacy module `mbedtls/cipher.h` has also been removed. The high-level legacy modules `mbedtls/md.h` and `mbedtls/pk.h` remain present with reduced functionality (see “[Changes to MD and PK](#changes-to-md-and-pk)”). TF-PSA-Crypto also retains non-PSA interfaces for data formats, platform support and miscellaneous utility functions.
In full detail, the following header files, and their former content, are no longer available.
```
everest/Hacl_Curve25519.h
everest/everest.h
everest/kremlib.h
everest/kremlib/*.h
everest/kremlin/*.h
everest/kremlin/internal/*.h
everest/vs2013/*.h
everest/x25519.h
mbedtls/aes.h
mbedtls/aria.h
mbedtls/bignum.h
mbedtls/block_cipher.h
mbedtls/camellia.h
mbedtls/ccm.h
mbedtls/chacha20.h
mbedtls/chachapoly.h
mbedtls/cipher.h
mbedtls/cmac.h
mbedtls/ctr_drbg.h
mbedtls/des.h
mbedtls/dhm.h
mbedtls/ecdh.h
mbedtls/ecdsa.h
mbedtls/ecjpake.h
mbedtls/ecp.h
mbedtls/entropy.h
mbedtls/gcm.h
mbedtls/hkdf.h
mbedtls/hmac_drbg.h
mbedtls/md5.h
mbedtls/pkcs12.h
mbedtls/pkcs5.h
mbedtls/poly1305.h
mbedtls/ripemd160.h
mbedtls/rsa.h
mbedtls/sha1.h
mbedtls/sha256.h
mbedtls/sha3.h
mbedtls/sha512.h
```
If your application was using functions from these headers, please see
[`docs/psa-transition.md`](../psa-transition.md) for ways to migrate to
the PSA API instead.
Some of the associated types still need to be visible to the compiler. For example, `mbedtls_aes_context` is used to define `psa_cipher_operation_t`. These types are still available when building application code, but we recommend that you no longer use them directly. The structure, the semantics and even the existence of these types may change without notice.
### Other removed functions related to low-level cryptography APIs
The functions `mbedtls_ecc_group_to_psa()` and `mbedtls_ecc_group_from_psa()` have been removed. They are no longer meaningful since the low-level representation of elliptic curve groups is no longer part of the API.
### Removal of alternative cryptographic module implementations
TF-PSA-Crypto no longer supports replacing a whole cryptographic module or an individual cryptographic function by defining a macro `MBEDTLS_xxx_ALT` and providing a custom implementation of the same interface. Instead, use PSA transparent drivers (i.e. accelerator drivers).
The PK module no longer supports `MBEDTLS_PK_RSA_ALT`. Instead, for opaque keys (RSA or otherwise), use PSA opaque drivers.
@@ -0,0 +1,176 @@
## Random number generation configuration
TF-PSA-Crypto no longer exposes the internals of the PSA random number generator. The entropy, CTR_DRBG, and HMAC_DRBG modules from Mbed TLS 3.6 are now for internal use only. As a result, their configuration has been updated, both to simplify them and to prepare for PSA entropy and random number generation drivers, which will be introduced in a future minor release.
The overall structure of the random number generator in TF-PSA-Crypto remains the same as in Mbed TLS 3.x. It consists of either:
* an external random number generator (when `MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG` is enabled), or
* a deterministic random number generator (CTR_DRBG or HMAC_DRBG) seeded with entropy by the entropy module.
### Entropy configuration
TF-PSA-Crypto does not expose an entropy interface to applications. The entropy module of Mbed TLS 3.6 is now for internal use only. As a consequence, its configuration has changed, both to simplify it and to prepare for PSA entropy drivers which will be added in a future minor release.
#### If you have a fast cryptographic-quality external random generator
If you have a fast, cryptographic-quality source of random data, enable `MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG` and provide the callback function `mbedtls_psa_external_get_random()`. This is unchanged since Mbed TLS 2.26.
#### If the built-in entropy source works for you
TF-PSA-Crypto, like Mbed TLS, recognizes the system entropy sources on some popular operating systems, and enables them by default. If you are writing your own configuration, you now need to define the option `MBEDTLS_PSA_BUILTIN_GET_ENTROPY`. (This is different from Mbed TLS 2.x and 3.x, where the built-in entropy sources were included unless the option `MBEDTLS_NO_PLATFORM_ENTROPY` was defined.)
#### If you have a custom entropy source
To provide a custom entropy source, disable `MBEDTLS_PSA_BUILTIN_GET_ENTROPY` and enable `MBEDTLS_PSA_DRIVER_GET_ENTROPY`. You will need to provide the callback function `mbedtls_platform_get_entropy()`. See [“Custom entropy collector”](#custom-entropy-collector) below for more details.
#### If you have no entropy source
If your hardware does not have any entropy source, you can use a non-volatile RNG seed which is injected from a trusted external source during device manufacturing or provisioning. Enable the option `MBEDTLS_ENTROPY_NV_SEED`, which is unchanged from previous versions of the library.
In TF-PSA-Crypto, when the non-volatile seed is the only (pseudo) entropy source, you also need to enable the option `MBEDTLS_ENTROPY_NO_SOURCES_OK`.
### Comparison of entropy source configurations
TF-PSA-Crypto 1.0 supports the same entropy sources as Mbed TLS 3.6, but the way to configure them has changed.
* The negative option `MBEDTLS_NO_PLATFORM_ENTROPY` to disable the default entropy collector for Unix-like and Windows platforms no longer exists. It has been replaced by the positive option `MBEDTLS_PSA_BUILTIN_GET_ENTROPY`, which is enabled by default.
* The option `MBEDTLS_ENTROPY_HARDWARE_ALT`, which allows you to provide a custom entropy collector, has been renamed to `MBEDTLS_PSA_DRIVER_GET_ENTROPY`. This replaces `MBEDTLS_ENTROPY_HARDWARE_ALT`. The callback has a different name and prototype as described in “[Custom hardware collector](#custom-entropy-collector)”.
* The option `MBEDTLS_ENTROPY_NV_SEED` to enable a non-volatile seed is unchanged. However, if this is your only entropy source, you must now enable the new option `MBEDTLS_ENTROPY_NO_SOURCES_OK`.
The following table describes common configurations.
<table>
<tr valign="top">
<th align="left">Configuration</th>
<th align="left">Mbed TLS 3.6</th>
<th align="left">TF-PSA-Crypto 1.0</th>
</tr>
<tr valign="top">
<td><strong>Unix, Linux, Windows</strong></td>
<td>(default)</td>
<td>(default)</td>
</tr>
<tr valign="top">
<td><strong>Embedded platform</strong></td>
<td>
<pre>
#define MBEDTLS_NO_PLATFORM_ENTROPY
#define MBEDTLS_ENTROPY_HARDWARE_ALT
</pre>
</td>
<td>
<pre>
#undef MBEDTLS_PSA_BUILTIN_GET_ENTROPY
#define MBEDTLS_PSA_DRIVER_GET_ENTROPY
</pre>
</td>
</tr>
<tr valign="top">
<td><strong>Fast external crypto RNG</strong></td>
<td>
<pre>
#define MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG
#undef MBEDTLS_ENTROPY_C
#undef MBEDTLS_CTR_DRBG_C
</pre>
</td>
<td>
<pre>
#define MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG
#undef MBEDTLS_ENTROPY_C
#undef MBEDTLS_CTR_DRBG_C
</pre>
</td>
</tr>
<tr valign="top">
<td><strong>NV seed only</strong></td>
<td>
<pre>
#define MBEDTLS_NO_PLATFORM_ENTROPY
#define MBEDTLS_ENTROPY_NV_SEED
</pre>
</td>
<td>
<pre>
#undef MBEDTLS_PSA_BUILTIN_GET_ENTROPY
#define MBEDTLS_ENTROPY_NV_SEED
#define MBEDTLS_ENTROPY_NO_SOURCES_OK
</pre>
</td>
</tr>
<tr valign="top">
<td><strong>No entropy at all</strong></td>
<td>
<pre>
#define MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES
</pre>
</td>
<td>
<em>not supported</em>
</td>
</tr>
</table>
#### Custom entropy collector
The custom entropy collector callback function has changed, to make it match the upcoming PSA entropy driver specification.
Formerly, the callback was enabled by `MBEDTLS_ENTROPY_HARDWARE_ALT` and had the following prototype:
```c
// from <entropy_poll.h>
int mbedtls_hardware_poll(void *data, unsigned char *output, size_t len,
size_t *olen);
```
The new callback is enabled by `MBEDTLS_PSA_DRIVER_GET_ENTROPY` and has the following prototype:
```c
```
to:
```c
// from <mbedtls/platform.h>
int mbedtls_platform_get_entropy(psa_driver_get_entropy_flags_t flags,
size_t *estimate_bits,
unsigned char *output, size_t output_size);
```
The `data` parameter was previously always `NULL`, and has been removed.
The new parameter `flags` is a bit-mask of flags that allows the caller to request special behaviors, such as avoiding blocking. The callback should return `PSA_ERROR_NOT_SUPPORTED` if it sees a flag that it does not support. As of TF-PSA-Crypto 1.0, `flags` is always 0.
The former callback could return less entropy than expected by only filling part of the buffer, and setting `*olen` to a value that is less than `output_size`. The new callback does not have an `olen` parameter, and the caller now reads the whole buffer. The new parameter `estimate_bits` is intended to allow the callback to report that it has accumulated less entropy than expected. However, this is not supported yet in TF-PSA-Crypto 1.0.
The new output parameter `estimate_bits` is the amount of entropy that the callback has placed in the output buffer. As of TF-PSA-Crypto 1.0, the output must have full entropy, thus `estimate_bits` must be equal to `8 * output_size`. A future version of TF-PSA-Crypto will allow entropy sources to report smaller amounts.
To indicate that entropy is not currently available, the legacy error code `MBEDTLS_ERR_ENTROPY_SOURCE_FAILED` has been replaced by `PSA_ERROR_INSUFFICIENT_ENTROPY`.
#### Removed entropy options
The option `MBEDTLS_ENTROPY_MIN_HARDWARE` has been removed. The entropy module requests the amount that it needs for the chosen security strength.
The option `MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES` has removed since it is no longer meaningful, now that the entropy module is private. TF-PSA-Crypto 1.0 does not support platforms without an entropy source. This ability will be reintroduced in a future minor release.
#### PSA entropy injection
The configuration option `MBEDTLS_PSA_INJECT_ENTROPY` has been removed. TF-PSA-Crypto 1.0 does not provide a way to store an entropy seed in the key store. This will be reimplemented in a future minor version.
### Configuration of the DRBG
As in previous versions of Mbed TLS, the PSA random generator in TF-PSA-Crypto uses CTR_DRBG with AES if `MBEDTLS_CTR_DRBG_C` is enabled, and HMAC_DRBG otherwise (requiring `MBEDTLS_HMAC_DRBG_C` to be enabled).
The DRBG modules are not exposed directly, they are only used internally.
In addition to the choice of DRBG module and entropy sources, the built-in random number generator is now configured through only three options:
* `MBEDTLS_PSA_CRYPTO_RNG_HASH`: Selects the hash algorithm used by the entropy and HMAC_DRBG modules. This option replaces both `MBEDTLS_PSA_HMAC_DRBG_MD_TYPE` and `MBEDTLS_ENTROPY_FORCE_SHA256`.
* `MBEDTLS_PSA_RNG_RESEED_INTERVAL`: Sets the reseed interval for both CTR_DRBG and HMAC_DRBG. It replaces `MBEDTLS_CTR_DRBG_RESEED_INTERVAL` and `MBEDTLS_HMAC_DRBG_RESEED_INTERVAL`.
* `MBEDTLS_PSA_CRYPTO_RNG_STRENGTH`: Specifies the security strength in bits. The default is 256 bits. If you previously enabled `MBEDTLS_CTR_DRBG_USE_128_BIT_KEY` in Mbed TLS 3.6, you should now set `MBEDTLS_PSA_CRYPTO_RNG_STRENGTH` to 128, although this is not recommended.
The option `MBEDTLS_ENTROPY_C` has been removed. The entropy module is now automatically enabled when `MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG` is disabled.
The following Mbed TLS 3.6 configuration options have been removed without any counterpart in TF-PSA-Crypto. Their corresponding APIs were also removed, making these options no longer relevant:
`MBEDTLS_ENTROPY_MAX_GATHER`, `MBEDTLS_ENTROPY_MAX_SOURCES`, `MBEDTLS_CTR_DRBG_ENTROPY_LEN`, `MBEDTLS_CTR_DRBG_MAX_INPUT`, `MBEDTLS_CTR_DRBG_MAX_REQUEST`, `MBEDTLS_CTR_DRBG_MAX_SEED_INPUT`, `MBEDTLS_HMAC_DRBG_MAX_INPUT`, `MBEDTLS_HMAC_DRBG_MAX_REQUEST`, and `MBEDTLS_HMAC_DRBG_MAX_SEED_INPUT`.
@@ -0,0 +1,24 @@
## Threading platform abstraction
### Extension to condition variables
The threading abstraction now includes primitives for condition variables in addition to mutexes.
As before, implementations of `MBEDTLS_THREADING_ALT` need to provide a header file `"threading_alt.h"`, and to call the function `mbedtls_threading_set_alt()` before any call to other TF-PSA-Crypto or Mbed TLS functions. The header file `"threading_alt.h"` now needs to define the following elements:
* The type `mbedtls_platform_mutex_t`, which is the type of mutex arguments passed to the platform functions. This type is now distinct from the type `mbedtls_threading_mutex_t` which library code and applications use.
* The type `mbedtls_platform_condition_variable_t`, which is the type of condition variable arguments passed to the platform functions.
### Changes to the mutex primitives
The type of mutex objects provided by the platform functions is now called `mbedtls_platform_mutex_t`, distinct from the API type `mbedtls_threading_mutex_t`.
The `mutex_init` primitive now returns a status code instead of `void`.
The documentation in `include/mbedtls/threading.h` now clarifies the expectations on mutex primitives. These expectations are somewhat relaxed from the mostly undocumented expectations in previous versions: mutex functions other than `mutex_init` can now assume that the mutex has been successfully initialized.
Platform threading primitives should now return the following error codes:
* `MBEDTLS_ERR_THREADING_USAGE_ERROR` to report a runtime failure (renamed from `MBEDTLS_ERR_THREADING_MUTEX_ERROR`, which is now an alias provided only for backward compatibility).
* `PSA_ERROR_BAD_STATE` only to report a library state error. If an error is detected in the state of a synchronization object, please return `MBEDTLS_ERR_THREADING_USAGE_ERROR` instead.
* `PSA_ERROR_INSUFFICIENT_MEMORY` to report resource exhaustion.
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,472 @@
Mbed TLS storage specification
=================================
This document specifies how Mbed TLS uses storage.
Key storage was originally introduced in a product called Mbed Crypto, which was re-distributed via Mbed TLS and has since been merged into Mbed TLS.
This document contains historical information both from before and after this merge.
Mbed Crypto may be upgraded on an existing device with the storage preserved. Therefore:
1. Any change may break existing installations and may require an upgrade path.
1. This document retains historical information about all past released versions. Do not remove information from this document unless it has always been incorrect or it is about a version that you are sure was never released.
Mbed Crypto 0.1.0
-----------------
Tags: mbedcrypto-0.1.0b, mbedcrypto-0.1.0b2
Released in November 2018. <br>
Integrated in Mbed OS 5.11.
Supported backends:
* [PSA ITS](#file-namespace-on-its-for-0.1.0)
* [C stdio](#file-namespace-on-stdio-for-0.1.0)
Supported features:
* [Persistent transparent keys](#key-file-format-for-0.1.0) designated by a [slot number](#key-names-for-0.1.0).
* [Nonvolatile random seed](#nonvolatile-random-seed-file-format-for-0.1.0) on ITS only.
This is a beta release, and we do not promise backward compatibility, with one exception:
> On Mbed OS, if a device has a nonvolatile random seed file produced with Mbed OS 5.11.x and is upgraded to a later version of Mbed OS, the nonvolatile random seed file is preserved or upgraded.
We do not make any promises regarding key storage, or regarding the nonvolatile random seed file on other platforms.
### Key names for 0.1.0
Information about each key is stored in a dedicated file whose name is constructed from the key identifier. The way in which the file name is constructed depends on the storage backend. The content of the file is described [below](#key-file-format-for-0.1.0).
The valid values for a key identifier are the range from 1 to 0xfffeffff. This limitation on the range is not documented in user-facing documentation: according to the user-facing documentation, arbitrary 32-bit values are valid.
The code uses the following constant in an internal header (note that despite the name, this value is actually one plus the maximum permitted value):
#define PSA_MAX_PERSISTENT_KEY_IDENTIFIER 0xffff0000
There is a shared namespace for all callers.
### Key file format for 0.1.0
All integers are encoded in little-endian order in 8-bit bytes.
The layout of a key file is:
* magic (8 bytes): `"PSA\0KEY\0"`
* version (4 bytes): 0
* type (4 bytes): `psa_key_type_t` value
* policy usage flags (4 bytes): `psa_key_usage_t` value
* policy usage algorithm (4 bytes): `psa_algorithm_t` value
* key material length (4 bytes)
* key material: output of `psa_export_key`
* Any trailing data is rejected on load.
### Nonvolatile random seed file format for 0.1.0
The nonvolatile random seed file contains a seed for the random generator. If present, it is rewritten at each boot as part of the random generator initialization.
The file format is just the seed as a byte string with no metadata or encoding of any kind.
### File namespace on ITS for 0.1.0
Assumption: ITS provides a 32-bit file identifier namespace. The Crypto service can use arbitrary file identifiers and no other part of the system accesses the same file identifier namespace.
* File 0: unused.
* Files 1 through 0xfffeffff: [content](#key-file-format-for-0.1.0) of the [key whose identifier is the file identifier](#key-names-for-0.1.0).
* File 0xffffff52 (`PSA_CRYPTO_ITS_RANDOM_SEED_UID`): [nonvolatile random seed](#nonvolatile-random-seed-file-format-for-0.1.0).
* Files 0xffff0000 through 0xffffff51, 0xffffff53 through 0xffffffff: unused.
### File namespace on stdio for 0.1.0
Assumption: C stdio, allowing names containing lowercase letters, digits and underscores, of length up to 23.
An undocumented build-time configuration value `CRYPTO_STORAGE_FILE_LOCATION` allows storing the key files in a directory other than the current directory. This value is simply prepended to the file name (so it must end with a directory separator to put the keys in a different directory).
* `CRYPTO_STORAGE_FILE_LOCATION "psa_key_slot_0"`: used as a temporary file. Must be writable. May be overwritten or deleted if present.
* `sprintf(CRYPTO_STORAGE_FILE_LOCATION "psa_key_slot_%lu", key_id)` [content](#key-file-format-for-0.1.0) of the [key whose identifier](#key-names-for-0.1.0) is `key_id`.
* Other files: unused.
Mbed Crypto 1.0.0
-----------------
Tags: mbedcrypto-1.0.0d4, mbedcrypto-1.0.0
Released in February 2019. <br>
Integrated in Mbed OS 5.12.
Supported integrations:
* [PSA platform](#file-namespace-on-a-psa-platform-for-1.0.0)
* [library using PSA ITS](#file-namespace-on-its-as-a-library-for-1.0.0)
* [library using C stdio](#file-namespace-on-stdio-for-1.0.0)
Supported features:
* [Persistent transparent keys](#key-file-format-for-1.0.0) designated by a [key identifier and owner](#key-names-for-1.0.0).
* [Nonvolatile random seed](#nonvolatile-random-seed-file-format-for-1.0.0) on ITS only.
Backward compatibility commitments: TBD
### Key names for 1.0.0
Information about each key is stored in a dedicated file designated by the key identifier. In integrations where there is no concept of key owner (in particular, in library integrations), the key identifier is exactly the key identifier as defined in the PSA Cryptography API specification (`psa_key_id_t`). In integrations where there is a concept of key owner (integration into a service for example), the key identifier is made of an owner identifier (its semantics and type are integration specific) and of the key identifier (`psa_key_id_t`) from the key owner point of view.
The way in which the file name is constructed from the key identifier depends on the storage backend. The content of the file is described [below](#key-file-format-for-1.0.0).
* Library integration: the key file name is just the key identifier as defined in the PSA crypto specification. This is a 32-bit value.
* PSA service integration: the key file name is `(uint64_t)owner_uid << 32 | key_id` where `key_id` is the key identifier from the owner point of view and `owner_uid` (of type `int32_t`) is the calling partition identifier provided to the server by the partition manager. This is a 64-bit value.
### Key file format for 1.0.0
The layout is identical to [0.1.0](#key-file-format-for-0.1.0) so far. However note that the encoding of key types, algorithms and key material has changed, therefore the storage format is not compatible (despite using the same value in the version field so far).
### Nonvolatile random seed file format for 1.0.0
The nonvolatile random seed file contains a seed for the random generator. If present, it is rewritten at each boot as part of the random generator initialization.
The file format is just the seed as a byte string with no metadata or encoding of any kind.
This is unchanged since [the feature was introduced in Mbed Crypto 0.1.0](#nonvolatile-random-seed-file-format-for-0.1.0).
### File namespace on a PSA platform for 1.0.0
Assumption: ITS provides a 64-bit file identifier namespace. The Crypto service can use arbitrary file identifiers and no other part of the system accesses the same file identifier namespace.
Assumption: the owner identifier is a nonzero value of type `int32_t`.
* Files 0 through 0xffffff51, 0xffffff53 through 0xffffffff: unused, reserved for internal use of the crypto library or crypto service.
* File 0xffffff52 (`PSA_CRYPTO_ITS_RANDOM_SEED_UID`): [nonvolatile random seed](#nonvolatile-random-seed-file-format-for-0.1.0).
* Files 0x100000000 through 0xffffffffffff: [content](#key-file-format-for-1.0.0) of the [key whose identifier is the file identifier](#key-names-for-1.0.0). The upper 32 bits determine the owner.
### File namespace on ITS as a library for 1.0.0
Assumption: ITS provides a 64-bit file identifier namespace. The entity using the crypto library can use arbitrary file identifiers and no other part of the system accesses the same file identifier namespace.
This is a library integration, so there is no owner. The key file identifier is identical to the key identifier.
* File 0: unused.
* Files 1 through 0xfffeffff: [content](#key-file-format-for-1.0.0) of the [key whose identifier is the file identifier](#key-names-for-1.0.0).
* File 0xffffff52 (`PSA_CRYPTO_ITS_RANDOM_SEED_UID`): [nonvolatile random seed](#nonvolatile-random-seed-file-format-for-1.0.0).
* Files 0xffff0000 through 0xffffff51, 0xffffff53 through 0xffffffff, 0x100000000 through 0xffffffffffffffff: unused.
### File namespace on stdio for 1.0.0
This is a library integration, so there is no owner. The key file identifier is identical to the key identifier.
[Identical to 0.1.0](#file-namespace-on-stdio-for-0.1.0).
### Upgrade from 0.1.0 to 1.0.0.
* Delete files 1 through 0xfffeffff, which contain keys in a format that is no longer supported.
### Suggested changes to make before 1.0.0
The library integration and the PSA platform integration use different sets of file names. This is annoyingly non-uniform. For example, if we want to store non-key files, we have room in different ranges (0 through 0xffffffff on a PSA platform, 0xffff0000 through 0xffffffffffffffff in a library integration).
It would simplify things to always have a 32-bit owner, with a nonzero value, and thus reserve the range 00xffffffff for internal library use.
Mbed Crypto 1.1.0
-----------------
Tags: mbedcrypto-1.1.0
Released in early June 2019. <br>
Integrated in Mbed OS 5.13.
Changes since [1.0.0](#mbed-crypto-1.0.0):
* The stdio backend for storage has been replaced by an implementation of [PSA ITS over stdio](#file-namespace-on-stdio-for-1.1.0).
* [Some changes in the key file format](#key-file-format-for-1.1.0).
### File namespace on stdio for 1.1.0
Assumption: C stdio, allowing names containing lowercase letters, digits and underscores, of length up to 23.
An undocumented build-time configuration value `PSA_ITS_STORAGE_PREFIX` allows storing the key files in a directory other than the current directory. This value is simply prepended to the file name (so it must end with a directory separator to put the keys in a different directory).
* `PSA_ITS_STORAGE_PREFIX "tempfile.psa_its"`: used as a temporary file. Must be writable. May be overwritten or deleted if present.
* `sprintf(PSA_ITS_STORAGE_PREFIX "%016llx.psa_its", key_id)`: a key or non-key file. The `key_id` in the name is the 64-bit file identifier, which is the [key identifier](#key-names-for-mbed-tls-2.25.0) for a key file or some reserved identifier for a non-key file (currently: only the [nonvolatile random seed](#nonvolatile-random-seed-file-format-for-1.0.0)). The contents of the file are:
* Magic header (8 bytes): `"PSA\0ITS\0"`
* File contents.
### Key file format for 1.1.0
The key file format is identical to [1.0.0](#key-file-format-for-1.0.0), except for the following changes:
* A new policy field, marked as [NEW:1.1.0] below.
* The encoding of key types, algorithms and key material has changed, therefore the storage format is not compatible (despite using the same value in the version field so far).
A self-contained description of the file layout follows.
All integers are encoded in little-endian order in 8-bit bytes.
The layout of a key file is:
* magic (8 bytes): `"PSA\0KEY\0"`
* version (4 bytes): 0
* type (4 bytes): `psa_key_type_t` value
* policy usage flags (4 bytes): `psa_key_usage_t` value
* policy usage algorithm (4 bytes): `psa_algorithm_t` value
* policy enrollment algorithm (4 bytes): `psa_algorithm_t` value [NEW:1.1.0]
* key material length (4 bytes)
* key material: output of `psa_export_key`
* Any trailing data is rejected on load.
Mbed Crypto TBD
---------------
Tags: TBD
Released in TBD 2019. <br>
Integrated in Mbed OS TBD.
### Changes introduced in TBD
* The layout of a key file now has a lifetime field before the type field.
* Key files can store references to keys in a secure element. In such key files, the key material contains the slot number.
### File namespace on a PSA platform on TBD
Assumption: ITS provides a 64-bit file identifier namespace. The Crypto service can use arbitrary file identifiers and no other part of the system accesses the same file identifier namespace.
Assumption: the owner identifier is a nonzero value of type `int32_t`.
* Files 0 through 0xfffeffff: unused.
* Files 0xffff0000 through 0xffffffff: reserved for internal use of the crypto library or crypto service. See [non-key files](#non-key-files-on-tbd).
* Files 0x100000000 through 0xffffffffffff: [content](#key-file-format-for-1.0.0) of the [key whose identifier is the file identifier](#key-names-for-1.0.0). The upper 32 bits determine the owner.
### File namespace on ITS as a library on TBD
Assumption: ITS provides a 64-bit file identifier namespace. The entity using the crypto library can use arbitrary file identifiers and no other part of the system accesses the same file identifier namespace.
This is a library integration, so there is no owner. The key file identifier is identical to the key identifier.
* File 0: unused.
* Files 1 through 0xfffeffff: [content](#key-file-format-for-1.0.0) of the [key whose identifier is the file identifier](#key-names-for-1.0.0).
* Files 0xffff0000 through 0xffffffff: reserved for internal use of the crypto library or crypto service. See [non-key files](#non-key-files-on-tbd).
* Files 0x100000000 through 0xffffffffffffffff: unused.
### Non-key files on TBD
File identifiers in the range 0xffff0000 through 0xffffffff are reserved for internal use in Mbed Crypto.
* Files 0xfffffe02 through 0xfffffeff (`PSA_CRYPTO_SE_DRIVER_ITS_UID_BASE + lifetime`): secure element driver storage. The content of the file is the secure element driver's persistent data.
* File 0xffffff52 (`PSA_CRYPTO_ITS_RANDOM_SEED_UID`): [nonvolatile random seed](#nonvolatile-random-seed-file-format-for-1.0.0).
* File 0xffffff54 (`PSA_CRYPTO_ITS_TRANSACTION_UID`): [transaction file](#transaction-file-format-for-tbd).
* Other files are unused and reserved for future use.
### Key file format for TBD
All integers are encoded in little-endian order in 8-bit bytes except where otherwise indicated.
The layout of a key file is:
* magic (8 bytes): `"PSA\0KEY\0"`.
* version (4 bytes): 0.
* lifetime (4 bytes): `psa_key_lifetime_t` value.
* type (4 bytes): `psa_key_type_t` value.
* policy usage flags (4 bytes): `psa_key_usage_t` value.
* policy usage algorithm (4 bytes): `psa_algorithm_t` value.
* policy enrollment algorithm (4 bytes): `psa_algorithm_t` value.
* key material length (4 bytes).
* key material:
* For a transparent key: output of `psa_export_key`.
* For an opaque key (unified driver interface): driver-specific opaque key blob.
* For an opaque key (key in a secure element): slot number (8 bytes), in platform endianness.
* Any trailing data is rejected on load.
### Transaction file format for TBD
The transaction file contains data about an ongoing action that cannot be completed atomically. It exists only if there is an ongoing transaction.
All integers are encoded in platform endianness.
All currently existing transactions concern a key in a secure element.
The layout of a transaction file is:
* type (2 bytes): the [transaction type](#transaction-types-on-tbd).
* unused (2 bytes)
* lifetime (4 bytes): `psa_key_lifetime_t` value that corresponds to a key in a secure element.
* slot number (8 bytes): `psa_key_slot_number_t` value. This is the unique designation of the key for the secure element driver.
* key identifier (4 bytes in a library integration, 8 bytes on a PSA platform): the internal representation of the key identifier. On a PSA platform, this encodes the key owner in the same way as [in file identifiers for key files](#file-namespace-on-a-psa-platform-on-tbd)).
#### Transaction types on TBD
* 0x0001: key creation. The following locations may or may not contain data about the key that is being created:
* The slot in the secure element designated by the slot number.
* The file containing the key metadata designated by the key identifier.
* The driver persistent data.
* 0x0002: key destruction. The following locations may or may not still contain data about the key that is being destroyed:
* The slot in the secure element designated by the slot number.
* The file containing the key metadata designated by the key identifier.
* The driver persistent data.
Mbed Crypto TBD
---------------
Tags: TBD
Released in TBD 2020. <br>
Integrated in Mbed OS TBD.
### Changes introduced in TBD
* The type field has been split into a type and a bits field of 2 bytes each.
### Key file format for TBD
All integers are encoded in little-endian order in 8-bit bytes except where otherwise indicated.
The layout of a key file is:
* magic (8 bytes): `"PSA\0KEY\0"`.
* version (4 bytes): 0.
* lifetime (4 bytes): `psa_key_lifetime_t` value.
* type (2 bytes): `psa_key_type_t` value.
* bits (2 bytes): `psa_key_bits_t` value.
* policy usage flags (4 bytes): `psa_key_usage_t` value.
* policy usage algorithm (4 bytes): `psa_algorithm_t` value.
* policy enrollment algorithm (4 bytes): `psa_algorithm_t` value.
* key material length (4 bytes).
* key material:
* For a transparent key: output of `psa_export_key`.
* For an opaque key (unified driver interface): driver-specific opaque key blob.
* For an opaque key (key in a secure element): slot number (8 bytes), in platform endianness.
* Any trailing data is rejected on load.
Mbed TLS 2.25.0
---------------
Tags: `mbedtls-2.25.0`, `mbedtls-2.26.0`, `mbedtls-2.27.0`, `mbedtls-2.28.0`, `mbedtls-3.0.0`, `mbedtls-3.1.0`
First released in December 2020.
Note: this is the first version that is officially supported. The version number is still 0.
Backward compatibility commitments: we promise backward compatibility for stored keys when Mbed TLS is upgraded from x to y if x >= 2.25 and y < 4. See [`BRANCHES.md`](../../BRANCHES.md) for more details.
Supported integrations:
* [PSA platform](#file-namespace-on-a-psa-platform-on-mbed-tls-2.25.0)
* [library using PSA ITS](#file-namespace-on-its-as-a-library-on-mbed-tls-2.25.0)
* [library using C stdio](#file-namespace-on-stdio-for-mbed-tls-2.25.0)
Supported features:
* [Persistent keys](#key-file-format-for-mbed-tls-2.25.0) designated by a [key identifier and owner](#key-names-for-mbed-tls-2.25.0). Keys can be:
* Transparent, stored in the export format.
* Opaque, using the PSA driver interface with statically registered drivers. The driver determines the content of the opaque key blob.
* Opaque, using the deprecated secure element interface with dynamically registered drivers (`MBEDTLS_PSA_CRYPTO_SE_C`). The driver picks a slot number which is stored in the place of the key material.
* [Nonvolatile random seed](#nonvolatile-random-seed-file-format-for-mbed-tls-2.25.0) on ITS only.
### Changes introduced in Mbed TLS 2.25.0
* The numerical encodings of `psa_key_type_t`, `psa_key_usage_t` and `psa_algorithm_t` have changed.
### File namespace on a PSA platform on Mbed TLS 2.25.0
Assumption: ITS provides a 64-bit file identifier namespace. The Crypto service can use arbitrary file identifiers and no other part of the system accesses the same file identifier namespace.
Assumption: the owner identifier is a nonzero value of type `int32_t`.
* Files 0 through 0xfffeffff: unused.
* Files 0xffff0000 through 0xffffffff: reserved for internal use of the crypto library or crypto service. See [non-key files](#non-key-files-on-mbed-tls-2.25.0).
* Files 0x100000000 through 0xffffffffffff: [content](#key-file-format-for-mbed-tls-2.25.0) of the [key whose identifier is the file identifier](#key-names-for-mbed-tls-2.25.0). The upper 32 bits determine the owner.
### File namespace on ITS as a library on Mbed TLS 2.25.0
Assumption: ITS provides a 64-bit file identifier namespace. The entity using the crypto library can use arbitrary file identifiers and no other part of the system accesses the same file identifier namespace.
This is a library integration, so there is no owner. The key file identifier is identical to the key identifier.
* File 0: unused.
* Files 1 through 0xfffeffff: [content](#key-file-format-for-mbed-tls-2.25.0) of the [key whose identifier is the file identifier](#key-names-for-mbed-tls-2.25.0).
* Files 0xffff0000 through 0xffffffff: reserved for internal use of the crypto library or crypto service. See [non-key files](#non-key-files-on-mbed-tls-2.25.0).
* Files 0x100000000 through 0xffffffffffffffff: unused.
### File namespace on stdio for Mbed TLS 2.25.0
Assumption: C stdio, allowing names containing lowercase letters, digits and underscores, of length up to 23.
An undocumented build-time configuration value `PSA_ITS_STORAGE_PREFIX` allows storing the key files in a directory other than the current directory. This value is simply prepended to the file name (so it must end with a directory separator to put the keys in a different directory).
* `PSA_ITS_STORAGE_PREFIX "tempfile.psa_its"`: used as a temporary file. Must be writable. May be overwritten or deleted if present.
* `sprintf(PSA_ITS_STORAGE_PREFIX "%016llx.psa_its", key_id)`: a key or non-key file. The `key_id` in the name is the 64-bit file identifier, which is the [key identifier](#key-names-for-mbed-tls-2.25.0) for a key file or some reserved identifier for a [non-key file](#non-key-files-on-mbed-tls-2.25.0). The contents of the file are:
* Magic header (8 bytes): `"PSA\0ITS\0"`
* File contents.
### Key names for Mbed TLS 2.25.0
Information about each key is stored in a dedicated file designated by the key identifier. In integrations where there is no concept of key owner (in particular, in library integrations), the key identifier is exactly the key identifier as defined in the PSA Cryptography API specification (`psa_key_id_t`). In integrations where there is a concept of key owner (integration into a service for example), the key identifier is made of an owner identifier (its semantics and type are integration specific) and of the key identifier (`psa_key_id_t`) from the key owner point of view.
The way in which the file name is constructed from the key identifier depends on the storage backend. The content of the file is described [below](#key-file-format-for-mbed-tls-2.25.0).
* Library integration: the key file name is just the key identifier as defined in the PSA crypto specification. This is a 32-bit value which must be in the range 0x00000001..0x3fffffff (`PSA_KEY_ID_USER_MIN`..`PSA_KEY_ID_USER_MAX`).
* PSA service integration: the key file name is `(uint64_t)owner_uid << 32 | key_id` where `key_id` is the key identifier from the owner point of view and `owner_uid` (of type `int32_t`) is the calling partition identifier provided to the server by the partition manager. This is a 64-bit value.
### Key file format for Mbed TLS 2.25.0
All integers are encoded in little-endian order in 8-bit bytes except where otherwise indicated.
The layout of a key file is:
* magic (8 bytes): `"PSA\0KEY\0"`.
* version (4 bytes): 0.
* lifetime (4 bytes): `psa_key_lifetime_t` value.
* type (2 bytes): `psa_key_type_t` value.
* bits (2 bytes): `psa_key_bits_t` value.
* policy usage flags (4 bytes): `psa_key_usage_t` value.
* policy usage algorithm (4 bytes): `psa_algorithm_t` value.
* policy enrollment algorithm (4 bytes): `psa_algorithm_t` value.
* key material length (4 bytes).
* key material:
* For a transparent key: output of `psa_export_key`.
* For an opaque key (unified driver interface): driver-specific opaque key blob.
* For an opaque key (key in a dynamic secure element): slot number (8 bytes), in platform endianness.
* Any trailing data is rejected on load.
### Non-key files on Mbed TLS 2.25.0
File identifiers that are outside the range of persistent key identifiers are reserved for internal use by the library. The only identifiers currently in use have the owner id (top 32 bits) set to 0.
* Files 0xfffffe02 through 0xfffffeff (`PSA_CRYPTO_SE_DRIVER_ITS_UID_BASE + lifetime`): dynamic secure element driver storage. The content of the file is the secure element driver's persistent data.
* File 0xffffff52 (`PSA_CRYPTO_ITS_RANDOM_SEED_UID`): [nonvolatile random seed](#nonvolatile-random-seed-file-format-for-mbed-tls-2.25.0).
* File 0xffffff54 (`PSA_CRYPTO_ITS_TRANSACTION_UID`): [transaction file](#transaction-file-format-for-mbed-tls-2.25.0).
* Other files are unused and reserved for future use.
### Nonvolatile random seed file format for Mbed TLS 2.25.0
[Identical to Mbed Crypto 0.1.0](#nonvolatile-random-seed-file-format-for-0.1.0).
### Transaction file format for Mbed TLS 2.25.0
The transaction file contains data about an ongoing action that cannot be completed atomically. It exists only if there is an ongoing transaction.
All integers are encoded in platform endianness.
All currently existing transactions concern a key in a dynamic secure element.
The layout of a transaction file is:
* type (2 bytes): the [transaction type](#transaction-types-on-mbed-tls-2.25.0).
* unused (2 bytes)
* lifetime (4 bytes): `psa_key_lifetime_t` value that corresponds to a key in a secure element.
* slot number (8 bytes): `psa_key_slot_number_t` value. This is the unique designation of the key for the secure element driver.
* key identifier (4 bytes in a library integration, 8 bytes on a PSA platform): the internal representation of the key identifier. On a PSA platform, this encodes the key owner in the same way as [in file identifiers for key files](#file-namespace-on-a-psa-platform-on-mbed-tls-2.25.0)).
#### Transaction types on Mbed TLS 2.25.0
* 0x0001: key creation. The following locations may or may not contain data about the key that is being created:
* The slot in the secure element designated by the slot number.
* The file containing the key metadata designated by the key identifier.
* The driver persistent data.
* 0x0002: key destruction. The following locations may or may not still contain data about the key that is being destroyed:
* The slot in the secure element designated by the slot number.
* The file containing the key metadata designated by the key identifier.
* The driver persistent data.
## TF-PSA-Crypto 1.0
The dynamic secure element interface `MBEDTLS_PSA_CRYPTO_SE_C` is removed. As a consequence files identifiers 0xfffffe02 through 0xfffffeff are no more used by the secure element driver storage.
+568
View File
@@ -0,0 +1,568 @@
The PK module in TF-PSA-Crypto 1 and Mbed TLS 4
===============================================
The goal of this document is to describe the evolution of the `pk.h` interface from Mbed TLS 3.x going into TF-PSA-Crypto 1.0 and Mbed TLS 4.0.
## Requirements
### Project goal
The goal of the PK-4.0 project is to make minimal changes to the `pk.h` interface to make it suitable for TF-PSA-Crypto 1.0, and for consumption in Mbed TLS 4.0. We want to preserve the essential features of PK, while removing aspects of the interface that will make it difficult to finish the migration to PSA, and minimize the amount of work to be done before the 1.0/4.0 releases.
In the short term, before the 1.0/4.0 releases, we will make parts of `pk.h` private, and provide replacements where needed. The goal of the project is to make the desired parts private (i.e. no longer part of the documented API), and to ensure that the replacements are working. The old API can still be used under the hood in Mbed TLS.
In the medium term, in TF-PSA-Crypto 1.x and Mbed TLS 4.x, we will remove the internal uses of private APIs from Mbed TLS and TF-PSA-Crypto, then remove the implementation of those private APIs.
In the long term, we want to fully replace `pk.h` with PSA APIs. This is a work topic for the PSA Crypto API working group. The API design is still at an early stage, far too early to be taken into account here.
### Essential functionality of PK
The following functionality does not exist in PSA, but we consider it absolutely necessary for TF-PSA-Crypto:
* The ability to construct a PSA key from a PK key and vice versa.
* The ability to parse a key in various commonplace formats. These formats include metadata indicating the key type, so this cannot be a simple extension of `psa_import_key`.
* The ability to write a key in various commonplace formats.
In addition, we choose to retain the following functionality, because it is easier to keep it in PK than to reimplement it where it is used:
* A sign/verify interface, using a signature format that's ready for X.509 and TLS.
Any other functionality in the `pk.h` interface in TF-PSA-Crypto will either be justified by these needs (e.g. metadata queries, object creation and destruction), or left over from Mbed TLS 3.x if there's no particular reason to remove it. Everything else will be made private.
### Functionality that is removed from PK
The following features are deliberately removed from the PK API. (They may remain as private interfaces until TF-PSA-Crypto 1.x.)
* The ability to inspect how data is stored in PK contexts: opaque-or-not, `mbedtls_pk_ec()`, `mbedtls_pk_rsa()`, `mbedtls_pk_get_type()`, `mbedtls_pk_info_t`, etc.
* The ability to construct a PK context manually: `mbedtls_pk_setup()`.
* Direct support for opaque keys (`mbedtls_pk_setup_opaque()`, `mbedtls_pk_setup_rsa_alt()`, etc.). Go via PSA instead.
* The poorly defined type `mbedtls_pk_type_t` and the associated function `mbedtls_pk_can_do()`. Use PSA metadata instead.
* Mechanism names: `mbedtls_pk_get_name()`.
* The RSA-oriented length function: `mbedtls_pk_get_len()`. Use `mbedtls_pk_get_bitlen()`.
* Encrypt/decrypt: `mbedtls_pk_decrypt()`, `mbedtls_pk_encrypt()`. Use PSA.
### Design philosophy for the new PK
We retain the concept of a “PK context”, which can either be empty or contain a public key or contain a key pair. The new PK handles key parsing and writing, and has convenience functions to sign with a key.
A PK context has the following conceptual properties:
* A PSA key type (key pair or public key). This is `PSA_KEY_TYPE_NONE` for an empty context.
* Key material that matches the key type. This can be directly in the PK object, or indirectly via a PSA key identifier.
* Optionally, an associated PSA key identifier. The PSA key may be owned by the PK context and destroyed when the context is destroyed, or it may be referenced by the PK context and left alone when the context is destroyed.
The PK module does not enforce key policies. In particular, it is possible to copy a PK context into a context with a different signature algorithm.
### Private interfaces
In this document, a ***private*** interface is one that is not documented. Applications should not use private interfaces, and we do not promise any kind of stability about them. Mbed TLS can use private interfaces of TF-PSA-Crypto, but in the medium term (over the lifetime of TF-PSA-Crypto 1.x and Mbed TLS 4.x), it should stop doing so. Public interfaces must not rely on private interfaces, for example a private type cannot be used in the prototype of a public function. However, public types can have a private implementation (we guarantee that the type will keep existing, but it may be implemented differently, typically adding and removing fields in a structure).
An ***internal*** interface is only usable inside TF-PSA-Crypto.
## Use case studies
### RSA in TLS
#### How Mbed TLS currently uses RSA
In Mbed TLS 4.x, TLS 1.2 cipher suites using RSA encryption are not supported. Thus we only care about RSA as a signature algorithm. This subsection studies how the TLS subsystem uses RSA.
TLS 1.2 normally uses PKCS#1v1.5. However, if an Mbed TLS client advertizes support for both TLS 1.2 and 1.3 and advertizes support for PSS-based signature algorithms, some servers may select PSS in TLS 1.2, and the Mbed TLS client supports that. In this case, the TLS 1.2 `ssl_parse_server_key_exchange()` checks an RSA-PSS signature using a public key that it finds as a `mbedtls_pk_context` in the peer's certificate. The public key is only used for a single algorithm, but the algorithm is not yet known when the PK object is created.
TLS 1.3 has a verification mechanism with the same data flow in `ssl_tls13_parse_certificate_verify()`. In TLS 1.3, this is done both on the client side and on the server side.
TLS 1.3 servers may need to produce either a PKCS#1v1.5 or a PSS signature, based on which signature algorithm the server selects among those offered by the client. The private key is a `mbedtls_pk_context` object passed to `mbedtls_conf_own_cert()`. The SSL configuration stores a chained list of key/certificate pairs, with no length limit. The same private key may be used a different RSA algorithm in each connection. The server commits to a private key and to a certificate chain at the same time, based on the keys it has available and their compatibility with the offered signature algorithms.
#### Dual-algorithm RSA verification
In both TLS and X.509, we want the following control flow:
1. Parse a certificate, creating a PK context containing a public key.
2. Determine which signature verification algorithm to use. This information does not come from the certiciate.
3. Verify a signature according to the chosen algorithm.
In Mbed TLS 3.6, the parsing step always results in an object where the key is public present in plain text (either in PSA import format or as a representation involving MPI objects). The verification step either calls built-in code or imports the key into PSA. In the latter case, it can freely choose the algorithm. Even if we change the data flow later to create a PSA key sooner, it will always be possible to export the public key, thus we do not need to take any particular precautions for future-proofing.
The ideal interface here is something similar to `mbedtls_pk_verify_ext()`, with a free selection of the verification algorithm at the time of verification.
It would be possible to create multiple PK contexts after parsing, one with each potential signature algorithm. However there is no incentive to do so. It would add complexity and memory consumption for no benefit.
#### Dual-algorithm RSA signature
The control flow for a TLS server using an RSA private key is as follows:
1. Construct a PK context around the private key. There are two ways:
* Parse a key file. Optionally, change some metadata associated with the key.
* Wrap an existing PSA key (opaque PK context). There is no way to change its policy.
2. Pass the PK context alongside a matching certificate to `mbedtls_ssl_conf_own_cert()`. Note that the same certificate is commonly used with the same key for both PKCS#1v1.5 and PSS.
3. Establish a connection and reach the point in the construction of the ServerKeyExchange message where the key in question is chosen, with a signature algorithm that can indicate either PKCS#1v1.5 or PSS.
4. Use the chosen algorithm to produce a signature.
In order to make it possible to use the same RSA key with both algorithm, some action is necessary at one of these steps.
At step 1, in Mbed TLS 3.6, RSA keys resulting from parsing can always be used for both algorithms, but this is not necessarily the case for opaque keys. (It can only be the case if the PSA key uses the “enrollment algorithm” policy feature, which is a proprietary extension of TF-PSA-Crypto that is not supported on some platforms such as TF-M.) Thus, if we want a single workflow for all cases, it has to be a **strict workflow**, where the application using TLS must pass two PK contexts if it wants to allow both algorithms. In the case of a PK context resulting from parsing, there must be some indication of which RSA algorithm will be chosen (this is to be documented in the PK module — parsing an RSA key defaults to PKCS#1v1.5). In this workflow, the signature operation always involves the algorithm associated with the PK context: there is no analog of `mbedtls_pk_sign_ext()`. The strict workflow has the downside that it requires each PK object to have a single associated algorithm, which was considered and discarded (see “[Rejected `mbedtls_pk_set_algorithm()`](#rejected-mbedtls_pk_set_algorithm)”).
We may also consider a **duplication workflow**. In this workflow, at step 2, when `mbedtls_ssl_conf_own_cert()` sees a PK context that could be used for both algorithms (e.g. a PK context that wraps an exportable key, or a PK context that wraps a key whose policy allows both algorithms), it adds two entries to the key/certificate list: the original PK object, and a copied object with the other protocol. This seems complicated, especially with respect to resource management (the SSL configuration object does not own the keys and certificates, but it would have to own the copy made here). Also this workflow is currently broken in TLS 1.3, since it only checks the public key from the certificate, not the private key ([#10233](https://github.com/Mbed-TLS/mbedtls/issues/10233)). Hence we will not consider this workflow further.
Steps 3 and 4 are performed in near succession for each connection, therefore there is no meaningful difference between an action taken at step 3 or step 4, and we will consider them together. Step 3 needs to determine whether the key is compatible with a given signature algorithm offered by the client. Therefore it must be able to tell when a key allows both algorithms. Then step 4 needs to use the chosen signature algorithm, using a function similar to `mbedtls_pk_sign_ext()`. Depending on how the PK context was constructed, this may be done in different ways (just pass the right algorithm to `psa_sign_hash()` if the PSA key allows it, pass the right algorithm when importing a key that wasn't in PSA already, copy the key, etc.). This is a **cheating workflow**.
Conclusion: we will continue to use the current cheating workflow. This approach minimizes the changes in how PK object construction determines which algorithms the key can be used with, and in how to query which algorithms a PK object can be used with.
The main cost of this approach is that we are committing to supporting permissive PK objects, as in, PK objects that can be used with any algorithm that the key type permits. This means that throughout the lifetime of TF-PSA-Crypto 1.x, we will continue to have code in the implementation of `mbedtls_pk_sign_ext()` that possibly exports an underlying PSA key to re-import it under a different policy. This is not ideal, but has the benefit of interface simplicity (PK doesn't do policy, period) and an easy migration from Mbed TLS 3.6 to TF-PSA-Crypto 1.x + Mbed TLS 4.x for both users and us implementers.
#### Enforcing the workflow
If the effective capabilities of `mbedtls_ssl_conf_own_cert()` change, we need to be careful not to end up in a situation where:
1. An application works fine with Mbed TLS 3.6, relying only on documented behavior.
2. The application still works in practice with Mbed TLS 4.0, but now relies on behavior that is no longer documented.
3. The application breaks when TF-PSA-Crypto 1.x moves to more PSA in PK (the change that is likely to be problematic being when `mbedtls_pk_parse_key()` starts constructing a PSA key for RSA key pairs).
We should make sure that `mbedtls_ssl_conf_own_cert()` is strict on what it accepts even in the 4.0 release, and validate this through tests. See [“Interface stability testing”](#interface-stability-testing).
## API elements
### PK context type
#### Keep `mbedtls_pk_context`
We keep `mbedtls_pk_context` largely as it is now. It will be reworked after 1.0 as needed. Keep:
```
mbedtls_pk_context
mbedtls_pk_init()
mbedtls_pk_free()
```
Also keep the following metadata access function:
```
mbedtls_pk_can_do_ext()
```
#### Meaning of `mbedtls_pk_type_t`
`mbedtls_pk_type_t` has several subtly different meanings:
* How the key is represented in a `mbedtls_pk_context`, with additional policy information for EC keys. Can be anything except `MBEDTLS_PK_RSAPSS`.
* Key type from parsing. Can be `MBEDTLS_PK_RSA`, `MBEDTLS_PK_ECKEY` or `MBEDTLS_PK_ECKEY_DH`. Note that obtaining `MBEDTLS_PK_ECKEY_DH` from parsing is fully untested.
* Signature algorithm in X.509. Can be `MBEDTLS_PK_RSA`, `MBEDTLS_PK_RSAPSS` or `MBEDTLS_PK_ECDSA`.
* In invocations of `mbedtls_pk_can_do()`, and possibly elsewhere in local variables or internal functions, it can be a union of two or more of the above.
In TF-PSA-Crypto, we don't want to expose the distinction between `MBEDTLS_PK_OPAQUE` (purely PSA-backed key) and other key types (non-PSA-backed, or partially PSA-backed in the case of ECC keys). We also don't want to guarantee the subtle distinctions between `MBEDTLS_PK_ECKEY`, `MBEDTLS_PK_ECKEY_DH` and `MBEDTLS_PK_ECDSA`. Hence the type `mbedtls_pk_type_t` will become private.
#### Public uses of `mbedtls_pk_type_t` or `mbedtls_pk_get_type()`
Public headers and sample programs are considered public. Library code (including Mbed TLS), test code and test programs are not considered public.
* In X.509 types, to specify an X.509 signature algorithm. See “[New type for signature algorithms](#new-type-for-signature-algorithms)”.
* In several of `programs/pkey/*.c`, to differentiate between RSA and ECC. See “[Use new APIs to distinguish between RSA and ECC in sample programs](#use-new-apis-to-distinguish-between-rsa-and-ecc-in-sample-programs)”.
#### New type for signature algorithms
ACTION (https://github.com/Mbed-TLS/TF-PSA-Crypto/issues/346): Define a new type `mbedtls_pk_sigalg_t` which is a subset of `mbedtls_pk_type_t`, containing only the values that are meaningful as a signature algorithm in an X.509 structure. Prototyped in [#204](https://github.com/Mbed-TLS/TF-PSA-Crypto/pull/204).
```
typedef enum {
MBEDTLS_PK_SIGALG_NONE = MBEDTLS_PK_NONE,
MBEDTLS_PK_SIGALG_RSA = MBEDTLS_PK_RSA,
MBEDTLS_PK_SIGALG_ECDSA = MBEDTLS_PK_ECDSA,
MBEDTLS_PK_SIGALG_RSASSA_PSS = MBEDTLS_PK_RSASSA_PSS,
} mbedtls_pk_sigalg_t;
```
Keep the same numerical values as `mbedtls_pk_type_t`, so that a `mbedtls_pk_sigalg_t` value can be cast to `mbedtls_pk_type_t` in library code that still uses this deprecated type.
ACTION (https://github.com/Mbed-TLS/mbedtls/issues/10264): Move `x509*.h` to the new type.
This task together with the changes to `mbedtls_pk_sign_ext()` and `mbedtls_pk_verify_ext()` described in “[Signature functionality](#signature-functionality)” remove the need for `mbedtls_pk_type_t` to be in the public API of Mbed TLS. Follow-up: make it (and `mbedtls_pk_get_type()`) private in “[Privatization](#privatization)”.
Maybe define public aliases for backward compatibility (it costs us pretty much nothing, and will facilitate the transition).
```
MBEDTLS_PK_NONE = MBEDTLS_PK_SIGALG_NONE
MBEDTLS_PK_RSA = MBEDTLS_PK_SIGALG_RSA
MBEDTLS_PK_RSASSA_PSS = MBEDTLS_PK_SIGALG_RSASSA_PSS
MBEDTLS_PK_ECDSA = MBEDTLS_PK_SIGALG_ECDSA
MBEDTLS_PK_ECKEY = MBEDTLS_PK_SIGALG_ECDSA
```
TODO: investigate merging `MBEDTLS_PK_ECKEY` with `MBEDTLS_PK_ECDSA`. Do we rely on the difference anywhere that's still relevant?
#### `mbedtls_pk_can_do()`
Remove `mbedtls_pk_can_do()` from the public API.
Everyone should use PSA metadata instead. For example, the question “can this key do RSA?” (`mbedtls_pk_can_do(pk, MBEDTLS_PK_RSA)`) is ambiguous since the answer depends on the desired algorithm, so users should instead call `mbedtls_pk_can_do_ext()` which takes an algorithm as a parameter.
#### `mbedtls_pk_get_name()`
PK no longer has a concept of a name for a key type or algorithm.
#### Custom PK context data
PK no longer supports custom setup and inspection of a PK object, thus we remove the following elements from the public API, to be done in “[Privatization](#privatization)”:
* `mbedtls_pk_setup()`. Construct from a PSA key or by parsing instead.
* `mbedtls_pk_ec()`, `mbedtls_pk_rsa()`. All code must also work when a PK context is backed by a PSA key.
#### `mbedtls_pk_check_pair()`
Keep `mbedtls_pk_check_pair()`. It's no burden to implement.
### Changes to `mbedtls_pk_can_do_ext`
#### Semantics of `mbedtls_pk_can_do_ext` in Mbed TLS 3.6
We keep `mbedtls_pk_can_do_ext()` because it's useful to check what a key can do after parsing it. It is partially redundant with `mbedtls_pk_get_psa_attributes()`, but it's sometimes more convenient, already implemented, and easy to implement for any evolution of PK that can accommodate `mbedtls_pk_get_psa_attributes()`.
The semantics of `mbedtls_pk_can_do_ext()` in Mbed TLS 3.6 is somewhat weird with respect to public keys. Although the function is advertised as “Tell if context can do the operation given by PSA algorithm”, that is not quite true. The function takes an algorithm and a usage flag (or a mask thereof), with only private-key usage flags allowed. But it accepts public keys, which could only do the corresponding public-key operation. For example,
```
mbedtls_pk_can_do_ext(pk, PSA_ALG_ECDSA(PSA_ALG_SHA_256), PSA_KEY_USAGE_SIGN_HASH)
```
is true for a builtin ECC key object containing only the public part of the key.
This is misleading and not documented.
#### New semantics of `mbedtls_pk_can_do_ext`
We should change the meaning of the usage flag to indicate what operations can actually be performed on the key:
* `PSA_KEY_USAGE_SIGN_HASH` means a key pair that can be used to sign;
* `PSA_KEY_USAGE_VERIFY_HASH` means a public key or key pair that can be used to verify;
* `PSA_KEY_USAGE_DECRYPT` means a key pair that can be used to decrypt;
* `PSA_KEY_USAGE_ENCRYPT` means a public key or key pair that can be used to encrypt;
* `PSA_KEY_USAGE_DERIVE` means a key pair that can be used as the private side in a key agreement;
* `PSA_KEY_USAGE_DERIVE_PUBLIC`: flag for a key pair or public key that can be used as the public side in a key agreement. This flag does not currently exist in PSA, and [may be added as part of adding s similar function to the PSA API](https://github.com/ARM-software/psa-api/issues/279). In the meantime, give it the value 0x80000000. Note that changing the value will be an ABI change.
This will be closer to how `mbedtls_pk_get_psa_attributes()` works.
To ease the transition, we will call the new function `mbedtls_pk_can_do_psa`. We will keep the current `mbedtls_pk_can_do_ext` as a private function until Mbed TLS stops using it (a [GitHub code search](https://github.com/search?q=%22mbedtls_pk_can_do_ext%28%22+path%3A*.c+NOT+path%3A**%2Fpk.c+NOT+path%3A**%2Fssl_*.c+NOT+path%3A**%2Fx509_c%3F%3F.c+NOT+path%3A**%2Ftest_suite_pk*.c&type=code&ref=advsearch) suggests application developers don't use this function).
ACTION (https://github.com/Mbed-TLS/TF-PSA-Crypto/issues/351): Implement and unit-test `mbedtls_pk_can_do_psa()`. Reuse most of the code of `mbedtls_pk_can_do_ext()` (it will probably help to break it into smaller functions). Should be done before 1.0, but can be done after.
#### Migrating to `mbedtls_pk_can_do_psa`
Note that the change of semantics on public keys will break [`ssl_pick_cert()`](https://github.com/Mbed-TLS/mbedtls/blob/mbedtls-3.6.3/library/ssl_tls12_server.c#L687) and [`ssl_tls13_pick_key_cert()`](https://github.com/Mbed-TLS/mbedtls/blob/mbedtls-3.6.3/library/ssl_tls13_server.c#L1115), as they rely on calling `mbedtls_pk_can_do_ext()` on the public key from the certificate. However, this should be an easy fix: just change these invocations to use `PSA_KEY_USAGE_VERIFY_HASH` as the usage to check.
ACTION (https://github.com/Mbed-TLS/mbedtls/issues/10266): migrate TLS to `mbedtls_pk_can_do_psa()`. Can be done after 4.0.
### PSA bridges
The new PK needs to have bridges between PK contexts and PSA keys.
Given a key in one form, there are two ways to obtain a key in the other form:
* Make a copy of the key data, so that the destination object lives independently from the source object. This is far easier to use in terms of resource management. However, it may not be possible if the source object's policy makes it impossible to copy. This can be the case with PSA keys, and also with PK contexts if they wrap around a non-copiable PSA key.
* Create an object that aliases the source object: wrap a PSA key in a PK context, or peek at the underlying PSA key of a PK context. The wrapper/underlying object is only valid as long as the source object is valid. A PK context created by wrapping an existing PSA key does not destroy the PSA key. Resource management is tricky, but this has a low overhead and works for keys whose material cannot be copied.
There is currently no way to access the underlying PSA key of a PK context. A nw function to [access the underlying PSA key of a PK context](#access-the-underlying-psa-key-of-a-pk-context) is not planned for TF-PSA-Crypto 1.0.
#### Choice of ECDSA variant
PK sometimes needs to choose between ECDSA variants, when it builds PSA attributes for an ECC key:
* To import an ECC key during parsing, and to sign with a built-in ECC key, when `MBEDTLS_PK_USE_PSA_EC_DATA` is enabled. This uses the macro `MBEDTLS_PK_ALG_ECDSA` defined in `mbedtls/pk.h`.
* In `mbedtls_pk_get_psa_attributes()` to choose the default policy for an ECC key used for signature.
ACTION (https://github.com/Mbed-TLS/TF-PSA-Crypto/issues/345): change `MBEDTLS_PK_PSA_ALG_ECDSA_MAYBE_DET` to a public macro `MBEDTLS_PK_ALG_ECDSA`. Switch `mbedtls_pk_get_psa_attributes()` to it. This is nice but not critical for 1.0.
#### `mbedtls_pk_get_psa_attributes()`
Keep `mbedtls_pk_get_psa_attributes()`.
Notes:
* An ECC public key in SubjectPublicKeyInfo format (possibly embedded in a key pair) can specify one of two algorithms: id-ecPublicKey (allows ECDSA signature) or id-ecDH (should not be used for signature). This is encoded in the old API through the PK type: id-ecDH leads to `MBEDTLS_PK_ECKEY_DH`. This is untested (we have no test key with id-ecDH; backlog issue: https://github.com/Mbed-TLS/TF-PSA-Crypto/issues/206). In the new API, you can find out whether a key had id-ecPublicKey or id-ecDH by looking at the algorithm chosen by `mbedtls_pk_get_psa_attributes()`.
* Arguably, since PK is now specialized towards signatures, we could remove the `usage` argument from `mbedtls_pk_get_psa_attributes()`, and make the function work only for a sign/verify usage. However, I don't think this would be right, especially because PK only handles signature: after parsing a key, to use it for something other than signature, you need to use PSA, which means you need to call `mbedtls_pk_get_psa_attributes()` then `mbedtls_pk_import_into_psa()` to create a PSA key with your desired non-signature algorithm. Also, the usage parameter allows for extracting the public part of a key when you don't know whether you have a public key or a key pair, which is very convenient in some cases such as managing a key store.
#### Copy between PK and PSA
Keep the following functions, which create a PK context from a PSA key and vice versa:
```
mbedtls_pk_import_into_psa()
mbedtls_pk_copy_from_psa()
mbedtls_pk_copy_public_from_psa()
```
#### Wrap a PSA key in PK
There is already a function to wrap a PSA private key in a PK context: `mbedtls_pk_setup_opaque()`. The function's name no longer makes sense, since there is no longer a concept of “opaque” PK contexts, and no longer a ”setup“ operation on PK contexts.
ACTION (crypto-opaque): rename `mbedtls_pk_setup_opaque()` to `mbedtls_pk_wrap_psa()` and adjust the documentation accordingly. (Updating internal references to “opaque” is out of scope and will be done later: [Update terminology from “opaque” to “wrapped”](#update-terminology-from-opaque-to-wrapped).) Prototyped in [#204](https://github.com/Mbed-TLS/TF-PSA-Crypto/pull/204).
ACTION (https://github.com/Mbed-TLS/TF-PSA-Crypto/issues/205): remove mentions of operations other than sign and verify from the documentation. Prototyped in [#204](https://github.com/Mbed-TLS/TF-PSA-Crypto/pull/204).
The function is somewhat dangerous, since the PK context will silently become invalid if the PSA key is destroyed. Experience in 3.x has shown the function to be handy nonetheless, so we shouldn't remove it without clear alternatives.
The current function has some limitations. We should lift them soon (“[Remove limitations of `mbedtls_pk_wrap_psa()`](#remove-limitations-of-mbedtls_pk_wrap_psa)”), but it isn't a deal breaker for TF-PSA-Crypto 1.0.
### Key parsing and writing
Keep:
```
mbedtls_pk_parse_key()
mbedtls_pk_parse_public_key()
mbedtls_pk_write_key_der()
mbedtls_pk_write_pubkey_der()
mbedtls_pk_write_pubkey_pem()
mbedtls_pk_write_key_pem()
```
Keep:
```
mbedtls_pk_parse_keyfile()
mbedtls_pk_parse_public_keyfile()
```
### Signature conveniences
#### Signature functionality
Keep the following:
```
MBEDTLS_PK_SIGNATURE_MAX_SIZE
```
Keep the following:
```
mbedtls_pk_verify()
mbedtls_pk_sign()
```
ACTION (https://github.com/Mbed-TLS/TF-PSA-Crypto/issues/347): document that `mbedtls_pk_sign()` and `mbedtls_pk_verify()` are legacy functions, that perform the same algorithm that `mbedtls_pk_get_psa_attributes()` would perform under the hood if given a sign or verify usage.
Tweak the following:
```
mbedtls_pk_verify_ext()
mbedtls_pk_sign_ext()
```
ACTION (https://github.com/Mbed-TLS/TF-PSA-Crypto/issues/348, https://github.com/Mbed-TLS/mbedtls/issues/10265, https://github.com/Mbed-TLS/TF-PSA-Crypto/issues/349): remove the `options` parameter to `mbedtls_pk_verify_ext`. Note that we have a changelog entry announcing that it's ignored, this changelog entry needs to be replaced.
ACTION (https://github.com/Mbed-TLS/TF-PSA-Crypto/issues/346): for `mbedtls_pk_sign_ext()` and `mbedtls_pk_verify_ext()`, change the `mbedtls_pk_type_t type` parameter (whose type is being removed from the API) to `mbedtls_pk_sigalg_t sigalg`. See “[New type for signature algorithms](new-type-for-signature-algorithms)”.
ACTION (https://github.com/Mbed-TLS/mbedtls/issues/5544): remove `MBEDTLS_ERR_PK_SIG_LEN_MISMATCH`. It's mostly useless for RSA, and it doesn't even work for ECDSA.
#### Restartable signature functionality
It's more convenient to keep using PK for restartable signature in X.509, for the same reason as non-restartable signature. So restartable PK should keep existing, so we might as well keep it public.
Keep:
```
mbedtls_pk_restart_ctx
mbedtls_pk_restart_init()
mbedtls_pk_restart_free()
mbedtls_pk_verify_restartable()
mbedtls_pk_sign_restartable()
```
No changes to the function's implementation: restartable behavior is only available for built-in ECDSA when built-in restartable ECC is enabled, but the function always works (in a non-restartable way if restartable is not possible).
There is a risk that the current API will be suboptimal when we port its implementation. However, I think this risk is low, since this is basically the interface that X.509 likes, and the primary goal of PK is to support X.509. If X.509 needs more adaptation than expected to migrate to PSA, PK is the natural place for the adaptation code.
### Removals
#### Removed functions
ACTION (https://github.com/Mbed-TLS/TF-PSA-Crypto/pull/297): remove the encrypt/decrypt functions.
```
mbedtls_pk_decrypt()
mbedtls_pk_encrypt()
```
#### Privatization
ACTION (https://github.com/Mbed-TLS/TF-PSA-Crypto/issues/343): Create a header `/include/mbedtls/private/pk_private.h`. At first, it just includes `../pk.h`.
ACTION (https://github.com/Mbed-TLS/mbedtls-framework/issues/178): Conditionally include `mbedtls/private/pk_private.h` in the framework.
ACTION (https://github.com/Mbed-TLS/mbedtls/issues/10263): Conditionally include `mbedtls/private/pk_private.h` in Mbed TLS.
ACTION (https://github.com/Mbed-TLS/TF-PSA-Crypto/issues/344): Move all private API elements to `mbedtls/private/pk_private.h`:
```
mbedtls_pk_type_t
mbedtls_pk_rsassa_pss_options
mbedtls_pk_debug_type
mbedtls_pk_debug_item
MBEDTLS_PK_DEBUG_MAX_ITEMS
mbedtls_pk_info_from_type()
mbedtls_pk_setup()
mbedtls_pk_get_len()
mbedtls_pk_can_do()
mbedtls_pk_can_do_ext()
mbedtls_pk_debug()
mbedtls_pk_get_name()
mbedtls_pk_get_type()
mbedtls_pk_rsa()
mbedtls_pk_ec()
mbedtls_pk_parse_subpubkey()
mbedtls_pk_write_pubkey()
```
Follow-up: [Make private API elements internal](#make-private-api-elements-internal)
#### Documentation update after privatization
ACTION (https://github.com/Mbed-TLS/TF-PSA-Crypto/issues/205): remove all mentions of private API elements from the public documentation.
This includes both direct mentions (where a type name, constant name or function name is mentioned), and indirect mentions (e.g. “verify\_ext”, “context has been set up”).
#### Remove RSA-ALT
ACTION (https://github.com/Mbed-TLS/TF-PSA-Crypto/issues/208): Remove the option `MBEDTLS_PK_RSA_ALT_SUPPORT` and all code guarded by it, as well as `MBEDTLS_PK_RSA_ALT`.
### Documentation updates
ACTION (https://github.com/Mbed-TLS/TF-PSA-Crypto/issues/209): update the PSA transition guide.
ACTION (https://github.com/Mbed-TLS/TF-PSA-Crypto/issues/209): write the 1.0 migration guide.
ACTION (https://github.com/Mbed-TLS/TF-PSA-Crypto/issues/209): write changelog entries.
## Changes in PK consumers
No changes are needed in X.509 before Mbed TLS 4.0. One area of TLS may need some tweaks: [private key selection in TLS servers](#changes-to-private-key-selection).
### Changes to private key selection in TLS
A TLS server can have multiple key-certificate pairs configured with `mbedtls_ssl_conf_own_cert()`. In principle, the server goes through the list of cipher suites (TLS 1.2) or signature algorithms (TLS 1.3) offered by the client, and picks the first one for which a key-certificate pair exists. See “[Dual-algorithm RSA signature](dual-algorithm-rsa-signature)” for a more detailed description.
There are known problems with the current implementation:
* [#10208](https://github.com/Mbed-TLS/mbedtls/issues/10208): for RSA keys, TLS 1.2 correctly checks the compatibility of the private key. But to perform the actual signature, it calls `mbedtls_pk_sign()`, so it uses the key's primary algorithm, which might not be the one required by the protocol (PKCS#1v1.5 for RSA keys).
* [#10220](https://github.com/Mbed-TLS/mbedtls/issues/10220): for ECDSA keys of type `MBEDTLS_PK_OPAQUE`, TLS 1.2 insists on randomized ECDSA, but the key may only permit deterministic ECDSA.
* [#10233](https://github.com/Mbed-TLS/mbedtls/issues/10233): TLS 1.3 can't cope with multiple private keys for the same certificate.
ACTION (https://github.com/Mbed-TLS/mbedtls/issues/10075): determine how to pass keys to `mbedtls_ssl_conf_own_cert()` in Mbed TLS 4.0, in the sense of documenting an official way to do it, ensuring that this way works, and ensuring that applications using the old way fails (unless we decide to preserve the old way throughout the lifetime of Mbed TLS 4.x and TF-PSA-Crypto 1.x).
This isn't a problem for verification because as a last resort, it's always possible to export a public key and re-import it with a different policy.
Note: the conclusion of this investigation is that with the current design, no particular precautions are needed here.
## Testing
### Unit tests
For the most part, the testing work is a matter of adapting the existing tests, and of creating unit tests for the new interfaces. This work is distributed throughout the coding tasks.
### Interface stability testing
One of the [project goals](#project-goal) is to prepare for moving crypto to be fully PSA, and in particular PK to be purely a wrapper around PSA keys, at least for private keys. We want to avoid breaking application code in TF-PSA-Crypto 1.x if the code worked with TF-PSA-Crypto 1.0. Normally our stability guarantee does not apply to applications that use undocumented behavior. However, it may happen that an application worked fine with Mbed TLS 3.6 and was relying only on documented behavior, and TF-PSA-Crypto 1.0 or Mbed TLS 4.0 stops documenting a critical aspect of the behavior, but in practice the application still works with 1.0/4.0. To reduce user frustration, we would like to minimize such cases. Thus the API in TF-PSA-Crypto 1.0 and Mbed TLS 4.0 should be strict and should reject “permissive” behavior that could work now, but would not be easy to migrate to PSA.
Given the choice of keeping PK permissive ([signature functionality](#signature-functionality) keeping `mbedtls_pk_sign_ext()`, cheating workflow chosen for [dual-algorithm RSA signature](#dual-algorithm-rsa-signature)), the combined behavior of PK and TLS remains mostly unchanged from Mbed TLS 3.6.
ACTION (https://github.com/Mbed-TLS/mbedtls/issues/10160): test `mbedtls_ssl_conf_own_cert()` to ensure that it doesn't cheat on key policies. Note: this would be nice, but at this point, it does not seem critical to do it before the 1.0/4.0 release. However, if we don't implement the tests, we do need to be mindful of not breaking cases that are currently possible. A draft exists in [#10217](https://github.com/Mbed-TLS/mbedtls/pull/10217).
## Open questions
### Parsing and writing
#### Remove file parsing functions?
Should we remove the file parsing functions `mbedtls_pk_parse_keyfile()` and `mbedtls_pk_parse_public_keyfile()`? They look misplaced in a library that generally doesn't access files. But it isn't really difficult to keep them.
These functions are used in test code and sample programs.
### Rejected: `mbedtls_pk_set_algorithm`
An earlier draft of this document proposed that every PK context would have an associated signature algorithm, which could be set with the function `mbedtls_pk_set_algorithm`. This algorithm was used for `mbedtls_pk_sign` and `mbedtls_pk_verify`. There were no `_ext` versions of these functions: users were supposed to import the key into PSA.
#### Effectiveness of `mbedtls_pk_set_algorithm`
How do I parse an RSA key, and then select PSS? More generally, how do I indicate what policy to use after parsing a key?
In my original draft, you can parse an RSA key and then call `mbedtls_pk_set_algorithm()` to select an algorithm other than the default (which is PKCS#1v1.5 signature). This may not be the right design: it won't work when we change PK to always go through PSA for RSA key pairs (i.e. making them systematically opaque in the old sense).
An alternative approach is to require copying the key after parsing. This is what we're effectively doing when the application wants to use the key through PSA: it calls `mbedtls_pk_parse_xxx()`, then `mbedtls_pk_import_into_psa()` (after which it can free the intermediate PK object). But what if the application wants to use the key through PK? The current workflow can be:
* `mbedtls_pk_set_algorithm()` — but as noted above this is not future-proof.
* `mbedtls_pk_import_into_psa()` then `mbedtls_pk_copy_from_psa()`. Inefficient but ok. If that's the intended way to do it, we need to document it clearly, and maybe we should remove `mbedtls_pk_set_algorithm()`?
* A new function `mbedtls_pk_copy()` allowing a policy change?
#### Why `mbedtls_pk_set_algorithm` was rejected
`mbedtls_pk_set_algorithm()` had to mutate the PK object, because the normal intended workflow was to parse a key, then inspect its type, then call `mbedtls_pk_set_algorithm()`. But this made it possible to mutate an object after passing it to a function, which could have unintended effect. Furthermore, this function could fail, since it may need to allocate resources (to copy the key, when it's already in PSA and the new algorithm isn't permitted by the key's policy).
The main intent of `mbedtls_pk_set_algorithm()` was to allow mimicking current flows involving `mbedtls_pk_sign()` and `mbedtls_pk_verify()`. However, on closer inspection, this didn't work so well. In particular, a major driving goal was to keep the internal workings TLS layer mostly unchanged from Mbed TLS 3.6, but change the way users had to call `mbedtls_pk_conf_own_cert()` (see “[RSA in TLS](#rsa-in-tls)”). This would both save time for the preparation of Mbed TLS 4.0, and serve as a sample of what implementers of other protocols might face.
However, it turns out that the way TLS 1.2 and TLS 1.3 use PK private keys is buggy in different ways:
* [#10208](https://github.com/Mbed-TLS/mbedtls/issues/10208): TLS 1.2 calls `mbedtls_pk_sign()`, so it uses the key's primary algorithm, which might not be the one required by the protocol (PKCS#1v1.5 for RSA keys).
* [#10233](https://github.com/Mbed-TLS/mbedtls/issues/10233): TLS 1.3 can't cope with multiple private keys for the same certificate.
These are issues in 3.6, so fixing them is desirable. But their impact is relatively minor in 3.6 because they're uncommon cases. On the other hand, in 4.0, they become more relevant, which risked adding a signficant amount of work to be done before 4.0.
Architecturally, #10208 highlights how having an algorithm associated with a PK object is inherently fragile. Hence the current design removes this concept, and instead orients the user of the PK module towards explicitly choosing the signature algorithm.
### Resource management
#### Access the underlying PSA key of a PK context
Should we provide a function to access the underlying PSA key of a PK context, if there is one?
This would be new work, and does not seem to be needed at the moment. If the PK context was created from a PSA key, the application might as well use the original PSA key. If the PK context was created by parsing, `mbedtls_pk_import_into_psa()` works, and does not require a special case if the PK context does not have an underlying PSA key.
If we add this in the future, it will be considerably easier if all PK contexts have an underlying PSA key, or at least all PK contexts containing a private key have an underlying PSA key.
Note that this function would be somewhat dangerous, like `mbedtls_pk_wrap_psa()`, since the PK object becomes invalid if the PSA key is destroyed independently, and the PSA key identifier becomes invalid if the PK context is destroyed. It is impossible to detect invalid uses at runtime since the PSA key identifier may be reused.
## Later tasks
The tasks described in this section do not need to be done before the 1.0/4.0 release. This section is incomplete.
### Missing functionality
#### Remove limitations of `mbedtls_pk_wrap_psa()`
Remove the limitations of wrapped keys:
* Implement verify for wrapped RSA keys.
* Implement check-pair for wrapped RSA keys.
### Migrate library and test code
#### Update terminology from “opaque” to “wrapped”
Update the library code to change the obsolete terminology “opaque” (as in e.g. `MBEDTLS_PK_OPAQUE`) to “wrapped”.
Originally, PK contexts could wrap a PSA key in order to support non-exportable keys kept in a secure partition, using a PSA implementation with client-server isolation. Thus the useful purpose of wrapping a PSA key was to make the key opaque, hence the name. In TF-PSA-Crypto, we plan to evolve to making PK keys contain a PSA key in more situations. What will matter is whether the underlying PSA key is owned by the PK context (and destroyed when the context is freed), or not (thus surviving when the context is freed). A key owned by the PK context could still potentially be opaque. Hence the distinction should be between _wrapped_ and _owned_ PSA keys.
#### Retire `MBEDTLS_PK_ECDSA`
It is no longer possible to construct a PK object with the legacy type `MBEDTLS_PK_ECDSA`. So get rid of the code that handles it, and remove `MBEDTLS_PK_ECDSA`.
#### Replace all uses of `mbedtls_pk_type_t`, `mbedtls_pk_get_type()` and `mbedtls_pk_can_do()` in X.509 library and test code
#### Replace all uses of `mbedtls_pk_type_t`, `mbedtls_pk_get_type()` and `mbedtls_pk_can_do()` in TLS library and test code
#### Get rid of `mbedtls_pk_can_do()`
Once it's no longer used anywhere, we can stop implementing it.
#### Get rid of `mbedtls_pk_info`
Dispatch based on an enum rather than a method table. This simplifies the code.
#### Make `mbedtls_pk_type_t` internal
Goal: `mbedtls_pk_type_t` is only used inside `pk*.c` and in PK unit tests. It may still be exposed in the `mbedtls_pk_context` type.
### Migrate sample programs
#### Use new APIs to distinguish between RSA and ECC in sample programs
### Removals
#### Make private API elements internal
As much as possible, make private API elements internal. That is, instead of being declared in a public header, declare them in `pk_internal.h` which should not be included by anything except `pk*.c` and PK unit tests.
This should ideally be done little by little, when we eliminate the uses of these elements in Mbed TLS.
#### Remove deprecated former API elements once they are no longer used
@@ -0,0 +1,173 @@
PSA Cryptography API implementation and PSA driver interface
===========================================================
## Introduction
The [PSA Cryptography API specification](https://armmbed.github.io/mbed-crypto/psa/#application-programming-interface) defines an interface to cryptographic operations for which the Mbed TLS library provides a reference implementation. The PSA Cryptography API specification is complemented by the PSA driver interface specification which defines an interface for cryptoprocessor drivers.
This document describes the high level organization of the Mbed TLS PSA Cryptography API implementation which is tightly related to the PSA driver interface.
## High level organization of the Mbed TLS PSA Cryptography API implementation
In one sentence, the Mbed TLS PSA Cryptography API implementation is made of a core and PSA drivers as defined in the PSA driver interface. The key point is that software cryptographic operations are organized as PSA drivers: they interact with the core through the PSA driver interface.
### Rationale
* Addressing software and hardware cryptographic implementations through the same C interface reduces the core code size and its call graph complexity. The core and its dispatching to software and hardware implementations are consequently easier to test and validate.
* The organization of the software cryptographic implementations in drivers promotes modularization of those implementations.
* As hardware capabilities, software cryptographic functionalities can be described by a JSON driver description file as defined in the PSA driver interface.
* Along with JSON driver description files, the PSA driver specification defines the deliverables for a driver to be included into the Mbed TLS PSA Cryptography implementation. This provides a natural framework to integrate third party or alternative software implementations of cryptographic operations.
## The Mbed TLS PSA Cryptography API implementation core
The core implements all the APIs as defined in the PSA Cryptography API specification but does not perform on its own any cryptographic operation. The core relies on PSA drivers to actually
perform the cryptographic operations. The core is responsible for:
* the key store.
* checking PSA API arguments and translating them into valid arguments for the necessary calls to the PSA driver interface.
* dispatching the cryptographic operations to the appropriate PSA drivers.
The sketch of an Mbed TLS PSA cryptographic API implementation is thus:
```C
psa_status_t psa_api( ... )
{
psa_status_t status;
/* Pre driver interface call processing: validation of arguments, building
* of arguments for the call to the driver interface, ... */
...
/* Call to the driver interface */
status = psa_driver_wrapper_<entry_point>( ... );
if( status != PSA_SUCCESS )
return( status );
/* Post driver interface call processing: validation of the values returned
* by the driver, finalization of the values to return to the caller,
* clean-up in case of error ... */
}
```
The code of most PSA APIs is expected to match precisely the above layout. However, it is likely that the code structure of some APIs will be more complicated with several calls to the driver interface, mainly to encompass a larger variety of hardware designs. For example, to encompass hardware accelerators that are capable of verifying a MAC and those that are only capable of computing a MAC, the psa_mac_verify() API could call first psa_driver_wrapper_mac_verify() and then fallback to psa_driver_wrapper_mac_compute().
The implementations of `psa_driver_wrapper_<entry_point>` functions are generated by the build system based on the JSON driver description files of the various PSA drivers making up the Mbed TLS PSA Cryptography API implementation. The implementations are splited into two parts. The static ones are generated in a psa_crypto_driver_wrappers.h header file, the non-static ones are generated in a psa_crypto_driver_wrappers_no_static.c C file and the function prototypes declared in a psa_crypto_driver_wrappers_no_static.h header file.
The psa_driver_wrapper_<entry_point>() functions dispatch cryptographic operations to accelerator drivers, secure element drivers as well as to the software implementations of cryptographic operations.
Note that the implementation allows to build the library with only a C compiler by shipping a generated file corresponding to a pure software implementation. The driver entry points and their code in this generated file are guarded by pre-processor directives based on PSA_WANT_xyz macros (see [Conditional inclusion of cryptographic mechanism through the PSA API in Mbed TLS](psa-conditional-inclusion-c.html). That way, it is possible to compile and include in the library only the desired cryptographic operations.
### Key creation
Key creation implementation in Mbed TLS PSA core is articulated around three internal functions: psa_start_key_creation(), psa_finish_key_creation() and psa_fail_key_creation(). Implementations of key creation PSA APIs, namely psa_import_key(), psa_generate_key(), psa_key_derivation_output_key() and psa_copy_key() go by the following sequence:
1. Check the input parameters.
2. Call psa_start_key_creation() that allocates a key slot, prepares it with the specified key attributes, and in case of a volatile key assign it a volatile key identifier.
3. Generate or copy the key material into the key slot. This entails the allocation of the buffer to store the key material.
4. Call psa_finish_key_creation() that mostly saves persistent keys into persistent storage.
In case of any error occurring at step 3 or 4, psa_fail_key_creation() is called. It wipes and cleans the slot especially the key material: reset to zero of the RAM memory that contained the key material, free the allocated buffer.
## Mbed TLS PSA Cryptography API implementation drivers
A driver of the Mbed TLS PSA Cryptography API implementation (Mbed TLS PSA driver in the following) is a driver in the sense that it is compliant with the PSA driver interface specification. But it is not an actual driver that drives some hardware. It implements cryptographic operations purely in software.
An Mbed TLS PSA driver C file is named psa_crypto_<driver_name>.c and its associated header file psa_crypto_<driver_name>.h. The functions implementing a driver entry point as defined in the PSA driver interface specification are named as mbedtls_psa_<driver name>_<entry point>(). As an example, the psa_crypto_rsa.c and psa_crypto_rsa.h are the files containing the Mbed TLS PSA driver implementing RSA cryptographic operations. This RSA driver implements among other entry points the "import_key" entry point. The function implementing this entry point is named mbedtls_psa_rsa_import_key().
## How to implement a new cryptographic mechanism
Summary of files to modify when adding a new algorithm or key type:
* [ ] PSA Crypto API draft, if not already done — [PSA standardization](#psa-standardization)
* [ ] `include/psa/crypto_values.h` or `include/psa/crypto_extra.h` — [New functions and macros](#new-functions-and-macros)
* [ ] `include/psa/crypto_config.h`, `tests/configs/crypto_config_test_driver_extension.h` — [Preprocessor symbols](#preprocessor-symbols)
* Occasionally `library/check_crypto_config.h` — [Preprocessor symbols](#preprocessor-symbols)
* [ ] `include/mbedtls/config_psa.h` — [Preprocessor symbols](#preprocessor-symbols)
* [ ] `library/psa_crypto.c`, `library/psa_crypto_*.[hc]` — [Implementation of the mechanisms](#implementation-of-the-mechanisms)
* [ ] `include/psa/crypto_builtin_*.h` — [Translucent data structures](#translucent-data-structures)
* [ ] `tests/suites/test_suite_psa_crypto_metadata.data` — [New functions and macros](#new-functions-and-macros)
* (If adding `PSA_IS_xxx`) `tests/suites/test_suite_psa_crypto_metadata.function` — [New functions and macros](#new-functions-and-macros)
* [ ] `tests/suites/test_suite_psa_crypto*.data`, `tests/suites/test_suite_psa_crypto*.function` — [Unit tests](#unit-tests)
* [ ] `framework/scripts/mbedtls_framework/crypto_knowledge.py`, `framework/scripts/mbedtls_framework/asymmetric_key_data.py` — [Unit tests](#unit-tests)
* [ ] `ChangeLog.d/*.txt` — changelog entry
Summary of files to modify when adding new API functions:
* [ ] `include/psa/crypto.h` and `include/psa/crypto_sizes.h`, or `include/psa/crypto_extra.h` — [New functions and macros](#new-functions-and-macros)
* [ ] `library/psa_crypto.c`, `scripts/data_files/driver_templates/*.jinja` — [Implementation of the mechanisms](#implementation-of-the-mechanisms)
* [ ] If adding stateful functions: `include/psa/crypto_struct.h`, `include/psa/crypto_builtin_*.h`, `include/psa/crypto_driver_contexts_*.h` — [Translucent data structures](#translucent-data-structures)
* [ ] `tests/suites/test_suite_psa_crypto.data`, `tests/suites/test_suite_psa_crypto.function`, `tests/suites/test_suite_psa_crypto_driver_wrappers.*` — [Unit tests](#unit-tests)
Note that this is just a basic guide. In some cases, you won't need to change all the files listed here. In some cases, you may need to change other files.
### PSA standardization
Typically, if there's enough demand for a cryptographic mechanism in Mbed TLS, there's enough demand for it to be part of the official PSA Cryptography specification. Therefore the first step before implementing a new mechanism should be to approach the PSA Cryptography working group in Arm for standardization.
At the time of writing, all cryptographic mechanisms that are accessible through `psa_xxx` APIs in in Mbed TLS are current or upcoming PSA standards. Mbed TLS implements some extensions to the PSA API that offer extra integration customization or extra key policies.
Mbed TLS routinely implements cryptographic mechanisms that are not yet part of a published PSA standard, but that are scheduled to be part of a future version of the standard. The Mbed TLS implementation validates the feasibility of the upcoming PSA standard. The PSA Cryptography working group and the Mbed TLS development team communicate during the elaboration of the new interfaces.
### New functions and macros
If a mechanism requires new functions, they should follow the design guidelines in the PSA Cryptography API specification.
Functions that are part of the current or upcoming API are declared in `include/psa/crypto.h`, apart from structure accessors defined in `include/psa/crypto_struct.h`. Functions that have output buffers have associated sufficient-output-size macros in `include/psa/crypto_sizes.h`.
Constants (algorithm identifiers, key type identifiers, etc.) and associated destructor macros (e.g. `PSA_IS_xxx()`) are defined in `include/psa/crypto_values.h`.
Functions and macros that are not intended for standardization, or that are at a stage where the draft standard might still evolve significantly, are declared in `include/psa/crypto_extra.h`.
The PSA Cryptography API specification defines both names and values for certain kinds of constants: algorithms (`PSA_ALG_xxx`), key types (`PSA_KEY_TYPE_xxx`), ECC curve families (`PSA_ECC_FAMILY_xxx`), DH group families (`PSA_DH_FAMILY_xxx`). If Mbed TLS defines an algorithm or a key type that is not part of a current or upcoming PSA standard, pick a value with the `VENDOR` flag set. If Mbed TLS defines an ECC curve or DH group family that is not part of a current or upcoming PSA standard, define a vendor key type and use the family identifier only with this vendor key type.
New constants must have a test case in `tests/suites/test_suite_psa_crypto_metadata.data` that verifies that `PSA_IS_xxx` macros behave properly with the new constant. New `PSA_IS_xxx` macros must be declared in `tests/suites/test_suite_psa_crypto_metadata.function`.
### Preprocessor symbols
Each cryptographic mechanism is optional and can be selected by the application at build time. For each feature `PSA_ttt_xxx`:
* The feature is available to applications when the preprocessor symbol `PSA_WANT_ttt_xxx` is defined. These symbols are set in the application configuration file `include/psa/crypto_config.h` (or `MBEDTLS_PSA_CRYPTO_CONFIG_FILE`, plus `MBEDTLS_PSA_CRYPTO_USER_CONFIG_FILE`), with code in `include/mbedtls/config_psa.h` deducing the necessary underlying `MBEDTLS_xxx` symbols.
* For transparent keys (keys that are not in a secure element), the feature is implemented by Mbed TLS if `MBEDTLS_PSA_BUILTIN_ttt_xxx` is defined, and by an accelerator driver if `MBEDTLS_PSA_ACCEL_ttt_xxx` is defined. `MBEDTLS_PSA_BUILTIN_ttt_xxx` constants are set in `include/mbedtls/config_psa.h` based on the application requests `PSA_WANT_ttt_xxx` and the accelerator driver declarations `MBEDTLS_PSA_ACCEL_ttt_xxx`.
* For the testing of the driver dispatch code, `tests/configs/crypto_config_test_driver_extension.h` sets additional `MBEDTLS_PSA_ACCEL_xxx` symbols.
For more details, see *[Conditional inclusion of cryptographic mechanism through the PSA API in Mbed TLS](../proposed/psa-conditional-inclusion-c.html)*.
Some mechanisms require other mechanisms. For example, you can't do GCM without a block cipher, or RSA-PSS without RSA keys. When mechanism A requires mechanism B, `include/mbedtls/config_psa.h` ensures that B is enabled whenever A is enabled. When mechanism A requires at least one of a set {B1, B2, B3, ...} but there is no particular reason why enabling A would enable any of the specific Bi's, it's up to the application to choose Bi's and the file `library/check_crypto_config.h` contains compile-time constraints to ensure that at least one Bi is enabled.
### Implementation of the mechanisms
The general structure of a cryptographic operation function is:
1. API function defined in `library/psa_crypto.c`. The entry point performs generic checks that don't depend on whether the mechanism is implemented in software or in a driver and looks up keys in the key store.
2. Driver dispatch code in `scripts/data_files/driver_templates/psa_crypto_driver_wrappers.h.jinja`, `scripts/data_files/driver_templates/psa_crypto_driver_wrappers_no_static.c.jinja` or files included from there.
3. Built-in implementation in `library/psa_crypto_*.c` (with function declarations in the corresponding `.h` file). These files typically contain the implementation of modes of operation over basic building blocks that are defined elsewhere. For example, HMAC is implemented in `library/psa_crypto_mac.c` but the underlying hash functions are implemented in `library/sha*.c` and `library/md*.c`.
4. Basic cryptographic building blocks in `library/*.c`.
When implementing a new algorithm or key type, there are typically things to change in `library/crypto.c` (e.g. buffer size calculations, algorithm/key-type compatibility) and in the built-in implementation, but not in the driver dispatch code.
### Translucent data structures
Some mechanisms require state to be kept between function calls. Keys and key-like data is kept in the key store, which PSA manages internally. Other state, for example the state of multipart operations, is kept in structures allocated by the caller.
The size of operation structures needs to be known at compile time, since callers may allocate them on the stack. Therefore these structures are defined in a public header: `include/psa/crypto_struct.h` for the parts that are independent of the underlying implementation, `include/psa/crypto_builtin_*` for parts that are specific to the Mbed TLS built-in implementation, `include/psa/crypto_driver_*.h` for structures implemented by drivers.
### Unit tests
A number of unit tests are automatically generated by `framework/scripts/generate_psa_tests.py` based on the algorithms and key types declared in `include/psa/crypto_values.h` and `include/psa/crypto_extra.h`:
* Attempt to create a key with a key type that is not supported.
* Attempt to perform an operation with a combination of key type and algorithm that is not valid or not supported.
* Storage and retrieval of a persistent key.
When adding a new key type or algorithm:
* `framework/scripts/mbedtls_framework/crypto_knowledge.py` contains knowledge about the compatibility of key types, key sizes and algorithms.
* `framework/scripts/mbedtls_framework/asymmetric_key_data.py` contains valid key data for asymmetric key types.
Other things need to be tested manually, either in `tests/suites/test_sutie_psa_crypto.data` or in another file. For example (this is not an exhaustive list):
* Known answer tests.
* Potential edge cases (e.g. data less/equal/more than the block size, number equal to zero in asymmetric cryptography).
* Tests with invalid keys (e.g. wrong size or format).
* Tests with invalid data (e.g. wrong size or format, output buffer too small, invalid padding).
* For new functions: incorrect function call sequence, driver dispatch (in `tests/suites/test_suite_psa_crypto_driver_wrappers.*`).
* For key derivation algorithms: variation on the sequence of input steps, variation on the output size.
@@ -0,0 +1,214 @@
PSA key store design
====================
## Introduction
This document describes the architecture of the key storage in memory in the Mbed TLS and TF-PSA-Crypto implementation of the PSA Cryptography API.
In the PSA Cryptography API, cryptographic operations access key materials via a key identifier (key ID for short). Applications must first create a key object, which allocates storage in memory for the key material and metadata. This storage is under the control of the library and may be located in a different memory space such as a trusted execution environment or a secure element.
The storage of persistent keys is out of scope of this document. See the [Mbed Crypto storage specification](mbed-crypto-storage-specification.md).
## Key slot management interface
### Key store and key slots
The **key store** consists of a collection of **key slots**. Each key slot contains the metadata for one key, as well as the key material or a reference to the key material.
A key slot has the type `psa_key_slot_t`. The key store is a global object which is private inside `psa_crypto_slot_management.c`.
### Key slot entry points
The following operations allocate a key slot by calling `psa_reserve_free_key_slot()`:
* **Creating** a key object, through means such as import, random generation, deterministic derivation, copy, or registration of an existing key that is stored in protected hardware (secure element, hardware unique key (HUK)).
* **Loading** a persistent key from storage, or loading a built-in key. This is done through `psa_get_and_lock_key_slot()`, which calls `psa_reserve_free_key_slot()` and loads the key if applicable.
The following operations free a key slot by calling `psa_wipe_key_slot()` and, if applicable, `psa_free_key_slot()`:
* **Destroying** a key.
* **Purging** a persistent key from memory, either explicitly at the application's request or to free memory.
Deinitializing the PSA Crypto subsystem with `mbedtls_psa_crypto_free()` destroys all volatile keys and purges all persistent keys.
The library accesses key slots in the following scenarios:
* while the key is being created or loaded;
* while the key is being destroyed or purged;
* while the key metadata or key material is being accessed.
### Key slot states
The state of a key slot is indicated by its `state` field of type `psa_key_slot_state_t`, which can be:
* `PSA_SLOT_EMPTY`: a slot that occupies memory but does not currently contain a key.
* `PSA_SLOT_FILLING`: a slot that is being filled to create or load a key.
* `PSA_SLOT_FULL`: a slot containing a key.
* `PSA_SLOT_PENDING_DELETION`: a slot whose key is being destroy or purged.
These states are mostly useful for concurrency. See [Concurrency](#concurrency) below and [key slot states in the PSA thread safety specification](psa-thread-safety/psa-thread-safety.md#key-slot-states).
#### Concurrency
In a multithreaded environment, since Mbed TLS 3.6.0, each key slot is protected by a reader-writer lock. (In earlier versions, the key store was not thread-safe.) The lock is controlled by a single global mutex `mbedtls_threading_psa_globaldata_mutex`. The concurrency state of the slot is indicated by the state and the `registered_readers` field:
* `EMPTY` or `FULL` state, `registered_readers == 0`: the slot is not in use by any thread.
* `FULL` state, `registered_readers != 0`: the slot is being read.
* `FILLING` or `PENDING_DELETION` state: the slot is being written.
For more information, see [PSA thread safety](psa-thread-safety/psa-thread-safety.md).
Note that a slot must not be moved in memory while it is being read or written.
## Key slot management implementations
### Key store implementation variants
There are three variants of the key store implementation, responding to different needs.
* Hybrid key store ([static key slots](#static-key-store) with dynamic key data): the key store is a statically allocated array of slots, of size `MBEDTLS_PSA_KEY_SLOT_COUNT`. Key material is allocated on the heap. This is the historical implementation. It remains the default in the Mbed TLS 3.6 long-time support (LTS) branch when using a handwritten `mbedtls_config.h`, as is common on resource-constrained platforms, because the alternatives have tradeoffs (key size limit and larger RAM usage at rest for the static key store, larger code size and more risk due to code complexity for the dynamic key store).
* Fully [static key store](#static-key-store) (since Mbed TLS 3.6.3): the key store is a statically allocated array of slots, of size `MBEDTLS_PSA_KEY_SLOT_COUNT`. Each key slot contains the key representation directly, and the key representation must be no more than `MBEDTLS_PSA_STATIC_KEY_SLOT_BUFFER_SIZE` bytes. This is intended for very constrained devices that do not have a heap.
* [Dynamic key store](#dynamic-key-store) (since Mbed TLS 3.6.1): the key store is dynamically allocated as multiple slices on the heap, with a size that adjusts to the application's usage. Key material is allocated on the heap. Compared to the hybrid key store, the code size and RAM consumption are larger. This is intended for higher-end devices where applications are not expected to have a highly predicatable resource usage. This is the default implementation when using the default `mbedtls_config.h` file, as is common on platforms such as Linux, starting with Mbed TLS 3.6.1.
#### Future improvement: merging the key store variants
In the future, we may reduce the number of key store variants to just two, perhaps even one.
We introduced the variants other than the hybrid key store in a patch release of a long-time support version. As a consequence, we wanted to minimize making changes to the default build (when not using the supplied `mbedtls_config.h`, as explained above), to minimize the risk of bugs and the increase in code size. These considerations will not apply in future major or minor releases, so the default key store can change later.
The static key store could become a runtime decision, where only keys larger than some threshold require the use of heap memory. The reasons not to do this in Mbed TLS 3.6.x are that this increases complexity somewhat (slightly more code size, and more risk), and this changes the RAM usage profile somewhat.
A major constraint on the design of the dynamic key store is the need to preserve slot pointers while a slot may be accessed by another thread (see [“Concurrency”](#concurrency)). With the concurrency primitives available in Mbed TLS 3.x, it is very hard to move a key slot in memory, because there could be an indefinite wait until some other thread has finished accessing the slot. This pushed towards the slice-based organisation described below, where each slice is allocated for the long term. In particular, slices cannot be compacted (compacting would be moving slots out of a sparsely-used slice to free it). Better concurrency primitives (e.g. condition variables or semaphores), together with a `realloc()` primitive, could allow freeing unused memory more aggressively, which could make the dynamic key store not detrimental in RAM usage compared to the historical hybrid key store.
#### Slice abstraction
Some parts of the key slot management code use **key slices** as an abstraction. A key slice is an array of key slots. Key slices are identified by an index which is a small non-negative integer.
* With a [static key store](#static-key-store), there is a single, statically allocated slice, with the index 0.
* With a [dynamic key store](#dynamic-key-store), there is statically allocated array of pointers to key slices. The index of a slice is the index in that array. The slices are allocated on the heap as needed.
#### Key identifiers and slot location
When creating a volatile key, the slice containing the slot and index of the slot in its slice determine the key identifier. When accessing a volatile key, the slice and the slot index in the slice are calculated from the key identifier. The encoding of the slot location in the volatile key identifier is different for a [static](#volatile-key-identifiers-in-the-static-key-store) or [dynamic](#volatile-key-identifiers-in-the-dynamic-key-store) key store.
### Static key store
The static key store is the historical implementation. The key store is a statically allocated array of slots, of size `MBEDTLS_PSA_KEY_SLOT_COUNT`. This value is an upper bound for the total number of volatile keys plus loaded keys.
Since Mbed TLS 3.6.3, there are two variants for the static key store: a hybrid variant (default), and a fully-static variant enabled by the configuration option `MBEDTLS_PSA_STATIC_KEY_SLOTS`. The two variants have the same key store management: the only difference is in how the memory for key data is managed. With fully static key slots, the key data is directly inside the slot, and limited to `MBEDTLS_PSA_KEY_SLOT_BUFFER_SIZE` bytes. With the hybrid key store, the slot contains a pointer to the key data, which is allocated on the heap.
#### Volatile key identifiers in the static key store
For easy lookup, a volatile key whose index is `id` is stored at the index `id - PSA_KEY_ID_VOLATILE_MIN`.
#### Key creation with a static key store
To create a key, `psa_reserve_free_key_slot()` searches the key slot array until it finds one that is empty. If there are none, the code looks for a persistent key that can be purged (see [“Persistent key cache”](#persistent-key-cache)), and purges it. If no slot is free and no slot contains a purgeable key, the key creation fails.
#### Freeing a key slot with a static key store
With a static key store, `psa_wipe_key_slot()` destroys or purges a key by freeing any associated resources, then setting the key slot to the empty state. The slot is then ready for reuse.
### Dynamic key store
The dynamic key store allows a large number of keys, at the expense of more complex memory management.
The dynamic key store was added in Mbed TLS 3.6.1. It is enabled by `MBEDTLS_PSA_KEY_STORE_DYNAMIC`, which is enabled by default since Mbed TLS 3.6.1.
#### Dynamic key slot performance characteristics
Key management and key access have $O(1)$ amortized performance, and mostly $O(1)$ performance for actions involving keys. More precisely:
* Access to an existing volatile key takes $O(1)$ time.
* Access to a persistent key (including creation and destruction) takes time that is linear in `MBEDTLS_PSA_KEY_SLOT_COUNT`.
* Allocating a key takes amortized $O(1)$ time. Usually the time is $O(s)$ where $s$ is the number of slices (which is a hard-coded value less than $30$), but when creating $k$ volatile keys, at most $\log(k)$ creations will involve calls to `calloc()`, totalling $O(k)$ memory.
* Destroying a volatile key takes $O(1)$ time as of Mbed TLS 3.6.1. Later improvements to memory consumption are likely to involve calls to `free()` which may total $O(k)$ memory where $k$ is the maximum number of volatile keys.
#### Key slices in the dynamic key store
The key slot is organized in slices, which are dynamically arrays of key slot. The number of slices is determined at compile time. The key store contains a static array of pointers to slices.
Volatile keys and loaded keys (persistent or built-in) are stored in separate slices.
Key slices number 0 to `KEY_SLOT_VOLATILE_SLICE_COUNT - 1` contain only volatile keys.
One key slice contains only loaded keys: that key slice is thus the cache slice. See [“Persistent key cache”](persistent-key-cache) for how the cache is managed.
#### Volatile key identifiers in the dynamic key store
A volatile key identifier encodes the slice index and the slot index at separate bit positions. That is, `key_id = BASE | slice_index | slot_index` where the bits set in `BASE`, `slice_index` and `slot_index` do not overlap.
#### From key slot to key slice
Some parts of the slot management code need to determine which key slice contains a key slot when given a pointer to the key slot. In principle, the key slice is uniquely determined from the key identifier which is located in the slot:
* for a volatile key identifier, the [slice index is encoded in the key identifier](#volatile-key-identifiers-in-the-dynamic-key-store);
* for a persistent key identifier or built-in key identifier, [the slot is in the sole cache slice](#key-slices-in-the-dynamic-key-store).
Nonetheless, we store the slice index as a field in the slot, for two reasons:
* It is more robust in case the slice assignment becomes more complex in the future or is somehow buggy.
* It allows the slot to slice correspondence to work even if the key identifier field has not been filled yet or has been wiped. The implementation in Mbed TLS 3.6.1 requires this because `psa_wipe_key_slot()` wipes the slot, then calls `psa_free_key_slot()`, which needs to determine the slice. Keeping the slice index as a separate field allows us to better separate the concerns of key liveness and slot liveness. A redesign of the internal interfaces could improve this, but would be too disruptive in the 3.6 LTS branch.
#### Length of the volatile key slices
The volatile key slices have exponentially increasing length: each slice is twice as long as the previous one. Thus if the length of slice 0 is `B` and there are `N` slices, then there are `B * (2^N - 1)` slots.
As of Mbed TLS 3.6.1, the maximum number of volatile key slots is less than the theoretical maximum of 2^30 - 2^16 (0x10000000..0x7ffeffff, the largest range of key identifiers reserved for the PSA Crypto implementation that does not overlap the range for built-in keys). The reason is that we limit the slot index to 2^25-1 so that the [encoding of volatile key identifiers](#volatile-key-identifiers-in-the-dynamic-key-store) has 25 bits for the slot index.
When `MBEDTLS_TEST_HOOKS` is enabled, the length of key slices can be overridden. We use this in tests that need to fill the key store.
#### Free list
Each volatile key slice has a **free list**. This is a linked list of all the slots in the slice that are free. The global data contains a static array of free list heads, i.e. the index of a free slot in the slice. Each free slot contains the index of the next free slot in that slice's free list. The end of the list is indicated by an index that is larger than the length of the slice. If the list is empty, the head contains an index that is larger than the length.
As a small optimization, a free slot does not actually contain the index of the next slot, but the index of the next free slot on the list _relative to the next slot in the array_. For example, 0 indicates that the next free slot is the slot immediately after the current slot. This fact is the reason for the encoding: a slice freshly obtained from `calloc` has all of its slots in the free list in order. The value 1 indicates that there is one element between this slot and the next free slot. The next element of the free list can come before the current slot: -2 indicates that it's the slot immediately before, -3 is two slots before, and so on (-1 is impossible). In general, the absolute index of the next slot after slot `i` in the free list is `i + 1 slice[i].next_free_relative_to_next`.
#### Dynamic key slot allocation
To create a volatile key, `psa_reserve_free_key_slot()` searches the free lists of each allocated slice until it finds a slice that is not full. If all allocated slices are full, the code allocates a new slice at the lowest possible slice index. If all possible slices are already allocated and full, the key creation fails.
The newly allocated slot is removed from the slice's free list.
We only allocate a slice of size `B * 2^k` if there are already `B * (2^k - 1)` occupied slots. Thus the memory overhead is at most `B` slots plus the number of occupied slots, i.e. the memory consumption for slots is at most twice the required memory plus a small constant overhead.
#### Dynamic key slot deallocation
When destroying a volatile key, `psa_wipe_key_slot()` calls `psa_free_key_slot()`. This function adds the newly freed slot to the head of the free list.
##### Future improvement: slice deallocation
As of Mbed TLS 3.6.1, `psa_free_key_slot()` does not deallocate slices. Thus the memory consumption for slots never decreases (except when the PSA crypto subsystem is deinitialized). Freeing key slices intelligently would be a desirable improvement.
We should not free a key slice as soon as it becomes empty, because that would cause large allocations and deallocations if there are slices full of long-lived keys, and then one slice keeps being allocate and deallocated for the occasional short-lived keys. Rather, there should be some hysteresis, e.g. only deallocate a slice if there are at least T free slots in the previous slice. [#9435](https://github.com/Mbed-TLS/mbedtls/issues/9435)
Note that currently, the slice array contains one sequence of allocated slices followed by one sequence of unallocated slices. Mixing allocated and unallocated slices may make some parts of the code a little more complex, and should be tested thoroughly.
### Persistent key cache
Persistent keys and built-in keys need to be loaded into the in-memory key store each time they are accessed:
* while creating them;
* to access their metadata;
* to start performing an operation with the key;
* when destroying the key.
To avoid frequent storage access, we cache persistent keys in memory. This cache also applies to built-in keys.
With the [static key store](#static-key-store), a non-empty slot can contain either a volatile key or a cache entry for a persistent or built-in key. With the [dynamic key store](#dynamic-key-store), volatile keys and cached keys are placed in separate [slices](#key-slices-in-the-dynamic-key-store).
The persistent key cache is a fixed-size array of `MBEDTLS_PSA_KEY_SLOT_COUNT` slots. In the static key store, this array is shared with volatile keys. In the dynamic key store, the cache is a separate array that does not contain volatile keys.
#### Accessing a persistent key
`psa_get_and_lock_key_slot()` automatically loads persistent and built-in keys if the specified key identifier is in the corresponding range. To that effect, it traverses the key cache to see if a key with the given identifier is already loaded. If not, it loads the key. This cache walk takes time that is proportional to the cache size.
#### Cache eviction
A key slot must be allocated in the cache slice:
* to create a volatile key (static key store only);
* to create a persistent key;
* to load a persistent or built-in key.
If the cache slice is full, the code will try to evict an entry. Only slots that do not have readers can be evicted (see [“Concurrency”](#concurrency)). In the static key store, slots containing volatile keys cannot be evicted.
As of Mbed TLS 3.6.1, there is no tracking of a key's usage frequency or age. The slot eviction code picks the first evictable slot it finds in its traversal order. We have not reasoned about or experimented with different strategies.
@@ -0,0 +1,685 @@
PSA API functions and shared memory
===================================
## Introduction
This document discusses the security architecture of systems where PSA API functions might receive arguments that are in memory that is shared with an untrusted process. On such systems, the untrusted process might access a shared memory buffer while the cryptography library is using it, and thus cause unexpected behavior in the cryptography code.
### Core assumptions
We assume the following scope limitations:
* Only PSA Crypto API functions are in scope (including Mbed TLS extensions to the official API specification). Legacy crypto, X.509, TLS, or any other function which is not called `psa_xxx` is out of scope.
* We only consider [input buffers](https://arm-software.github.io/psa-api/crypto/1.1/overview/conventions.html#input-buffer-sizes) and [output buffers](https://arm-software.github.io/psa-api/crypto/1.1/overview/conventions.html#output-buffer-sizes). Any other data is assumed to be in non-shared memory.
## System architecture discussion
### Architecture overview
We consider a system that has memory separation between partitions: a partition can't access another partition's memory directly. Partitions are meant to be isolated from each other: a partition may only affect the integrity of another partition via well-defined system interfaces. For example, this can be a Unix/POSIX-like system that isolates processes, or isolation between the secure world and the non-secure world relying on a mechanism such as TrustZone, or isolation between secure-world applications on such a system.
More precisely, we consider such a system where our PSA Crypto implementation is running inside one partition, called the **crypto service**. The crypto service receives remote procedure calls (RPC) from other partitions, validates their arguments (e.g. validation of key identifier ownership), and calls a PSA Crypto API function. This document is concerned with environments where the arguments passed to a PSA Crypto API function may be in shared memory (as opposed to environments where the inputs are always copied into memory that is solely accessible by the crypto service before calling the API function, and likewise with output buffers after the function returns).
When the data is accessible to another partition, there is a risk that this other partition will access it while the crypto implementation is working. Although this could be prevented by suspending the whole system while crypto is working, such a limitation is rarely desirable and most systems don't offer a way to do it. (Even systems that have absolute thread priorities, and where crypto has a higher priority than any untrusted partition, may be vulnerable due to having multiple cores or asynchronous data transfers with peripherals.)
The crypto service must guarantee that it behaves as if the rest of the world was suspended while it is executed. A behavior that is only possible if an untrusted entity accesses a buffer while the crypto service is processing the data is a security violation.
### Risks and vulnerabilities
We consider a security architecture with two or three entities:
* a crypto service, which offers PSA crypto API calls over RPC (remote procedure call) using shared memory for some input or output arguments;
* a client of the crypto service, which makes a RPC to the crypto service;
* in some scenarios, a client of the client, which makes a RPC to the crypto client which re-shares the memory with the crypto service.
The behavior of RPC is defined for in terms of values of inputs and outputs. This models an ideal world where the content of input and output buffers is not accessible outside the crypto service while it is processing an RPC. It is a security violation if the crypto service behaves in a way that cannot be achieved by setting the inputs before the RPC call, and reading the outputs after the RPC call is finished.
#### Read-read inconsistency
If an input argument is in shared memory, there is a risk of a **read-read inconsistency**:
1. The crypto code reads part of the input and validates it, or injects it into a calculation.
2. The client (or client's client) modifies the input.
3. The crypto code reads the same part again, and performs an action which would be impossible if the input had had the same value all along.
Vulnerability example (parsing): suppose the input contains data with a type-length-value or length-value encoding (for example, importing an RSA key). The crypto code reads the length field and checks that it fits within the buffer. (This could be the length of the overall data, or the length of an embedded field) Later, the crypto code reads the length again and uses it without validation. A malicious client can modify the length field in the shared memory between the two reads and thus cause a buffer overread on the second read.
Vulnerability example (dual processing): consider an RPC to perform authenticated encryption, using a mechanism with an encrypt-and-MAC structure. The authenticated encryption implementation separately calculates the ciphertext and the MAC from the plaintext. A client sets the plaintext input to `"PPPP"`, then starts the RPC call, then changes the input buffer to `"QQQQ"` while the crypto service is working.
* Any of `enc("PPPP")+mac("PPPP")`, `enc("PPQQ")+mac("PPQQ")` or `enc("QQQQ")+mac("QQQQ")` are valid outputs: they are outputs that can be produced by this authenticated encryption RPC.
* If the authenticated encryption calculates the ciphertext before the client changes the output buffer and calculates the MAC after that change, reading the input buffer again each time, the output will be `enc("PPPP")+mac("QQQQ")`. There is no input that can lead to this output, hence this behavior violates the security guarantees of the crypto service.
#### Write-read inconsistency
If an output argument is in shared memory, there is a risk of a **write-read inconsistency**:
1. The crypto code writes some intermediate data into the output buffer.
2. The client (or client's client) modifies the intermediate data.
3. The crypto code reads the intermediate data back and continues the calculation, leading to an outcome that would not be possible if the intermediate data had not been modified.
Vulnerability example: suppose that an RSA signature function works by formatting the data in place in the output buffer, then applying the RSA private-key operation in place. (This is how `mbedtls_rsa_pkcs1_sign` works.) A malicious client may write badly formatted data into the buffer, so that the private-key operation is not a valid signature (e.g. it could be a decryption), violating the RSA key's usage policy.
Vulnerability example with chained calls: we consider the same RSA signature operation as before. In this example, we additionally assume that the data to sign comes from an attestation application which signs some data on behalf of a final client: the key and the data to sign are under the attestation application's control, and the final client must not be able to obtain arbitrary signatures. The final client shares an output buffer for the signature with the attestation application, and the attestation application re-shares this buffer with the crypto service. A malicious final client can modify the intermediate data and thus sign arbitrary data.
#### Write-write disclosure
If an output argument is in shared memory, there is a risk of a **write-write disclosure**:
1. The crypto code writes some intermediate data into the output buffer. This intermediate data must remain confidential.
2. The client (or client's client) reads the intermediate data.
3. The crypto code overwrites the intermediate data.
Vulnerability example with chained calls (temporary exposure): an application encrypts some data, and lets its clients store the ciphertext. Clients may not have access to the plaintext. To save memory, when it calls the crypto service, it passes an output buffer that is in the final client's memory. Suppose the encryption mechanism works by copying its input to the output buffer then encrypting in place (for example, to simplify considerations related to overlap, or because the implementation relies on a low-level API that works in place). In this scenario, the plaintext is exposed to the final client while the encryption in progress, which violates the confidentiality of the plaintext.
Vulnerability example with chained calls (backtrack): we consider a provisioning application that provides a data encryption service on behalf of multiple clients, using a single shared key. Clients are not allowed to access each other's data. The provisioning application isolates clients by including the client identity in the associated data. Suppose that an AEAD decryption function processes the ciphertext incrementally by simultaneously writing the plaintext to the output buffer and calculating the tag. (This is how AEAD decryption usually works.) At the end, if the tag is wrong, the decryption function wipes the output buffer. Assume that the output buffer for the plaintext is shared from the client to the provisioning application, which re-shares it with the crypto service. A malicious client can read another client (the victim)'s encrypted data by passing the ciphertext to the provisioning application, which will attempt to decrypt it with associated data identifying the requesting client. Although the operation will fail beacuse the tag is wrong, the malicious client still reads the victim plaintext.
#### Write-read feedback
If a function both has an input argument and an output argument in shared memory, and processes its input incrementally to emit output incrementally, the following sequence of events is possible:
1. The crypto code processes part of the input and writes the corresponding part of the output.
2. The client reads the early output and uses that to calculate the next part of the input.
3. The crypto code processes the rest of the input.
There are cryptographic mechanisms for which this breaks security properties. An example is [CBC encryption](https://link.springer.com/content/pdf/10.1007/3-540-45708-9_2.pdf): if the client can choose the content of a plaintext block after seeing the immediately preceding ciphertext block, this gives the client a decryption oracle. This is a security violation if the key policy only allowed the client to encrypt, not to decrypt.
TODO: is this a risk we want to take into account? Although this extends the possible behaviors of the one-shot interface, the client can do the same thing legitimately with the multipart interface.
### Possible countermeasures
In this section, we briefly discuss generic countermeasures.
#### Copying
Copying is a valid countermeasure. It is conceptually simple. However, it is often unattractive because it requires additional memory and time.
Note that although copying is very easy to write into a program, there is a risk that a compiler (especially with whole-program optimization) may optimize the copy away, if it does not understand that copies between shared memory and non-shared memory are semantically meaningful.
Example: the PSA Firmware Framework 1.0 forbids shared memory between partitions. This restriction is lifted in version 1.1 due to concerns over RAM usage.
#### Careful accesses
The following rules guarantee that shared memory cannot result in a security violation other than [write-read feedback](#write-read-feedback):
* Never read the same input twice at the same index.
* Never read back from an output.
* Never write to the output twice at the same index.
* This rule can usefully be relaxed in many circumstances. It is ok to write data that is independent of the inputs (and not otherwise confidential), then overwrite it. For example, it is ok to zero the output buffer before starting to process the input.
These rules are very difficult to enforce.
Example: these are the rules that a GlobalPlatform TEE Trusted Application (application running on the secure side of TrustZone on Cortex-A) must follow.
## Protection requirements
### Responsibility for protection
A call to a crypto service to perform a crypto operation involves the following components:
1. The remote procedure call framework provided by the operating system.
2. The code of the crypto service.
3. The code of the PSA Crypto dispatch layer (also known as the core), which is provided by Mbed TLS.
4. The driver implementing the cryptographic mechanism, which may be provided by Mbed TLS (built-in driver) or by a third-party driver.
The [PSA Crypto API specification](https://arm-software.github.io/psa-api/crypto/1.1/overview/conventions.html#stability-of-parameters) puts the responsibility for protection on the implementation of the PSA Crypto API, i.e. (3) or (4).
> In an environment with multiple threads or with shared memory, the implementation carefully accesses non-overlapping buffer parameters in order to prevent any security risk resulting from the content of the buffer being modified or observed during the execution of the function. (...)
In Mbed TLS 2.x and 3.x up to and including 3.5.0, there is no defense against buffers in shared memory. The responsibility shifts to (1) or (2), but this is not documented.
In the remainder of this chapter, we will discuss how to implement this high-level requirement where it belongs: inside the implementation of the PSA Crypto API. Note that this allows two possible levels: in the dispatch layer (independently of the implementation of each mechanism) or in the driver (specific to each implementation).
#### Protection in the dispatch layer
The dispatch layer has no control over how the driver layer will access buffers. Therefore the only possible protection at this layer method is to ensure that drivers have no access to shared memory. This means that any buffer located in shared memory must be copied into or out of a buffer in memory owned by the crypto service (heap or stack). This adds inefficiency, mostly in terms of RAM usage.
For buffers with a small static size limit, this is something we often do for convenience, especially with output buffers. However, as of Mbed TLS 3.5.0, it is not done systematically.
It is ok to skip the copy if it is known for sure that a buffer is not in shared memory. However, the location of the buffer is not under the control of Mbed TLS. This means skipping the copy would have to be a compile-time or run-time option which has to be set by the application using Mbed TLS. This is both an additional maintenance cost (more code to analyze, more testing burden), and a residual security risk in case the party who is responsible for setting this option does not set it correctly. As a consequence, Mbed TLS will not offer this configurability unless there is a compelling argument.
#### Protection in the driver layer
Putting the responsibility for protection in the driver layer increases the overall amount of work since there are more driver implementations than dispatch implementations. (This is true even inside Mbed TLS: almost all API functions have multiple underlying implementations, one for each algorithm.) It also increases the risk to the ecosystem since some drivers might not protect correctly. Therefore having drivers be responsible for protection is only a good choice if there is a definite benefit to it, compared to allocating an internal buffer and copying. An expected benefit in some cases is that there are practical protection methods other than copying.
Some cryptographic mechanisms are naturally implemented by processing the input in a single pass, with a low risk of ever reading the same byte twice, and by writing the final output directly into the output buffer. For such mechanism, it is sensible to mandate that drivers respect these rules.
In the next section, we will analyze how susceptible various cryptographic mechanisms are to shared memory vulnerabilities.
### Susceptibility of different mechanisms
#### Operations involving small buffers
For operations involving **small buffers**, the cost of copying is low. For many of those, the risk of not copying is high:
* Any parsing of formatted data has a high risk of [read-read inconsistency](#read-read-inconsistency).
* An internal review shows that for RSA operations, it is natural for an implementation to have a [write-read inconsistency](#write-read-inconsistency) or a [write-write disclosure](#write-write-disclosure).
Note that in this context, a “small buffer” is one with a size limit that is known at compile time, and small enough that copying the data is not prohibitive. For example, an RSA key fits in a small buffer. A hash input is not a small buffer, even if it happens to be only a few bytes long in one particular call.
The following buffers are considered small buffers:
* Any input or output directly related to asymmetric cryptography (signature, encryption/decryption, key exchange, PAKE), including key import and export.
* Note that this does not include inputs or outputs that are not processed by an asymmetric primitives, for example the message input to `psa_sign_message` or `psa_verify_message`.
* Cooked key derivation output.
* The output of a hash or MAC operation.
**Design decision: the dispatch layer shall copy all small buffers**.
#### Symmetric cryptography inputs with small output
Message inputs to hash, MAC and key derivation operations are at a low risk of [read-read inconsistency](#read-read-inconsistency) because they are unformatted data, and for all specified algorithms, it is natural to process the input one byte at a time.
**Design decision: require symmetric cryptography drivers to read their input without a risk of read-read inconsistency**.
TODO: what about IV/nonce inputs? They are typically small, but don't necessarily have a static size limit (e.g. GCM recommends a 12-byte nonce, but also allows large nonces).
#### Key derivation outputs
Key derivation typically emits its output as a stream, with no error condition detected after setup other than operational failures (e.g. communication failure with an accelerator) or running out of data to emit (which can easily be checked before emitting any data, since the data size is known in advance).
(Note that this is about raw byte output, not about cooked key derivation, i.e. deriving a structured key, which is considered a [small buffer](#operations-involving-small-buffers).)
**Design decision: require key derivation drivers to emit their output without reading back from the output buffer**.
#### Cipher and AEAD
AEAD decryption is at risk of [write-write disclosure](#write-write-disclosure) when the tag does not match.
AEAD encryption and decryption are at risk of [read-read inconsistency](#read-read-inconsistency) if they process the input multiple times, which is natural in a number of cases:
* when encrypting with an encrypt-and-authenticate or authenticate-then-encrypt structure (one read to calculate the authentication tag and another read to encrypt);
* when decrypting with an encrypt-then-authenticate structure (one read to decrypt and one read to calculate the authentication tag);
* with SIV modes (not yet present in the PSA API, but likely to come one day) (one full pass to calculate the IV, then another full pass for the core authenticated encryption);
Cipher and AEAD outputs are at risk of [write-read inconsistency](#write-read-inconsistency) and [write-write disclosure](#write-write-disclosure) if they are implemented by copying the input into the output buffer with `memmove`, then processing the data in place. In particular, this approach makes it easy to fully support overlapping, since `memmove` will take care of overlapping cases correctly, which is otherwise hard to do portably (C99 does not offer an efficient, portable way to check whether two buffers overlap).
**Design decision: the dispatch layer shall allocate an intermediate buffer for cipher and AEAD plaintext/ciphertext inputs and outputs**.
Note that this can be a single buffer for the input and the output if the driver supports in-place operation (which it is supposed to, since it is supposed to support arbitrary overlap, although this is not always the case in Mbed TLS, a [known issue](https://github.com/Mbed-TLS/mbedtls/issues/3266)). A side benefit of doing this intermediate copy is that overlap will be supported.
For all currently implemented AEAD modes, the associated data is only processed once to calculate an intermediate value of the authentication tag.
**Design decision: for now, require AEAD drivers to read the additional data without a risk of read-read inconsistency**. Make a note to revisit this when we start supporting an SIV mode, at which point the dispatch layer shall copy the input for modes that are not known to be low-risk.
#### Message signature
For signature algorithms with a hash-and-sign framework, the input to sign/verify-message is passed to a hash, and thus can follow the same rules as [symmetric cryptography inputs with small output](#symmetric-cryptography-inputs-with-small-output). This is also true for `PSA_ALG_RSA_PKCS1V15_SIGN_RAW`, which is the only non-hash-and-sign signature mechanism implemented in Mbed TLS 3.5. This is not true for PureEdDSA (`#PSA_ALG_PURE_EDDSA`), which is not yet implemented: [PureEdDSA signature](https://www.rfc-editor.org/rfc/rfc8032#section-5.1.6) processes the message twice. (However, PureEdDSA verification only processes the message once.)
**Design decision: for now, require sign/verify-message drivers to read their input without a risk of read-read inconsistency**. Make a note to revisit this when we start supporting PureEdDSA, at which point the dispatch layer shall copy the input for algorithms such as PureEdDSA that are not known to be low-risk.
## Design of shared memory protection
This section explains how Mbed TLS implements the shared memory protection strategy summarized below.
### Shared memory protection strategy
* The core (dispatch layer) shall make a copy of the following buffers, so that drivers do not receive arguments that are in shared memory:
* Any input or output from asymmetric cryptography (signature, encryption/decryption, key exchange, PAKE), including key import and export.
* Plaintext/ciphertext inputs and outputs for cipher and AEAD.
* The output of a hash or MAC operation.
* Cooked key derivation output.
* A document shall explain the requirements on drivers for arguments whose access needs to be protected:
* Hash and MAC input.
* Cipher/AEAD IV/nonce (to be confirmed).
* AEAD associated data (to be confirmed).
* Key derivation input (excluding key agreement).
* Raw key derivation output (excluding cooked key derivation output).
* The built-in implementations of cryptographic mechanisms with arguments whose access needs to be protected shall protect those arguments.
Justification: see “[Susceptibility of different mechanisms](#susceptibility-of-different-mechanisms)”.
### Implementation of copying
Copy what needs copying. This is broadly straightforward, however there are a few things to consider.
#### Compiler optimization of copies
It is unclear whether the compiler will attempt to optimize away copying operations.
Once the copying code is implemented, it should be evaluated to see whether compiler optimization is a problem. Specifically, for the major compilers supported by Mbed TLS:
* Write a small program that uses a PSA function which copies inputs or outputs.
* Build the program with link-time optimization / full-program optimization enabled (e.g. `-flto` with `gcc`). Try also enabling the most extreme optimization options such as `-Ofast` (`gcc`) and `-Oz` (`clang`).
* Inspect the generated code with `objdump` or a similar tool to see if copying operations are preserved.
If copying behaviour is preserved by all major compilers then assume that compiler optimization is not a problem.
If copying behaviour is optimized away by the compiler, further investigation is needed. Experiment with using the `volatile` keyword to force the compiler not to optimize accesses to the copied buffers. If the `volatile` keyword is not sufficient, we may be able to use compiler or target-specific techniques to prevent optimization, for example memory barriers or empty `asm` blocks. These may be implemented and verified for important platforms while retaining a C implementation that is likely to be correct on most platforms as a fallback - the same approach taken by the constant-time module.
**Open questions: Will the compiler optimize away copies? If so, can it be prevented from doing so in a portable way?**
#### Copying code
We may either copy buffers on an ad-hoc basis using `memcpy()` in each PSA function, or use a unified set of functions for copying input and output data. The advantages of the latter are obvious:
* Any test hooks need only be added in one place.
* Copying code must only be reviewed for correctness in one place, rather than in all functions where it occurs.
* Copy bypass is simpler as we can just replace these functions with no-ops in a single place.
* Any complexity needed to prevent the compiler optimizing copies away does not have to be duplicated.
On the other hand, the only advantage of ad-hoc copying is slightly greater flexibility.
**Design decision: Create a unified set of functions for copying input and output data.**
#### Copying in multipart APIs
Multipart APIs may follow one of 2 possible approaches for copying of input:
##### 1. Allocate a buffer and copy input on each call to `update()`
This is simple and mirrors the approach for one-shot APIs nicely. However, allocating memory in the middle of a multi-part operation is likely to be bad for performance. Multipart APIs are designed in part for systems that do not have time to perform an operation at once, so introducing poor performance may be a problem here.
**Open question: Does memory allocation in `update()` cause a performance problem? If so, to what extent?**
##### 2. Allocate a buffer at the start of the operation and subdivide calls to `update()`
In this approach, input and output buffers are allocated at the start of the operation that are large enough to hold the expected average call to `update()`. When `update()` is called with larger buffers than these, the PSA API layer makes multiple calls to the driver, chopping the input into chunks of the temporary buffer size and filling the output from the results until the operation is finished.
This would be more complicated than approach (1) and introduces some extra issues. For example, if one of the intermediate calls to the driver's `update()` returns an error, it is not possible for the driver's state to be rolled back to before the first call to `update()`. It is unclear how this could be solved.
However, this approach would reduce memory usage in some cases and prevent memory allocation during an operation. Additionally, since the input and output buffers would be fixed-size it would be possible to allocate them statically, avoiding the need for any dynamic memory allocation at all.
**Design decision: Initially use approach (1) and treat approach (2) as an optimization to be done if necessary.**
### Validation of copying
#### Validation of copying by review
This is fairly self-explanatory. Review all functions that use shared memory and ensure that they each copy memory. This is the simplest strategy to implement but is less reliable than automated validation.
#### Validation of copying with memory pools
Proposed general idea: have tests where the test code calling API functions allocates memory in a certain pool, and code in the library allocates memory in a different pool. Test drivers check that needs-copying arguments are within the library pool, not within the test pool.
#### Validation of copying by memory poisoning
Proposed general idea: in test code, “poison” the memory area used by input and output parameters that must be copied. Poisoning means something that prevents accessing memory while it is poisoned. This could be via memory protection (allocate with `mmap` then disable access with `mprotect`), or some kind of poisoning for an analyzer such as MSan or Valgrind.
In the library, the code that does the copying temporarily unpoisons the memory by calling a test hook.
```c
static void copy_to_user(void *copy_buffer, void *const input_buffer, size_t length) {
#if defined(MBEDTLS_TEST_HOOKS)
if (memory_poison_hook != NULL) {
memory_poison_hook(copy_buffer, length);
}
#endif
memcpy(copy_buffer, input_buffer, length);
#if defined(MBEDTLS_TEST_HOOKS)
if (memory_unpoison_hook != NULL) {
memory_unpoison_hook(copy_buffer, length);
}
#endif
}
```
The reason to poison the memory before calling the library, rather than after the copy-in (and symmetrically for output buffers) is so that the test will fail if we forget to copy, or we copy the wrong thing. This would not be the case if we relied on the library's copy function to do the poisoning: that would only validate that the driver code does not access the memory on the condition that the copy is done as expected.
##### Options for implementing poisoning
There are several different ways that poisoning could be implemented:
1. Using Valgrind's memcheck tool. Valgrind provides a macro `VALGRIND_MAKE_MEM_NO_ACCESS` that allows manual memory poisoning. Valgrind memory poisoning is already used for constant-flow testing in Mbed TLS.
2. Using Memory Sanitizer (MSan), which allows us to mark memory as uninitialized. This is also used for constant-flow testing. It is suitable for input buffers only, since it allows us to detect when a poisoned buffer is read but not when it is written.
3. Using Address Sanitizer (ASan). This provides `ASAN_POISON_MEMORY_REGION` which marks memory as inaccessible.
4. Allocating buffers separate pages and calling `mprotect()` to set pages as inaccessible. This has the disadvantage that we will have to manually ensure that buffers sit in their own pages, which likely means making a copy.
5. Filling buffers with random data, keeping a copy of the original. For input buffers, keep a copy of the original and copy it back once the PSA function returns. For output buffers, fill them with random data and keep a separate copy of it. In the memory poisoning hooks, compare the copy of random data with the original to ensure that the output buffer has not been written directly.
Approach (2) is insufficient for the full testing we require as we need to be able to check both input and output buffers.
Approach (5) is simple and requires no extra tooling. It is likely to have good performance as it does not use any sanitizers. However, it requires the memory poisoning test hooks to maintain extra copies of the buffers, which seems difficult to implement in practice. Additionally, it does not precisely test the property we want to validate, so we are relying on the tests to fail if given random data as input. It is possible (if unlikely) that the PSA function will access the poisoned buffer without causing the test to fail. This becomes more likely when we consider test cases that call PSA functions on incorrect inputs to check that the correct error is returned. For these reasons, this memory poisoning approach seems unsuitable.
All three remaining approaches are suitable for our purposes. However, approach (4) is more complex than the other two. To implement it, we would need to allocate poisoned buffers in separate memory pages. They would require special handling and test code would likely have to be designed around this special handling.
Meanwhile, approaches (1) and (3) are much more convenient. We are simply required to call a special macro on some buffer that was allocated by us and the sanitizer takes care of everything else. Of these two, ASan appears to have a limitation related to buffer alignment. From code comments quoted in [the documentation](https://github.com/google/sanitizers/wiki/AddressSanitizerManualPoisoning):
> This function is not guaranteed to poison the whole region - it may poison only subregion of [addr, addr+size) due to ASan alignment restrictions.
Specifically, ASan will round the buffer size down to 8 bytes before poisoning due to details of its implementation. For more information on this, see [Microsoft documentation of this feature](https://learn.microsoft.com/en-us/cpp/sanitizers/asan-runtime?view=msvc-170#alignment-requirements-for-addresssanitizer-poisoning).
It should be possible to work around this by manually rounding buffer lengths up to the nearest multiple of 8 in the poisoning function, although it's remotely possible that this will cause other problems. Valgrind does not appear to have this limitation (unless Valgrind is simply more poorly documented). However, running tests under Valgrind causes a much greater slowdown compared with ASan. As a result, it would be beneficial to implement support for both Valgrind and ASan, to give the extra flexibility to choose either performance or accuracy as required. This should be simple as both have very similar memory poisoning interfaces.
**Design decision: Implement memory poisoning tests with both Valgrind's memcheck and ASan manual poisoning.**
##### Validation with new tests
Validation with newly created tests would be simpler to implement than using existing tests, since the tests can be written to take into account memory poisoning. It is also possible to build such a testsuite using existing tests as a starting point - `mbedtls_test_psa_exercise_key` is a test helper that already exercises many PSA operations on a key. This would need to be extended to cover operations without keys (e.g. hashes) and multipart operations, but it provides a good base from which to build all of the required testing.
Additionally, we can ensure that all functions are exercised by automatically generating test data files.
##### Validation with existing tests
An alternative approach would be to integrate memory poisoning validation with existing tests. This has two main advantages:
* All of the tests are written already, potentially saving development time.
* The code coverage of these tests is greater than would be achievable writing new tests from scratch. In practice this advantage is small as buffer copying will take place in the dispatch layer. The tests are therefore independent of the values of parameters passed to the driver, so extra coverage in these parameters does not gain anything.
It may be possible to transparently implement memory poisoning so that existing tests can work without modification. This would be achieved by replacing the implementation of `malloc()` with one that allocates poisoned buffers. However, there are some difficulties with this:
* Not all buffers allocated by tests are used as inputs and outputs to PSA functions being tested.
* Those buffers that are inputs to a PSA function need to be unpoisoned right up until the function is called, so that they can be filled with input data.
* Those buffers that are outputs from a PSA function need to be unpoisoned straight after the function returns, so that they can be read to check the output is correct.
These issues may be solved by creating some kind of test wrapper around every PSA function call that poisons the memory. However, it is unclear how straightforward this will be in practice. If this is simple to achieve, the extra coverage and time saved on new tests will be a benefit. If not, writing new tests is the best strategy.
**Design decision: Add memory poisoning transparently to existing tests.**
#### Discussion of copying validation
Of all discussed approaches, validation by memory poisoning appears as the best. This is because it:
* Does not require complex linking against different versions of `malloc()` (as is the case with the memory pool approach).
* Allows automated testing (unlike the review approach).
**Design decision: Use a memory poisoning approach to validate copying.**
### Shared memory protection requirements
TODO: write document and reference it here.
### Validation of careful access for built-in drivers
For PSA functions whose inputs and outputs are not copied, it is important that we validate that the builtin drivers are correctly accessing their inputs and outputs so as not to cause a security issue. Specifically, we must check that each memory location in a shared buffer is not accessed more than once by a driver function. In this section we examine various possible methods for performing this validation.
Note: We are focusing on read-read inconsistencies for now, as most of the cases where we aren't copying are inputs.
#### Review
As with validation of copying, the simplest method of validation we can implement is careful code review. This is the least desirable method of validation for several reasons:
1. It is tedious for the reviewers.
2. Reviewers are prone to make mistakes (especially when performing tedious tasks).
3. It requires engineering time linear in the number of PSA functions to be tested.
4. It cannot assure the quality of third-party drivers, whereas automated tests can be ported to any driver implementation in principle.
If all other approaches turn out to be prohibitively difficult, code review exists as a fallback option. However, it should be understood that this is far from ideal.
#### Tests using `mprotect()`
Checking that a memory location is not accessed more than once may be achieved by using `mprotect()` on a Linux system to cause a segmentation fault whenever a memory access happens. Tests based on this approach are sketched below.
##### Linux mprotect+ptrace
Idea: call `mmap` to allocate memory for arguments and `mprotect` to deny or reenable access. Use `ptrace` from a parent process to react to SIGSEGV from a denied access. On SIGSEGV happening in the faulting region:
1. Use `ptrace` to execute a `mprotect` system call in the child to enable access. TODO: How? `ptrace` can modify registers and memory in the child, which includes changing parameters of a syscall that's about to be executed, but not directly cause the child process to execute a syscall that it wasn't about to execute.
2. Use `ptrace` with `PTRACE_SINGLESTEP` to re-execute the failed load/store instrution.
3. Use `ptrace` to execute a `mprotect` system call in the child to disable access.
4. Use `PTRACE_CONT` to resume the child execution.
Record the addresses that are accessed. Mark the test as failed if the same address is read twice.
##### Debugger + mprotect
Idea: call `mmap` to allocate memory for arguments and `mprotect` to deny or reenable access. Use a debugger to handle SIGSEGV (Gdb: set signal catchpoint). If the segfault was due to accessing the protected region:
1. Execute `mprotect` to allow access.
2. Single-step the load/store instruction.
3. Execute `mprotect` to disable access.
4. Continue execution.
Record the addresses that are accessed. Mark the test as failed if the same address is read twice. This part might be hard to do in the gdb language, so we may want to just log the addresses and then use a separate program to analyze the logs, or do the gdb tasks from Python.
#### Instrumentation (Valgrind)
An alternative approach is to use a dynamic instrumentation tool (the most obvious being Valgrind) to trace memory accesses and check that each of the important memory addresses is accessed no more than once.
Valgrind has no tool specifically that checks the property that we are looking for. However, it is possible to generate a memory trace with Valgrind using the following:
```
valgrind --tool=lackey --trace-mem=yes --log-file=logfile ./myprogram
```
This will execute `myprogram` and dump a record of every memory access to `logfile`, with its address and data width. If `myprogram` is a test that does the following:
1. Set up input and output buffers for a PSA function call.
2. Leak the start and end address of each buffer via `print()`.
3. Write data into the input buffer exactly once.
4. Call the PSA function.
5. Read data from the output buffer exactly once.
Then it should be possible to parse the output from the program and from Valgrind and check that each location was accessed exactly twice: once by the program's setup and once by the PSA function.
#### Fixed Virtual Platform testing
It may be possible to measure double accesses by running tests on a Fixed Virtual Platform such as Corstone 310 ecosystem FVP, available [here](https://developer.arm.com/downloads/-/arm-ecosystem-fvps). There exists a pre-packaged example program for the Corstone 310 FVP available as part of the Open IoT SDK [here](https://git.gitlab.arm.com/iot/open-iot-sdk/examples/sdk-examples/-/tree/main/examples/mbedtls/cmsis-rtx/corstone-310) that could provide a starting point for a set of tests.
Running on an FVP allows two approaches to careful-access testing:
* Convenient scripted use of a debugger with [Iris](https://developer.arm.com/documentation/101196/latest/). This allows memory watchpoints to be set, perhaps more flexibly than with GDB.
* Tracing of all memory accesses with [Tarmac Trace](https://developer.arm.com/documentation/100964/1123/Plug-ins-for-Fast-Models/TarmacTrace). To validate the single-access properties, the [processor memory access trace source](https://developer.arm.com/documentation/100964/1123/Plug-ins-for-Fast-Models/TarmacTrace/Processor-memory-access-trace) can be used to output all memory accesses happening on the FVP. This output can then be easily parsed and processed to ensure that the input and output buffers are accessed only once. The addresses of buffers can either be leaked by the program through printing to the serial port or set to fixed values in the FVP's linker script.
#### Discussion of careful-access validation
The best approach for validating the correctness of memory accesses is an open question that requires further investigation. To answer this question, each of the test strategies discussed above must be prototyped as follows:
1. Take 1-2 days to create a basic prototype of a test that uses the approach.
2. Document the prototype - write a short guide that can be followed to arrive at the same prototype.
3. Evaluate the prototype according to its usefulness. The criteria of evaluation should include:
* Ease of implementation - Was the prototype simple to implement? Having implemented it, is it simple to extend it to do all of the required testing?
* Flexibility - Could the prototype be extended to cover other careful-access testing that may be needed in future?
* Performance - Does the test method perform well? Will it cause significant slowdown to CI jobs?
* Ease of reproduction - Does the prototype require a particular platform or tool to be set up? How easy would it be for an external user to run the prototype?
* Comprehensibility - Accounting for the lower code quality of a prototype, would developers unfamiliar with the tests based on the prototype be able to understand them easily?
* Portability - How well can this approach be ported to multiple platforms? This would allow us to ensure that there are no double-accesses due to a bug that only affects a specific target.
Once each prototype is complete, choose the best approach to implement the careful-access testing. Implement tests using this approach for each of the PSA interfaces that require careful-access testing:
* Hash
* MAC
* AEAD (additional data only)
* Key derivation
* Asymmetric signature (input only)
##### New vs existing tests
Most of the test methods discussed above need extra setup. Some require leaking of buffer bounds, predictable memory access patterns or allocation of special buffers. FVP testing even requires the tests to be run on a non-host target.
With this complexity in mind it does not seem feasible to run careful-access tests using existing testsuites. Instead, new tests should be written that exercise the drivers in the required way. Fortunately, the only interfaces that need testing are hash, MAC, AEAD (testing over AD only), Key derivation and Asymmetric signature, which limits the number of new tests that must be written.
#### Validation of validation for careful-access
In order to ensure that the careful-access validation works, it is necessary to write tests to check that we can correctly detect careful-access violations when they occur. To do this, write a test function that:
* Reads its input multiple times at the same location.
* Writes to its output multiple times at the same location.
Then, write a careful-access test for this function and ensure that it fails.
## Analysis of argument protection in built-in drivers
TODO: analyze the built-in implementations of mechanisms for which there is a requirement on drivers. By code inspection, how satisfied are we that they meet the requirement?
## Copy bypass
For efficiency, we are likely to want mechanisms to bypass the copy and process buffers directly in builds that are not affected by shared memory considerations.
Expand this section to document any mechanisms that bypass the copy.
Make sure that such mechanisms preserve the guarantees when buffers overlap.
## Detailed design
### Implementation by module
Module | Input protection strategy | Output protection strategy | Notes
---|---|---|---
Hash and MAC | Careful access | Careful access | Low risk of multiple-access as the input and output are raw unformatted data.
Cipher | Copying | Copying |
AEAD | Copying (careful access for additional data) | Copying |
Key derivation | Careful access | Careful access |
Asymmetric signature | Careful access | Copying | Inputs to signatures are passed to a hash. This will no longer hold once PureEdDSA support is implemented.
Asymmetric encryption | Copying | Copying |
Key agreement | Copying | Copying |
PAKE | Copying | Copying |
Key import / export | Copying | Copying | Keys may be imported and exported in DER format, which is a structured format and therefore susceptible to read-read inconsistencies and potentially write-read inconsistencies.
### Copying functions
As discussed in [Copying code](#copying-code), it is simpler to use a single unified API for copying. Therefore, we create the following functions:
* `psa_crypto_copy_input(const uint8_t *input, size_t input_length, uint8_t *input_copy, size_t input_copy_length)`
* `psa_crypto_copy_output(const uint8_t *output_copy, size_t output_copy_length, uint8_t *output, size_t output_length)`
These seem to be a repeat of the same function, however it is useful to retain two separate functions for input and output parameters so that we can use different test hooks in each when using memory poisoning for tests.
Given that the majority of functions will be allocating memory on the heap to copy, it is helpful to build convenience functions that allocate the memory as well.
In order to keep track of allocated copies on the heap, we can create new structs:
```c
typedef struct psa_crypto_local_input_s {
uint8_t *buffer;
size_t length;
} psa_crypto_local_input_t;
typedef struct psa_crypto_local_output_s {
uint8_t *original;
uint8_t *buffer;
size_t length;
} psa_crypto_local_output_t;
```
These may be used to keep track of input and output copies' state, and ensure that their length is always stored with them. In the case of output copies, we keep a pointer to the original buffer so that it is easy to perform a writeback to the original once we have finished outputting.
With these structs we may create 2 pairs of functions, one pair for input copies:
```c
psa_status_t psa_crypto_local_input_alloc(const uint8_t *input, size_t input_len,
psa_crypto_local_input_t *local_input);
void psa_crypto_local_input_free(psa_crypto_local_input_t *local_input);
```
* `psa_crypto_local_input_alloc()` calls `calloc()` to allocate a new buffer of length `input_len`, copies the contents across from `input`. It then stores `input_len` and the pointer to the copy in the struct `local_input`.
* `psa_crypto_local_input_free()` calls `free()` on the local input that is referred to by `local_input` and sets the pointer in the struct to `NULL`.
We also create a pair of functions for output copies:
```c
psa_status_t psa_crypto_local_output_alloc(uint8_t *output, size_t output_len,
psa_crypto_local_output_t *local_output);
psa_status_t psa_crypto_local_output_free(psa_crypto_local_output_t *local_output);
```
* `psa_crypto_local_output_alloc()` calls `calloc()` to allocate a new buffer of length `output_len` and stores `output_len` and the pointer to the buffer in the struct `local_output`. It also stores a pointer to `output` in `local_output->original`.
* `psa_crypto_local_output_free()` copies the contents of the output buffer `local_output->buffer` into the buffer `local_output->original`, calls `free()` on `local_output->buffer` and sets it to `NULL`.
Some PSA functions may not use these convenience functions as they may have local optimizations that reduce memory usage. For example, ciphers may be able to use a single intermediate buffer for both input and output.
In order to abstract the management of the copy state further, to make it simpler to add, we create the following 6 convenience macros:
For inputs:
* `LOCAL_INPUT_DECLARE(input, input_copy_name)`, which declares and initializes a `psa_crypto_local_input_t` and a pointer with the name `input_copy_name` in the current scope.
* `LOCAL_INPUT_ALLOC(input, input_size, input_copy)`, which tries to allocate an input using `psa_crypto_local_input_alloc()`. On failure, it sets an error code and jumps to an exit label. On success, it sets `input_copy` to point to the copy of the buffer.
* `LOCAL_INPUT_FREE(input, input_copy)`, which frees the input copy using `psa_crypto_local_input_free()` and sets `input_copy` to `NULL`.
For outputs:
* `LOCAL_OUTPUT_DECLARE(output, output_copy_name)`, analogous to `LOCAL_INPUT_DECLARE()` for `psa_crypto_local_output_t`.
* `LOCAL_OUTPUT_ALLOC(output, output_size, output_copy)`, analogous to `LOCAL_INPUT_ALLOC()` for outputs, calling `psa_crypto_local_output_alloc()`.
* `LOCAL_OUTPUT_FREE(output, output_copy)`, analogous to `LOCAL_INPUT_FREE()` for outputs. If the `psa_crypto_local_output_t` is in an invalid state (the copy pointer is valid, but the original pointer is `NULL`) this macro sets an error status.
These macros allow PSA functions to have copying added while keeping the code mostly unmodified. Consider a hypothetical PSA function:
```c
psa_status_t psa_foo(const uint8_t *input, size_t input_length,
uint8_t *output, size_t output_size, size_t *output_length)
{
/* Do some operation on input and output */
}
```
By changing the name of the input and output parameters, we can retain the original variable name as the name of the local copy while using a new name (e.g. with the suffix `_external`) for the original buffer. This allows copying to be added near-seamlessly as follows:
```c
psa_status_t psa_foo(const uint8_t *input_external, size_t input_length,
uint8_t *output_external, size_t output_size, size_t *output_length)
{
psa_status_t status;
LOCAL_INPUT_DECLARE(input_external, input);
LOCAL_OUTPUT_DECLARE(output_external, output);
LOCAL_INPUT_ALLOC(input_external, input);
LOCAL_OUTPUT_ALLOC(output_external, output);
/* Do some operation on input and output */
exit:
LOCAL_INPUT_FREE(input_external, input);
LOCAL_OUTPUT_FREE(output_external, output);
}
```
A second advantage of using macros for the copying (other than simple convenience) is that it allows copying to be easily disabled by defining alternate macros that function as no-ops. Since buffer copying is specific to systems where shared memory is passed to PSA functions, it is useful to be able to disable it where it is not needed, to save code size.
To this end, the macros above are defined conditionally on a new config option, `MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS`, which may be set whenever PSA functions are assumed to have exclusive access to their input and output buffers. When `MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS` is set, the macros do not perform copying.
### Implementation of copying validation
As discussed in the [design exploration of copying validation](#validation-of-copying), the best strategy for validation of copies appears to be validation by memory poisoning, implemented using Valgrind and ASan.
To perform memory poisoning, we must implement the functions alluded to in [Validation of copying by memory poisoning](#validation-of-copying-by-memory-poisoning):
```c
void mbedtls_test_memory_poison(const unsigned char *ptr, size_t size);
void mbedtls_test_memory_unpoison(const unsigned char *ptr, size_t size);
```
This should poison or unpoison the given buffer, respectively.
* `mbedtls_test_memory_poison()` is equivalent to calling `VALGRIND_MAKE_MEM_NOACCESS(ptr, size)` or `ASAN_POISON_MEMORY_REGION(ptr, size)`.
* `mbedtls_test_memory_unpoison()` is equivalent to calling `VALGRIND_MAKE_MEM_DEFINED(ptr, size)` or `ASAN_UNPOISON_MEMORY_REGION(ptr, size)`.
The PSA copying function must then have test hooks implemented as outlined in [Validation of copying by memory poisoning](#validation-of-copying-by-memory-poisoning).
As discussed in [the design exploration](#validation-with-existing-tests), the preferred approach for implementing copy-testing is to implement it transparently using existing tests. This is specified in more detail below.
#### Transparent allocation-based memory poisoning
In order to implement transparent memory poisoning we require a wrapper around all PSA function calls that poisons any input and output buffers.
The easiest way to do this is to create wrapper functions that poison the memory and then `#define` PSA function names to be wrapped versions of themselves. For example, to replace `psa_aead_update()`:
```c
psa_status_t mem_poison_psa_aead_update(psa_aead_operation_t *operation,
const uint8_t *input,
size_t input_length,
uint8_t *output,
size_t output_size,
size_t *output_length)
{
mbedtls_test_memory_poison(input, input_length);
mbedtls_test_memory_poison(output, output_size);
psa_status_t status = psa_aead_update(operation, input, input_length,
output, output_size, output_length);
mbedtls_test_memory_unpoison(input, input_length);
mbedtls_test_memory_unpoison(output, output_size);
return status;
}
#define psa_aead_update(...) mem_poison_psa_aead_update(__VA_ARGS__)
```
There now exists a more generic mechanism for making exactly this kind of transformation - the PSA test wrappers, which exist in the files `tests/include/test/psa_test_wrappers.h` and `tests/src/psa_test_wrappers.c`. These are wrappers around all PSA functions that allow testing code to be inserted at the start and end of a PSA function call.
The test wrappers are generated by a script, although they are not automatically generated as part of the build process. Instead, they are checked into source control and must be manually updated when functions change by running `framework/scripts/generate_psa_wrappers.py`.
Poisoning code is added to these test wrappers where relevant in order to pre-poison and post-unpoison the parameters to the functions.
#### Configuration of poisoning tests
Since the memory poisoning tests will require the use of interfaces specific to the sanitizers used to poison memory, they must only be enabled when we are building with ASan or Valgrind. For now, we can auto-detect ASan at compile-time and set an option: `MBEDTLS_TEST_MEMORY_CAN_POISON`. When this option is enabled, we build with memory-poisoning support. This enables transparent testing with ASan without needing any extra configuration options.
Auto-detection and memory-poisoning with Valgrind is left for future work.
#### Validation of validation for copying
To make sure that we can correctly detect functions that access their input/output buffers rather than the copies, it would be best to write a test function that misbehaves and test it with memory poisoning. Specifically, the function should:
* Read its input buffer and after calling the input-buffer-copying function to create a local copy of its input.
* Write to its output buffer before and after calling the output-buffer-copying function to copy-back its output.
Then, we could write a test that uses this function with memory poisoning and ensure that it fails. Since we are expecting a failure due to memory-poisoning, we would run this test separately from the rest of the memory-poisoning testing.
This testing is implemented in `framework/tests/programs/metatest.c`, which is a program designed to check that test failures happen correctly. It may be run via the script `tests/scripts/run-metatests.sh`.
@@ -0,0 +1,530 @@
# PSA storage resilience design
## Introduction
The PSA crypto subsystem includes a persistent key store. It is possible to create a persistent key and read it back later. This must work even if the underlying storage exhibits non-nominal behavior. In this document, _resilience_ means correct behavior of the key store even under if the underlying platform behaves in a non-nominal, but still partially controlled way.
At this point, we are only concerned about one specific form of resilience: to a system crash or power loss. That is, we assume that the underlying platform behaves nominally, except that occasionally it may restart. In the field, this can happen due to a sudden loss of power.
This document explores the problem space, defines a library design and a test design.
## Resilience goals for API functions
**Goal: PSA Crypto API functions are atomic and committing.**
_Atomic_ means that when an application calls an API function, as far as the application is concerned, at any given point in time, the system is either in a state where the function has not started yet, or in a state where the function has returned. The application never needs to worry about an intermediate state.
_Committing_ means that when a function returns, the data has been written to the persistent storage. As a consequence, if the system restarts during a sequence of storage modifications $M_1, M_2, \ldots, M_n$, we know that when the system restarts, a prefix of the sequence has been performed. For example, there will never be a situation where $M_2$ has been performed but not $M_1$.
The committing property is important not only for sequences of operations, but also when reporting the result of an operation to an external system. For example, if a key creation function in the PSA Crypto API reports to the application that a key has been created, and the application reports to a server that the key has been created, it is guaranteed that the key exists even if the system restarts.
## Assumptions on the underlying file storage
PSA relies on a PSA ITS (Internal Trusted Storage) interface, which exposes a simple API. There are two functions to modify files:
* `set()` writes a whole file (either creating it, or replacing the previous content).
* `remove()` removes a file (returning a specific error code if the file does not exist).
**Assumption: the underlying ITS functions are atomic and committing.**
Since the underlying functions are atomic, the content of a file is always a version that was previously passed to `set()`. We do not try to handle the case where a file might be partially written.
## Overview of API functions
For a transparent key, all key management operations (creation or destruction) on persistent keys rely on a single call to the underlying storage (`set()` for a key creation, `remove()` for a key destruction). This also holds for an opaque key stored in a secure element that does not have its own key store: in this case, the core stores a wrapped (i.e. encrypted) copy of the key material, but this does not impact how the core interacts with the storage. Other API functions do not modify the storage.
The following case requires extra work related to resilience:
* [Key management for stateful secure element keys](#designing-key-management-for-secure-element-keys).
As a consequence, apart from the listed cases, the API calls inherit directly from the [resilience properties of the underyling storage](#assumptions-on-the-underlying-file-storage). We do not need to take any special precautions in the library design, and we do not need to perform any testing of resilience for transparent keys.
(This section was last updated for Mbed TLS 3.4.0 implementing PSA Crypto API 1.1.)
## Designing key management for secure element keys
In this section, we use “(stateful) secure element key” to mean a key stored in a stateful secure element, i.e. a secure element that stores keys. This excludes keys in a stateleess secure element for which the core stores a wrapped copy of the key. We study the problem of how key management in stateful secure elements interacts with storage and explore the design space.
### Assumptions on stateful secure elements
**Assumption: driver calls for key management in stateful secure elements are atomic and committing.**
(For stateless secure elements, this assumption is vacuously true.)
### Dual management of keys: the problem
For a secure element key, key management requires a commitment on both sites. For example, consider a successful key creation operation:
1. The core sends a request to the secure element to create a key.
2. The secure element modifies its key store to create the key.
3. The secure element reports to the core that the key has been created.
4. The core reports to the application that the key has been created.
If the core loses power between steps 1 and 2, the key does not exist yet. This is fine from an application's perspective since the core has not committed to the key's existence, but the core needs to take care not to leave resources in storage that are related to the non-existent key. If the core loses power between steps 2 and 3, the key exists in the secure element. From an application's perspective, the core may either report that the key exists or that it does not exist, but in the latter case, the core needs to free the key in the secure element, to avoid leaving behind inaccessible resources.
As a consequence, the content of the storage cannot remain the same between the end of step 1 and the end of step 3, since the core must behave differently depending on whether step 2 has taken place.
Accomplishing a transaction across system boundaries is a well-known problem in database management, with a well-known solution: two-phase commit.
### Overview of two-phase commit with stateful secure elements
With a key in a stateful secure element, a successful creation process goes as follows (see [“Key management in a secure element with storage” in the driver interface specification](../../proposed/psa-driver-interface.html#key-management-in-a-secure-element-with-storage)):
1. The core calls the driver's `"allocate_key"` entry point.
2. The driver allocates a unique identifier _D_ for the key. This is unrelated to the key identifier _A_ used by the application interface. This step must not modify the state of the secure element.
3. The core updates the storage to indicate that key identifier _A_ has the identifier _D_ in the driver, and that _A_ is in a half-created state.
4. The core calls the driver's key creation entry point, passing it the driver's chosen identifier _D_.
5. The driver creates the key in the secure element. When this happens, it concludes the voting phase of the two-phase commit: effectively, the secure element decides to commit. (It is however possible to revert this commitment by giving the secure element the order to destroy the key.)
6. The core updates the storage to indicate that _A_ is now in a fully created state. This concludes the commit phase of the two-phase commit.
If there is a loss of power:
* Before step 3: the system state has not changed at all. As far as the world is concerned, the key creation attempt never happened.
* Between step 3 and step 6: upon restart, the core needs to find out whether the secure element completed step 5 or not, and reconcile the state of the storage with the state of the secure element.
* After step 6: the key has been created successfully.
Key destruction goes as follows:
1. The core updates the storage indicating that the key is being destroyed.
2. The core calls the driver's `"destroy_key"` entry point.
3. The secure element destroys the key.
4. The core updates the storage to indicate that the key has been destroyed.
If there is a loss of power:
* Before step 1: the system state has not changed at all. As far as the world is concerned, the key destruction attempt never happened.
* Between step 1 and step 4: upon restart, the core needs to find out whether the secure element completed step 3 or not, and reconcile the state of the storage with the state of the secure element.
* After step 4: the key has been destroyed successfully.
In both cases, upon restart, the core needs to perform a transaction recovery. When a power loss happens, the core decides whether to commit or abort the transaction.
Note that the analysis in this section assumes that the driver does not update its persistent state during a key management operation (or at least not in a way that is influences the key management process — for example, it might renew an authorization token).
### Optimization considerations for transactions
We assume that power failures are rare. Therefore we will primarily optimize for the normal case. Transaction recovery needs to be practical, but does not have to be fully optimized.
The main quantity we will optimize for is the number of storage updates in the nominal case. This is good for performance because storage writes are likely to dominate the runtime in some hardware configurations where storage writes are slow and communication with the secure element is fast, for key management operations that require a small amount of computation. In addition, minimizing the number of storage updates is good for the longevity of flash media.
#### Information available during recovery
The PSA ITS API does not support enumerating files in storage: an ITS call can only access one file identifier. Therefore transaction recovery cannot be done by traversing files whose name is or encodes the key identifier. It must start by traversing a small number of files whose names are independent of the key identifiers involved.
#### Minimum effort for a transaction
Per the [assumptions on the underlying file storage](#assumptions-on-the-underlying-file-storage), each atomic operation in the internal storage concerns a single file: either removing it, or setting its content. Furthermore there is no way to enumerate the files in storage.
A key creation function must transform the internal storage from a state where file `id` does not exist, to a state where file `id` exists and has its desired final content (containing the key attributes and the driver's key identifier). The situation is similar with key destruction, except that the initial and final states are exchanged. Neither the initial state nor the final state reference `id` otherwise.
For a key that is not in a stateful element, the transaction consists of a single write operation. As discussed previously, this is not possible with a stateful secure element because the state of the internal storage needs to change both before and after the state change in the secure element. No other single-write algorithm works.
If there is a power failure around the time of changing the state of the secure element, there must be information in the internal storage that indicates that key `id` has a transaction in progress. The file `id` cannot be used for this purpose because there is no way to enumerate all keys (and even if there was, it would not be practical). Therefore the transaction will need to modify some other file `t` with a fixed name (a name that doesn't depend on the key). Since the final system state should be identical to the initial state except for the file `id`, the minimum number of storage operations for a transaction is 3:
* Write (create or update) a file `t` referencing `id`.
* Write the final state of `id`.
* Restore `t` to its initial state.
The strategies discussed in the [overview above](#overview-of-two-phase-commit-with-stateful-secure-elements) follow this pattern, with `t` being the file containing the transaction list that the recovery consults. We have just proved that this pattern is optimal.
Note that this pattern requires the state of `id` to be modified only once. In particular, if a key management involves writing an intermediate state for `id` before modifying the secure element state and writing a different state after that, this will require a total of 4 updates to internal storage. Since we want to minimize the number of storage updates, we will not explore designs that involved updating `id` twice or more.
### Recovery strategies
When the core starts, it needs to know about transaction(s) that need to be resumed. This information will be stored in a persistent “transaction list”, with one entry per key. In this section, we explore recovery strategies, and we determine what the transaction list needs to contain as well as when it needs to be updated. Other sections will explore the format of the transaction list, as well as how many keys it needs to contain.
#### Exploring the recovery decision tree
There are four cases for recovery when a transaction is in progress. In each case, the core can either decide to commit the transaction (which may require replaying the interrupted part) or abort it (which may require a rewind in the secure element). It may call the secure element driver's `"get_key_attributes"` entry point to find out whether the key is present.
* Key creation, key not present in the secure element:
* Committing means replaying the driver call in the key creation. This requires all the input, for example the data to import. This seems impractical in general. Also, the second driver call require a new call to `"allocate_key"` which will in general changing the key's driver identifier, which complicates state management in the core. Given the likely complexity, we exclude this strategy.
* Aborting means removing any trace of the key creation.
* Key creation, key present in the secure element:
* Committing means finishing the update of the core's persistent state, as would have been done if the transaction had not been interrupted.
* Aborting means destroying the key in the secure element and removing any local storage used for that key.
* Key destruction, key not present in the secure element:
* Committing means finishing the update of the core's persistent state, as would have been done if the transaction had not been interrupted, by removing any remaining local storage used for that key.
* Aborting would mean re-creating the key in the secure element, which is impossible in general since the key material is no longer present.
* Key destruction, key present in the secure element:
* Committing means finishing the update of the core's persistent state, as would have been done if the transaction had not been interrupted, by removing any remaining local storage used for that key and destroying the key in the secure element.
* Aborting means keeping the key. This requires no action on the secure element, and is only practical locally if the local storage is intact.
#### Comparing recovery strategies
From the analysis above, assuming that all keys are treated in the same way, there are 4 possible strategies.
* [Always follow the state of the secure element](#exploring-the-follow-the-secure-element-strategy). This requires the secure element driver to have a `"get_key_attributes"` entry point. Recovery means resuming the operation where it left off. For key creation, this means that the key metadata needs to be saved before calling the secure element's key creation entry point.
* Minimize the information processing: [always destroy the key](#exploring-the-always-destroy-strategy), i.e. abort all key creations and commit all key destructions. This does not require querying the state of the secure element. This does not require any special precautions to preserve information about the key during the transaction. It simplifies recovery in that the recovery process might not even need to know whether it's recovering a key creation or a key destruction.
* Follow the state of the secure element for key creation, but always go ahead with key destruction. This requires the secure element driver to have a `"get_key_attributes"` entry point. Compared to always following the state of the secure element, this has the advantage of maximizing the chance that a command to destroy key material is effective. Compared to always destroying the key, this has a performance advantage if a key creation is interrupted. These do not seem like decisive advantages, so we will not consider this strategy further.
* Always abort key creation, but follow the state of the secure element for key destruction. I can't think of a good reason to choose this strategy.
Requiring the driver to have a `"get_key_attributes"` entry point is potentially problematic because some secure elements don't have room to store key attributes: a key slot always exists, and it's up to the user to remember what, if anything, they put in it. The driver has to remember anyway, so that it can find a free slot when creating a key. But with a recovery strategy that doesn't involve a `"get_key_attributes"` entry point, the driver design is easier: the driver doesn't need to protect the information about slots in use against a power failure, the core takes care of that.
#### Exploring the follow-the-secure-element strategy
Each entry in the transaction list contains the API key identifier, the key lifetime (or at least the location), the driver key identifier (not constant-size), and an indication of whether the key is being created or destroyed.
For key creation, we have all the information to store in the key file once the `"allocate_key"` call returns. We must store all the information that will go in the key file before calling the driver's key creation entry point. Therefore the normal sequence of operations is:
1. Call the driver's `"allocate_key"` entry point.
2. Add the key to the transaction list, indicating that it is being created.
3. Write the key file.
4. Call the driver's key creation entry point.
5. Remove the key from the transaction list.
During recovery, for each key in the transaction list that was being created:
* If the key exists in the secure element, just remove it from the transaction list.
* If the key does not exist in the secure element, first remove the key file if it is present, then remove the key from the transaction list.
For key destruction, we need to preserve the key file until after the key has been destroyed. Therefore the normal sequence of operations is:
1. Add the key to the transaction list, indicating that it is being destroyed.
2. Call the driver's `"destroy_key"` entry point.
3. Remove the key file.
4. Remove the key from the transaction list.
During recovery, for each key in the transaction list that was being created:
* If the key exists in the secure element, call the driver's `"destroy_key"` entry point, then remove the key file, and finally remote the key from the transaction lits.
* If the key does not exist in the secure element, remove the key file if it is still present, then remove the key from the transaction list.
#### Exploring the always-destroy strategy
Each entry in the transaction list contains the API key identifier, the key lifetime (or at least the location), and the driver key identifier (not constant-size).
For key creation, we do not need to store the key's metadata until it has been created in the secure element. Therefore the normal sequence of operations is:
1. Call the driver's `"allocate_key"` entry point.
2. Add the key to the transaction list.
3. Call the driver's key creation entry point.
4. Write the key file.
5. Remove the key from the transaction list.
For key destruction, we can remove the key file before contacting the secure element. Therefore the normal sequence of operations is:
1. Add the key to the transaction list.
2. Remove the key file.
3. Call the driver's `"destroy_key"` entry point.
4. Remove the key from the transaction list.
Recovery means removing all traces of all keys on the transaction list. This means following the destruction process, starting after the point where the key has been added to the transaction list, and ignoring any failure of a removal action if the item to remove does not exist:
1. Remove the key file, treating `DOES_NOT_EXIST` as a success.
2. Call the driver's `"destroy_key"` entry point, treating `DOES_NOT_EXIST` as a success.
3. Remove the key from the transaction list.
#### Always-destroy strategy with a simpler transaction file
We can modify the [always-destroy strategy](#exploring-the-always-destroy-strategy) to make the transaction file simpler: if we ensure that the key file always exists if the key exists in the secure element, then the transaction list does not need to include the driver key identifier: it can be read from the key file.
For key creation, we need to store the key's metadata before creating in the secure element. Therefore the normal sequence of operations is:
1. Call the driver's `"allocate_key"` entry point.
2. Add the key to the transaction list.
3. Write the key file.
4. Call the driver's key creation entry point.
5. Remove the key from the transaction list.
For key destruction, we need to contact the secure element before removing the key file. Therefore the normal sequence of operations is:
1. Add the key to the transaction list.
2. Call the driver's `"destroy_key"` entry point.
3. Remove the key file.
4. Remove the key from the transaction list.
Recovery means removing all traces of all keys on the transaction list. This means following the destruction process, starting after the point where the key has been added to the transaction list, and ignoring any failure of a removal action if the item to remove does not exist:
1. Load the driver key identifier from the key file. If the key file does not exist, skip to step 4.
2. Call the driver's `"destroy_key"` entry point, treating `DOES_NOT_EXIST` as a success.
3. Remove the key file, treating `DOES_NOT_EXIST` as a success.
4. Remove the key from the transaction list.
Compared with the basic always-destroy strategy:
* The transaction file handling is simpler since its entries have a fixed size.
* The flow of information is somewhat different from transparent keys and keys in stateless secure elements: we aren't just replacing “create the key material” by “tell the secure element to create the key material”, those happen at different times. But there's a different flow for stateful secure elements anyway, since the call to `"allocate_key"` has no analog in the stateless secure element or transparent cases.
#### Assisting secure element drivers with recovery
The actions of the secure element driver may themselves be non-atomic. So the driver must be given a chance to perform recovery.
To simplify the design of the driver, the core should guarantee that the driver will know if a transaction was in progress and the core cannot be sure about the state of the secure element. Merely calling a read-only entry point such as `"get_key_attributes"` does not provide enough information to the driver for it to know that it should actively perform recovery related to that key.
This gives an advantage to the “always destroy” strategy. Under this strategy, if the key might be in a transitional state, the core will request a key destruction from the driver. This means that, if the driver has per-key auxiliary data to clean up, it can bundle that as part of the key's destruction.
### Testing non-atomic processes
In this section, we discuss how to test non-atomic processes that must implement an atomic and committing interface. As discussed in [“Overview of API functions”](#overview-of-api-functions), this concerns key management in stateful secure elements.
#### Naive test strategy for non-atomic processes
Non-atomic processes consist of a series of atomic, committing steps.
Our general strategy to test them is as follows: every time there is a modification of persistent state, either in storage or in the (simulated) secure element, try both the nominal case and simulating a power loss. If a power loss occurs, restart the system (i.e. clean up and call `psa_crypto_init()`), and check that the system ends up in a consistent state.
Note that this creates a binary tree of possibilities: after each state modification, there may or may not be a restart, and after that different state modifications may occur, each of which may or may not be followed by a restart.
For example, consider testing of one key creation operation (see [“Overview of two-phase commit with stateful secure elements”](#overview-of-two-phase-commit-with-stateful-secure-elements), under the simplifying assumption that each storage update step, as well as the recovery after a restart, each make a single (atomic) storage modification and no secure element access. The nominal case consists of three state modifications: storage modification (start transaction), creation on the secure element, storage modification (commit transaction). We need to test the following sequences:
* Start transaction, restart, recovery.
* Start transaction, secure element operation, restart, recovery.
* Start transaction, secure element operation, commit transaction.
If, for example, recovery consists of two atomic steps, the tree of possibilities expands and may be infinite:
* Start transaction, restart, recovery step 1, restart, recovery step 1, recovery step 2.
* Start transaction, restart, recovery step 1, restart, recovery step 1, restart, recovery step 1, recovery step 2.
* Start transaction, restart, recovery step 1, restart, recovery step 1, restart, recovery step 1, restart, recovery step 1, recovery step 2.
* etc.
* Start transaction, secure element operation, restart, ...
* Start transaction, secure element operation, commit transaction.
In order to limit the possibilities, we need to make some assumptions about the recovery step. For example, if we have confidence that recovery step 1 is idempotent (i.e. doing it twice is the same as doing it once), we don't need to test what happens in execution sequences that take recovery step 1 more than twice in a row.
### Splitting normal behavior and transaction recovery
We introduce an abstraction level in transaction recovery:
* Normal operation must maintain a certain invariant on the state of the world (internal storage and secure element).
* Transaction recovery is defined over all states of the world that satisfy this invariant.
This separation of concerns greatly facilitates testing, since it is now split into two parts:
* During the testing of normal operation, we can use read-only invasive testing to ensure that the invariant is maintained. No modification of normal behavior (such as simulated power failures) is necessary.
* Testing of transaction recovery is independent of how the system state was reached. We only need to artificially construct a representative sample of system states that match the invariant. Transaction recovery is itself an operation that must respect the invariant, and so we do not need any special testing for the case of an interrupted recovery.
Another benefit of this approach is that it is easier to specify and test what happens if the library is updated on a device with leftovers from an interrupted transaction. We will require and test that the new version of the library supports recovery of the old library's states, without worrying how those states were reached.
#### Towards an invariant for transactions
As discussed in the section [“Recovery strategies”](#recovery-strategies), the information about active transactions is stored in a transaction list file. The name of the transaction list file does not depend on the identifiers of the keys in the list, but there may be more than one transaction list, for example one per secure element. If so, each transaction list can be considered independently.
When no transaction is in progress, the transaction list does not exist, or is empty. The empty case must be supported because this is the initial state of the filesystem. When no transaction is in progress, the state of the secure element must be consistent with references to keys in that secure element contained in key files. More generally, if a key is not in the transaction list, then the key must be present in the secure element if and only if the key file is in the internal storage.
For the purposes of the state invariant, it matters whether the transaction list file contains the driver key identifier, or if the driver key identifier is only stored in the key file. This is because the core needs to know the driver key id in order to access the secure element. If the transaction list does not contain the driver key identifier, and the key file does not exist, the key must not be present in the secure element.
We thus have two scenarios, each with their own invariant: one where the transaction list contains only key identifiers, and one where it also contains the secure element's key identifier (as well as the location of the secure element if this is not encoded in the name of the transaction list file).
#### Storage invariant if the transaction list contains application key identifiers only
Invariants:
* If the file `id` does not exist, then no resources corresponding to that key are in a secure element. This holds whether `id` is in the transaction list or not.
* If `id` is not in the transaction list and the file `id` exists and references a key in a stateful secure element, then the key is present in the secure element.
If `id` is in the transaction list and the file `id` exists, the key may or may not be present in the secure element.
The invariant imposes constraints on the [order of operations for the two-phase commit](#overview-of-two-phase-commit-with-stateful-secure-elements): key creation must create `id` before calling the secure element's key creation entry point, and key destruction must remove `id` after calling the secure element's key destruction entry point.
For recovery:
* If the file `id` does not exist, then nothing needs to be done for recovery, other than removing `id` from the transaction list.
* If the file `id` exists:
* It is correct to destroy the key in the secure element (treating a `DOES_NOT_EXIST` error as a success), then remove `id`.
* It is correct to check whether the key exists in the secure element, and if it does, keep it and keep `id`. If not, remove `id` from the internal storage.
#### Storage invariant if the transaction list contains driver key identifiers
Invariants:
* If `id` is not in the transaction list and the file `id` does not exist, then no resources corresponding to that key are in a secure element.
* If `id` is not in the transaction list and the file `id` exists, then the key is present in the secure element.
If `id` is in the transaction list, neither the state of `id` in the internal storage nor the state of the key in the secure element is known.
For recovery:
* If the file `id` does not exist, then destroy the key in the secure element (treating a `DOES_NOT_EXIST` error as a success).
* If the file `id` exists:
* It is correct to destroy the key in the secure element (treating a `DOES_NOT_EXIST` error as a success), then remove `id`.
* It is correct to check whether the key exists in the secure element, and if it does, keep it and keep `id`. If not, remove `id` from the internal storage.
#### Coverage of states that respect the invariant
For a given key, we have to consider three a priori independent boolean states:
* Whether the key file exists.
* Whether the key is in the secure element.
* Whether the key is in the transaction list.
There is full coverage for one key if we have tests of recovery for the states among these $2^3 = 8$ possibilities that satisfy the storage invariant.
In addition, testing should adequately cover the case of multiple keys in the transaction list. How much coverage is adequate depends on the layout of the list as well as white-box considerations of how the list is manipulated.
### Choice of a transaction design
#### Chosen transaction algorithm
Based on [“Optimization considerations for transactions”](#optimization-considerations-for-transactions), we choose a transaction algorithm that consists in the following operations:
1. Add the key identifier to the transaction list.
2. Call the secure element's key creation or destruction entry point.
3. Remove the key identifier from the transaction list.
In addition, before or after step 2, create or remove the key file in the internal storage.
In order to conveniently support multiple transactions at the same time, we pick the simplest possible layout for the transaction list: a simple array of key identifiers. Since the transaction list does not contain the driver key identifier:
* During key creation, create the key file in internal storage in the internal storage before calling the secure element's key creation entry point.
* During key destruction, call the secure element's key destruction entry point before removing the key file in internal storage.
This choice of algorithm does not require the secure element driver to have a `"get_key_attributes"` entry point.
#### Chosen storage invariant
The [storage invariant](#storage-invariant-if-the-transaction-list-contains-application-key-identifiers-only) is as follows:
* If the file `id` does not exist, then no resources corresponding to that key are in a secure element. This holds whether `id` is in the transaction list or not.
* If `id` is not in the transaction list and the file `id` exists and references a key in a stateful secure element, then the key is present in the secure element.
* If `id` is in the transaction list and a key exists by that identifier, the key's location is a stateful secure element.
#### Chosen recovery process
To [assist secure element drivers with recovery](#assisting-secure-element-drivers-with-recovery), we pick the [always-destroy recovery strategy with a simple transaction file](#always-destroy-strategy-with-a-simpler-transaction-file). The the recovery process is as follows:
* If the file `id` does not exist, then nothing needs to be done for recovery, other than removing `id` from the transaction list.
* If the file `id` exists, call the secure element's key destruction entry point (treating a `DOES_NOT_EXIST` error as a success), then remove `id`.
## Specification of key management in stateful secure elements
This section only concerns stateful secure elements as discussed in [“Designing key management for secure element keys”](#designing-key-management-for-secure-element-keys), i.e. secure elements with an `"allocate_key"` entry point. The design follows the general principle described in [“Overview of two-phase commit with stateful secure elements”](#overview-of-two-phase-commit-with-stateful-secure-elements) and the specific choices justified in [“Choice of a transaction design”](choice-of-a-transaction-design).
### Transaction list file manipulation
The transaction list is a simple array of key identifiers.
To add a key identifier to the list:
1. Load the current list from the transaction list if it exists and it is not already cached in memory.
2. Append the key identifier to the array.
3. Write the updated list file.
To remove a key identifier from the list:
1. Load the current list if it is not already cached in memory. It is an error if the file does not exist since it must contain this identifier.
2. Remove the key identifier from the array. If it wasn't the last element in array, move array elements to fill the hole.
3. If the list is now empty, remove the transaction list file. Otherwise write the updated list to the file.
### Key creation process in the core
Let _A_ be the application key identifier.
1. Call the driver's `"allocate_key"` entry point, obtaining the driver key identifier _D_ chosen by the driver.
2. Add _A_ [to the transaction list file](#transaction-list-file-manipulation).
3. Create the key file _A_ in the internal storage. Note that this is done at a different time from what happens when creating a transparent key or a key in a stateless secure element: in those cases, creating the key file happens after the actual creation of the key material.
4. Call the secure element's key creation entry point.
5. Remove _A_ [from the transaction list file](#transaction-list-file-manipulation).
If any step fails:
* If the secure element's key creation entry point has been called and succeeded, call the secure element's destroy entry point.
* If the key file has been created in the internal storage, remove it.
* Remove the key from the transaction list.
Note that this process is identical to key destruction, except that the key is already in the transaction list.
### Key destruction process in the core
Let _A_ be the application key identifier.
We assume that the key is loaded in a key slot in memory: the core needs to know the key's location in order to determine whether the key is in a stateful secure element, and if so to know the driver key identifier. A possible optimization would be to load only that information in local variables, without occupying a key store; this has the advantage that key destruction works even if the key store is full.
1. Add _A_ [to the transaction list file](#transaction-list-file-manipulation).
2. Call the secure element's `"destroy_key"` entry point.
3. Remove the key file _A_ from the internal storage.
4. Remove _A_ [from the transaction list file](#transaction-list-file-manipulation).
5. Free the corresponding key slot in memory.
If any step fails, remember the error but continue the process, to destroy the resources associated with the key as much as is practical.
### Transaction recovery
For each key _A_ in the transaction list file, if the file _A_ exists in the internal storage:
1. Load the key into a key slot in memory (to get its location and the driver key identifier, although we could get the location from the transaction list).
2. Call the secure element's `"destroy_key"` entry point.
3. Remove the key file _A_ from the internal storage.
4. Remove _A_ [from the transaction list file](#transaction-list-file-manipulation).
5. Free the corresponding key slot in memory.
The transaction list file can be processed in any order.
It is correct to update the transaction list after recovering each key, or to only delete the transaction list file once the recovery is over.
### Concrete format of the transaction list file
The transaction list file contains a [fixed header](#transaction-list-header-format) followed by a list of [fixed-size elements](#transaction-list-element-format).
The file uid is `PSA_CRYPTO_ITS_TRANSACTION_LIST_UID` = 0xffffff53.
#### Transaction list header format
* Version (2 bytes): 0x0003. (Chosen to differ from the first two bytes of a [dynamic secure element transaction file](#dynamic-secure-element-transaction-file), to reduce the risk of a mix-up.)
* Key name size (2 bytes): `sizeof(psa_storage_uid_t)`. Storing this size avoids reading bad data if Mbed TLS is upgraded to a different integration that names keys differently.
#### Transaction list element format
In practice, there will rarely be more than one active transaction at a time, so the size of an element is not critical for efficiency. Therefore, in addition to the key identifier which is required, we add some potentially useful information in case it becomes useful later. We do not put the driver key identifier because its size is not a constant.
* Key id: `sizeof(psa_storage_uid_t)` bytes.
* Key lifetime: 4 bytes (`sizeof(psa_key_lifetime_t)`). Currently unused during recovery.
* Operation type: 1 byte. Currently unused during recovery.
* 0: destroy key.
* 1: import key.
* 2: generate key.
* 3: derive key.
* 4: import key.
* Padding: 3 bytes. Reserved for future use. Currently unused during recovery.
## Testing key management in secure elements
### Instrumentation for checking the storage invariant
#### Test hook locations
When `MBEDTLS_TEST_HOOKS` is enabled, each call to `psa_its_set()` or `psa_its_remove()` also calls a test hook, passing the file UID as an argument to the hook.
When a stateful secure element driver is present in the build, we use this hook to verify that the storage respects the [storage invariant](#chosen-storage-invariant). In addition, if there is some information about key ongoing operation (set explicitly by the test function as a global variable in the test framework), the hook tests that the content of the storage is compatible with the ongoing operation.
#### Test hook behavior
The storage invariant check cannot check all keys in storage, and does not need to (for example, it would be pointless to check anything about transparent keys). It checks the following keys:
* When invoked from the test hook on a key file: on that key.
* When invoked from the test hook on the transaction file: on all the keys listed in the transaction file.
* When invoked from a test secure element: on the specified key.
#### Test hook extra data
Some tests set global variables to indicate which persistent keys they manipulate. We instrument at least some of these tests to also indicate what operation is in progress on the key. See the GitHub issues or the source code for details.
### Testing of transaction recovery
When no secure element driver is present in the build, the presence of a transaction list file during initialization is an error.
#### Recovery testing process
When the stateful test secure element driver is present in the build, we run test cases on a representative selection of states of the internal storage and the test secure element. Each test case for transaction recovery has the following form:
1. Create the initial state:
* Create a transaction list file with a certain content.
* Create key files that we want to have in the test.
* Call the secure element test driver to create keys without going throught the PSA API.
2. Call `psa_crypto_init()`. Expect success if the initial state satisfies the [storage invariant](#chosen-storage-invariant) and failure otherwise.
3. On success, check that the expected keys exist, and that keys that are expected to have been destroyed by recovery do not exist.
4. Clean up the storage and the secure element test driver's state.
#### States to test recovery on
For a given key located in a secure element, the following combination of states are possible:
* Key file: present, absent.
* Key in secure element: present, absent.
* Key in the transaction file: no, creation (import), destruction.
We test all $2 \times 2 \times 3 = 12$ possibilities, each in its own test case. In each case, call the test function that checks the storage invariant and check that its result is as expected. Then, if the storage invariant is met, follow the [recovery testing process](#recovery-testing-process).
In addition, have at least one positive test case for each creation method other than import, to ensure that we don't reject a valid value.
Note: testing of a damaged filesystem (including a filesystem that doesn't meet the invariant) is out of scope of the present document.
Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

@@ -0,0 +1,367 @@
# Thread-safety of the PSA subsystem
Currently, PSA Crypto API calls in Mbed TLS releases are not thread-safe.
As of Mbed TLS 3.6, an MVP for making the [PSA Crypto key management API](https://arm-software.github.io/psa-api/crypto/1.1/api/keys/management.html) and [`psa_crypto_init`](https://arm-software.github.io/psa-api/crypto/1.1/api/library/library.html#c.psa_crypto_init) thread-safe has been implemented. Implementations which only ever call PSA functions from a single thread are not affected by this new feature.
Summary of recent work:
- Key Store:
- Slot states are described in the [Key slot states](#key-slot-states) section. They guarantee safe concurrent access to slot contents.
- Key slots are protected by a global mutex, as described in [Key store consistency and abstraction function](#key-store-consistency-and-abstraction-function).
- Key destruction strategy abiding by [Key destruction guarantees](#key-destruction-guarantees), with an implementation discussed in [Key destruction implementation](#key-destruction-implementation).
- `global_data` variables in `psa_crypto.c` and `psa_crypto_slot_management.c` are now protected by mutexes, as described in the [Global data](#global-data) section.
- The testing system has now been made thread-safe. Tests can now spin up multiple threads, see [Thread-safe testing](#thread-safe-testing) for details.
- Some multithreaded testing of the key management API has been added, this is outlined in [Testing-and-analysis](#testing-and-analysis).
- The solution uses the pre-existing `MBEDTLS_THREADING_C` threading abstraction.
- The core makes no additional guarantees for drivers. See [Driver policy](#driver-policy) for details.
The other functions in the PSA Crypto API are planned to be made thread-safe in future, but currently we are not testing this.
## Overview of the document
* The [Guarantees](#guarantees) section describes the properties that are followed when PSA functions are invoked by multiple threads.
* The [Usage guide](#usage-guide) section gives guidance on initializing, using and freeing PSA when using multiple threads.
* The [Current strategy](#current-strategy) section describes how thread-safety of key management and `global_data` is achieved.
* The [Testing and analysis](#testing-and-analysis) section discusses the state of our testing, as well as how this testing will be extended in future.
* The [Future work](#future-work) section outlines our long-term goals for thread-safety; it also analyses how we might go about achieving these goals.
## Definitions
*Concurrent calls*
The PSA specification defines concurrent calls as: "In some environments, an application can make calls to the Crypto API in separate threads. In such an environment, concurrent calls are two or more calls to the API whose execution can overlap in time." (See PSA documentation [here](https://arm-software.github.io/psa-api/crypto/1.1/overview/conventions.html#concurrent-calls).)
*Thread-safety*
In general, a system is thread-safe if any valid set of concurrent calls is handled as if the effect and return code of every call is equivalent to some sequential ordering. We implement a weaker notion of thread-safety, we only guarantee thread-safety in the circumstances described in the [PSA Concurrent calling conventions](#psa-concurrent-calling-conventions) section.
## Guarantees
### Correctness out of the box
Building with `MBEDTLS_PSA_CRYPTO_C` and `MBEDTLS_THREADING_C` gives code which is correct; there are no race-conditions, deadlocks or livelocks when concurrently calling any set of PSA key management functions once `psa_crypto_init` has been called (see the [Initialization](#initialization) section for details on how to correctly initialize the PSA subsystem when using multiple threads).
We do not test or support calling other PSA API functions concurrently.
There is no busy-waiting in our implementation, every API call completes in a finite number of steps regardless of the locking policy of the underlying mutexes.
When only considering key management functions: Mbed TLS 3.6 abides by the minimum expectation for concurrent calls set by the PSA specification (see [PSA Concurrent calling conventions](#psa-concurrent-calling-conventions)).
#### PSA Concurrent calling conventions
These are the conventions which are planned to be added to the PSA 1.2 specification, Mbed TLS 3.6 abides by these when only considering [key management functions](https://arm-software.github.io/psa-api/crypto/1.1/api/keys/management.html):
> The result of two or more concurrent calls must be consistent with the same set of calls being executed sequentially in some order, provided that the calls obey the following constraints:
>
> * There is no overlap between an output parameter of one call and an input or output parameter of another call. Overlap between input parameters is permitted.
>
> * A call to `psa_destroy_key()` must not overlap with a concurrent call to any of the following functions:
> - Any call where the same key identifier is a parameter to the call.
> - Any call in a multi-part operation, where the same key identifier was used as a parameter to a previous step in the multi-part operation.
>
> * Concurrent calls must not use the same operation object.
>
> If any of these constraints are violated, the behaviour is undefined.
>
> The consistency requirement does not apply to errors that arise from resource failures or limitations. For example, errors resulting from resource exhaustion can arise in concurrent execution that do not arise in sequential execution.
>
> As an example of this rule: suppose two calls are executed concurrently which both attempt to create a new key with the same key identifier that is not already in the key store. Then:
> * If one call returns `PSA_ERROR_ALREADY_EXISTS`, then the other call must succeed.
> * If one of the calls succeeds, then the other must fail: either with `PSA_ERROR_ALREADY_EXISTS` or some other error status.
> * Both calls can fail with error codes that are not `PSA_ERROR_ALREADY_EXISTS`.
>
> If the application concurrently modifies an input parameter while a function call is in progress, the behaviour is undefined.
### Backwards compatibility
Code which was working prior to Mbed TLS 3.6 will still work. Implementations which only ever call PSA functions from a single thread, or which protect all PSA calls using a mutex, are not affected by this new feature. If an application previously worked with a 3.X version, it will still work on version 3.6.
### Supported threading implementations
Currently, the only threading library with support shipped in the code base is pthread (enabled by `MBEDTLS_THREADING_PTHREAD`). The only concurrency primitives we use are mutexes, see [Condition variables](#condition-variables) for discussion about implementing new primitives in future major releases.
Users can add support to any platform which has mutexes using the Mbed TLS platform abstraction layer (see `include/mbedtls/threading.h` for details).
We intend to ship support for other platforms including Windows in future releases.
### Key destruction guarantees
Much like all other API calls, `psa_destroy_key` does not block indefinitely, and when `psa_destroy_key` returns:
1. The key identifier does not exist. This is a functional requirement for persistent keys: any thread can immediately create a new key with the same identifier.
2. The resources from the key have been freed. This allows threads to create similar keys immediately after destruction, regardless of resources.
When `psa_destroy_key` is called on a key that is in use, guarantee 2 may be violated. This is consistent with the PSA specification requirements, as destruction of a key in use is undefined.
In future versions we aim to enforce stronger requirements for key destruction, see [Long term key destruction requirements](#long-term-key-destruction-requirements) for details.
### Driver policy
The core makes no additional guarantees for drivers. Driver entry points may be called concurrently from multiple threads. Threads can concurrently call entry points using the same key, there is also no protection from destroying a key which is in use.
### Random number generators
The PSA RNG can be accessed both from various PSA functions, and from application code via `mbedtls_psa_get_random`.
When using the built-in RNG implementations, i.e. when `MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG` is disabled, querying the RNG is thread-safe (`mbedtls_psa_random_init` and `mbedtls_psa_random_seed` are only thread-safe when called while holding `mbedtls_threading_psa_rngdata_mutex`. `mbedtls_psa_random_free` is not thread-safe).
When `MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG` is enabled, it is down to the external implementation to ensure thread-safety, should threading be enabled.
## Usage guide
### Initialization
The PSA subsystem is initialized via a call to [`psa_crypto_init`](https://arm-software.github.io/psa-api/crypto/1.1/api/library/library.html#c.psa_crypto_init). This is a thread-safe function, and multiple calls to `psa_crypto_init` are explicitly allowed. It is valid to have multiple threads each calling `psa_crypto_init` followed by a call to any PSA key management function (if the init succeeds).
### General usage
Once initialized, threads can use any PSA function if there is no overlap between their calls. All threads share the same set of keys, as soon as one thread returns from creating/loading a key via a key management API call the key can be used by any thread. If multiple threads attempt to load the same persistent key, with the same key identifier, only one thread can succeed - the others will return `PSA_ERROR_ALREADY_EXISTS`.
Applications may need careful handling of resource management errors. As explained in ([PSA Concurrent calling conventions](#psa-concurrent-calling-conventions)), operations in progress can have memory related side effects. It is possible for a lack of resources to cause errors which do not arise in sequential execution. For example, multiple threads attempting to load the same persistent key can lead to some threads returning `PSA_ERROR_INSUFFICIENT_MEMORY` if the key is not currently in the key store - while trying to load a persistent key into the key store a thread temporarily reserves a free key slot.
If a mutex operation fails, which only happens if the mutex implementation fails, the error code `PSA_ERROR_SERVICE_FAILURE` will be returned. If this code is returned, execution of the PSA subsystem must be stopped. All functions which have internal mutex locks and unlocks (except for when the lock/unlock occurs in a function that has no return value) will return with this error code in this situation.
### Freeing
There is no thread-safe way to free all PSA resources. This is because any such operation would need to wait for all other threads to complete their tasks before wiping resources.
`mbedtls_psa_crypto_free` must only be called by a single thread once all threads have completed their operations.
## Current strategy
This section describes how we have implemented thread-safety. There is discussion of: techniques, internal properties for enforcing thread-safe access, how the system stays consistent and our abstraction model.
### Protected resources
#### Global data
We have added a mutex `mbedtls_threading_psa_globaldata_mutex` defined in `include/mbedtls/threading.h`, which is used to make `psa_crypto_init` thread-safe.
There are two `psa_global_data_t` structs, each with a single instance `global_data`:
* The struct in `library/psa_crypto.c` is protected by `mbedtls_threading_psa_globaldata_mutex`. The RNG fields within this struct are not protected by this mutex, and are not always thread-safe (see [Random number generators](#random-number-generators)).
* The struct in `library/psa_crypto_slot_management.c` has two fields: `key_slots` is protected as described in [Key slots](#key-slots), `key_slots_initialized` is protected by the global data mutex.
#### Mutex usage
A deadlock would occur if a thread attempts to lock a mutex while already holding it. Functions which need to be called while holding the global mutex have documentation to say this.
To avoid performance degradation, functions must hold mutexes for as short a time as possible. In particular, they must not start expensive operations (eg. doing cryptography) while holding the mutex.
#### Key slots
Keys are stored internally in a global array of key slots known as the "key store", defined in `library/psa_slot_management.c`.
##### Key slot states
Each key slot has a state variable and a `registered_readers` counter. These two variables dictate whether an operation can access a slot, and in what way the slot can be used.
There are four possible states for a key slot:
* `PSA_SLOT_EMPTY`: no thread is currently accessing the slot, and no information is stored in the slot. Any thread is able to change the slot's state to `PSA_SLOT_FILLING` and begin to load data into the slot.
* `PSA_SLOT_FILLING`: one thread is currently loading or creating material to fill the slot, this thread is responsible for the next state transition. Other threads cannot read the contents of a slot which is in this state.
* `PSA_SLOT_FULL`: the slot contains a key, and any thread is able to use the key after registering as a reader, increasing `registered_readers` by 1.
* `PSA_SLOT_PENDING_DELETION`: the key within the slot has been destroyed or marked for destruction, but at least one thread is still registered as a reader (`registered_readers > 0`). No thread can register to read this slot. The slot must not be wiped until the last reader unregisters. It is during the last unregister that the contents of the slot are wiped, and the slot's state is set to `PSA_SLOT_EMPTY`.
###### Key slot state transition diagram
![](key-slot-state-transitions.png)
In the state transition diagram above, an arrow between two states `q1` and `q2` with label `f` indicates that if the state of a slot is `q1` immediately before `f`'s linearization point, it may be `q2` immediately after `f`'s linearization point. Internal functions have italicized labels. The `PSA_SLOT_PENDING_DELETION -> PSA_SLOT_EMPTY` transition can be done by any function which calls `psa_unregister_read`.
The state transition diagram can be generated in https://app.diagrams.net/ via this [url](https://viewer.diagrams.net/?tags=%7B%7D&highlight=0000ff&edit=_blank&layers=1&nav=1#R3Vxbd5s4EP4t%2B%2BDH5CBxf6zrJJvW7aYn7W7dFx9qZFstBg7gW379CnMxkoUtY%2BGQ%2BiVISCPQjD59mhnSU98vNg%2BRE84%2FBS7yelBxNz110IMQAEsnf9KabVZjmHnFLMJu3mhf8YxfUF6p5LVL7KKYapgEgZfgkK6cBL6PJglV50RRsKabTQOPHjV0Zuig4nnieIe1%2F2E3mWe1FjT39X8jPJsXIwPDzu4snKJx%2Fibx3HGDdaVKveup76MgSLKrxeY98tLJK%2BYl63dfc7d8sAj5iUiHH%2BBlOP338cP6i%2B37%2Ff7oV%2Fjr442aSVk53jJ%2F4R40PCKv7%2BIVuZyll%2FffhsOimsiv3OE0njvxOEKOi6K4uPszYtuzUnbzk2yLSScPTvRLCv31HCfoOXQm6Z01MbF0hGThkRIgl04cZkqf4g1yS1HVScnnaYWiBG0qVfkkPaBggZJoS5rkdzUrV1hhsUpeXlf0n1fNK6ov6pzc4mal5L1SyEWulzN0BABHSeyM%2Be671NpJaeI5cYwn9ERFwdJ30xkaKKREJifafs9v7QqjamGwqbYbbIvSBidlJ3I9qtTvu6SFoketNuJgGU3QabtMnGiGkiPttKwdcqlVfKjbiu50ju6Kugh5ToJX9NrnKTQf4SnA5M1qTUc3GJvI3jvvVV2rrCDTvrUrP4sSq6mM2GyaDsTurK2chAsMENaiBC7WcBg746UfoRmOExTtEKCy2HH9UieaGzo%2Fya5BL2wPz%2FzUmInloIhUpOsXE1h%2Bl99YYNdNZfQjFOMX5%2BdOXmpzYToLu3nR%2Bz19wLXC48uMRYpyc8lHofCbhyDKLVRMm1LZDbzMwAoxgOkSTKcxakfpIjvD3aenr6O3CfOdQ3lbOsrneK1U8BocxetyXygLo2qhZl9ojvJQEOVBt1CetpwDNBYG%2BRObRcuoXvDSU6g%2BdbA3%2Fo224wkB9QQH%2FlvD9WJhdRHXc8mQEsr2bw%2FkDzf2%2B8fh8PHzQ6exWjVeGas1kb3xrFPTX3%2FcsenVlaSLKOnp7vNgZ%2B6CehrcDe%2B%2BPv7z%2BW3qqHOkx2yL84ifUZudhZtznsKJdYrzwE5xHqiQzc%2FSoAnI2VTTDXoX1DXj1gS6CS1TJwWVES9KiIDBMCvtuozIEkEMLkciZAVFKzSeRgjtuFLsBQmfJwkCDXeYmExAwuViXBw6OWpnOVuBC12kbKUY7VosDfD4hnyYvNWbHA6zXq96POyWEzCFSkUpoNIgqEaDGkhdewVWqpZiNgNLTWHAkti6yphk237B5oA5xT6O5wLHyjcGXOVSvRi5bogVabZJQ5cqx0ItrtQrABmPkzO6nCzJRuqWFOx6YQ1xN1lzRBMNa6idQjStiNmWMdyGHi%2FdYASxB4sawCI24GwrzfLlWf%2FANo2NpqIcfy7ItAcn2mvWMfnkInvipotn0NcmAD9MQu8FLR%2Fxs%2F7uaSN2nq1hpyejMpew0pqwTzNKKjYkMZKx47tjL5j8Lvn2%2BPtFA6VyJ14Q7wj8Wb3CJbHaaq%2BDwf8wel7iuIxdDqgWvZou5Oe5ZJr0Q%2F1ae5zKS6mQQtarG5SgT6PCztuN5GiCG1u3IjnQhJSV6HrDjQ3UOdauxMRV3gmRi1UuipMo2F6OcXLwtLMQVy5jCS4IzTLoM2CxDC403xuaTdktQByXicj32nKJ%2Bym0Oh8X28e3bnltVYbX6k1D1arJOBsEibssi6t3NDR1w3YBeI4uLinUymYc9ZJwBxRujjY9CNzZuUqSjLAnlIarFj2hon4DvdPwY4Cm8MOkyhjtJUByra547orZHXCpzgKKtPSXFFCKrpKJDO3mbCP9ha%2FXK2VWn4aGJjDUHE50QTjp2Gmtxkt3NpxAhs0Y7WXe8c0O1tKZhr42eZ61NQ4PqdPbdV8dX%2FYywsvlF05yIRGorwSJPKrNaFJ6iKaxX6oryMTEGxoHSFTNvIWWpWtQszUbqpbKyqVCy1AIts6NnpC3qY4CbPohTEW9NaFS%2FtTjbwTso8IAOEeY3vzJ2gnKcLP23%2FKnMcdBQQJgKrpFc0hJFLKNbJwnvNwMp3BsWbMvqx%2F3Hye%2BH3I%2FjJHDGanEmkZf47XGGEWzFruViqMyOTI667YSxmX9hCNNHmPk2pwQYUxxBi%2FCIEsRPMtPP0M%2BipykgYM%2FCM%2BPJaT00kURXu3yfsbBMgmX1DOfn1X9GlB5FB0kIKWuAe65%2BGLvHSX0almMsLMJDCeyCeScfv6wT%2FdEAyKimUz7YFkRebtSbpNNu7IPcs6F8zEZQaIh4L0gqUvww0j7vh7F%2FW9ujL7iR%2FfmYWy1QF0KOy2JxzmWSicnvP4nF93KumPJi9n4UMmQFxOKWea550bW3W9qcrPiuCZdz4yaJ4x1gVwcXb8SyAWwDTlsQmUijIxPogmYkeL%2B3%2BJkzff%2FXEi9%2Bx8%3D).
##### Key slot access primitives
The state of a key slot is updated via the internal function `psa_key_slot_state_transition`. To change the state of `slot` from `expected_state` to `new_state`, when `new_state` is not `PSA_SLOT_EMPTY`, one must call `psa_key_slot_state_transition(slot, expected_state, new_state)`; if the state was not `expected_state` then `PSA_ERROR_CORRUPTION_DETECTED` is returned. The sole reason for having an expected state parameter here is to help guarantee that our functions work as expected, this error code cannot occur without an internal coding error.
Changing a slot's state to `PSA_SLOT_EMPTY` is done via `psa_wipe_key_slot`, this function wipes the entirety of the key slot.
The reader count of a slot is incremented via `psa_register_read`, and decremented via `psa_unregister_read`. Library functions register to read a slot via the `psa_get_and_lock_key_slot_X` functions, read from the slot, then call `psa_unregister_read` to make known that they have finished reading the slot's contents.
##### Key store consistency and abstraction function
The key store is protected by a single global mutex `mbedtls_threading_key_slot_mutex`.
We maintain the consistency of the key store by ensuring that all reads and writes to `slot->state` and `slot->registered_readers` are performed under `mbedtls_threading_key_slot_mutex`. All the access primitives described above must be called while the mutex is held; there is a convenience function `psa_unregister_read_under_mutex` which wraps a call to `psa_unregister_read` in a mutex lock/unlock pair.
A thread can only traverse the key store while holding `mbedtls_threading_key_slot_mutex`, the set of keys within the key store which the thread holding the mutex can access is equivalent to the set:
{mbedtls_svc_key_id_t k : (\exists slot := &global_data.key_slots[i]) [
(slot->state == PSA_SLOT_FULL) &&
(slot->attr.id == k)]}
The union of this set and the set of persistent keys not currently loaded into slots is our abstraction function for the key store, any key not in this union does not currently exist as far as the code is concerned (even if the key is in a slot which has a `PSA_SLOT_FILLING` or `PSA_SLOT_PENDING_DELETION` state). Attempting to start using any key which is not a member of the union will result in a `PSA_ERROR_INVALID_HANDLE` error code.
##### Locking and unlocking the mutex
If a lock or unlock operation fails and this is the first failure within a function, the function will return `PSA_ERROR_SERVICE_FAILURE`. If a lock or unlock operation fails after a different failure has been identified, the status code is not overwritten.
We have defined a set of macros in `library/psa_crypto_core.h` to capture the common pattern of (un)locking the mutex and returning or jumping to an exit label upon failure.
##### Key creation and loading
To load a new key into a slot, the following internal utility functions are used:
* `psa_reserve_free_key_slot` - This function, which must be called under `mbedtls_threading_key_slot_mutex`, iterates through the key store to find a slot whose state is `PSA_SLOT_EMPTY`. If found, it reserves the slot by setting its state to `PSA_SLOT_FILLING`. If not found, it will see if there are any persistent keys loaded which do not have any readers, if there are it will kick one such key out of the key store.
* `psa_start_key_creation` - This function wraps around `psa_reserve_free_key_slot`, if a slot has been found then the slot id is set. This second step is not done under the mutex, at this point the calling thread has exclusive access to the slot.
* `psa_finish_key_creation` - After the contents of the key have been loaded (again this loading is not done under the mutex), the thread calls `psa_finish_key_creation`. This function takes the mutex, checks that the key does not exist in the key store (this check cannot be done before this stage), sets the slot's state to `PSA_SLOT_FULL` and releases the mutex. Upon success, any thread is immediately able to use the new key.
* `psa_fail_key_creation` - If there is a failure at any point in the key creation stage, this clean-up function takes the mutex, wipes the slot, and releases the mutex. Immediately after this unlock, any thread can start to use the slot for another key load.
##### Re-loading persistent keys
As described above, persistent keys can be kicked out of the key slot array provided they are not currently being used (`registered_readers == 0`). When attempting to use a persistent key that has been kicked out of a slot, the call to `psa_get_and_lock_key_slot` will see that the key is not in a slot, call `psa_reserve_free_key_slot` and load the key back into the reserved slot. This entire sequence is done during a single mutex lock, which is necessary for thread-safety (see documentation of `psa_get_and_lock_key_slot`).
If `psa_reserve_free_key_slot` cannot find a suitable slot, the key cannot be loaded back in. This will lead to a `PSA_ERROR_INSUFFICIENT_MEMORY` error.
##### Using existing keys
One-shot operations follow a standard pattern when using an existing key:
* They call one of the `psa_get_and_lock_key_slot_X` functions, which then finds the key and registers the thread as a reader.
* They operate on the key slot, usually copying the key into a separate buffer to be used by the operation. This step is not performed under the key slot mutex.
* Once finished, they call `psa_unregister_read_under_mutex`.
Multi-part and restartable operations each have a "setup" function where the key is passed in, these functions follow the above pattern. The key is copied into the `operation` object, and the thread unregisters from reading the key (the operations do not access the key slots again). The copy of the key will not be destroyed during a call to `psa_destroy_key`, the thread running the operation is responsible for deleting its copy in the clean-up. This may need to change to enforce the long term key requirements ([Long term key destruction requirements](#long-term-key-destruction-requirements)).
##### Key destruction implementation
The locking strategy here is explained in `library/psa_crypto.c`. The destroying thread (the thread calling `psa_destroy_key`) does not always wipe the key slot. The destroying thread registers to read the key, sets the slot's state to `PSA_SLOT_PENDING_DELETION`, wipes the slot from memory if the key is persistent, and then unregisters from reading the slot.
`psa_unregister_read` internally calls `psa_wipe_key_slot` if and only if the slot's state is `PSA_SLOT_PENDING_DELETION` and the slot's registered reader counter is equal to 1. This implements a "last one out closes the door" approach. The final thread to unregister from reading a destroyed key will automatically wipe the contents of the slot; no readers remain to reference the slot post deletion, so there cannot be corruption.
### linearizability of the system
To satisfy the requirements in [Correctness out of the box](#correctness-out-of-the-box), we require our functions to be "linearizable" (under certain constraints). This means that any (constraint satisfying) set of concurrent calls are performed as if they were executed in some sequential order.
The standard way of reasoning that this is the case is to identify a "linearization point" for each call, this is a single execution step where the function takes effect (this is usually a step in which the effects of the call become visible to other threads). If every call has a linearization point, the set of calls is equivalent to sequentially performing the calls in order of when their linearization point occurred.
We only require linearizability to hold in the case where a resource-management error is not returned. In a set of concurrent calls, it is permitted for a call c to fail with a `PSA_ERROR_INSUFFICIENT_MEMORY` return code even if there does not exist a sequential ordering of the calls in which c returns this error. Even if such an error occurs, all calls are still required to be functionally correct.
To help justify that our system is linearizable, here are the linearization points/planned linearization points of each PSA call :
* Key creation functions (including `psa_copy_key`) - The linearization point for a successful call is the mutex unlock within `psa_finish_key_creation`; it is at this point that the key becomes visible to other threads. The linearization point for a failed call is the closest mutex unlock after the failure is first identified.
* `psa_destroy_key` - The linearization point for a successful destruction is the mutex unlock, the slot is now in the state `PSA_SLOT_PENDING_DELETION` meaning that the key has been destroyed. For failures, the linearization point is the same.
* `psa_purge_key`, `psa_close_key` - The linearization point is the mutex unlock after wiping the slot for a success, or unregistering for a failure.
* One shot operations - The linearization point is the final unlock of the mutex within `psa_get_and_lock_key_slot`, as that is the point in which it is decided whether or not the key exists.
* Multi-part operations - The linearization point of the key input function is the final unlock of the mutex within `psa_get_and_lock_key_slot`. All other steps have no non resource-related side effects (except for key derivation, covered in the key creation functions).
Please note that one shot operations and multi-part operations are not yet considered thread-safe, as we have not yet tested whether they rely on unprotected global resources. The key slot access in these operations is thread-safe.
## Testing and analysis
### Thread-safe testing
It is now possible for individual tests to spin up multiple threads. This work has made the global variables used in tests thread-safe. If multiple threads fail a test assert, the first failure will be reported with correct line numbers.
Although the `step` feature used in some tests is thread-safe, it may produce unexpected results for multi-threaded tests. `mbedtls_test_set_step` or `mbedtls_test_increment_step` calls within threads can happen in any order, thus may not produce the desired result when precise ordering is required.
### Current state of testing
Our testing is a work in progress. It is not feasible to run our traditional, single-threaded, tests in such a way that tests concurrency. We need to write new test suites for concurrency testing.
Our tests currently only run on pthread, we hope to expand this in the future (our API already allows this).
We run tests using [ThreadSanitizer](https://clang.llvm.org/docs/ThreadSanitizer.html) to detect data races. We test the key store, and test that our key slot state system is enforced. We also test the thread-safety of `psa_crypto_init`.
Currently, not every API call is tested, we also cannot feasibly test every combination of concurrent API calls. API calls can in general be split into a few categories, each category calling the same internal key management functions in the same order - it is the internal functions that are in charge of locking mutexes and interacting with the key store; we test the thread-safety of these functions.
Since we do not run every cryptographic operation concurrently, we do not test that operations are free of unexpected global variables.
### Expanding testing
Through future work on testing, it would be good to:
* For every API call, have a test which runs multiple copies of the call simultaneously.
* After implementing other threading platforms, expand the tests to these platforms.
* Have increased testing for kicking persistent keys out of slots.
* Explicitly test that all global variables are protected, for this we would need to cover every operation in a concurrent scenario while running ThreadSanitizer.
* Run tests on more threading implementations, once these implementations are supported.
### Performance
Key loading does somewhat run in parallel, deriving the key and copying it key into the slot is not done under any mutex.
Key destruction is entirely sequential, this is required for persistent keys to stop issues with re-loading keys which cannot otherwise be avoided without changing our approach to thread-safety.
## Future work
### Long term requirements
As explained previously, we eventually aim to make the entirety of the PSA API thread-safe. This will build on the work that we have already completed. This requires a full suite of testing, see [Expanding testing](#expanding-testing) for details.
### Long term performance requirements
Our plan for cryptographic operations is that they are not performed under any global mutex. One-shot operations and multi-part operations will each only hold the global mutex for finding the relevant key in the key slot, and unregistering as a reader after the operation, using their own operation-specific mutexes to guard any shared data that they use.
We aim to eventually replace some/all of the mutexes with RWLocks, if possible.
### Long term key destruction requirements
The [PSA Crypto Key destruction specification](https://arm-software.github.io/psa-api/crypto/1.1/api/keys/management.html#key-destruction) mandates that implementations make a best effort to ensure that the key material cannot be recovered. In the long term, it would be good to guarantee that `psa_destroy_key` wipes all copies of the key material.
Here are our long term key destruction goals:
`psa_destroy_key` does not block indefinitely, and when `psa_destroy_key` returns:
1. The key identifier does not exist. This is a functional requirement for persistent keys: any thread can immediately create a new key with the same identifier.
2. The resources from the key have been freed. This allows threads to create similar keys immediately after destruction, regardless of resources.
4. No copy of the key material exists. Rationale: this is a security requirement. We do not have this requirement yet, but we need to document this as a security weakness, and we would like to satisfy this security requirement in the future.
#### Condition variables
It would be ideal to add these to a future major version; we cannot add these as requirements to the default `MBEDTLS_THREADING_C` for backwards compatibility reasons.
Condition variables would enable us to fulfil the final requirement in [Long term key destruction requirements](#long-term-key-destruction-requirements). Destruction would then work as follows:
* When a thread calls `psa_destroy_key`, they continue as normal until the `psa_unregister_read` call.
* Instead of calling `psa_unregister_read`, the thread waits until the condition `slot->registered_readers == 1` is true (the destroying thread is the final reader).
* At this point, the destroying thread directly calls `psa_wipe_key_slot`.
A few changes are needed for this to follow our destruction requirements:
* Multi-part operations will need to remain registered as readers of their key slot until their copy of the key is destroyed, i.e. at the end of the finish/abort call.
* The functionality where `psa_unregister_read` can wipe the key slot will need to be removed, slot wiping is now only done by the destroying/wiping thread.
### Protecting operation contexts
Currently, we rely on the crypto service to ensure that the same operation is not invoked concurrently. This abides by the PSA Crypto API Specification ([PSA Concurrent calling conventions](#psa-concurrent-calling-conventions)).
Concurrent access to the same operation object can compromise the crypto service. For example, if the operation context has a pointer (depending on the compiler and the platform, the pointer assignment may or may not be atomic). This violates the functional correctness requirement of the crypto service.
If, in future, we want to protect against this within the library then operations will require a status field protected by a global mutex. On entry, API calls would check the state and return an error if the state is ACTIVE. If the state is INACTIVE, then the call will set the state to ACTIVE, do the operation section and then restore the state to INACTIVE before returning.
### Future driver work
A future policy we may wish to enforce for drivers is:
* By default, each driver only has at most one entry point active at any given time. In other words, each driver has its own exclusive lock.
* Drivers have an optional `"thread_safe"` boolean property. If true, it allows concurrent calls to this driver.
* Even with a thread-safe driver, the core never starts the destruction of a key while there are operations in progress on it, and never performs concurrent calls on the same multipart operation.
In the non-thread-safe case we have these natural assumptions/requirements:
1. Drivers don't call the core for any operation for which they provide an entry point.
2. The core doesn't hold the driver mutex between calls to entry points.
With these, the only way of a deadlock is when there are several drivers with circular dependencies. That is, Driver A makes a call that is dispatched to Driver B; upon executing this call Driver B makes a call that is dispatched to Driver A. For example Driver A does CCM, which calls driver B to do CBC-MAC, which in turn calls Driver A to perform AES.
Potential ways for resolving this:
1. Non-thread-safe drivers must not call the core.
2. Provide a new public API that drivers can safely call.
3. Make the dispatch layer public for drivers to call.
4. There is a whitelist of core APIs that drivers can call. Drivers providing entry points to these must not make a call to the core when handling these calls. (Drivers are still allowed to call any core API that can't have a driver entry point.)
The first is too restrictive, the second and the third would require making it a stable API, and would likely increase the code size for a relatively rare feature. We are choosing the fourth as that is the most viable option.
**Thread-safe drivers:**
A driver would be non-thread-safe if the `thread-safe` property is set to true.
To make re-entrancy in non-thread-safe drivers work, thread-safe drivers must not make a call to the core when handling a call that is on the non-thread-safe driver core API whitelist.
Thread-safe drivers have fewer guarantees from the core and need to implement more complex logic. We can reasonably expect them to be more flexible in terms of re-entrancy as well. At this point it is hard to see what further guarantees would be useful and feasible. Therefore, we don't provide any further guarantees for now.
Thread-safe drivers must not make any assumption about the operation of the core beyond what is discussed here.
+432
View File
@@ -0,0 +1,432 @@
This document explains how to create builds of Mbed TLS where some
cryptographic mechanisms are provided only by PSA drivers (that is, no
built-in implementation of those algorithms), from a user's perspective.
This is useful to save code size for people who are using either a hardware
accelerator, or an alternative software implementation that is more
aggressively optimized for code size than the default one in Mbed TLS.
General considerations
----------------------
This document assumes that you already have a working driver.
Otherwise, please see the [PSA driver example and
guide](psa-driver-example-and-guide.md) for information on writing a
driver.
For each mechanism you want provided only by your driver:
- Define the corresponding `PSA_WANT` macro in `psa/crypto_config.h` - this
means the algorithm will be available in the PSA Crypto API.
- Define the corresponding `MBEDTLS_PSA_ACCEL` in your build. This could be
defined in `psa/crypto_config.h` or your compiler's command line. This
informs the PSA code that an accelerator is available for this mechanism.
- Undefine / comment out the corresponding `MBEDTLS_xxx_C` macro in
`mbedtls/mbedtls_config.h`. This ensures the built-in implementation is not
included in the build.
For example, if you want SHA-256 to be provided only by a driver, you'll want
`PSA_WANT_ALG_SHA_256` and `MBEDTLS_PSA_ACCEL_SHA_256` defined, and
`MBEDTLS_SHA256_C` undefined.
Recall that applications must call `psa_crypto_init()` prior to performing any
cryptographic or key management operation.
Mechanisms covered
------------------
For now, only the following (families of) mechanisms are supported:
- hashes: SHA-3, SHA-2, SHA-1, MD5, etc.
- elliptic-curve cryptography (ECC): ECDH, ECDSA, EC J-PAKE, ECC key types.
- finite-field Diffie-Hellman: FFDH algorithm, DH key types.
- RSA: PKCS#1 v1.5 and v2.1 signature and encryption algorithms, RSA key types
(for now, only crypto, no X.509 or TLS support).
- AEADs:
- GCM and CCM with AES, ARIA and Camellia key types
- ChachaPoly with ChaCha20 Key type
- Unauthenticated ciphers:
- key types: AES, ARIA, Camellia
- modes: ECB, CBC, CTR, CFB, OFB, XTS
For each family listed above, all the mentioned alorithms/key types are also
all the mechanisms that exist in PSA API.
Supported means that when those are provided only by drivers, everything
(including PK, X.509 and TLS) should work in the same way as if the mechanisms
where built-in, except as documented in the "Limitations" sub-sections of the
sections dedicated to each family below.
Hashes
------
It is possible to have all hash operations provided only by a driver.
More precisely:
- you can enable `PSA_WANT_ALG_SHA_256` without `MBEDTLS_SHA256_C`, provided
you have `MBEDTLS_PSA_ACCEL_ALG_SHA_256` enabled;
- and similarly for all supported hash algorithms: `MD5`, `RIPEMD160`,
`SHA_1`, `SHA_224`, `SHA_256`, `SHA_384`, `SHA_512`, `SHA3_224`, `SHA3_256`,
`SHA3_384`, `SHA3_512`.
In such a build, all crypto operations (via the PSA Crypto API, or non-PSA
APIs), as well as X.509 and TLS, will work as usual, except that direct calls
to low-level hash APIs (`mbedtls_sha256()` etc.) are not possible for the
modules that are disabled.
You need to call `psa_crypto_init()` before any crypto operation that uses
a hash algorithm that is provided only by a driver, as mentioned in [General
considerations](#general-considerations) above.
If you want to check at compile-time whether a certain hash algorithm is
available in the present build of Mbed TLS, regardless of whether it's
provided by a driver or built-in, you should use `PSA_WANT_ALG_xxx` from
`psa/crypto.h`.
### HMAC
In addition to accelerated hash operations, it is also possible to accelerate
HMAC by enabling and accelerating:
- HMAC algorithm and key type, i.e. `[PSA_WANT|MBEDTLS_PSA_ACCEL]_ALG_HMAC` and
`[PSA_WANT|MBEDTLS_PSA_ACCEL]KEY_TYPE_HMAC`.
- Required hash algorithm(s) as explained in [Hashes](#hashes) section.
In such a build it is possible to disable legacy HMAC support by disabling
`MBEDTLS_MD_C` and still getting crypto operations, X.509 and TLS to work as
usual. Exceptions are:
- As mentioned in [Hashes](#hashes) direct calls to legacy lo-level hash APIs
(`mbedtls_sha256()` etc.) will not be possible for the legacy modules that
are disabled.
- Legacy HMAC support (`mbedtls_md_hmac_xxx()`) won't be possible.
- `MBEDTLS_PKCS[5|7]_C` and `MBEDTLS_HMAC_DRBG_C` since they
depend on the legacy implementation of HMAC.
- disabling HMAC_DRBG_C cause deterministic ECDSA (i.e.
`MBEDTLS_DETERMINISTIC_ECDSA` on the legacy side and
`PSA_WANT_ALG_DETERMINISTIC_ECDSA` on the PSA one) to be not available.
Elliptic-curve cryptography (ECC)
---------------------------------
It is possible to have most ECC operations provided only by a driver:
- the ECDH, ECDSA and EC J-PAKE algorithms;
- key import, export, and random generation.
More precisely, if:
- you have driver support for ECC public and using private keys (that is,
`MBEDTLS_PSA_ACCEL_KEY_TYPE_ECC_PUBLIC_KEY` and
`MBEDTLS_PSA_ACCEL_KEY_TYPE_ECC_KEY_PAIR_BASIC` are enabled), and
- you have driver support for all ECC curves that are enabled (that is, for
each `PSA_WANT_ECC_xxx` macro enabled, the corresponding
`MBEDTLS_PSA_ACCEL_ECC_xxx` macros is enabled as well);
then you can:
- enable `PSA_WANT_ALG_ECDH` without `MBEDTLS_ECDH_C`, provided
`MBEDTLS_PSA_ACCEL_ALG_ECDH` is enabled
- enable `PSA_WANT_ALG_ECDSA` without `MBEDTLS_ECDSA_C`, provided
`MBEDTLS_PSA_ACCEL_ALG_ECDSA` is enabled;
- enable `PSA_WANT_ALG_JPAKE` without `MBEDTLS_ECJPAKE_C`, provided
`MBEDTLS_PSA_ACCEL_ALG_JPAKE` is enabled.
In addition, if:
- none of `MBEDTLS_ECDH_C`, `MBEDTLS_ECDSA_C`, `MBEDTLS_ECJPAKE_C` are enabled
(see conditions above), and
- you have driver support for all enabled ECC key pair operations - that is,
for each `PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_xxx` macro enabled, the
corresponding `MBEDTLS_PSA_ACCEL_KEY_TYPE_ECC_KEY_PAIR_xxx` macros is also
enabled,
then you can also disable `MBEDTLS_ECP_C`. However, a small subset of it might
still be included in the build, see limitations sub-section below.
In addition, if:
- `MBEDTLS_ECP_C` is fully removed (see limitation sub-section below),
- and support for RSA key types and algorithms is either fully disabled or
fully provided by a driver,
- and support for DH key types and the FFDH algorithm is either disabled or
fully provided by a driver,
then you can also disable `MBEDTLS_BIGNUM_C`.
In such builds, all crypto operations via the PSA Crypto API will work as
usual, as well as the PK, X.509 and TLS modules, with the following exceptions:
- direct calls to APIs from the disabled modules are not possible;
- PK, X.509 and TLS will not support restartable ECC operations (see
limitation sub-section below).
If you want to check at compile-time whether a certain curve is available in
the present build of Mbed TLS, regardless of whether ECC is provided by a
driver or built-in, you should use `PSA_WANT_ECC_xxx` from
`psa/crypto.h`.
Note that for externally-provided drivers, the integrator is responsible for
ensuring the appropriate `MBEDTLS_PSA_ACCEL_xxx` macros are defined. However,
for the p256-m driver that's provided with the library, those macros are
automatically defined when enabling `MBEDTLS_PSA_P256M_DRIVER_ENABLED`.
### Limitations regarding fully removing `ecp.c`
A limited subset of `ecp.c` will still be automatically re-enabled if any of
the following is enabled:
- `MBEDTLS_PK_PARSE_EC_COMPRESSED` - support for parsing ECC keys where the
public part is in compressed format;
- `MBEDTLS_PK_PARSE_EC_EXTENDED` - support for parsing ECC keys where the
curve is identified not by name, but by explicit parameters;
- `PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_DERIVE` - support for deterministic
derivation of an ECC keypair with `psa_key_derivation_output_key()`.
Note: when any of the above options is enabled, a subset of `ecp.c` will
automatically be included in the build in order to support it. Therefore
you can still disable `MBEDTLS_ECP_C` in `mbedtls_config.h` and this will
result in some code size savings, but not as much as when none of the
above features are enabled.
We do have plans to support each of these with `ecp.c` fully removed in the
future, however there is no established timeline. If you're interested, please
let us know, so we can take it into consideration in our planning.
### Limitations regarding restartable / interruptible ECC operations
At the moment, there is no driver support for interruptible operations
(see `psa_sign_hash_start()` + `psa_sign_hash_complete()` etc.) so as a
consequence these are not supported in builds without `MBEDTLS_ECDSA_C`.
Similarly, there is no PSA support for interruptible ECDH operations so these
are not supported without `ECDH_C`. See also limitations regarding restartable
operations in [the documentation of
MBEDTLS_ECP_RESTARTABLE](include/psa/crypto_config.h).
Again, we have plans to support this in the future but not with an established
timeline, please let us know if you're interested.
### Limitations regarding "mixed" builds (driver and built-in)
In order for a build to be driver-only (no built-in implementation), all the
requested algorithms, key types (key operations) and curves must be
accelerated (plus a few other restrictions, see "Limitations regarding fully
removing `ecp.c`" above). However, what if you have an accelerator that only
supports some algorithms, some key types (key operations), or some curves, but
want to have more enabled in you build?
It is possible to have acceleration for only a subset of the requested
algorithms. In this case, the built-in implementation of the accelerated
algorithms will be disabled, provided all the requested curves and key types
that can be used with this algorithm are also declared as accelerated.
There is very limited support for having acceleration for only a subset of the
requested key type operations. The only configuration that's tested is that of
a driver accelerating `PUBLIC_KEY`, `KEY_PAIR_BASIC`, `KEY_PAIR_IMPORT`,
`KEY_PAIR_EXPORT` but not `KEY_PAIR_GENERATE`. (Note: currently the driver
interface does not support `KEY_PAIR_DERIVE`.)
There is limited support for having acceleration for only a subset of the
requested curves. In such builds, only the PSA API is currently tested and
working; there are known issues in PK, and X.509 and TLS are untested.
Finite-field Diffie-Hellman
---------------------------
Support is pretty similar to the "Elliptic-curve cryptography (ECC)" section
above.
Key management and usage can be enabled by means of the usual `PSA_WANT` +
`MBEDTLS_PSA_ACCEL` pairs:
- `[PSA_WANT|MBEDTLS_PSA_ACCEL]_KEY_TYPE_DH_PUBLIC_KEY`;
- `[PSA_WANT|MBEDTLS_PSA_ACCEL]_KEY_TYPE_DH_KEY_PAIR_BASIC`;
- `[PSA_WANT|MBEDTLS_PSA_ACCEL]_KEY_TYPE_DH_KEY_PAIR_IMPORT`;
- `[PSA_WANT|MBEDTLS_PSA_ACCEL]_KEY_TYPE_DH_KEY_PAIR_EXPORT`;
- `[PSA_WANT|MBEDTLS_PSA_ACCEL]_KEY_TYPE_DH_KEY_PAIR_GENERATE`;
The same holds for the associated algorithm:
`[PSA_WANT|MBEDTLS_PSA_ACCEL]_ALG_FFDH` allow builds accelerating FFDH and
removing builtin support.
Note that the PSA API only supports FFDH with RFC 7919 groups.
In theory TLS 1.2 allows custom FFDH groups to be used in DHE key exchanges, but
since DHE-RSA and DHE-PSK key exchanges support has been removed from Mbed TLS,
PSA API limitation to RFC 7919 groups is not a problem.
TLS 1.3 is also fine because the protocol itself does not allows custom FFDH
groups.
RSA
---
It is possible for all RSA operations to be provided only by a driver.
More precisely, if:
- all the RSA algorithms that are enabled (`PSA_WANT_ALG_RSA_*`) are also
accelerated (`MBEDTLS_PSA_ACCEL_ALG_RSA_*`),
- and all the RSA key types that are enabled (`PSA_WANT_KEY_TYPE_RSA_*`) are
also accelerated (`MBEDTLS_PSA_ACCEL_KEY_TYPE_RSA_*`),
then you can disable `MBEDTLS_RSA_C`, `MBEDTLS_PKCS1_V15` and
`MBEDTLS_PKCS1_V21`, and RSA will still work in PSA Crypto.
### Limitations on RSA acceleration
Unlike other mechanisms, for now in configurations with driver-only RSA, only
PSA Crypto works. In particular, PK, X.509 and TLS will _not_ work with
driver-only RSA.
Currently (early 2024) we don't have plans to extend this support. If you're
interested in wider driver-only support for RSA, please let us know.
Ciphers (unauthenticated and AEAD)
----------------------------------
It is possible to have all ciphers and AEAD operations provided only by a
driver. More precisely, for each desired combination of key type and
algorithm/mode you can:
- Enable desired PSA key type(s):
- `PSA_WANT_KEY_TYPE_AES`,
- `PSA_WANT_KEY_TYPE_ARIA`,
- `PSA_WANT_KEY_TYPE_CAMELLIA`,
- `PSA_WANT_KEY_TYPE_CHACHA20`,
- Enable desired PSA algorithm(s):
- Unauthenticated ciphers modes:
- `PSA_WANT_ALG_CBC_NO_PADDING`,
- `PSA_WANT_ALG_CBC_PKCS7`,
- `PSA_WANT_ALG_CCM_STAR_NO_TAG`,
- `PSA_WANT_ALG_CFB`,
- `PSA_WANT_ALG_CTR`,
- `PSA_WANT_ALG_ECB_NO_PADDING`,
- `PSA_WANT_ALG_OFB`,
- `PSA_WANT_ALG_STREAM_CIPHER`.
- AEADs:
- `PSA_WANT_ALG_CCM`,
- `PSA_WANT_ALG_GCM`,
- `PSA_WANT_ALG_CHACHA20_POLY1305`.
- Enable `MBEDTLS_PSA_ACCEL_[KEY_TYPE_xxx|ALG_yyy]` symbol(s) which correspond
to the `PSA_WANT_KEY_TYPE_xxx` and `PSA_WANT_ALG_yyy` of the previous steps.
- Disable builtin support of key types:
- `MBEDTLS_AES_C`,
- `MBEDTLS_ARIA_C`,
- `MBEDTLS_CAMELLIA_C`,
- `MBEDTLS_CHACHA20_C`.
and algorithms/modes:
- `MBEDTLS_CBC_C`,
- `MBEDTLS_CFB_C`,
- `MBEDTLS_CTR_C`,
- `MBEDTLS_OFB_C`,
- `MBEDTLS_XTS_C`,
- `MBEDTLS_CCM_C`,
- `MBEDTLS_GCM_C`,
- `MBEDTLS_CHACHAPOLY_C`,
- `MBEDTLS_NULL_CIPHER`.
Once a key type and related algorithm are accelerated, all the PSA Crypto APIs
will work, as well as X.509 and TLS but some non-PSA APIs will be absent or
have reduced functionality, see [Restrictions](#restrictions) for details.
### Restrictions
- If an algorithm other than CCM and GCM (see
["Partial acceleration for CCM/GCM"](#partial-acceleration-for-ccmgcm) below)
is enabled but not accelerated, then all key types that can be used with it
will need to be built-in.
- If a key type is enabled but not accelerated, then all algorithms that can be
used with it will need to be built-in.
Some legacy modules can't take advantage of PSA drivers yet, and will either
need to be disabled, or have reduced features when the built-in implementations
of some ciphers are removed:
- `MBEDTLS_NIST_KW_C` needs built-in AES: it must be disabled when
`MBEDTLS_AES_C` is disabled.
- `MBEDTLS_CMAC_C` needs built-in AES: it must be disabled when
`MBEDTLS_AES_C` is disabled. (Note: if there is driver support for
CMAC and all compatible key types, then `PSA_WANT_ALG_CMAC` can be enabled
without `MBEDTLS_CMAC_C` and CMAC will be usable with `psa_max_xxx` APIs.)
- `MBEDTLS_CIPHER_C`: the `mbedtls_cipher_xxx()` APIs will only work with
ciphers that are built-in - that is, both the underlying cipher
(eg `MBEDTLS_AES_C`) and the mode (eg `MBEDTLS_CIPHER_MODE_CBC` or
`MBEDTLS_GCM_C`).
- `MBEDTLS_PKCS5_C`: encryption/decryption (PBES2, PBE) will only work with
ciphers that are built-in.
- PEM decryption will only work with ciphers that are built-in.
- PK parse will only be able to parse encrypted keys using built-in ciphers.
Note that if you also disable `MBEDTLS_CIPHER_C`, there will be additional
restrictions, see [Disabling `MBEDTLS_CIPHER_C`](#disabling-mbedtls_cipher_c).
### Legacy <-> PSA matching
Note that the relationship between legacy (i.e. `MBEDTLS_xxx_C`) and PSA
(i.e. `PSA_WANT_xxx`) symbols is not always 1:1. For example:
- ECB mode is always enabled in the legacy configuration for each key type that
allows it (AES, ARIA, Camellia), whereas it must be explicitly enabled
in PSA with `PSA_WANT_ALG_ECB_NO_PADDING`.
- In the legacy API, `MBEDTLS_CHACHA20_C` enables the ChaCha20 stream cipher, and
enabling `MBEDTLS_CHACHAPOLY_C` also enables the ChaCha20-Poly1305 AEAD. In the
PSA API, you need to enable `PSA_KEY_TYPE_CHACHA20` for both, plus
`PSA_ALG_STREAM_CIPHER` or `PSA_ALG_CHACHA20_POLY1305` as desired.
- The legacy symbol `MBEDTLS_CCM_C` adds support for both cipher and AEAD,
whereas in PSA there are 2 different symbols: `PSA_WANT_ALG_CCM_STAR_NO_TAG`
and `PSA_WANT_ALG_CCM`, respectively.
### Partial acceleration for CCM/GCM
[This section depends on #8598 so it might be updated while that PR progresses.]
In case legacy CCM/GCM algorithms are enabled, it is still possible to benefit
from PSA acceleration of the underlying block cipher by enabling support for
ECB mode (`PSA_WANT_ALG_ECB_NO_PADDING` + `MBEDTLS_PSA_ACCEL_ALG_ECB_NO_PADDING`)
together with desired key type(s) (`PSA_WANT_KEY_TYPE_[AES|ARIA|CAMELLIA]` +
`MBEDTLS_PSA_ACCEL_KEY_TYPE_[AES|ARIA|CAMELLIA]`).
In such configurations it is possible to:
- Use CCM and GCM via the PSA Crypto APIs.
- Use CCM and GCM via legacy functions `mbedtls_[ccm|gcm]_xxx()` (but not the
legacy functions `mbedtls_cipher_xxx()`).
- Disable legacy key types (`MBEDTLS_[AES|ARIA|CAMELLIA]_C`) if there is no
other dependency requiring them.
ChaChaPoly has no such feature, so it requires full acceleration (key type +
algorithm) in order to work with a driver.
### CTR-DRBG
The legacy CTR-DRBG module (enabled by `MBEDTLS_CTR_DRBG_C`) can also benefit
from PSA acceleration if both of the following conditions are met:
- The legacy AES module (`MBEDTLS_AES_C`) is not enabled and
- AES is supported on the PSA side together with ECB mode, i.e.
`PSA_WANT_KEY_TYPE_AES` + `PSA_WANT_ALG_ECB_NO_PADDING`.
### Disabling `MBEDTLS_CIPHER_C`
It is possible to save code size by disabling MBEDTLS_CIPHER_C when all of the
following conditions are met:
- The application is not using the `mbedtls_cipher_` API.
- In PSA, all unauthenticated (that is, non-AEAD) ciphers are either disabled or
fully accelerated (that is, all compatible key types are accelerated too).
- `MBEDTLS_NIST_KW` is disabled.
- `MBEDTLS_CMAC_C` is disabled. (Note: support for CMAC in PSA can be provided by
a driver.)
In such a build, everything will work as usual except for the following:
- Encryption/decryption functions from the PKCS5 and PKCS12 module will not be
available (only key derivation functions).
- Parsing of PKCS5- or PKCS12-encrypted keys in PK parse will fail.
Note: AEAD ciphers (CCM, GCM, ChachaPoly) do not have a dependency on
MBEDTLS_CIPHER_C even when using the built-in implementations.
If you also have some ciphers fully accelerated and the built-ins removed, see
[Restrictions](#restrictions) for restrictions related to removing the built-ins.
@@ -0,0 +1,241 @@
Conditional inclusion of cryptographic mechanism through the PSA API in Mbed TLS
================================================================================
This document is a proposed interface for deciding at build time which cryptographic mechanisms to include in the PSA Cryptography interface.
This is currently a proposal for Mbed TLS. It is not currently on track for standardization in PSA.
## Introduction
### Purpose of this specification
The [PSA Cryptography API specification](https://armmbed.github.io/mbed-crypto/psa/#application-programming-interface) specifies the interface between a PSA Cryptography implementation and an application. The interface defines a number of categories of cryptographic algorithms (hashes, MAC, signatures, etc.). In each category, a typical implementation offers many algorithms (e.g. for signatures: RSA-PKCS#1v1.5, RSA-PSS, ECDSA). When building the implementation for a specific use case, it is often desirable to include only a subset of the available cryptographic mechanisms, primarily in order to reduce the code footprint of the compiled system.
The present document proposes a way for an application using the PSA cryptography interface to declare which mechanisms it requires.
### Conditional inclusion of legacy cryptography modules
Mbed TLS offers a way to select which cryptographic mechanisms are included in a build through its configuration file (`mbedtls_config.h`). This mechanism is based on two main sets of symbols: `MBEDTLS_xxx_C` controls the availability of the mechanism to the application, and `MBEDTLS_xxx_ALT` controls the availability of an alternative implementation, so the software implementation is only included if `MBEDTLS_xxx_C` is defined but not `MBEDTLS_xxx_ALT`.
### PSA evolution
In the PSA cryptography interface, the **core** (built-in implementations of cryptographic mechanisms) can be augmented with drivers. **Transparent drivers** replace the built-in implementation of a cryptographic mechanism (or, with **fallback**, the built-in implementation is tried if the driver only has partial support for the mechanism). **Opaque drivers** implement cryptographic mechanisms on keys which are stored in a separate domain such as a secure element, for which the core only does key management and dispatch using wrapped key blobs or key identifiers.
The current model is difficult to adapt to the PSA interface for several reasons. The `MBEDTLS_xxx_ALT` symbols are somewhat inconsistent, and in particular do not work well for asymmetric cryptography. For example, many parts of the ECC code have no `MBEDTLS_xxx_ALT` symbol, so a platform with ECC acceleration that can perform all ECDSA and ECDH operations in the accelerator would still embark the `bignum` module and large parts of the `ecp_curves`, `ecp` and `ecdsa` modules. Also the availability of a transparent driver for a mechanism does not translate directly to `MBEDTLS_xxx` symbols.
### Requirements
[Req.interface] The application can declare which cryptographic mechanisms it needs.
[Req.inclusion] If the application does not require a mechanism, a suitably configured Mbed TLS build must not include it. The granularity of mechanisms must work for typical use cases and has [acceptable limitations](#acceptable-limitations).
[Req.drivers] If a PSA driver is available in the build, a suitably configured Mbed TLS build must not include the corresponding software code (unless a software fallback is needed).
[Req.c] The configuration mechanism consists of C preprocessor definitions, and the build does not require tools other than a C compiler. This is necessary to allow building an application and Mbed TLS in development environments that do not allow third-party tools.
[Req.adaptability] The implementation of the mechanism must be adaptable with future evolution of the PSA cryptography specifications and Mbed TLS. Therefore the interface must remain sufficiently simple and abstract.
### Acceptable limitations
[Limitation.matrix] If a mechanism is defined by a combination of algorithms and key types, for example a block cipher mode (CBC, CTR, CFB, …) and a block permutation (AES, CAMELLIA, ARIA, …), there is no requirement to include only specific combinations.
[Limitation.direction] For mechanisms that have multiple directions (for example encrypt/decrypt, sign/verify), there is no requirement to include only one direction.
[Limitation.size] There is no requirement to include only support for certain key sizes.
[Limitation.multipart] Where there are multiple ways to perform an operation, for example single-part and multi-part, there is no mechanism to select only one or a subset of the possible ways.
## Interface
### PSA Crypto configuration file
The PSA Crypto configuration file `psa/crypto_config.h` defines a series of symbols of the form `PSA_WANT_xxx` where `xxx` describes the feature that the symbol enables. The symbols are documented in the section [“PSA Crypto configuration symbols”](#psa-crypto-configuration-symbols) below.
The necessary software implementations of cryptographic algorithms are included based on the content of the PSA Crypto configuration file. For example, the code in `aes.c` is enabled if `psa/crypto_config.h` contains `PSA_WANT_KEY_TYPE_AES`.
### PSA Crypto configuration symbols
#### Configuration symbol syntax
A PSA Crypto configuration symbol is a C preprocessor symbol whose name starts with `PSA_WANT_`.
* If the symbol is not defined, the corresponding feature is not included.
* If the symbol is defined to a preprocessor expression with the value `1`, the corresponding feature is included.
* If the symbol is defined with a different value, the behavior is currently undefined and reserved for future use.
#### Configuration symbol usage
The presence of a symbol `PSA_WANT_xxx` in the Mbed TLS configuration determines whether a feature is available through the PSA API. These symbols should be used in any place that requires conditional compilation based on the availability of a cryptographic mechanism through the PSA API, including:
* In Mbed TLS test code.
* In Mbed TLS library code, for example in TLS to determine which cipher suites to enable.
* In application code that provides additional features based on cryptographic capabilities, for example additional key parsing and formatting functions, or cipher suite availability for network protocols.
#### Configuration symbol semantics
If a feature is not requested for inclusion in the PSA Crypto configuration file, it may still be included in the build, either because the feature has been requested in some other way, or because the library does not support the exclusion of this feature. Mbed TLS should make a best effort to support the exclusion of all features, but in some cases this may be judged too much effort for too little benefit.
#### Configuration symbols for key types
For most constant or constructor macros of the form `PSA_KEY_TYPE_xxx`, the symbol **`PSA_WANT_KEY_TYPE_xxx`** indicates that support for this key type is desired.
As an exception, starting in Mbed TLS 3.5.0, for `KEY_PAIR` types (that is, private keys for asymmetric cryptography), the feature selection is more fine-grained, with an additional suffix:
* `PSA_WANT_KEY_TYPE_xxx_KEY_PAIR_BASIC` enables basic support for the key type, and in particular support for operations with a key of that type for enabled algorithms. This is automatically enabled if any of the other `PSA_WANT_KEY_TYPE_xxx_KEY_PAIR_yyy` options is enabled.
* `PSA_WANT_KEY_TYPE_xxx_KEY_PAIR_IMPORT` enables support for `psa_import_key` to import a key of that type.
* `PSA_WANT_KEY_TYPE_xxx_KEY_PAIR_GENERATE` enables support for `psa_generate_key` to randomly generate a key of that type.
* `PSA_WANT_KEY_TYPE_xxx_KEY_PAIR_DERIVE` enables support for `psa_key_derivation_output_key` to deterministically derive a key of that type.
* `PSA_WANT_KEY_TYPE_xxx_KEY_PAIR_EXPORT` enables support for `psa_export_key` to export a key of that type.
For asymmetric cryptography, `PSA_WANT_KEY_TYPE_xxx_KEY_PAIR_BASIC` determines whether private-key operations are desired, and `PSA_WANT_KEY_TYPE_xxx_PUBLIC_KEY` determines whether public-key operations are desired. `PSA_WANT_KEY_TYPE_xxx_KEY_PAIR_BASIC` implicitly enables `PSA_WANT_KEY_TYPE_xxx_PUBLIC_KEY`, as well as support for `psa_export_public_key` on the private key: there is no way to only include private-key operations (which typically saves little code).
Note: the implementation is always free to include support for more than what was explicitly requested. (For example, as of Mbed TLS 3.5.0, `PSA_WANT_KEY_TYPE_xxx_KEY_PAIR_BASIC` implicitly enables import and export support for that key type, but this may not be the case in future versions.) Applications should always request support for all operations they need, rather than rely on them being implicitly enabled by the implementation. The only thing that is documented and guaranteed in the future is as follows: `PSA_WANT_KEY_TYPE_xxx_KEY_PAIR_yyy` -> `PSA_WANT_KEY_TYPE_xxx_KEY_PAIR_BASIC` -> `PSA_WANT_KEY_TYPE_xxx_PUBLIC_KEY`.
#### Configuration symbols for elliptic curves
For elliptic curve key types, only the specified curves are included. To include a curve, include a symbol of the form **`PSA_WANT_ECC_family_size`**. For example: `PSA_WANT_ECC_SECP_R1_256` for secp256r1, `PSA_WANT_ECC_MONTGOMERY_255` for Curve25519. It is an error to require an ECC key type but no curve, and Mbed TLS will reject this at compile time.
Rationale: this is a deviation of the general principle that `PSA_ECC_FAMILY_xxx` would have a corresponding symbol `PSA_WANT_ECC_FAMILY_xxx`. This deviation is justified by the fact that it is very common to wish to include only certain curves in a family, and that can lead to a significant gain in code size.
#### Configuration symbols for Diffie-Hellman groups
There are no configuration symbols for Diffie-Hellman groups (`PSA_DH_GROUP_xxx`).
Rationale: Finite-field Diffie-Hellman code is usually not specialized for any particular group, so reducing the number of available groups at compile time only saves a little code space. Constrained implementations tend to omit FFDH anyway, so the small code size gain is not important.
#### Configuration symbols for algorithms
For each constant or constructor macro of the form `PSA_ALG_xxx`, the symbol **`PSA_WANT_ALG_xxx`** indicates that support for this algorithm is desired.
For parametrized algorithms, the `PSA_WANT_ALG_xxx` symbol indicates whether the base mechanism is supported. Parameters must themselves be included through their own `PSA_WANT_ALG_xxx` symbols. It is an error to include a base mechanism without at least one possible parameter, and Mbed TLS will reject this at compile time. For example, `PSA_WANT_ALG_ECDSA` requires the inclusion of randomized ECDSA for all hash algorithms whose corresponding symbol `PSA_WANT_ALG_xxx` is enabled.
## Implementation
### Additional non-public symbols
#### Accounting for transparent drivers
In addition to the [configuration symbols](#psa-crypto-configuration-symbols), we need two parallel or mostly parallel sets of symbols:
* **`MBEDTLS_PSA_ACCEL_xxx`** indicates whether a fully-featured, fallback-free transparent driver is available.
* **`MBEDTLS_PSA_BUILTIN_xxx`** indicates whether the software implementation is needed.
`MBEDTLS_PSA_ACCEL_xxx` is one of the outputs of the transpilation of a driver description, alongside the glue code for calling the drivers.
`MBEDTLS_PSA_BUILTIN_xxx` is enabled when `PSA_WANT_xxx` is enabled and `MBEDTLS_PSA_ACCEL_xxx` is disabled.
These symbols are not part of the public interface of Mbed TLS towards applications or to drivers, regardless of whether the symbols are actually visible.
### Architecture of symbol definitions
#### Definition of configuration symbols
The header file `mbedtls/mbedtls_config.h` defines all the `MBEDTLS_xxx_C` configuration symbols, including the ones deduced from the PSA Crypto configuration. It does this by including the new header file **`mbedtls/config_psa.h`**, which defines the `MBEDTLS_PSA_BUILTIN_xxx` symbols and deduces the corresponding `MBEDTLS_xxx_C` (and other) symbols.
`mbedtls/config_psa.h` includes `psa/crypto_config.h`, the user-editable file that defines application requirements.
#### Summary of definitions of configuration symbols
`mbedtls/config_psa.h` includes `mbedtls/crypto_drivers.h`, a header file generated by the transpilation of the driver descriptions. It defines `MBEDTLS_PSA_ACCEL_xxx` symbols according to the availability of transparent drivers without fallback.
The following table summarizes where symbols are defined depending on the configuration mode.
* (U) indicates a symbol that is defined by the user (application).
* (D) indicates a symbol that is deduced from other symbols by code that ships with Mbed TLS.
* (G) indicates a symbol that is generated from driver descriptions.
| Symbols | |
| ------------------------- | --------------------------------- |
| `MBEDTLS_xxx_C` | `mbedtls/mbedtls_config.h` (U) or |
| | `mbedtls/config_psa.h` (D) |
| `PSA_WANT_xxx` | `psa/crypto_config.h` (U) |
| `MBEDTLS_PSA_BUILTIN_xxx` | `mbedtls/config_psa.h` (D) |
| `MBEDTLS_PSA_ACCEL_xxx` | `mbedtls/crypto_drivers.h` (G) |
#### Visibility of internal symbols
Ideally, the `MBEDTLS_PSA_ACCEL_xxx` and `MBEDTLS_PSA_BUILTIN_xxx` symbols should not be visible to application code or driver code, since they are not part of the public interface of the library. However these symbols are needed to deduce whether to include library modules (for example `MBEDTLS_AES_C` has to be enabled if `MBEDTLS_PSA_BUILTIN_KEY_TYPE_AES` is enabled), which makes it difficult to keep them private.
#### Compile-time checks
The header file **`library/psa_check_config.h`** applies sanity checks to the configuration, throwing `#error` if something is wrong.
A mechanism similar to `mbedtls/check_config.h` detects errors such as enabling ECDSA but no curve.
Since configuration symbols must be undefined or 1, any other value should trigger an `#error`.
#### Automatic generation of preprocessor symbol manipulations
A lot of the preprocessor symbol manipulation is systematic calculations that analyze the configuration. `mbedtls/config_psa.h` and `library/psa_check_config.h` should be generated automatically, in the same manner as `version_features.c`.
### Structure of PSA Crypto library code
#### Conditional inclusion of library entry points
An entry point can be eliminated entirely if no algorithm requires it.
#### Conditional inclusion of mechanism-specific code
Code that is specific to certain key types or to certain algorithms must be guarded by the applicable symbols: `PSA_WANT_xxx` for code that is independent of the application, and `MBEDTLS_PSA_BUILTIN_xxx` for code that calls an Mbed TLS software implementation.
## PSA standardization
### JSON configuration mechanism
At the time of writing, the preferred configuration mechanism for a PSA service is in JSON syntax. The translation from JSON to build instructions is not specified by PSA.
For PSA Crypto, the preferred configuration mechanism would be similar to capability specifications of transparent drivers. The same JSON properties that are used to mean “this driver can perform that mechanism” in a driver description would be used to mean “the application wants to perform that mechanism” in the application configuration.
### From JSON to C
The JSON capability language allows a more fine-grained selection than the C mechanism proposed here. For example, it allows requesting only single-part mechanisms, only certain key sizes, or only certain combinations of algorithms and key types.
The JSON capability language can be translated approximately to the boolean symbol mechanism proposed here. The approximation considers a feature to be enabled if any part of it is enabled. For example, if there is a capability for AES-CTR and one for CAMELLIA-GCM, the translation to boolean symbols will also include AES-GCM and CAMELLIA-CTR. If there is a capability for AES-128, the translation will also include AES-192 and AES-256.
The boolean symbol mechanism proposed here can be translated to a list of JSON capabilities: for each included algorithm, include a capability with that algorithm, the key types that apply to that algorithm, no size restriction, and all the entry points that apply to that algorithm.
## Open questions
### Open questions about the interface
#### Naming of symbols
The names of [elliptic curve symbols](#configuration-symbols-for-elliptic-curves) are a bit weird: `SECP_R1_256` instead of `SECP256R1`, `MONTGOMERY_255` instead of `CURVE25519`. Should we make them more classical, but less systematic?
#### Impossible combinations
What does it mean to have `PSA_WANT_ALG_ECDSA` enabled but with only Curve25519? Is it a mandatory error?
#### Diffie-Hellman
Way to request only specific groups? Not a priority: constrained devices don't do FFDH. Specify it as may change in future versions.
#### Coexistence with the current Mbed TLS configuration
The two mechanisms have very different designs. Is there serious potential for confusion? Do we understand how the combinations work?
### Open questions about the design
#### Algorithms without a key type or vice versa
Is it realistic to mandate a compile-time error if a key type is required, but no matching algorithm, or vice versa? Is it always the right thing, for example if there is an opaque driver that manipulates this key type?
#### Opaque-only mechanisms
If a mechanism should only be supported in an opaque driver, what does the core need to know about it? Do we have all the information we need?
This is especially relevant to suppress a mechanism completely if there is no matching algorithm. For example, if there is no transparent implementation of RSA or ECDSA, `psa_sign_hash` and `psa_verify_hash` may still be needed if there is an opaque signature driver.
### Open questions about the implementation
#### Testability
Is this proposal decently testable? There are a lot of combinations. What combinations should we test?
<!--
Local Variables:
time-stamp-line-limit: 40
time-stamp-start: "Time-stamp: *\""
time-stamp-end: "\""
time-stamp-format: "%04Y/%02m/%02d %02H:%02M:%02S %Z"
time-stamp-time-zone: "GMT"
End:
-->
@@ -0,0 +1,52 @@
PSA Cryptoprocessor driver developer's guide
============================================
**This is a specification of work in progress. The implementation is not yet merged into Mbed TLS.**
For a description of the current state of drivers Mbed TLS, see our [PSA Cryptoprocessor driver development examples](../psa-driver-example-and-guide.html).
This document describes how to write drivers of cryptoprocessors such as accelerators and secure elements for the PSA cryptography subsystem of Mbed TLS.
This document focuses on behavior that is specific to Mbed TLS. For a reference of the interface between Mbed TLS and drivers, refer to the [PSA Cryptoprocessor Driver Interface specification](psa-driver-interface.html).
The interface is not fully implemented in Mbed TLS yet. Please note that the interface may still change: until further notice, we do not guarantee backward compatibility with existing driver code.
## Introduction
### Purpose
The PSA cryptography driver interface provides a way to build Mbed TLS with additional code that implements certain cryptographic primitives. This is primarily intended to support platform-specific hardware.
There are two types of drivers:
* **Transparent** drivers implement cryptographic operations on keys that are provided in cleartext at the beginning of each operation. They are typically used for hardware **accelerators**. When a transparent driver is available for a particular combination of parameters (cryptographic algorithm, key type and size, etc.), it is used instead of the default software implementation. Transparent drivers can also be pure software implementations that are distributed as plug-ins to a PSA Crypto implementation.
* **Opaque** drivers implement cryptographic operations on keys that can only be used inside a protected environment such as a **secure element**, a hardware security module, a smartcard, a secure enclave, etc. An opaque driver is invoked for the specific key location that the driver is registered for: the dispatch is based on the key's lifetime.
### Deliverables for a driver
To write a driver, you need to implement some functions with C linkage, and to declare these functions in a **driver description file**. The driver description file declares which functions the driver implements and what cryptographic mechanisms they support. Depending on the driver type, you may also need to define some C types and macros in a header file.
The concrete syntax for a driver description file is JSON. The structure of this JSON file is specified in the section [“Driver description syntax”](psa-driver-interface.html#driver-description-syntax) of the PSA cryptography driver interface specification.
A driver therefore consists of:
* A driver description file (in JSON format).
* C header files defining the types required by the driver description. The names of these header files is declared in the driver description file.
* An object file compiled for the target platform defining the functions required by the driver description. Implementations may allow drivers to be provided as source files and compiled with the core instead of being pre-compiled.
## Driver C interfaces
Mbed TLS calls driver entry points [as specified in the PSA Cryptography Driver Interface specification](psa-driver-interface.html#driver-entry-points) except as otherwise indicated in this section.
## Mbed TLS extensions
The driver description can include Mbed TLS extensions (marked by the namespace "mbedtls"). Mbed TLS extensions are meant to extend/help integrating the driver into the library's infrastructure.
* `"mbedtls/h_condition"` (optional, string) can include complex preprocessor definitions to conditionally include header files for a given driver.
* `"mbedtls/c_condition"` (optional, string) can include complex preprocessor definitions to conditionally enable dispatch capabilities for a driver.
## Building and testing your driver
<!-- TODO -->
## Dependencies on the Mbed TLS configuration
<!-- TODO -->
@@ -0,0 +1,39 @@
Building Mbed TLS with PSA cryptoprocessor drivers
==================================================
**This is a specification of work in progress. The implementation is not yet merged into Mbed TLS.**
For a description of the current state of drivers Mbed TLS, see our [PSA Cryptoprocessor driver development examples](../psa-driver-example-and-guide.html).
This document describes how to build Mbed TLS with additional cryptoprocessor drivers that follow the PSA cryptoprocessor driver interface.
The interface is not fully implemented in Mbed TLS yet. Please note that the interface may still change: until further notice, we do not guarantee backward compatibility with existing driver code.
## Introduction
The PSA cryptography driver interface provides a way to build Mbed TLS with additional code that implements certain cryptographic primitives. This is primarily intended to support platform-specific hardware.
Note that such drivers are only available through the PSA cryptography API (crypto functions beginning with `psa_`, and X.509 and TLS interfaces that reference PSA types).
Concretely speaking, a driver consists of one or more **driver description files** in JSON format and some code to include in the build. The driver code can either be provided in binary form as additional object file to link, or in source form.
## How to build Mbed TLS with drivers
To build Mbed TLS with drivers:
1. Pass the driver description files through the Make variable `PSA_DRIVERS` when building the library.
```
cd /path/to/mbedtls
make PSA_DRIVERS="/path/to/acme/driver.json /path/to/nadir/driver.json" lib
```
2. Link your application with the implementation of the driver functions.
```
cd /path/to/application
ld myapp.o -L/path/to/acme -lacmedriver -L/path/to/nadir -lnadirdriver -L/path/to/mbedtls -lmbedcrypto
```
<!-- TODO: what if the driver is provided as C source code? -->
<!-- TODO: what about additional include files? -->
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,40 @@
Migrating to an auto generated psa_crypto_driver_wrappers.h file
================================================================
This document describes how to migrate to the auto generated psa_crypto_driver_wrappers.h file.
It is meant to give the library user migration guidelines while the Mbed TLS project tides over multiple minor revs of version 1.0, after which this will be merged into psa-driver-interface.md.
For a practical guide with a description of the current state of drivers Mbed TLS, see our [PSA Cryptoprocessor driver development examples](../psa-driver-example-and-guide.md).
## Introduction
The design of the Driver Wrappers code generation is based on the design proposal https://github.com/Mbed-TLS/mbedtls/pull/5067
During the process of implementation there might be minor variations wrt versioning and broader implementation specific ideas, but the design remains the same.
## Prerequisites
Python3, Jinja2 rev 2.10.1 and jsonschema rev 3.2.0
## Feature Version
1.1
### What's critical for a migrating user
The Driver Wrapper auto generation project is designed to use a python templating library ( Jinja2 ) to render templates based on drivers that are defined using a Driver description JSON file(s).
While that is the larger goal, for version 1.1 here's what's changed
#### What's changed
(1) psa_crypto_driver_wrappers.h will from this point on be auto generated.
(2) The auto generation is based on the template file at **scripts/data_files/driver_templates/psa_crypto_driver_wrappers.h.jinja**.
(3) The driver JSONS to be used for generating the psa_crypto_driver_wrappers.h file can be found at **scripts/data_files/driver_jsons/** as their default location, this path includes the schemas against which the driver schemas will be validated (driver_opaque_schema.json, driver_transparent_schema.json) and a driverlist.json which specifies the drivers to be considered and the order in which they want to be called into. The default location for driverlist.json and driver JSONS can be overloaded by passing an argument --json-dir while running the script generate_driver_wrappers.py.
(4) While the complete driver wrapper templating support is yet to come in, if the library user sees a need to patch psa_crypto_driver_wrappers.h file, the user will need to patch into the template file as needed (psa_crypto_driver_wrappers.h.jinja).
#### How to set your driver up
Please refer to psa-driver-interface.md for information on how a driver schema can be written.
One can also refer to the example test drivers/ JSON schemas under **scripts/data_files/driver_jsons/**.
The JSON file 'driverlist.json' is meant to be edited by the user to reflect the drivers one wants to use on a device. The order in which the drivers are passed is also essential if/when there are multiple transparent drivers on a given system to retain the same order in the templating.
@@ -0,0 +1,179 @@
# PSA Cryptoprocessor driver development examples
As of Mbed TLS 3.4.0, the PSA Driver Interface has only been partially implemented. As a result, the deliverables for writing a driver and the method for integrating a driver with Mbed TLS will vary depending on the operation being accelerated. This document describes how to write and integrate cryptoprocessor drivers depending on which operation or driver type is being implemented.
The `docs/proposed/` directory contains three documents which pertain to the proposed, work-in-progress driver system. The [PSA Driver Interface](https://github.com/Mbed-TLS/mbedtls/blob/development/docs/proposed/psa-driver-interface.md) describes how drivers will interface with Mbed TLS in the future, as well as driver types, operation types, and entry points. As many key terms and concepts used in the examples in this document are defined in the PSA Driver Interface, it is recommended that developers read it prior to starting work on implementing drivers.
The PSA Driver [Developer](https://github.com/Mbed-TLS/mbedtls/blob/development/docs/proposed/psa-driver-developer-guide.md) Guide describes the deliverables for writing a driver that can be used with Mbed TLS, and the PSA Driver [Integration](https://github.com/Mbed-TLS/mbedtls/blob/development/docs/proposed/psa-driver-integration-guide.md) Guide describes how a driver can be built alongside Mbed TLS.
## Contents:
[Background on how Mbed TLS calls drivers](#background-on-how-mbed-tls-calls-drivers)\
[Process for Entry Points where auto-generation is implemented](#process-for-entry-points-where-auto-generation-is-implemented) \
[Process for Entry Points where auto-generation is not implemented](#process-for-entry-points-where-auto-generation-is-not-implemented) \
[Example: Manually integrating a software accelerator alongside Mbed TLS](#example-manually-integrating-a-software-accelerator-alongside-mbed-tls)
## Background on how Mbed TLS calls drivers
The PSA Driver Interface specification specifies which cryptographic operations can be accelerated by third-party drivers. Operations that are completed within one step (one function call), such as verifying a signature, are called *Single-Part Operations*. On the other hand, operations that consist of multiple steps implemented by different functions called sequentially are called *Multi-Part Operations*. Single-part operations implemented by a driver will have one entry point, while multi-part operations will have multiple: one for each step.
There are two types of drivers: *transparent* or *opaque*. See below an excerpt from the PSA Driver Interface specification defining them:
* **Transparent** drivers implement cryptographic operations on keys that are provided in cleartext at the beginning of each operation. They are typically used for hardware **accelerators**. When a transparent driver is available for a particular combination of parameters (cryptographic algorithm, key type and size, etc.), it is used instead of the default software implementation. Transparent drivers can also be pure software implementations that are distributed as plug-ins to a PSA Cryptography implementation (for example, an alternative implementation with different performance characteristics, or a certified implementation).
* **Opaque** drivers implement cryptographic operations on keys that can only be used inside a protected environment such as a **secure element**, a hardware security module, a smartcard, a secure enclave, etc. An opaque driver is invoked for the specific [key location](https://github.com/Mbed-TLS/mbedtls/blob/development/docs/proposed/psa-driver-interface.md#lifetimes-and-locations) that the driver is registered for: the dispatch is based on the key's lifetime.
Mbed TLS contains a **driver dispatch layer** (also called a driver wrapper layer). For each cryptographic operation that supports driver acceleration (or sub-part of a multi-part operation), the library calls the corresponding function in the driver wrapper. Using flags set at compile time, the driver wrapper ascertains whether any present drivers support the operation. When no such driver is present, the built-in library implementation is called as a fallback (if allowed). When a compatible driver is present, the driver wrapper calls the driver entry point function provided by the driver author.
The long-term goal is for the driver dispatch layer to be auto-generated using a JSON driver description file provided by the driver author.
For some cryptographic operations, this auto-generation logic has already been implemented. When accelerating these operations, the instructions in the above documents can be followed. For the remaining operations which do not yet support auto-generation of the driver wrapper, developers will have to manually edit the driver dispatch layer and call their driver's entry point functions from there.
Auto-generation of the driver wrapper is supported for the operation entry points specified in the table below. Certain operations are only permitted for opaque drivers. All other operation entry points do not support auto-generation of the driver wrapper.
| Transparent Driver | Opaque Driver |
|---------------------|---------------------|
| `import_key` | `import_key` |
| `export_public_key` | `export_public_key` |
| | `export_key` |
| | `copy_key` |
| | `get_builtin_key` |
### Process for Entry Points where auto-generation is implemented
If the driver is accelerating operations whose entry points are in the above table, the instructions in the driver [developer](https://github.com/Mbed-TLS/mbedtls/blob/development/docs/proposed/psa-driver-developer-guide.md) and [integration](https://github.com/Mbed-TLS/mbedtls/blob/development/docs/proposed/psa-driver-integration-guide.md) guides should be followed.
There are three deliverables for creating such a driver. These are:
- A driver description file (in JSON format).
- C header files defining the types required by the driver description. The names of these header files are declared in the driver description file.
- An object file compiled for the target platform defining the functions required by the driver description. Implementations may allow drivers to be provided as source files and compiled with the core instead of being pre-compiled.
The Mbed TLS driver tests for the aforementioned entry points provide examples of how these deliverables can be implemented. For sample driver description JSON files, see [`mbedtls_test_transparent_driver.json`](https://github.com/Mbed-TLS/mbedtls/blob/development/tf-psa-crypto/scripts/data_files/driver_jsons/mbedtls_test_transparent_driver.json) or [`mbedtls_test_opaque_driver.json`](https://github.com/Mbed-TLS/mbedtls/blob/development/tf-psa-crypto/scripts/data_files/driver_jsons/mbedtls_test_transparent_driver.json). The header file required by the driver description is [`test_driver.h`](https://github.com/Mbed-TLS/mbedtls/blob/development/framework/tests/include/test/drivers/test_driver.h). As Mbed TLS tests are built from source, there is no object file for the test driver. However, the source for the test driver can be found under `framework/tests/src/drivers`.
### Process for Entry Points where auto-generation is not implemented
If the driver is accelerating operations whose entry points are not present in the table, a different process is followed where the developer manually edits the driver dispatch layer. The following steps describe this process. Steps 1, 2, 3, and 7 only need to be done once *per driver*. Steps 4, 5, and 6 must be done *for each single-part operation* or *for each sub-part of a multi-part operation* implemented by the driver.
**1. Choose a driver prefix and a macro name that indicates whether the driver is enabled** \
A driver prefix is simply a word (often the name of the driver) that all functions/macros associated with the driver should begin with. This is similar to how most functions/macros in Mbed TLS begin with `PSA_XXX/psa_xxx` or `MBEDTLS_XXX/mbedtls_xxx`. The macro name can follow the form `DRIVER_PREFIX_ENABLED` or something similar; it will be used to indicate the driver is available to be called. When building with the driver present, define this macro at compile time.
**2. Include the following in one of the driver header files:**
```
#if defined(DRIVER_PREFIX_ENABLED)
#ifndef PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT
#define PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT
#endif
// other definitions here
#endif
```
**3. Conditionally include header files required by the driver**
Include any header files required by the driver in `psa_crypto_driver_wrappers.h`, placing the `#include` statements within an `#if defined` block which checks if the driver is available:
```
#if defined(DRIVER_PREFIX_ENABLED)
#include ...
#endif
```
**4. For each operation being accelerated, locate the function in the driver dispatch layer that corresponds to the entry point of that operation.** \
The file `psa_crypto_driver_wrappers.h.jinja` and `psa_crypto_driver_wrappers_no_static.c.jinja` contains the driver wrapper functions. For the entry points that have driver wrapper auto-generation implemented, the functions have been replaced with `jinja` templating logic. While the file has a `.jinja` extension, the driver wrapper functions for the remaining entry points are simple C functions. The names of these functions are of the form `psa_driver_wrapper` followed by the entry point name. So, for example, the function `psa_driver_wrapper_sign_hash()` corresponds to the `sign_hash` entry point.
**5. If a driver entry point function has been provided then ensure it has the same signature as the driver wrapper function.** \
If one has not been provided then write one. Its name should begin with the driver prefix, followed by transparent/opaque (depending on driver type), and end with the entry point name. It should have the same signature as the driver wrapper function. The purpose of the entry point function is to take arguments in PSA format for the implemented operation and return outputs/status codes in PSA format. \
*Return Codes:*
* `PSA_SUCCESS`: Successful Execution
* `PSA_ERROR_NOT_SUPPORTED`: Input arguments are correct, but the driver does not support the operation. If a transparent driver returns this then it allows fallback to another driver or software implementation.
* `PSA_ERROR_XXX`: Any other PSA error code, see API documentation
**6. Modify the driver wrapper function** \
Each driver wrapper function contains a `switch` statement which checks the location of the key. If the key is stored in local storage, then operations are performed by a transparent driver. If it is stored elsewhere, then operations are performed by an opaque driver.
* **Transparent drivers:** Calls to driver entry points go under `case PSA_KEY_LOCATION_LOCAL_STORAGE`.
* **Opaque Drivers** Calls to driver entry points go in a separate `case` block corresponding to the key location.
The diagram below shows the layout of a driver wrapper function which can dispatch to two transparent drivers `Foo` and `Bar`, and one opaque driver `Baz`.
```
psa_driver_wrapper_xxx()
├── switch(location)
| |
| ├── case PSA_KEY_LOCATION_LOCAL_STORAGE //transparent driver
| | ├── #if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT)
| | | ├── #if defined(FOO_DRIVER_PREFIX_ENABLED)
| | | | ├── if(//conditions for foo driver capibilities)
| | | | ├── foo_driver_transparent_xxx() //call to driver entry point
| | | | ├── if (status != PSA_ERROR_NOT_SUPPORTED) return status
| | | ├── #endif
| | | ├── #if defined(BAR_DRIVER_PREFIX_ENABLED)
| | | | ├── if(//conditions for bar driver capibilities)
| | | | ├── bar_driver_transparent_xxx() //call to driver entry point
| | | | ├── if (status != PSA_ERROR_NOT_SUPPORTED) return status
| | | ├── #endif
| | ├── #endif
| |
| ├── case SECURE_ELEMENT_LOCATION //opaque driver
| | ├── #if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT)
| | | ├── #if defined(BAZ_DRIVER_PREFIX_ENABLED)
| | | | ├── if(//conditions for baz driver capibilities)
| | | | ├── baz_driver_opaque_xxx() //call to driver entry point
| | | | ├── if (status != PSA_ERROR_NOT_SUPPORTED) return status
| | | ├── #endif
| | ├── #endif
└── return psa_xxx_builtin() // fall back to built in implementation
```
All code related to driver calls within each `case` must be contained between `#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT)` and a corresponding `#endif`. Within this block, each individual driver's compatibility checks and call to the entry point must be contained between `#if defined(DRIVER_PREFIX_ENABLED)` and a corresponding `#endif`. Checks that involve accessing key material using PSA macros, such as determining the key type or number of bits, must be done in the driver wrapper.
**7. Build Mbed TLS with the driver**
This guide assumes you are building Mbed TLS from source alongside your project. If building with a driver present, the chosen driver macro (`DRIVER_PREFIX_ENABLED`) must be defined. This can be done in two ways:
* *At compile time via flags.* This is the preferred option when your project uses Mbed TLS mostly out-of-the-box without significantly modifying the configuration. This can be done by passing the option via `CFLAGS`.
* **Make**:
```
make CFLAGS="-DDRIVER_PREFIX_ENABLED"
```
* **CMake**: CFLAGS must be passed to CMake when it is invoked. Invoke CMake with
```
CFLAGS="-DDRIVER_PREFIX_ENABLED" cmake path/to/source
```
* *Providing a user config file.* This is the preferred option when your project requires a custom configuration that is significantly different to the default. Define the macro for the driver, along with any other custom configurations in a separate header file, then use `config.py`, to set `MBEDTLS_USER_CONFIG_FILE`, providing the path to the defined header file. This will include your custom config file after the default. If you wish to completely replace the default config file, set `MBEDTLS_CONFIG_FILE` instead.
### Example: Manually integrating a software accelerator alongside Mbed TLS
[p256-m](https://github.com/mpg/p256-m) is a minimalistic implementation of ECDH and ECDSA on the NIST P-256 curve, specifically optimized for use in constrained 32-bit environments. It started out as an independent project and has been integrated in Mbed TLS as a PSA transparent driver. The source code of p256-m and the driver entry points is located in the Mbed TLS source tree under `drivers/p256-m`. In this section, we will look at how this integration was done.
The Mbed TLS build system includes the instructions needed to build p256-m. To build with and use p256-m, set the macro `MBEDTLS_PSA_P256M_DRIVER_ENABLED` using `config.py`, then build as usual using make/cmake. From the root of the `mbedtls/` directory, run:
python3 scripts/config.py set MBEDTLS_PSA_P256M_DRIVER_ENABLED
make
(You need extra steps if you want to disable the built-in implementation of ECC algorithms, which includes more features than p256-m. Refer to the documentation of `MBEDTLS_PSA_P256M_DRIVER_ENABLED` and [`driver-only-builds.md`](driver-only-builds.md) for more information.)
The driver prefix for p256-m is `P256`/`p256`.
The p256-m driver implements the following entry points: `"import_key"`, `"export_public_key"`, `"generate_key"`, `"key_agreement"`, `"sign_hash"`, `"verify_hash"`.
There are no entry points for `"sign_message"` and `"verify_message"`, which are not necessary for a sign-and-hash algorithm. The core still implements these functions by doing the hashes and then calling the sign/verify-hash entry points.
The driver entry point functions can be found in `p256m_driver_entrypoints.[hc]`. These functions act as an interface between Mbed TLS and p256-m; converting between PSA and p256-m argument formats and performing sanity checks. If the driver's status codes differ from PSA's, it is recommended to implement a status code translation function. The function `p256_to_psa_error()` converts error codes returned by p256-m into PSA error codes.
The driver wrapper functions in `psa_crypto_driver_wrappers.h.jinja` for all four entry points have also been modified. The code block below shows the additions made to `psa_driver_wrapper_sign_hash()`. In adherence to the defined process, all code related to the driver call is placed within a check for `MBEDTLS_PSA_P256M_DRIVER_ENABLED`. p256-m only supports non-deterministic ECDSA using keys based on NIST P256; these constraints are enforced through checks (see the `if` statement). Checks that involve accessing key attributes, (e.g. checking key type or bits) **must** be performed in the driver wrapper. This is because this information is marked private and may not be accessed outside the library. Other checks can be performed here or in the entry point function. The status returned by the driver is propagated up the call hierarchy **unless** the driver does not support the operation (i.e. return `PSA_ERROR_NOT_SUPPORTED`). In that case the next available driver/built-in implementation is called.
```
#if defined (MBEDTLS_PSA_P256M_DRIVER_ENABLED)
if( PSA_KEY_TYPE_IS_ECC( psa_get_key_type(attributes) ) &&
PSA_ALG_IS_ECDSA(alg) &&
!PSA_ALG_ECDSA_IS_DETERMINISTIC( alg ) &&
PSA_KEY_TYPE_ECC_GET_FAMILY(psa_get_key_type(attributes)) == PSA_ECC_FAMILY_SECP_R1 &&
psa_get_key_bits(attributes) == 256 )
{
status = p256_transparent_sign_hash( attributes,
key_buffer,
key_buffer_size,
alg,
hash,
hash_length,
signature,
signature_size,
signature_length );
if( status != PSA_ERROR_NOT_SUPPORTED )
return( status );
}
#endif /* MBEDTLS_PSA_P256M_DRIVER_ENABLED */
```
Following this, p256-m is now ready to use alongside Mbed TLS as a software accelerator. If `MBEDTLS_PSA_P256M_DRIVER_ENABLED` is set in the config, p256-m's implementations of key generation, ECDH, and ECDSA will be used where applicable.
File diff suppressed because it is too large Load Diff
+1
View File
@@ -0,0 +1 @@
tfpsacrypto.doxyfile
+1
View File
@@ -0,0 +1 @@
doc_mainpage.h
@@ -0,0 +1,51 @@
/**
* \file doc_mainpage.h
*
* \brief Main page documentation file.
*/
/*
*
* Copyright The Mbed TLS Contributors
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
*/
/**
* @mainpage v@TF-PSA-Crypto_VERSION@ source code documentation
*
* This documentation describes the application programming interface (API)
* of TF-PSA-Crypto.
* It was automatically generated from specially formatted comment blocks in
* TF-PSA-Crypto's source code using [Doxygen](https://www.doxygen.nl).
*
* ## Main entry points
*
* You can explore the full API from the “Files” or “Files list” section.
* Locate the header file for the module that you are interested in and
* explore its contents.
*
* Some parts of the API are best explored from the “Topics” or
* “Group list” section.
* This is notably the case for the PSA Cryptography API.
* Note that many parts of the API are not classified under a topic and
* can only be seen through the file structure.
*
* For information on configuring the library at compile time, see the
* configuration header file psa/crypto_config.h.
*
* ## Private interfaces
*
* For technical reasons, the rendered documentation includes elements
* that are not considered part of the stable API. Private elements may
* be removed or may have their semantics changed in a future minor release
* without notice.
*
* The following elements are considered private:
*
* - Any header file whose path contains `/private`, and its contents
* (unless re-exported and documented in another non-private header).
* - Any structure or union field whose name starts with `private_`.
* - Any preprocessor macro that is just listed with its automatically
* rendered parameter list, value and location. Macros are part of
* the API only if their documentation has custom text.
*
*/
@@ -0,0 +1,54 @@
PROJECT_NAME = "TF-PSA-Crypto v@TF-PSA-Crypto_VERSION@"
OUTPUT_DIRECTORY = ../apidoc/
FULL_PATH_NAMES = NO
OPTIMIZE_OUTPUT_FOR_C = YES
EXTRACT_ALL = YES
EXTRACT_PRIVATE = YES
EXTRACT_STATIC = YES
CASE_SENSE_NAMES = NO
INPUT = ../include input ../tests/include/alt-dummy
FILE_PATTERNS = *.h
EXCLUDE = ../include/mbedtls/private
RECURSIVE = YES
EXCLUDE_SYMLINKS = YES
SOURCE_BROWSER = YES
REFERENCED_BY_RELATION = YES
REFERENCES_RELATION = YES
ALPHABETICAL_INDEX = NO
HTML_OUTPUT = .
HTML_TIMESTAMP = YES
SEARCHENGINE = YES
GENERATE_LATEX = NO
MACRO_EXPANSION = YES
EXPAND_ONLY_PREDEF = YES
INCLUDE_PATH = ../include ../drivers/builtin/include
EXPAND_AS_DEFINED = MBEDTLS_PRIVATE
CLASS_DIAGRAMS = NO
HAVE_DOT = YES
DOT_GRAPH_MAX_NODES = 200
MAX_DOT_GRAPH_DEPTH = 1000
DOT_TRANSPARENT = YES
# We mostly use \retval declarations to document which error codes a function
# can return. The reader can follow the hyperlink to the definition of the
# constant to get the generic documentation of that error code. If we don't
# have anything to say about the specific error code for the specific
# function, we can leave the description part of the \retval command blank.
# This is perfectly valid as far as Doxygen is concerned. However, with
# Clang >=15, the -Wdocumentation option emits a warning for empty
# descriptions.
# https://github.com/Mbed-TLS/mbedtls/issues/6960
# https://github.com/llvm/llvm-project/issues/60315
# As a workaround, you can write something like
# \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription
# This avoids writing redundant text and keeps Clang happy.
ALIASES += emptydescription=""
# Define away macros that make parsing definitions difficult.
# MBEDTLS_DEPRECATED is not included in this list as it's important to
# display deprecated status in the documentation.
PREDEFINED = "MBEDTLS_CHECK_RETURN_CRITICAL=" \
"MBEDTLS_CHECK_RETURN_TYPICAL=" \
"MBEDTLS_CHECK_RETURN_OPTIONAL=" \
"MBEDTLS_PRINTF_ATTRIBUTE(a,b)=" \
"__DOXYGEN__" \
+116
View File
@@ -0,0 +1,116 @@
set(drivers
builtin
everest
p256-m
pqcp
)
# Drivers currently depend on each other through the indirect inclusion of
# `crypto_driver_contexts_*.h` headers, so all driver include paths must be
# visible when building each driver. TF_PSA_CRYPTO_DRIVERS_INCLUDE_DIRS
# provides these include paths.
set(TF_PSA_CRYPTO_DRIVERS_INCLUDE_DIRS
${CMAKE_CURRENT_SOURCE_DIR}/builtin/include
${CMAKE_CURRENT_SOURCE_DIR}/everest/include
${CMAKE_CURRENT_SOURCE_DIR}/p256-m
${CMAKE_CURRENT_SOURCE_DIR}/pqcp/include
)
if(CMAKE_COMPILER_IS_MSVC)
if(MSVC_STATIC_RUNTIME)
foreach(flag_var
CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE
CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO
CMAKE_C_FLAGS_CHECK)
string(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}")
endforeach(flag_var)
endif()
endif()
if(TF_PSA_CRYPTO_TEST_DRIVER)
# Use `libtestdriver1` as the driver name to align with the name used so
# far for driver dispatch testing in Mbed TLS. This allows to reuse most
# of the test driver code as it is.
list(APPEND drivers libtestdriver1)
list(APPEND TF_PSA_CRYPTO_DRIVERS_INCLUDE_DIRS ${CMAKE_CURRENT_BINARY_DIR}/libtestdriver1/include)
# TF_PSA_CRYPTO_TEST_DRIVER_GENERATION_TARGETS:
# The list of targets involved in generating the test drivers. Test code
# includes driver headers, and drivers indirectly include headers from
# other drivers, so driver and test object targets must not start building
# until test driver generation has completed. The variable
# TF_PSA_CRYPTO_TEST_DRIVER_GENERATION_TARGETS provides the list of generation
# targets that driver and test targets should depend on.
set(TF_PSA_CRYPTO_TEST_DRIVER_GENERATION_TARGETS "libtestdriver1_generation")
set(TF_PSA_CRYPTO_TEST_DRIVER_GENERATION_TARGETS
"${TF_PSA_CRYPTO_TEST_DRIVER_GENERATION_TARGETS}" PARENT_SCOPE)
# In the build tree, create a `drivers/libtestdriver1` directory, copy
# `tests/scripts/libtestdriver1.cmake` to it as `CMakeLists.txt`, and add
# that directory as a subdirectory. This causes the test driver tree
# defined in `libtestdriver1.cmake` to be configured and built as part of
# the main build. The libtestdriver1 code is generated and compiled in the
# build tree, similarly to an in-source-tree build.
file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/libtestdriver1)
configure_file(
${PROJECT_SOURCE_DIR}/tests/scripts/libtestdriver1.cmake
${CMAKE_CURRENT_BINARY_DIR}/libtestdriver1/CMakeLists.txt
COPYONLY
)
add_subdirectory(${CMAKE_CURRENT_BINARY_DIR}/libtestdriver1
${CMAKE_CURRENT_BINARY_DIR}/libtestdriver1)
endif()
# Lists of driver targets.
#
# TF_PSA_CRYPTO_DRIVER_STATIC_TARGETS:
# The list of driver targets to use when building the static library
# (defined only if USE_STATIC_TF_PSA_CRYPTO_LIBRARY is enabled).
#
# TF_PSA_CRYPTO_DRIVER_TARGETS:
# The list of driver targets to use when building the shared library.
# If shared-library support is disabled, this list is identical to
# TF_PSA_CRYPTO_DRIVER_STATIC_TARGETS.
#
# Notes:
# - TF_PSA_CRYPTO_DRIVER_TARGETS is not limited to shared builds; it may be
# used whenever the static/shared distinction does not matter (e.g. when
# collecting include directories from driver targets).
#
set(driver_targets "")
foreach(driver ${drivers})
list(APPEND driver_targets "${TF_PSA_CRYPTO_TARGET_PREFIX}${driver}")
endforeach()
if (USE_STATIC_TF_PSA_CRYPTO_LIBRARY)
if(NOT USE_SHARED_TF_PSA_CRYPTO_LIBRARY)
set(driver_static_targets ${driver_targets})
else()
set(driver_static_targets "")
foreach(target ${driver_targets})
list(APPEND driver_static_targets "${target}_static")
endforeach()
endif()
endif()
set(TF_PSA_CRYPTO_DRIVERS "${drivers}" PARENT_SCOPE)
set(TF_PSA_CRYPTO_DRIVER_STATIC_TARGETS "${driver_static_targets}" PARENT_SCOPE)
set(TF_PSA_CRYPTO_DRIVER_TARGETS "${driver_targets}" PARENT_SCOPE)
add_subdirectory(everest)
add_subdirectory(p256-m)
add_subdirectory(builtin)
add_subdirectory(pqcp)
#
# Add to the list of directories with internal headers the driver ones that
# must be visible by core and tests code.
# Done after adding the driver sub-directories as drivers do not need to see
# each other internal headers.
#
list(APPEND TF_PSA_CRYPTO_PRIVATE_INCLUDE_DIRS
${CMAKE_CURRENT_SOURCE_DIR}/builtin/src
${CMAKE_CURRENT_SOURCE_DIR}/pqcp/src
)
set(TF_PSA_CRYPTO_PRIVATE_INCLUDE_DIRS
"${TF_PSA_CRYPTO_PRIVATE_INCLUDE_DIRS}" PARENT_SCOPE)
@@ -0,0 +1,3 @@
file(GLOB builtin_src_files RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} src/*.c)
set(tf_psa_crypto_driver "builtin")
include(${PROJECT_SOURCE_DIR}/drivers/driver.cmake)
@@ -0,0 +1,607 @@
/**
* \file aes.h
*
* \brief This file contains AES definitions and functions.
*
* The Advanced Encryption Standard (AES) specifies a FIPS-approved
* cryptographic algorithm that can be used to protect electronic
* data.
*
* The AES algorithm is a symmetric block cipher that can
* encrypt and decrypt information. For more information, see
* <em>FIPS Publication 197: Advanced Encryption Standard</em> and
* <em>ISO/IEC 18033-2:2006: Information technology -- Security
* techniques -- Encryption algorithms -- Part 2: Asymmetric
* ciphers</em>.
*
* The AES-XTS block mode is standardized by NIST SP 800-38E
* <https://nvlpubs.nist.gov/nistpubs/legacy/sp/nistspecialpublication800-38e.pdf>
* and described in detail by IEEE P1619
* <https://ieeexplore.ieee.org/servlet/opac?punumber=4375278>.
*/
/*
* Copyright The Mbed TLS Contributors
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
*/
#ifndef TF_PSA_CRYPTO_MBEDTLS_PRIVATE_AES_H
#define TF_PSA_CRYPTO_MBEDTLS_PRIVATE_AES_H
#include "mbedtls/private_access.h"
#include "tf-psa-crypto/build_info.h"
#include "mbedtls/platform_util.h"
#include <stddef.h>
#include <stdint.h>
#if defined(MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS)
/* aesni.c relies on these values! */
#define MBEDTLS_AES_ENCRYPT 1 /**< AES encryption. */
#define MBEDTLS_AES_DECRYPT 0 /**< AES decryption. */
#endif /* MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS */
/* Error codes in range 0x0020-0x0022 */
/** Invalid key length. */
#define MBEDTLS_ERR_AES_INVALID_KEY_LENGTH -0x0020
/** Invalid data input length. */
#define MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH -0x0022
/** Invalid input data. */
#define MBEDTLS_ERR_AES_BAD_INPUT_DATA PSA_ERROR_INVALID_ARGUMENT
#ifdef __cplusplus
extern "C" {
#endif
/**
* \brief The AES context-type definition.
*/
typedef struct mbedtls_aes_context {
int MBEDTLS_PRIVATE(nr); /*!< The number of rounds. */
size_t MBEDTLS_PRIVATE(rk_offset); /*!< The offset in array elements to AES
round keys in the buffer. */
#if defined(MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH)
uint32_t MBEDTLS_PRIVATE(buf)[44]; /*!< Aligned data buffer to hold
10 round keys for 128-bit case. */
#else
uint32_t MBEDTLS_PRIVATE(buf)[68]; /*!< Unaligned data buffer. This buffer can
hold 32 extra Bytes, which can be used for
simplifying key expansion in the 256-bit
case by generating an extra round key. */
#endif /* MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH */
}
mbedtls_aes_context;
#if defined(MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS)
#if defined(MBEDTLS_CIPHER_MODE_XTS)
/**
* \brief The AES XTS context-type definition.
*/
typedef struct mbedtls_aes_xts_context {
mbedtls_aes_context MBEDTLS_PRIVATE(crypt); /*!< The AES context to use for AES block
encryption or decryption. */
mbedtls_aes_context MBEDTLS_PRIVATE(tweak); /*!< The AES context used for tweak
computation. */
} mbedtls_aes_xts_context;
#endif /* MBEDTLS_CIPHER_MODE_XTS */
typedef enum {
MBEDTLS_AES_IMP_UNKNOWN = -1,
MBEDTLS_AES_IMP_SOFTWARE,
MBEDTLS_AES_IMP_AESCE,
MBEDTLS_AES_IMP_AESNI_ASM,
MBEDTLS_AES_IMP_AESNI_INTRINSICS,
} mbedtls_aes_implementation;
/**
* \brief This function initializes the specified AES context.
*
* It must be the first API called before using
* the context.
*
* \param ctx The AES context to initialize. This must not be \c NULL.
*/
void mbedtls_aes_init(mbedtls_aes_context *ctx);
/**
* \brief This function releases and clears the specified AES context.
*
* \param ctx The AES context to clear.
* If this is \c NULL, this function does nothing.
* Otherwise, the context must have been at least initialized.
*/
void mbedtls_aes_free(mbedtls_aes_context *ctx);
/**
* \brief This function returns the AES implementation.
*
* The options are: unknown, software AES, AESCE, AESNI
* assembly, and AESNI intrinsics.
*
* \return The enum corresponding to the AES implementation.
*/
mbedtls_aes_implementation mbedtls_aes_get_implementation(void);
#if defined(MBEDTLS_CIPHER_MODE_XTS)
/**
* \brief This function initializes the specified AES XTS context.
*
* It must be the first API called before using
* the context.
*
* \param ctx The AES XTS context to initialize. This must not be \c NULL.
*/
void mbedtls_aes_xts_init(mbedtls_aes_xts_context *ctx);
/**
* \brief This function releases and clears the specified AES XTS context.
*
* \param ctx The AES XTS context to clear.
* If this is \c NULL, this function does nothing.
* Otherwise, the context must have been at least initialized.
*/
void mbedtls_aes_xts_free(mbedtls_aes_xts_context *ctx);
#endif /* MBEDTLS_CIPHER_MODE_XTS */
/**
* \brief This function sets the encryption key.
*
* \param ctx The AES context to which the key should be bound.
* It must be initialized.
* \param key The encryption key.
* This must be a readable buffer of size \p keybits bits.
* \param keybits The size of data passed in bits. Valid options are:
* <ul><li>128 bits</li>
* <li>192 bits</li>
* <li>256 bits</li></ul>
*
* \return \c 0 on success.
* \return #MBEDTLS_ERR_AES_INVALID_KEY_LENGTH on failure.
*/
MBEDTLS_CHECK_RETURN_TYPICAL
int mbedtls_aes_setkey_enc(mbedtls_aes_context *ctx, const unsigned char *key,
unsigned int keybits);
#if !defined(MBEDTLS_BLOCK_CIPHER_NO_DECRYPT)
/**
* \brief This function sets the decryption key.
*
* \param ctx The AES context to which the key should be bound.
* It must be initialized.
* \param key The decryption key.
* This must be a readable buffer of size \p keybits bits.
* \param keybits The size of data passed. Valid options are:
* <ul><li>128 bits</li>
* <li>192 bits</li>
* <li>256 bits</li></ul>
*
* \return \c 0 on success.
* \return #MBEDTLS_ERR_AES_INVALID_KEY_LENGTH on failure.
*/
MBEDTLS_CHECK_RETURN_TYPICAL
int mbedtls_aes_setkey_dec(mbedtls_aes_context *ctx, const unsigned char *key,
unsigned int keybits);
#endif /* !MBEDTLS_BLOCK_CIPHER_NO_DECRYPT */
#if defined(MBEDTLS_CIPHER_MODE_XTS)
/**
* \brief This function prepares an XTS context for encryption and
* sets the encryption key.
*
* \param ctx The AES XTS context to which the key should be bound.
* It must be initialized.
* \param key The encryption key. This is comprised of the XTS key1
* concatenated with the XTS key2.
* This must be a readable buffer of size \p keybits bits.
* \param keybits The size of \p key passed in bits. Valid options are:
* <ul><li>256 bits (each of key1 and key2 is a 128-bit key)</li>
* <li>512 bits (each of key1 and key2 is a 256-bit key)</li></ul>
*
* \return \c 0 on success.
* \return #MBEDTLS_ERR_AES_INVALID_KEY_LENGTH on failure.
*/
MBEDTLS_CHECK_RETURN_TYPICAL
int mbedtls_aes_xts_setkey_enc(mbedtls_aes_xts_context *ctx,
const unsigned char *key,
unsigned int keybits);
/**
* \brief This function prepares an XTS context for decryption and
* sets the decryption key.
*
* \param ctx The AES XTS context to which the key should be bound.
* It must be initialized.
* \param key The decryption key. This is comprised of the XTS key1
* concatenated with the XTS key2.
* This must be a readable buffer of size \p keybits bits.
* \param keybits The size of \p key passed in bits. Valid options are:
* <ul><li>256 bits (each of key1 and key2 is a 128-bit key)</li>
* <li>512 bits (each of key1 and key2 is a 256-bit key)</li></ul>
*
* \return \c 0 on success.
* \return #MBEDTLS_ERR_AES_INVALID_KEY_LENGTH on failure.
*/
MBEDTLS_CHECK_RETURN_TYPICAL
int mbedtls_aes_xts_setkey_dec(mbedtls_aes_xts_context *ctx,
const unsigned char *key,
unsigned int keybits);
#endif /* MBEDTLS_CIPHER_MODE_XTS */
/**
* \brief This function performs an AES single-block encryption or
* decryption operation.
*
* It performs the operation defined in the \p mode parameter
* (encrypt or decrypt), on the input data buffer defined in
* the \p input parameter.
*
* mbedtls_aes_init(), and either mbedtls_aes_setkey_enc() or
* mbedtls_aes_setkey_dec() must be called before the first
* call to this API with the same context.
*
* \param ctx The AES context to use for encryption or decryption.
* It must be initialized and bound to a key.
* \param mode The AES operation: MBEDTLS_AES_ENCRYPT or
* MBEDTLS_AES_DECRYPT.
* \param input The buffer holding the input data.
* It must be readable and at least \c 16 Bytes long.
* \param output The buffer where the output data will be written.
* It must be writeable and at least \c 16 Bytes long.
* \return \c 0 on success.
*/
MBEDTLS_CHECK_RETURN_TYPICAL
int mbedtls_aes_crypt_ecb(mbedtls_aes_context *ctx,
int mode,
const unsigned char input[16],
unsigned char output[16]);
#if defined(MBEDTLS_CIPHER_MODE_CBC)
/**
* \brief This function performs an AES-CBC encryption or decryption operation
* on full blocks.
*
* It performs the operation defined in the \p mode
* parameter (encrypt/decrypt), on the input data buffer defined in
* the \p input parameter.
*
* It can be called as many times as needed, until all the input
* data is processed. mbedtls_aes_init(), and either
* mbedtls_aes_setkey_enc() or mbedtls_aes_setkey_dec() must be called
* before the first call to this API with the same context.
*
* \note This function operates on full blocks, that is, the input size
* must be a multiple of the AES block size of \c 16 Bytes.
*
* \note Upon exit, the content of the IV is updated so that you can
* call the same function again on the next
* block(s) of data and get the same result as if it was
* encrypted in one call. This allows a "streaming" usage.
* If you need to retain the contents of the IV, you should
* either save it manually or use the cipher module instead.
*
*
* \param ctx The AES context to use for encryption or decryption.
* It must be initialized and bound to a key.
* \param mode The AES operation: MBEDTLS_AES_ENCRYPT or
* MBEDTLS_AES_DECRYPT.
* \param length The length of the input data in Bytes. This must be a
* multiple of the block size (\c 16 Bytes).
* \param iv Initialization vector (updated after use).
* It must be a readable and writeable buffer of \c 16 Bytes.
* \param input The buffer holding the input data.
* It must be readable and of size \p length Bytes.
* \param output The buffer holding the output data.
* It must be writeable and of size \p length Bytes.
*
* \return \c 0 on success.
* \return #MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH
* on failure.
*/
MBEDTLS_CHECK_RETURN_TYPICAL
int mbedtls_aes_crypt_cbc(mbedtls_aes_context *ctx,
int mode,
size_t length,
unsigned char iv[16],
const unsigned char *input,
unsigned char *output);
#endif /* MBEDTLS_CIPHER_MODE_CBC */
#if defined(MBEDTLS_CIPHER_MODE_XTS)
/**
* \brief This function performs an AES-XTS encryption or decryption
* operation for an entire XTS data unit.
*
* AES-XTS encrypts or decrypts blocks based on their location as
* defined by a data unit number. The data unit number must be
* provided by \p data_unit.
*
* NIST SP 800-38E limits the maximum size of a data unit to 2^20
* AES blocks. If the data unit is larger than this, this function
* returns #MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH.
*
* \param ctx The AES XTS context to use for AES XTS operations.
* It must be initialized and bound to a key.
* \param mode The AES operation: MBEDTLS_AES_ENCRYPT or
* MBEDTLS_AES_DECRYPT.
* \param length The length of a data unit in Bytes. This can be any
* length between 16 bytes and 2^24 bytes inclusive
* (between 1 and 2^20 block cipher blocks).
* \param data_unit The address of the data unit encoded as an array of 16
* bytes in little-endian format. For disk encryption, this
* is typically the index of the block device sector that
* contains the data.
* \param input The buffer holding the input data (which is an entire
* data unit). This function reads \p length Bytes from \p
* input.
* \param output The buffer holding the output data (which is an entire
* data unit). This function writes \p length Bytes to \p
* output.
*
* \return \c 0 on success.
* \return #MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH if \p length is
* smaller than an AES block in size (16 Bytes) or if \p
* length is larger than 2^20 blocks (16 MiB).
*/
MBEDTLS_CHECK_RETURN_TYPICAL
int mbedtls_aes_crypt_xts(mbedtls_aes_xts_context *ctx,
int mode,
size_t length,
const unsigned char data_unit[16],
const unsigned char *input,
unsigned char *output);
#endif /* MBEDTLS_CIPHER_MODE_XTS */
#if defined(MBEDTLS_CIPHER_MODE_CFB)
/**
* \brief This function performs an AES-CFB128 encryption or decryption
* operation.
*
* It performs the operation defined in the \p mode
* parameter (encrypt or decrypt), on the input data buffer
* defined in the \p input parameter.
*
* For CFB, you must set up the context with mbedtls_aes_setkey_enc(),
* regardless of whether you are performing an encryption or decryption
* operation, that is, regardless of the \p mode parameter. This is
* because CFB mode uses the same key schedule for encryption and
* decryption.
*
* \note Upon exit, the content of the IV is updated so that you can
* call the same function again on the next
* block(s) of data and get the same result as if it was
* encrypted in one call. This allows a "streaming" usage.
* If you need to retain the contents of the
* IV, you must either save it manually or use the cipher
* module instead.
*
*
* \param ctx The AES context to use for encryption or decryption.
* It must be initialized and bound to a key.
* \param mode The AES operation: MBEDTLS_AES_ENCRYPT or
* MBEDTLS_AES_DECRYPT.
* \param length The length of the input data in Bytes.
* \param iv_off The offset in IV (updated after use).
* It must point to a valid \c size_t.
* \param iv The initialization vector (updated after use).
* It must be a readable and writeable buffer of \c 16 Bytes.
* \param input The buffer holding the input data.
* It must be readable and of size \p length Bytes.
* \param output The buffer holding the output data.
* It must be writeable and of size \p length Bytes.
*
* \return \c 0 on success.
*/
MBEDTLS_CHECK_RETURN_TYPICAL
int mbedtls_aes_crypt_cfb128(mbedtls_aes_context *ctx,
int mode,
size_t length,
size_t *iv_off,
unsigned char iv[16],
const unsigned char *input,
unsigned char *output);
/**
* \brief This function performs an AES-CFB8 encryption or decryption
* operation.
*
* It performs the operation defined in the \p mode
* parameter (encrypt/decrypt), on the input data buffer defined
* in the \p input parameter.
*
* Due to the nature of CFB, you must use the same key schedule for
* both encryption and decryption operations. Therefore, you must
* use the context initialized with mbedtls_aes_setkey_enc() for
* both MBEDTLS_AES_ENCRYPT and MBEDTLS_AES_DECRYPT.
*
* \note Upon exit, the content of the IV is updated so that you can
* call the same function again on the next
* block(s) of data and get the same result as if it was
* encrypted in one call. This allows a "streaming" usage.
* If you need to retain the contents of the
* IV, you should either save it manually or use the cipher
* module instead.
*
*
* \param ctx The AES context to use for encryption or decryption.
* It must be initialized and bound to a key.
* \param mode The AES operation: MBEDTLS_AES_ENCRYPT or
* MBEDTLS_AES_DECRYPT
* \param length The length of the input data.
* \param iv The initialization vector (updated after use).
* It must be a readable and writeable buffer of \c 16 Bytes.
* \param input The buffer holding the input data.
* It must be readable and of size \p length Bytes.
* \param output The buffer holding the output data.
* It must be writeable and of size \p length Bytes.
*
* \return \c 0 on success.
*/
MBEDTLS_CHECK_RETURN_TYPICAL
int mbedtls_aes_crypt_cfb8(mbedtls_aes_context *ctx,
int mode,
size_t length,
unsigned char iv[16],
const unsigned char *input,
unsigned char *output);
#endif /*MBEDTLS_CIPHER_MODE_CFB */
#if defined(MBEDTLS_CIPHER_MODE_OFB)
/**
* \brief This function performs an AES-OFB (Output Feedback Mode)
* encryption or decryption operation.
*
* For OFB, you must set up the context with
* mbedtls_aes_setkey_enc(), regardless of whether you are
* performing an encryption or decryption operation. This is
* because OFB mode uses the same key schedule for encryption and
* decryption.
*
* The OFB operation is identical for encryption or decryption,
* therefore no operation mode needs to be specified.
*
* \note Upon exit, the content of iv, the Initialisation Vector, is
* updated so that you can call the same function again on the next
* block(s) of data and get the same result as if it was encrypted
* in one call. This allows a "streaming" usage, by initialising
* iv_off to 0 before the first call, and preserving its value
* between calls.
*
* For non-streaming use, the iv should be initialised on each call
* to a unique value, and iv_off set to 0 on each call.
*
* If you need to retain the contents of the initialisation vector,
* you must either save it manually or use the cipher module
* instead.
*
* \warning For the OFB mode, the initialisation vector must be unique
* every encryption operation. Reuse of an initialisation vector
* will compromise security.
*
* \param ctx The AES context to use for encryption or decryption.
* It must be initialized and bound to a key.
* \param length The length of the input data.
* \param iv_off The offset in IV (updated after use).
* It must point to a valid \c size_t.
* \param iv The initialization vector (updated after use).
* It must be a readable and writeable buffer of \c 16 Bytes.
* \param input The buffer holding the input data.
* It must be readable and of size \p length Bytes.
* \param output The buffer holding the output data.
* It must be writeable and of size \p length Bytes.
*
* \return \c 0 on success.
*/
MBEDTLS_CHECK_RETURN_TYPICAL
int mbedtls_aes_crypt_ofb(mbedtls_aes_context *ctx,
size_t length,
size_t *iv_off,
unsigned char iv[16],
const unsigned char *input,
unsigned char *output);
#endif /* MBEDTLS_CIPHER_MODE_OFB */
#if defined(MBEDTLS_CIPHER_MODE_CTR)
/**
* \brief This function performs an AES-CTR encryption or decryption
* operation.
*
* Due to the nature of CTR, you must use the same key schedule
* for both encryption and decryption operations. Therefore, you
* must use the context initialized with mbedtls_aes_setkey_enc()
* for both MBEDTLS_AES_ENCRYPT and MBEDTLS_AES_DECRYPT.
*
* \warning You must never reuse a nonce value with the same key. Doing so
* would void the encryption for the two messages encrypted with
* the same nonce and key.
*
* There are two common strategies for managing nonces with CTR:
*
* 1. You can handle everything as a single message processed over
* successive calls to this function. In that case, you want to
* set \p nonce_counter and \p nc_off to 0 for the first call, and
* then preserve the values of \p nonce_counter, \p nc_off and \p
* stream_block across calls to this function as they will be
* updated by this function.
*
* With this strategy, you must not encrypt more than 2**128
* blocks of data with the same key.
*
* 2. You can encrypt separate messages by dividing the \p
* nonce_counter buffer in two areas: the first one used for a
* per-message nonce, handled by yourself, and the second one
* updated by this function internally.
*
* For example, you might reserve the first 12 bytes for the
* per-message nonce, and the last 4 bytes for internal use. In that
* case, before calling this function on a new message you need to
* set the first 12 bytes of \p nonce_counter to your chosen nonce
* value, the last 4 to 0, and \p nc_off to 0 (which will cause \p
* stream_block to be ignored). That way, you can encrypt at most
* 2**96 messages of up to 2**32 blocks each with the same key.
*
* The per-message nonce (or information sufficient to reconstruct
* it) needs to be communicated with the ciphertext and must be unique.
* The recommended way to ensure uniqueness is to use a message
* counter. An alternative is to generate random nonces, but this
* limits the number of messages that can be securely encrypted:
* for example, with 96-bit random nonces, you should not encrypt
* more than 2**32 messages with the same key.
*
* Note that for both strategies, sizes are measured in blocks and
* that an AES block is 16 bytes.
*
* \warning Upon return, \p stream_block contains sensitive data. Its
* content must not be written to insecure storage and should be
* securely discarded as soon as it's no longer needed.
*
* \param ctx The AES context to use for encryption or decryption.
* It must be initialized and bound to a key.
* \param length The length of the input data.
* \param nc_off The offset in the current \p stream_block, for
* resuming within the current cipher stream. The
* offset pointer should be 0 at the start of a stream.
* It must point to a valid \c size_t.
* \param nonce_counter The 128-bit nonce and counter.
* It must be a readable-writeable buffer of \c 16 Bytes.
* \param stream_block The saved stream block for resuming. This is
* overwritten by the function.
* It must be a readable-writeable buffer of \c 16 Bytes.
* \param input The buffer holding the input data.
* It must be readable and of size \p length Bytes.
* \param output The buffer holding the output data.
* It must be writeable and of size \p length Bytes.
*
* \return \c 0 on success.
*/
MBEDTLS_CHECK_RETURN_TYPICAL
int mbedtls_aes_crypt_ctr(mbedtls_aes_context *ctx,
size_t length,
size_t *nc_off,
unsigned char nonce_counter[16],
unsigned char stream_block[16],
const unsigned char *input,
unsigned char *output);
#endif /* MBEDTLS_CIPHER_MODE_CTR */
#if defined(MBEDTLS_SELF_TEST)
/**
* \brief Checkup routine.
*
* \return \c 0 on success.
* \return \c 1 on failure.
*/
MBEDTLS_CHECK_RETURN_CRITICAL
int mbedtls_aes_self_test(int verbose);
#endif /* MBEDTLS_SELF_TEST */
#endif /* MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS */
#ifdef __cplusplus
}
#endif
#endif /* TF_PSA_CRYPTO_MBEDTLS_PRIVATE_AES_H */
@@ -0,0 +1,342 @@
/**
* \file aria.h
*
* \brief ARIA block cipher
*
* The ARIA algorithm is a symmetric block cipher that can encrypt and
* decrypt information. It is defined by the Korean Agency for
* Technology and Standards (KATS) in <em>KS X 1213:2004</em> (in
* Korean, but see http://210.104.33.10/ARIA/index-e.html in English)
* and also described by the IETF in <em>RFC 5794</em>.
*/
/*
* Copyright The Mbed TLS Contributors
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
*/
#ifndef TF_PSA_CRYPTO_MBEDTLS_PRIVATE_ARIA_H
#define TF_PSA_CRYPTO_MBEDTLS_PRIVATE_ARIA_H
#include "mbedtls/private_access.h"
#include "tf-psa-crypto/build_info.h"
#include <stddef.h>
#include <stdint.h>
#include "mbedtls/platform_util.h"
#if defined(MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS)
#define MBEDTLS_ARIA_ENCRYPT 1 /**< ARIA encryption. */
#define MBEDTLS_ARIA_DECRYPT 0 /**< ARIA decryption. */
#endif /* MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS */
#define MBEDTLS_ARIA_BLOCKSIZE 16 /**< ARIA block size in bytes. */
#define MBEDTLS_ARIA_MAX_ROUNDS 16 /**< Maximum number of rounds in ARIA. */
#if defined(MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS)
#define MBEDTLS_ARIA_MAX_KEYSIZE 32 /**< Maximum size of an ARIA key in bytes. */
#endif /* MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS */
/** Bad input data. */
#define MBEDTLS_ERR_ARIA_BAD_INPUT_DATA PSA_ERROR_INVALID_ARGUMENT
/** Invalid data input length. */
#define MBEDTLS_ERR_ARIA_INVALID_INPUT_LENGTH -0x005E
#ifdef __cplusplus
extern "C" {
#endif
/**
* \brief The ARIA context-type definition.
*/
typedef struct mbedtls_aria_context {
unsigned char MBEDTLS_PRIVATE(nr); /*!< The number of rounds (12, 14 or 16) */
/*! The ARIA round keys. */
uint32_t MBEDTLS_PRIVATE(rk)[MBEDTLS_ARIA_MAX_ROUNDS + 1][MBEDTLS_ARIA_BLOCKSIZE / 4];
}
mbedtls_aria_context;
#if defined(MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS)
/**
* \brief This function initializes the specified ARIA context.
*
* It must be the first API called before using
* the context.
*
* \param ctx The ARIA context to initialize. This must not be \c NULL.
*/
void mbedtls_aria_init(mbedtls_aria_context *ctx);
/**
* \brief This function releases and clears the specified ARIA context.
*
* \param ctx The ARIA context to clear. This may be \c NULL, in which
* case this function returns immediately. If it is not \c NULL,
* it must point to an initialized ARIA context.
*/
void mbedtls_aria_free(mbedtls_aria_context *ctx);
/**
* \brief This function sets the encryption key.
*
* \param ctx The ARIA context to which the key should be bound.
* This must be initialized.
* \param key The encryption key. This must be a readable buffer
* of size \p keybits Bits.
* \param keybits The size of \p key in Bits. Valid options are:
* <ul><li>128 bits</li>
* <li>192 bits</li>
* <li>256 bits</li></ul>
*
* \return \c 0 on success.
* \return A negative error code on failure.
*/
int mbedtls_aria_setkey_enc(mbedtls_aria_context *ctx,
const unsigned char *key,
unsigned int keybits);
#if !defined(MBEDTLS_BLOCK_CIPHER_NO_DECRYPT)
/**
* \brief This function sets the decryption key.
*
* \param ctx The ARIA context to which the key should be bound.
* This must be initialized.
* \param key The decryption key. This must be a readable buffer
* of size \p keybits Bits.
* \param keybits The size of data passed. Valid options are:
* <ul><li>128 bits</li>
* <li>192 bits</li>
* <li>256 bits</li></ul>
*
* \return \c 0 on success.
* \return A negative error code on failure.
*/
int mbedtls_aria_setkey_dec(mbedtls_aria_context *ctx,
const unsigned char *key,
unsigned int keybits);
#endif /* !MBEDTLS_BLOCK_CIPHER_NO_DECRYPT */
/**
* \brief This function performs an ARIA single-block encryption or
* decryption operation.
*
* It performs encryption or decryption (depending on whether
* the key was set for encryption on decryption) on the input
* data buffer defined in the \p input parameter.
*
* mbedtls_aria_init(), and either mbedtls_aria_setkey_enc() or
* mbedtls_aria_setkey_dec() must be called before the first
* call to this API with the same context.
*
* \param ctx The ARIA context to use for encryption or decryption.
* This must be initialized and bound to a key.
* \param input The 16-Byte buffer holding the input data.
* \param output The 16-Byte buffer holding the output data.
* \return \c 0 on success.
* \return A negative error code on failure.
*/
int mbedtls_aria_crypt_ecb(mbedtls_aria_context *ctx,
const unsigned char input[MBEDTLS_ARIA_BLOCKSIZE],
unsigned char output[MBEDTLS_ARIA_BLOCKSIZE]);
#if defined(MBEDTLS_CIPHER_MODE_CBC)
/**
* \brief This function performs an ARIA-CBC encryption or decryption operation
* on full blocks.
*
* It performs the operation defined in the \p mode
* parameter (encrypt/decrypt), on the input data buffer defined in
* the \p input parameter.
*
* It can be called as many times as needed, until all the input
* data is processed. mbedtls_aria_init(), and either
* mbedtls_aria_setkey_enc() or mbedtls_aria_setkey_dec() must be called
* before the first call to this API with the same context.
*
* \note This function operates on aligned blocks, that is, the input size
* must be a multiple of the ARIA block size of 16 Bytes.
*
* \note Upon exit, the content of the IV is updated so that you can
* call the same function again on the next
* block(s) of data and get the same result as if it was
* encrypted in one call. This allows a "streaming" usage.
* If you need to retain the contents of the IV, you should
* either save it manually or use the cipher module instead.
*
*
* \param ctx The ARIA context to use for encryption or decryption.
* This must be initialized and bound to a key.
* \param mode The mode of operation. This must be either
* MBEDTLS_ARIA_ENCRYPT for encryption, or
* MBEDTLS_ARIA_DECRYPT for decryption.
* \param length The length of the input data in Bytes. This must be a
* multiple of the block size (16 Bytes).
* \param iv Initialization vector (updated after use).
* This must be a readable buffer of size 16 Bytes.
* \param input The buffer holding the input data. This must
* be a readable buffer of length \p length Bytes.
* \param output The buffer holding the output data. This must
* be a writable buffer of length \p length Bytes.
*
* \return \c 0 on success.
* \return A negative error code on failure.
*/
int mbedtls_aria_crypt_cbc(mbedtls_aria_context *ctx,
int mode,
size_t length,
unsigned char iv[MBEDTLS_ARIA_BLOCKSIZE],
const unsigned char *input,
unsigned char *output);
#endif /* MBEDTLS_CIPHER_MODE_CBC */
#if defined(MBEDTLS_CIPHER_MODE_CFB)
/**
* \brief This function performs an ARIA-CFB128 encryption or decryption
* operation.
*
* It performs the operation defined in the \p mode
* parameter (encrypt or decrypt), on the input data buffer
* defined in the \p input parameter.
*
* For CFB, you must set up the context with mbedtls_aria_setkey_enc(),
* regardless of whether you are performing an encryption or decryption
* operation, that is, regardless of the \p mode parameter. This is
* because CFB mode uses the same key schedule for encryption and
* decryption.
*
* \note Upon exit, the content of the IV is updated so that you can
* call the same function again on the next
* block(s) of data and get the same result as if it was
* encrypted in one call. This allows a "streaming" usage.
* If you need to retain the contents of the
* IV, you must either save it manually or use the cipher
* module instead.
*
*
* \param ctx The ARIA context to use for encryption or decryption.
* This must be initialized and bound to a key.
* \param mode The mode of operation. This must be either
* MBEDTLS_ARIA_ENCRYPT for encryption, or
* MBEDTLS_ARIA_DECRYPT for decryption.
* \param length The length of the input data \p input in Bytes.
* \param iv_off The offset in IV (updated after use).
* This must not be larger than 15.
* \param iv The initialization vector (updated after use).
* This must be a readable buffer of size 16 Bytes.
* \param input The buffer holding the input data. This must
* be a readable buffer of length \p length Bytes.
* \param output The buffer holding the output data. This must
* be a writable buffer of length \p length Bytes.
*
* \return \c 0 on success.
* \return A negative error code on failure.
*/
int mbedtls_aria_crypt_cfb128(mbedtls_aria_context *ctx,
int mode,
size_t length,
size_t *iv_off,
unsigned char iv[MBEDTLS_ARIA_BLOCKSIZE],
const unsigned char *input,
unsigned char *output);
#endif /* MBEDTLS_CIPHER_MODE_CFB */
#if defined(MBEDTLS_CIPHER_MODE_CTR)
/**
* \brief This function performs an ARIA-CTR encryption or decryption
* operation.
*
* Due to the nature of CTR, you must use the same key schedule
* for both encryption and decryption operations. Therefore, you
* must use the context initialized with mbedtls_aria_setkey_enc()
* for both MBEDTLS_ARIA_ENCRYPT and MBEDTLS_ARIA_DECRYPT.
*
* \warning You must never reuse a nonce value with the same key. Doing so
* would void the encryption for the two messages encrypted with
* the same nonce and key.
*
* There are two common strategies for managing nonces with CTR:
*
* 1. You can handle everything as a single message processed over
* successive calls to this function. In that case, you want to
* set \p nonce_counter and \p nc_off to 0 for the first call, and
* then preserve the values of \p nonce_counter, \p nc_off and \p
* stream_block across calls to this function as they will be
* updated by this function.
*
* With this strategy, you must not encrypt more than 2**128
* blocks of data with the same key.
*
* 2. You can encrypt separate messages by dividing the \p
* nonce_counter buffer in two areas: the first one used for a
* per-message nonce, handled by yourself, and the second one
* updated by this function internally.
*
* For example, you might reserve the first 12 bytes for the
* per-message nonce, and the last 4 bytes for internal use. In that
* case, before calling this function on a new message you need to
* set the first 12 bytes of \p nonce_counter to your chosen nonce
* value, the last 4 to 0, and \p nc_off to 0 (which will cause \p
* stream_block to be ignored). That way, you can encrypt at most
* 2**96 messages of up to 2**32 blocks each with the same key.
*
* The per-message nonce (or information sufficient to reconstruct
* it) needs to be communicated with the ciphertext and must be unique.
* The recommended way to ensure uniqueness is to use a message
* counter. An alternative is to generate random nonces, but this
* limits the number of messages that can be securely encrypted:
* for example, with 96-bit random nonces, you should not encrypt
* more than 2**32 messages with the same key.
*
* Note that for both strategies, sizes are measured in blocks and
* that an ARIA block is 16 bytes.
*
* \warning Upon return, \p stream_block contains sensitive data. Its
* content must not be written to insecure storage and should be
* securely discarded as soon as it's no longer needed.
*
* \param ctx The ARIA context to use for encryption or decryption.
* This must be initialized and bound to a key.
* \param length The length of the input data \p input in Bytes.
* \param nc_off The offset in Bytes in the current \p stream_block,
* for resuming within the current cipher stream. The
* offset pointer should be \c 0 at the start of a
* stream. This must not be larger than \c 15 Bytes.
* \param nonce_counter The 128-bit nonce and counter. This must point to
* a read/write buffer of length \c 16 bytes.
* \param stream_block The saved stream block for resuming. This must
* point to a read/write buffer of length \c 16 bytes.
* This is overwritten by the function.
* \param input The buffer holding the input data. This must
* be a readable buffer of length \p length Bytes.
* \param output The buffer holding the output data. This must
* be a writable buffer of length \p length Bytes.
*
* \return \c 0 on success.
* \return A negative error code on failure.
*/
int mbedtls_aria_crypt_ctr(mbedtls_aria_context *ctx,
size_t length,
size_t *nc_off,
unsigned char nonce_counter[MBEDTLS_ARIA_BLOCKSIZE],
unsigned char stream_block[MBEDTLS_ARIA_BLOCKSIZE],
const unsigned char *input,
unsigned char *output);
#endif /* MBEDTLS_CIPHER_MODE_CTR */
#if defined(MBEDTLS_SELF_TEST)
/**
* \brief Checkup routine.
*
* \return \c 0 on success, or \c 1 on failure.
*/
int mbedtls_aria_self_test(int verbose);
#endif /* MBEDTLS_SELF_TEST */
#endif /* MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS */
#ifdef __cplusplus
}
#endif
#endif /* TF_PSA_CRYPTO_MBEDTLS_PRIVATE_ARIA_H */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,76 @@
/**
* \file block_cipher.h
*
* \brief Internal abstraction layer.
*/
/*
* Copyright The Mbed TLS Contributors
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
*/
#ifndef TF_PSA_CRYPTO_MBEDTLS_PRIVATE_BLOCK_CIPHER_H
#define TF_PSA_CRYPTO_MBEDTLS_PRIVATE_BLOCK_CIPHER_H
#include "mbedtls/private_access.h"
#include "tf-psa-crypto/build_info.h"
#if defined(MBEDTLS_AES_C)
#include "mbedtls/private/aes.h"
#endif
#if defined(MBEDTLS_ARIA_C)
#include "mbedtls/private/aria.h"
#endif
#if defined(MBEDTLS_CAMELLIA_C)
#include "mbedtls/private/camellia.h"
#endif
#if defined(MBEDTLS_BLOCK_CIPHER_SOME_PSA)
#include "psa/crypto_types.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
MBEDTLS_BLOCK_CIPHER_ID_NONE = 0, /**< Unset. */
MBEDTLS_BLOCK_CIPHER_ID_AES, /**< The AES cipher. */
MBEDTLS_BLOCK_CIPHER_ID_CAMELLIA, /**< The Camellia cipher. */
MBEDTLS_BLOCK_CIPHER_ID_ARIA, /**< The Aria cipher. */
} mbedtls_block_cipher_id_t;
/**
* Used internally to indicate whether a context uses legacy or PSA.
*
* Internal use only.
*/
typedef enum {
MBEDTLS_BLOCK_CIPHER_ENGINE_LEGACY = 0,
MBEDTLS_BLOCK_CIPHER_ENGINE_PSA,
} mbedtls_block_cipher_engine_t;
typedef struct {
mbedtls_block_cipher_id_t MBEDTLS_PRIVATE(id);
#if defined(MBEDTLS_BLOCK_CIPHER_SOME_PSA)
mbedtls_block_cipher_engine_t MBEDTLS_PRIVATE(engine);
mbedtls_svc_key_id_t MBEDTLS_PRIVATE(psa_key_id);
#endif
union {
unsigned dummy; /* Make the union non-empty even with no supported algorithms. */
#if defined(MBEDTLS_AES_C)
mbedtls_aes_context MBEDTLS_PRIVATE(aes);
#endif
#if defined(MBEDTLS_ARIA_C)
mbedtls_aria_context MBEDTLS_PRIVATE(aria);
#endif
#if defined(MBEDTLS_CAMELLIA_C)
mbedtls_camellia_context MBEDTLS_PRIVATE(camellia);
#endif
} MBEDTLS_PRIVATE(ctx);
} mbedtls_block_cipher_context_t;
#ifdef __cplusplus
}
#endif
#endif /* TF_PSA_CRYPTO_MBEDTLS_PRIVATE_BLOCK_CIPHER_H */
@@ -0,0 +1,302 @@
/**
* \file camellia.h
*
* \brief Camellia block cipher
*/
/*
* Copyright The Mbed TLS Contributors
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
*/
#ifndef TF_PSA_CRYPTO_MBEDTLS_PRIVATE_CAMELLIA_H
#define TF_PSA_CRYPTO_MBEDTLS_PRIVATE_CAMELLIA_H
#include "mbedtls/private_access.h"
#include "tf-psa-crypto/build_info.h"
#include <stddef.h>
#include <stdint.h>
#include "mbedtls/platform_util.h"
#if defined(MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS)
#define MBEDTLS_CAMELLIA_ENCRYPT 1
#define MBEDTLS_CAMELLIA_DECRYPT 0
#endif /* MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS */
/** Bad input data. */
#define MBEDTLS_ERR_CAMELLIA_BAD_INPUT_DATA PSA_ERROR_INVALID_ARGUMENT
/** Invalid data input length. */
#define MBEDTLS_ERR_CAMELLIA_INVALID_INPUT_LENGTH -0x0026
#ifdef __cplusplus
extern "C" {
#endif
/**
* \brief CAMELLIA context structure
*/
typedef struct mbedtls_camellia_context {
int MBEDTLS_PRIVATE(nr); /*!< number of rounds */
uint32_t MBEDTLS_PRIVATE(rk)[68]; /*!< CAMELLIA round keys */
}
mbedtls_camellia_context;
#if defined(MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS)
/**
* \brief Initialize a CAMELLIA context.
*
* \param ctx The CAMELLIA context to be initialized.
* This must not be \c NULL.
*/
void mbedtls_camellia_init(mbedtls_camellia_context *ctx);
/**
* \brief Clear a CAMELLIA context.
*
* \param ctx The CAMELLIA context to be cleared. This may be \c NULL,
* in which case this function returns immediately. If it is not
* \c NULL, it must be initialized.
*/
void mbedtls_camellia_free(mbedtls_camellia_context *ctx);
/**
* \brief Perform a CAMELLIA key schedule operation for encryption.
*
* \param ctx The CAMELLIA context to use. This must be initialized.
* \param key The encryption key to use. This must be a readable buffer
* of size \p keybits Bits.
* \param keybits The length of \p key in Bits. This must be either \c 128,
* \c 192 or \c 256.
*
* \return \c 0 if successful.
* \return A negative error code on failure.
*/
int mbedtls_camellia_setkey_enc(mbedtls_camellia_context *ctx,
const unsigned char *key,
unsigned int keybits);
#if !defined(MBEDTLS_BLOCK_CIPHER_NO_DECRYPT)
/**
* \brief Perform a CAMELLIA key schedule operation for decryption.
*
* \param ctx The CAMELLIA context to use. This must be initialized.
* \param key The decryption key. This must be a readable buffer
* of size \p keybits Bits.
* \param keybits The length of \p key in Bits. This must be either \c 128,
* \c 192 or \c 256.
*
* \return \c 0 if successful.
* \return A negative error code on failure.
*/
int mbedtls_camellia_setkey_dec(mbedtls_camellia_context *ctx,
const unsigned char *key,
unsigned int keybits);
#endif /* !MBEDTLS_BLOCK_CIPHER_NO_DECRYPT */
/**
* \brief Perform a CAMELLIA-ECB block encryption/decryption operation.
*
* \param ctx The CAMELLIA context to use. This must be initialized
* and bound to a key.
* \param mode The mode of operation. This must be either
* MBEDTLS_CAMELLIA_ENCRYPT or MBEDTLS_CAMELLIA_DECRYPT.
* \param input The input block. This must be a readable buffer
* of size \c 16 Bytes.
* \param output The output block. This must be a writable buffer
* of size \c 16 Bytes.
*
* \return \c 0 if successful.
* \return A negative error code on failure.
*/
int mbedtls_camellia_crypt_ecb(mbedtls_camellia_context *ctx,
int mode,
const unsigned char input[16],
unsigned char output[16]);
#if defined(MBEDTLS_CIPHER_MODE_CBC)
/**
* \brief Perform a CAMELLIA-CBC buffer encryption/decryption operation.
*
* \note Upon exit, the content of the IV is updated so that you can
* call the function same function again on the following
* block(s) of data and get the same result as if it was
* encrypted in one call. This allows a "streaming" usage.
* If on the other hand you need to retain the contents of the
* IV, you should either save it manually or use the cipher
* module instead.
*
* \param ctx The CAMELLIA context to use. This must be initialized
* and bound to a key.
* \param mode The mode of operation. This must be either
* MBEDTLS_CAMELLIA_ENCRYPT or MBEDTLS_CAMELLIA_DECRYPT.
* \param length The length in Bytes of the input data \p input.
* This must be a multiple of \c 16 Bytes.
* \param iv The initialization vector. This must be a read/write buffer
* of length \c 16 Bytes. It is updated to allow streaming
* use as explained above.
* \param input The buffer holding the input data. This must point to a
* readable buffer of length \p length Bytes.
* \param output The buffer holding the output data. This must point to a
* writable buffer of length \p length Bytes.
*
* \return \c 0 if successful.
* \return A negative error code on failure.
*/
int mbedtls_camellia_crypt_cbc(mbedtls_camellia_context *ctx,
int mode,
size_t length,
unsigned char iv[16],
const unsigned char *input,
unsigned char *output);
#endif /* MBEDTLS_CIPHER_MODE_CBC */
#if defined(MBEDTLS_CIPHER_MODE_CFB)
/**
* \brief Perform a CAMELLIA-CFB128 buffer encryption/decryption
* operation.
*
* \note Due to the nature of CFB mode, you should use the same
* key for both encryption and decryption. In particular, calls
* to this function should be preceded by a key-schedule via
* mbedtls_camellia_setkey_enc() regardless of whether \p mode
* is MBEDTLS_CAMELLIA_ENCRYPT or MBEDTLS_CAMELLIA_DECRYPT.
*
* \note Upon exit, the content of the IV is updated so that you can
* call the function same function again on the following
* block(s) of data and get the same result as if it was
* encrypted in one call. This allows a "streaming" usage.
* If on the other hand you need to retain the contents of the
* IV, you should either save it manually or use the cipher
* module instead.
*
* \param ctx The CAMELLIA context to use. This must be initialized
* and bound to a key.
* \param mode The mode of operation. This must be either
* MBEDTLS_CAMELLIA_ENCRYPT or MBEDTLS_CAMELLIA_DECRYPT.
* \param length The length of the input data \p input. Any value is allowed.
* \param iv_off The current offset in the IV. This must be smaller
* than \c 16 Bytes. It is updated after this call to allow
* the aforementioned streaming usage.
* \param iv The initialization vector. This must be a read/write buffer
* of length \c 16 Bytes. It is updated after this call to
* allow the aforementioned streaming usage.
* \param input The buffer holding the input data. This must be a readable
* buffer of size \p length Bytes.
* \param output The buffer to hold the output data. This must be a writable
* buffer of length \p length Bytes.
*
* \return \c 0 if successful.
* \return A negative error code on failure.
*/
int mbedtls_camellia_crypt_cfb128(mbedtls_camellia_context *ctx,
int mode,
size_t length,
size_t *iv_off,
unsigned char iv[16],
const unsigned char *input,
unsigned char *output);
#endif /* MBEDTLS_CIPHER_MODE_CFB */
#if defined(MBEDTLS_CIPHER_MODE_CTR)
/**
* \brief Perform a CAMELLIA-CTR buffer encryption/decryption operation.
*
* *note Due to the nature of CTR mode, you should use the same
* key for both encryption and decryption. In particular, calls
* to this function should be preceded by a key-schedule via
* mbedtls_camellia_setkey_enc() regardless of whether the mode
* is MBEDTLS_CAMELLIA_ENCRYPT or MBEDTLS_CAMELLIA_DECRYPT.
*
* \warning You must never reuse a nonce value with the same key. Doing so
* would void the encryption for the two messages encrypted with
* the same nonce and key.
*
* There are two common strategies for managing nonces with CTR:
*
* 1. You can handle everything as a single message processed over
* successive calls to this function. In that case, you want to
* set \p nonce_counter and \p nc_off to 0 for the first call, and
* then preserve the values of \p nonce_counter, \p nc_off and \p
* stream_block across calls to this function as they will be
* updated by this function.
*
* With this strategy, you must not encrypt more than 2**128
* blocks of data with the same key.
*
* 2. You can encrypt separate messages by dividing the \p
* nonce_counter buffer in two areas: the first one used for a
* per-message nonce, handled by yourself, and the second one
* updated by this function internally.
*
* For example, you might reserve the first \c 12 Bytes for the
* per-message nonce, and the last \c 4 Bytes for internal use.
* In that case, before calling this function on a new message you
* need to set the first \c 12 Bytes of \p nonce_counter to your
* chosen nonce value, the last four to \c 0, and \p nc_off to \c 0
* (which will cause \p stream_block to be ignored). That way, you
* can encrypt at most \c 2**96 messages of up to \c 2**32 blocks
* each with the same key.
*
* The per-message nonce (or information sufficient to reconstruct
* it) needs to be communicated with the ciphertext and must be
* unique. The recommended way to ensure uniqueness is to use a
* message counter. An alternative is to generate random nonces,
* but this limits the number of messages that can be securely
* encrypted: for example, with 96-bit random nonces, you should
* not encrypt more than 2**32 messages with the same key.
*
* Note that for both strategies, sizes are measured in blocks and
* that a CAMELLIA block is \c 16 Bytes.
*
* \warning Upon return, \p stream_block contains sensitive data. Its
* content must not be written to insecure storage and should be
* securely discarded as soon as it's no longer needed.
*
* \param ctx The CAMELLIA context to use. This must be initialized
* and bound to a key.
* \param length The length of the input data \p input in Bytes.
* Any value is allowed.
* \param nc_off The offset in the current \p stream_block (for resuming
* within current cipher stream). The offset pointer to
* should be \c 0 at the start of a stream. It is updated
* at the end of this call.
* \param nonce_counter The 128-bit nonce and counter. This must be a read/write
* buffer of length \c 16 Bytes.
* \param stream_block The saved stream-block for resuming. This must be a
* read/write buffer of length \c 16 Bytes.
* \param input The input data stream. This must be a readable buffer of
* size \p length Bytes.
* \param output The output data stream. This must be a writable buffer
* of size \p length Bytes.
*
* \return \c 0 if successful.
* \return A negative error code on failure.
*/
int mbedtls_camellia_crypt_ctr(mbedtls_camellia_context *ctx,
size_t length,
size_t *nc_off,
unsigned char nonce_counter[16],
unsigned char stream_block[16],
const unsigned char *input,
unsigned char *output);
#endif /* MBEDTLS_CIPHER_MODE_CTR */
#if defined(MBEDTLS_SELF_TEST)
/**
* \brief Checkup routine
*
* \return 0 if successful, or 1 if the test failed
*/
int mbedtls_camellia_self_test(int verbose);
#endif /* MBEDTLS_SELF_TEST */
#endif /* MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS */
#ifdef __cplusplus
}
#endif
#endif /* TF_PSA_CRYPTO_MBEDTLS_PRIVATE_CAMELLIA_H */
@@ -0,0 +1,523 @@
/**
* \file ccm.h
*
* \brief This file provides an API for the CCM authenticated encryption
* mode for block ciphers.
*
* CCM combines Counter mode encryption with CBC-MAC authentication
* for 128-bit block ciphers.
*
* Input to CCM includes the following elements:
* <ul><li>Payload - data that is both authenticated and encrypted.</li>
* <li>Associated data (Adata) - data that is authenticated but not
* encrypted, For example, a header.</li>
* <li>Nonce - A unique value that is assigned to the payload and the
* associated data.</li></ul>
*
* Definition of CCM:
* http://csrc.nist.gov/publications/nistpubs/800-38C/SP800-38C_updated-July20_2007.pdf
* RFC 3610 "Counter with CBC-MAC (CCM)"
*
* Related:
* RFC 5116 "An Interface and Algorithms for Authenticated Encryption"
*
* Definition of CCM*:
* IEEE 802.15.4 - IEEE Standard for Local and metropolitan area networks
* Integer representation is fixed most-significant-octet-first order and
* the representation of octets is most-significant-bit-first order. This is
* consistent with RFC 3610.
*/
/*
* Copyright The Mbed TLS Contributors
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
*/
#ifndef TF_PSA_CRYPTO_MBEDTLS_PRIVATE_CCM_H
#define TF_PSA_CRYPTO_MBEDTLS_PRIVATE_CCM_H
#include "mbedtls/private_access.h"
#include "tf-psa-crypto/build_info.h"
#include "mbedtls/private/cipher.h"
#if defined(MBEDTLS_BLOCK_CIPHER_C)
#include "mbedtls/private/block_cipher.h"
#endif
#if defined(MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS)
#define MBEDTLS_CCM_DECRYPT 0
#define MBEDTLS_CCM_ENCRYPT 1
#define MBEDTLS_CCM_STAR_DECRYPT 2
#define MBEDTLS_CCM_STAR_ENCRYPT 3
#endif /* MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS */
/** Bad input parameters to the function. */
#define MBEDTLS_ERR_CCM_BAD_INPUT PSA_ERROR_INVALID_ARGUMENT
/** Authenticated decryption failed. */
#define MBEDTLS_ERR_CCM_AUTH_FAILED PSA_ERROR_INVALID_SIGNATURE
#ifdef __cplusplus
extern "C" {
#endif
/**
* \brief The CCM context-type definition. The CCM context is passed
* to the APIs called.
*/
typedef struct mbedtls_ccm_context {
unsigned char MBEDTLS_PRIVATE(y)[16]; /*!< The Y working buffer */
unsigned char MBEDTLS_PRIVATE(ctr)[16]; /*!< The counter buffer */
size_t MBEDTLS_PRIVATE(plaintext_len); /*!< Total plaintext length */
size_t MBEDTLS_PRIVATE(add_len); /*!< Total authentication data length */
size_t MBEDTLS_PRIVATE(tag_len); /*!< Total tag length */
size_t MBEDTLS_PRIVATE(processed); /*!< Track how many bytes of input data
were processed (chunked input).
Used independently for both auth data
and plaintext/ciphertext.
This variable is set to zero after
auth data input is finished. */
unsigned int MBEDTLS_PRIVATE(q); /*!< The Q working value */
unsigned int MBEDTLS_PRIVATE(mode); /*!< The operation to perform:
MBEDTLS_CCM_ENCRYPT or
MBEDTLS_CCM_DECRYPT or
MBEDTLS_CCM_STAR_ENCRYPT or
MBEDTLS_CCM_STAR_DECRYPT. */
#if defined(MBEDTLS_BLOCK_CIPHER_C)
mbedtls_block_cipher_context_t MBEDTLS_PRIVATE(block_cipher_ctx); /*!< The cipher context used. */
#else
mbedtls_cipher_context_t MBEDTLS_PRIVATE(cipher_ctx); /*!< The cipher context used. */
#endif
int MBEDTLS_PRIVATE(state); /*!< Working value holding context's
state. Used for chunked data input */
}
mbedtls_ccm_context;
#if defined(MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS)
/**
* \brief This function initializes the specified CCM context,
* to make references valid, and prepare the context
* for mbedtls_ccm_setkey() or mbedtls_ccm_free().
*
* \param ctx The CCM context to initialize. This must not be \c NULL.
*/
void mbedtls_ccm_init(mbedtls_ccm_context *ctx);
/**
* \brief This function initializes the CCM context set in the
* \p ctx parameter and sets the encryption key.
*
* \param ctx The CCM context to initialize. This must be an initialized
* context.
* \param cipher The 128-bit block cipher to use.
* \param key The encryption key. This must not be \c NULL.
* \param keybits The key size in bits. This must be acceptable by the cipher.
*
* \return \c 0 on success.
* \return A CCM or cipher-specific error code on failure.
*/
int mbedtls_ccm_setkey(mbedtls_ccm_context *ctx,
mbedtls_cipher_id_t cipher,
const unsigned char *key,
unsigned int keybits);
/**
* \brief This function releases and clears the specified CCM context
* and underlying cipher sub-context.
*
* \param ctx The CCM context to clear. If this is \c NULL, the function
* has no effect. Otherwise, this must be initialized.
*/
void mbedtls_ccm_free(mbedtls_ccm_context *ctx);
/**
* \brief This function encrypts a buffer using CCM.
*
* \note The tag is written to a separate buffer. To concatenate
* the \p tag with the \p output, as done in <em>RFC-3610:
* Counter with CBC-MAC (CCM)</em>, use
* \p tag = \p output + \p length, and make sure that the
* output buffer is at least \p length + \p tag_len wide.
*
* \param ctx The CCM context to use for encryption. This must be
* initialized and bound to a key.
* \param length The length of the input data in Bytes.
* \param iv The initialization vector (nonce). This must be a readable
* buffer of at least \p iv_len Bytes.
* \param iv_len The length of the nonce in Bytes: 7, 8, 9, 10, 11, 12,
* or 13. The length L of the message length field is
* 15 - \p iv_len.
* \param ad The additional data field. If \p ad_len is greater than
* zero, \p ad must be a readable buffer of at least that
* length.
* \param ad_len The length of additional data in Bytes.
* This must be less than `2^16 - 2^8`.
* \param input The buffer holding the input data. If \p length is greater
* than zero, \p input must be a readable buffer of at least
* that length.
* \param output The buffer holding the output data. If \p length is greater
* than zero, \p output must be a writable buffer of at least
* that length.
* \param tag The buffer holding the authentication field. This must be a
* writable buffer of at least \p tag_len Bytes.
* \param tag_len The length of the authentication field to generate in Bytes:
* 4, 6, 8, 10, 12, 14 or 16.
*
* \return \c 0 on success.
* \return A CCM or cipher-specific error code on failure.
*/
int mbedtls_ccm_encrypt_and_tag(mbedtls_ccm_context *ctx, size_t length,
const unsigned char *iv, size_t iv_len,
const unsigned char *ad, size_t ad_len,
const unsigned char *input, unsigned char *output,
unsigned char *tag, size_t tag_len);
/**
* \brief This function encrypts a buffer using CCM*.
*
* \note The tag is written to a separate buffer. To concatenate
* the \p tag with the \p output, as done in <em>RFC-3610:
* Counter with CBC-MAC (CCM)</em>, use
* \p tag = \p output + \p length, and make sure that the
* output buffer is at least \p length + \p tag_len wide.
*
* \note When using this function in a variable tag length context,
* the tag length has to be encoded into the \p iv passed to
* this function.
*
* \param ctx The CCM context to use for encryption. This must be
* initialized and bound to a key.
* \param length The length of the input data in Bytes.
* For tag length = 0, input length is ignored.
* \param iv The initialization vector (nonce). This must be a readable
* buffer of at least \p iv_len Bytes.
* \param iv_len The length of the nonce in Bytes: 7, 8, 9, 10, 11, 12,
* or 13. The length L of the message length field is
* 15 - \p iv_len.
* \param ad The additional data field. This must be a readable buffer of
* at least \p ad_len Bytes.
* \param ad_len The length of additional data in Bytes.
* This must be less than 2^16 - 2^8.
* \param input The buffer holding the input data. If \p length is greater
* than zero, \p input must be a readable buffer of at least
* that length.
* \param output The buffer holding the output data. If \p length is greater
* than zero, \p output must be a writable buffer of at least
* that length.
* \param tag The buffer holding the authentication field. This must be a
* writable buffer of at least \p tag_len Bytes.
* \param tag_len The length of the authentication field to generate in Bytes:
* 0, 4, 6, 8, 10, 12, 14 or 16.
*
* \warning Passing \c 0 as \p tag_len means that the message is no
* longer authenticated.
*
* \return \c 0 on success.
* \return A CCM or cipher-specific error code on failure.
*/
int mbedtls_ccm_star_encrypt_and_tag(mbedtls_ccm_context *ctx, size_t length,
const unsigned char *iv, size_t iv_len,
const unsigned char *ad, size_t ad_len,
const unsigned char *input, unsigned char *output,
unsigned char *tag, size_t tag_len);
/**
* \brief This function performs a CCM authenticated decryption of a
* buffer.
*
* \param ctx The CCM context to use for decryption. This must be
* initialized and bound to a key.
* \param length The length of the input data in Bytes.
* \param iv The initialization vector (nonce). This must be a readable
* buffer of at least \p iv_len Bytes.
* \param iv_len The length of the nonce in Bytes: 7, 8, 9, 10, 11, 12,
* or 13. The length L of the message length field is
* 15 - \p iv_len.
* \param ad The additional data field. This must be a readable buffer
* of at least that \p ad_len Bytes..
* \param ad_len The length of additional data in Bytes.
* This must be less than 2^16 - 2^8.
* \param input The buffer holding the input data. If \p length is greater
* than zero, \p input must be a readable buffer of at least
* that length.
* \param output The buffer holding the output data. If \p length is greater
* than zero, \p output must be a writable buffer of at least
* that length.
* \param tag The buffer holding the authentication field. This must be a
* readable buffer of at least \p tag_len Bytes.
* \param tag_len The length of the authentication field to generate in Bytes:
* 4, 6, 8, 10, 12, 14 or 16.
*
* \return \c 0 on success. This indicates that the message is authentic.
* \return #MBEDTLS_ERR_CCM_AUTH_FAILED if the tag does not match.
* \return A cipher-specific error code on calculation failure.
*/
int mbedtls_ccm_auth_decrypt(mbedtls_ccm_context *ctx, size_t length,
const unsigned char *iv, size_t iv_len,
const unsigned char *ad, size_t ad_len,
const unsigned char *input, unsigned char *output,
const unsigned char *tag, size_t tag_len);
/**
* \brief This function performs a CCM* authenticated decryption of a
* buffer.
*
* \note When using this function in a variable tag length context,
* the tag length has to be decoded from \p iv and passed to
* this function as \p tag_len. (\p tag needs to be adjusted
* accordingly.)
*
* \param ctx The CCM context to use for decryption. This must be
* initialized and bound to a key.
* \param length The length of the input data in Bytes.
* For tag length = 0, input length is ignored.
* \param iv The initialization vector (nonce). This must be a readable
* buffer of at least \p iv_len Bytes.
* \param iv_len The length of the nonce in Bytes: 7, 8, 9, 10, 11, 12,
* or 13. The length L of the message length field is
* 15 - \p iv_len.
* \param ad The additional data field. This must be a readable buffer of
* at least that \p ad_len Bytes.
* \param ad_len The length of additional data in Bytes.
* This must be less than 2^16 - 2^8.
* \param input The buffer holding the input data. If \p length is greater
* than zero, \p input must be a readable buffer of at least
* that length.
* \param output The buffer holding the output data. If \p length is greater
* than zero, \p output must be a writable buffer of at least
* that length.
* \param tag The buffer holding the authentication field. This must be a
* readable buffer of at least \p tag_len Bytes.
* \param tag_len The length of the authentication field in Bytes.
* 0, 4, 6, 8, 10, 12, 14 or 16.
*
* \warning Passing \c 0 as \p tag_len means that the message is nos
* longer authenticated.
*
* \return \c 0 on success.
* \return #MBEDTLS_ERR_CCM_AUTH_FAILED if the tag does not match.
* \return A cipher-specific error code on calculation failure.
*/
int mbedtls_ccm_star_auth_decrypt(mbedtls_ccm_context *ctx, size_t length,
const unsigned char *iv, size_t iv_len,
const unsigned char *ad, size_t ad_len,
const unsigned char *input, unsigned char *output,
const unsigned char *tag, size_t tag_len);
/**
* \brief This function starts a CCM encryption or decryption
* operation.
*
* This function and mbedtls_ccm_set_lengths() must be called
* before calling mbedtls_ccm_update_ad() or
* mbedtls_ccm_update(). This function can be called before
* or after mbedtls_ccm_set_lengths().
*
* \note This function is not implemented in Mbed TLS yet.
*
* \param ctx The CCM context. This must be initialized.
* \param mode The operation to perform: MBEDTLS_CCM_ENCRYPT or
* MBEDTLS_CCM_DECRYPT or MBEDTLS_CCM_STAR_ENCRYPT or
* MBEDTLS_CCM_STAR_DECRYPT.
* \param iv The initialization vector. This must be a readable buffer
* of at least \p iv_len Bytes.
* \param iv_len The length of the nonce in Bytes: 7, 8, 9, 10, 11, 12,
* or 13. The length L of the message length field is
* 15 - \p iv_len.
*
* \return \c 0 on success.
* \return #MBEDTLS_ERR_CCM_BAD_INPUT on failure:
* \p ctx is in an invalid state,
* \p mode is invalid,
* \p iv_len is invalid (lower than \c 7 or greater than
* \c 13).
*/
int mbedtls_ccm_starts(mbedtls_ccm_context *ctx,
int mode,
const unsigned char *iv,
size_t iv_len);
/**
* \brief This function declares the lengths of the message
* and additional data for a CCM encryption or decryption
* operation.
*
* This function and mbedtls_ccm_starts() must be called
* before calling mbedtls_ccm_update_ad() or
* mbedtls_ccm_update(). This function can be called before
* or after mbedtls_ccm_starts().
*
* \note This function is not implemented in Mbed TLS yet.
*
* \param ctx The CCM context. This must be initialized.
* \param total_ad_len The total length of additional data in bytes.
* This must be less than `2^16 - 2^8`.
* \param plaintext_len The length in bytes of the plaintext to encrypt or
* result of the decryption (thus not encompassing the
* additional data that are not encrypted).
* \param tag_len The length of the tag to generate in Bytes:
* 4, 6, 8, 10, 12, 14 or 16.
* For CCM*, zero is also valid.
*
* \return \c 0 on success.
* \return #MBEDTLS_ERR_CCM_BAD_INPUT on failure:
* \p ctx is in an invalid state,
* \p total_ad_len is greater than \c 0xFF00.
*/
int mbedtls_ccm_set_lengths(mbedtls_ccm_context *ctx,
size_t total_ad_len,
size_t plaintext_len,
size_t tag_len);
/**
* \brief This function feeds an input buffer as associated data
* (authenticated but not encrypted data) in a CCM
* encryption or decryption operation.
*
* You may call this function zero, one or more times
* to pass successive parts of the additional data. The
* lengths \p ad_len of the data parts should eventually add
* up exactly to the total length of additional data
* \c total_ad_len passed to mbedtls_ccm_set_lengths(). You
* may not call this function after calling
* mbedtls_ccm_update().
*
* \note This function is not implemented in Mbed TLS yet.
*
* \param ctx The CCM context. This must have been started with
* mbedtls_ccm_starts(), the lengths of the message and
* additional data must have been declared with
* mbedtls_ccm_set_lengths() and this must not have yet
* received any input with mbedtls_ccm_update().
* \param ad The buffer holding the additional data, or \c NULL
* if \p ad_len is \c 0.
* \param ad_len The length of the additional data. If \c 0,
* \p ad may be \c NULL.
*
* \return \c 0 on success.
* \return #MBEDTLS_ERR_CCM_BAD_INPUT on failure:
* \p ctx is in an invalid state,
* total input length too long.
*/
int mbedtls_ccm_update_ad(mbedtls_ccm_context *ctx,
const unsigned char *ad,
size_t ad_len);
/**
* \brief This function feeds an input buffer into an ongoing CCM
* encryption or decryption operation.
*
* You may call this function zero, one or more times
* to pass successive parts of the input: the plaintext to
* encrypt, or the ciphertext (not including the tag) to
* decrypt. After the last part of the input, call
* mbedtls_ccm_finish(). The lengths \p input_len of the
* data parts should eventually add up exactly to the
* plaintext length \c plaintext_len passed to
* mbedtls_ccm_set_lengths().
*
* This function may produce output in one of the following
* ways:
* - Immediate output: the output length is always equal
* to the input length.
* - Buffered output: except for the last part of input data,
* the output consists of a whole number of 16-byte blocks.
* If the total input length so far (not including
* associated data) is 16 \* *B* + *A* with *A* < 16 then
* the total output length is 16 \* *B*.
* For the last part of input data, the output length is
* equal to the input length plus the number of bytes (*A*)
* buffered in the previous call to the function (if any).
* The function uses the plaintext length
* \c plaintext_len passed to mbedtls_ccm_set_lengths()
* to detect the last part of input data.
*
* In particular:
* - It is always correct to call this function with
* \p output_size >= \p input_len + 15.
* - If \p input_len is a multiple of 16 for all the calls
* to this function during an operation (not necessary for
* the last one) then it is correct to use \p output_size
* =\p input_len.
*
* \note This function is not implemented in Mbed TLS yet.
*
* \param ctx The CCM context. This must have been started with
* mbedtls_ccm_starts() and the lengths of the message and
* additional data must have been declared with
* mbedtls_ccm_set_lengths().
* \param input The buffer holding the input data. If \p input_len
* is greater than zero, this must be a readable buffer
* of at least \p input_len bytes.
* \param input_len The length of the input data in bytes.
* \param output The buffer for the output data. If \p output_size
* is greater than zero, this must be a writable buffer of
* at least \p output_size bytes.
* \param output_size The size of the output buffer in bytes.
* See the function description regarding the output size.
* \param output_len On success, \p *output_len contains the actual
* length of the output written in \p output.
* On failure, the content of \p *output_len is
* unspecified.
*
* \return \c 0 on success.
* \return #MBEDTLS_ERR_CCM_BAD_INPUT on failure:
* \p ctx is in an invalid state,
* total input length too long,
* or \p output_size too small.
*/
int mbedtls_ccm_update(mbedtls_ccm_context *ctx,
const unsigned char *input, size_t input_len,
unsigned char *output, size_t output_size,
size_t *output_len);
/**
* \brief This function finishes the CCM operation and generates
* the authentication tag.
*
* It wraps up the CCM stream, and generates the
* tag. The tag can have a maximum length of 16 Bytes.
*
* \note This function is not implemented in Mbed TLS yet.
*
* \param ctx The CCM context. This must have been started with
* mbedtls_ccm_starts() and the lengths of the message and
* additional data must have been declared with
* mbedtls_ccm_set_lengths().
* \param tag The buffer for holding the tag. If \p tag_len is greater
* than zero, this must be a writable buffer of at least \p
* tag_len Bytes.
* \param tag_len The length of the tag. Must match the tag length passed to
* mbedtls_ccm_set_lengths() function.
*
* \return \c 0 on success.
* \return #MBEDTLS_ERR_CCM_BAD_INPUT on failure:
* \p ctx is in an invalid state,
* invalid value of \p tag_len,
* the total amount of additional data passed to
* mbedtls_ccm_update_ad() was lower than the total length of
* additional data \c total_ad_len passed to
* mbedtls_ccm_set_lengths(),
* the total amount of input data passed to
* mbedtls_ccm_update() was lower than the plaintext length
* \c plaintext_len passed to mbedtls_ccm_set_lengths().
*/
int mbedtls_ccm_finish(mbedtls_ccm_context *ctx,
unsigned char *tag, size_t tag_len);
#if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_CCM_GCM_CAN_AES)
/**
* \brief The CCM checkup routine.
*
* \return \c 0 on success.
* \return \c 1 on failure.
*/
int mbedtls_ccm_self_test(int verbose);
#endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */
#endif /* MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS */
#ifdef __cplusplus
}
#endif
#endif /* TF_PSA_CRYPTO_MBEDTLS_PRIVATE_CCM_H */
@@ -0,0 +1,201 @@
/**
* \file chacha20.h
*
* \brief This file contains ChaCha20 definitions and functions.
*
* ChaCha20 is a stream cipher that can encrypt and decrypt
* information. ChaCha was created by Daniel Bernstein as a variant of
* its Salsa cipher https://cr.yp.to/chacha/chacha-20080128.pdf
* ChaCha20 is the variant with 20 rounds, that was also standardized
* in RFC 7539.
*
* \author Daniel King <damaki.gh@gmail.com>
*/
/*
* Copyright The Mbed TLS Contributors
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
*/
#ifndef TF_PSA_CRYPTO_MBEDTLS_PRIVATE_CHACHA20_H
#define TF_PSA_CRYPTO_MBEDTLS_PRIVATE_CHACHA20_H
#include "mbedtls/private_access.h"
#include "tf-psa-crypto/build_info.h"
#include <stdint.h>
#include <stddef.h>
#define MBEDTLS_CHACHA20_BLOCK_SIZE_BYTES (4U * 16U)
/** Invalid input parameter(s). */
#define MBEDTLS_ERR_CHACHA20_BAD_INPUT_DATA PSA_ERROR_INVALID_ARGUMENT
#ifdef __cplusplus
extern "C" {
#endif
typedef struct mbedtls_chacha20_context {
uint32_t MBEDTLS_PRIVATE(state)[16]; /*! The state (before round operations). */
uint8_t MBEDTLS_PRIVATE(keystream8)[64]; /*! Leftover keystream bytes. */
size_t MBEDTLS_PRIVATE(keystream_bytes_used); /*! Number of keystream bytes already used. */
}
mbedtls_chacha20_context;
#if defined(MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS)
/**
* \brief This function initializes the specified ChaCha20 context.
*
* It must be the first API called before using
* the context.
*
* It is usually followed by calls to
* \c mbedtls_chacha20_setkey() and
* \c mbedtls_chacha20_starts(), then one or more calls to
* to \c mbedtls_chacha20_update(), and finally to
* \c mbedtls_chacha20_free().
*
* \param ctx The ChaCha20 context to initialize.
* This must not be \c NULL.
*/
void mbedtls_chacha20_init(mbedtls_chacha20_context *ctx);
/**
* \brief This function releases and clears the specified
* ChaCha20 context.
*
* \param ctx The ChaCha20 context to clear. This may be \c NULL,
* in which case this function is a no-op. If it is not
* \c NULL, it must point to an initialized context.
*
*/
void mbedtls_chacha20_free(mbedtls_chacha20_context *ctx);
/**
* \brief This function sets the encryption/decryption key.
*
* \note After using this function, you must also call
* \c mbedtls_chacha20_starts() to set a nonce before you
* start encrypting/decrypting data with
* \c mbedtls_chacha_update().
*
* \param ctx The ChaCha20 context to which the key should be bound.
* It must be initialized.
* \param key The encryption/decryption key. This must be \c 32 Bytes
* in length.
*
* \return \c 0 on success.
* \return #MBEDTLS_ERR_CHACHA20_BAD_INPUT_DATA if ctx or key is NULL.
*/
int mbedtls_chacha20_setkey(mbedtls_chacha20_context *ctx,
const unsigned char key[32]);
/**
* \brief This function sets the nonce and initial counter value.
*
* \note A ChaCha20 context can be re-used with the same key by
* calling this function to change the nonce.
*
* \warning You must never use the same nonce twice with the same key.
* This would void any confidentiality guarantees for the
* messages encrypted with the same nonce and key.
*
* \param ctx The ChaCha20 context to which the nonce should be bound.
* It must be initialized and bound to a key.
* \param nonce The nonce. This must be \c 12 Bytes in size.
* \param counter The initial counter value. This is usually \c 0.
*
* \return \c 0 on success.
* \return #MBEDTLS_ERR_CHACHA20_BAD_INPUT_DATA if ctx or nonce is
* NULL.
*/
int mbedtls_chacha20_starts(mbedtls_chacha20_context *ctx,
const unsigned char nonce[12],
uint32_t counter);
/**
* \brief This function encrypts or decrypts data.
*
* Since ChaCha20 is a stream cipher, the same operation is
* used for encrypting and decrypting data.
*
* \note The \p input and \p output pointers must either be equal or
* point to non-overlapping buffers.
*
* \note \c mbedtls_chacha20_setkey() and
* \c mbedtls_chacha20_starts() must be called at least once
* to setup the context before this function can be called.
*
* \note This function can be called multiple times in a row in
* order to encrypt of decrypt data piecewise with the same
* key and nonce.
*
* \param ctx The ChaCha20 context to use for encryption or decryption.
* It must be initialized and bound to a key and nonce.
* \param size The length of the input data in Bytes.
* \param input The buffer holding the input data.
* This pointer can be \c NULL if `size == 0`.
* \param output The buffer holding the output data.
* This must be able to hold \p size Bytes.
* This pointer can be \c NULL if `size == 0`.
*
* \return \c 0 on success.
* \return A negative error code on failure.
*/
int mbedtls_chacha20_update(mbedtls_chacha20_context *ctx,
size_t size,
const unsigned char *input,
unsigned char *output);
/**
* \brief This function encrypts or decrypts data with ChaCha20 and
* the given key and nonce.
*
* Since ChaCha20 is a stream cipher, the same operation is
* used for encrypting and decrypting data.
*
* \warning You must never use the same (key, nonce) pair more than
* once. This would void any confidentiality guarantees for
* the messages encrypted with the same nonce and key.
*
* \note The \p input and \p output pointers must either be equal or
* point to non-overlapping buffers.
*
* \param key The encryption/decryption key.
* This must be \c 32 Bytes in length.
* \param nonce The nonce. This must be \c 12 Bytes in size.
* \param counter The initial counter value. This is usually \c 0.
* \param size The length of the input data in Bytes.
* \param input The buffer holding the input data.
* This pointer can be \c NULL if `size == 0`.
* \param output The buffer holding the output data.
* This must be able to hold \p size Bytes.
* This pointer can be \c NULL if `size == 0`.
*
* \return \c 0 on success.
* \return A negative error code on failure.
*/
int mbedtls_chacha20_crypt(const unsigned char key[32],
const unsigned char nonce[12],
uint32_t counter,
size_t size,
const unsigned char *input,
unsigned char *output);
#if defined(MBEDTLS_SELF_TEST)
/**
* \brief The ChaCha20 checkup routine.
*
* \return \c 0 on success.
* \return \c 1 on failure.
*/
int mbedtls_chacha20_self_test(int verbose);
#endif /* MBEDTLS_SELF_TEST */
#endif /* MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS */
#ifdef __cplusplus
}
#endif
#endif /* TF_PSA_CRYPTO_MBEDTLS_PRIVATE_CHACHA20_H */
@@ -0,0 +1,339 @@
/**
* \file chachapoly.h
*
* \brief This file contains the AEAD-ChaCha20-Poly1305 definitions and
* functions.
*
* ChaCha20-Poly1305 is an algorithm for Authenticated Encryption
* with Associated Data (AEAD) that can be used to encrypt and
* authenticate data. It is based on ChaCha20 and Poly1305 by Daniel
* Bernstein and was standardized in RFC 7539.
*
* \author Daniel King <damaki.gh@gmail.com>
*/
/*
* Copyright The Mbed TLS Contributors
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
*/
#ifndef TF_PSA_CRYPTO_MBEDTLS_PRIVATE_CHACHAPOLY_H
#define TF_PSA_CRYPTO_MBEDTLS_PRIVATE_CHACHAPOLY_H
#include "mbedtls/private_access.h"
#include "tf-psa-crypto/build_info.h"
/* for shared error codes */
#include "mbedtls/private/poly1305.h"
/** The requested operation is not permitted in the current state. */
#define MBEDTLS_ERR_CHACHAPOLY_BAD_STATE -0x0054
/** Authenticated decryption failed: data was not authentic. */
#define MBEDTLS_ERR_CHACHAPOLY_AUTH_FAILED PSA_ERROR_INVALID_SIGNATURE
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
MBEDTLS_CHACHAPOLY_ENCRYPT, /**< The mode value for performing encryption. */
MBEDTLS_CHACHAPOLY_DECRYPT /**< The mode value for performing decryption. */
}
mbedtls_chachapoly_mode_t;
#include "mbedtls/private/chacha20.h"
typedef struct mbedtls_chachapoly_context {
mbedtls_chacha20_context MBEDTLS_PRIVATE(chacha20_ctx); /**< The ChaCha20 context. */
mbedtls_poly1305_context MBEDTLS_PRIVATE(poly1305_ctx); /**< The Poly1305 context. */
uint64_t MBEDTLS_PRIVATE(aad_len); /**< The length (bytes) of the Additional Authenticated Data. */
uint64_t MBEDTLS_PRIVATE(ciphertext_len); /**< The length (bytes) of the ciphertext. */
int MBEDTLS_PRIVATE(state); /**< The current state of the context. */
mbedtls_chachapoly_mode_t MBEDTLS_PRIVATE(mode); /**< Cipher mode (encrypt or decrypt). */
}
mbedtls_chachapoly_context;
#if defined(MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS)
/**
* \brief This function initializes the specified ChaCha20-Poly1305 context.
*
* It must be the first API called before using
* the context. It must be followed by a call to
* \c mbedtls_chachapoly_setkey() before any operation can be
* done, and to \c mbedtls_chachapoly_free() once all
* operations with that context have been finished.
*
* In order to encrypt or decrypt full messages at once, for
* each message you should make a single call to
* \c mbedtls_chachapoly_crypt_and_tag() or
* \c mbedtls_chachapoly_auth_decrypt().
*
* In order to encrypt messages piecewise, for each
* message you should make a call to
* \c mbedtls_chachapoly_starts(), then 0 or more calls to
* \c mbedtls_chachapoly_update_aad(), then 0 or more calls to
* \c mbedtls_chachapoly_update(), then one call to
* \c mbedtls_chachapoly_finish().
*
* \warning Decryption with the piecewise API is discouraged! Always
* use \c mbedtls_chachapoly_auth_decrypt() when possible!
*
* If however this is not possible because the data is too
* large to fit in memory, you need to:
*
* - call \c mbedtls_chachapoly_starts() and (if needed)
* \c mbedtls_chachapoly_update_aad() as above,
* - call \c mbedtls_chachapoly_update() multiple times and
* ensure its output (the plaintext) is NOT used in any other
* way than placing it in temporary storage at this point,
* - call \c mbedtls_chachapoly_finish() to compute the
* authentication tag and compared it in constant time to the
* tag received with the ciphertext.
*
* If the tags are not equal, you must immediately discard
* all previous outputs of \c mbedtls_chachapoly_update(),
* otherwise you can now safely use the plaintext.
*
* \param ctx The ChachaPoly context to initialize. Must not be \c NULL.
*/
void mbedtls_chachapoly_init(mbedtls_chachapoly_context *ctx);
/**
* \brief This function releases and clears the specified
* ChaCha20-Poly1305 context.
*
* \param ctx The ChachaPoly context to clear. This may be \c NULL, in which
* case this function is a no-op.
*/
void mbedtls_chachapoly_free(mbedtls_chachapoly_context *ctx);
/**
* \brief This function sets the ChaCha20-Poly1305
* symmetric encryption key.
*
* \param ctx The ChaCha20-Poly1305 context to which the key should be
* bound. This must be initialized.
* \param key The \c 256 Bit (\c 32 Bytes) key.
*
* \return \c 0 on success.
* \return A negative error code on failure.
*/
int mbedtls_chachapoly_setkey(mbedtls_chachapoly_context *ctx,
const unsigned char key[32]);
/**
* \brief This function starts a ChaCha20-Poly1305 encryption or
* decryption operation.
*
* \warning You must never use the same nonce twice with the same key.
* This would void any confidentiality and authenticity
* guarantees for the messages encrypted with the same nonce
* and key.
*
* \note If the context is being used for AAD only (no data to
* encrypt or decrypt) then \p mode can be set to any value.
*
* \warning Decryption with the piecewise API is discouraged, see the
* warning on \c mbedtls_chachapoly_init().
*
* \param ctx The ChaCha20-Poly1305 context. This must be initialized
* and bound to a key.
* \param nonce The nonce/IV to use for the message.
* This must be a readable buffer of length \c 12 Bytes.
* \param mode The operation to perform: #MBEDTLS_CHACHAPOLY_ENCRYPT or
* #MBEDTLS_CHACHAPOLY_DECRYPT (discouraged, see warning).
*
* \return \c 0 on success.
* \return A negative error code on failure.
*/
int mbedtls_chachapoly_starts(mbedtls_chachapoly_context *ctx,
const unsigned char nonce[12],
mbedtls_chachapoly_mode_t mode);
/**
* \brief This function feeds additional data to be authenticated
* into an ongoing ChaCha20-Poly1305 operation.
*
* The Additional Authenticated Data (AAD), also called
* Associated Data (AD) is only authenticated but not
* encrypted nor included in the encrypted output. It is
* usually transmitted separately from the ciphertext or
* computed locally by each party.
*
* \note This function is called before data is encrypted/decrypted.
* I.e. call this function to process the AAD before calling
* \c mbedtls_chachapoly_update().
*
* You may call this function multiple times to process
* an arbitrary amount of AAD. It is permitted to call
* this function 0 times, if no AAD is used.
*
* This function cannot be called any more if data has
* been processed by \c mbedtls_chachapoly_update(),
* or if the context has been finished.
*
* \warning Decryption with the piecewise API is discouraged, see the
* warning on \c mbedtls_chachapoly_init().
*
* \param ctx The ChaCha20-Poly1305 context. This must be initialized
* and bound to a key.
* \param aad_len The length in Bytes of the AAD. The length has no
* restrictions.
* \param aad Buffer containing the AAD.
* This pointer can be \c NULL if `aad_len == 0`.
*
* \return \c 0 on success.
* \return #MBEDTLS_ERR_POLY1305_BAD_INPUT_DATA
* if \p ctx or \p aad are NULL.
* \return #MBEDTLS_ERR_CHACHAPOLY_BAD_STATE
* if the operations has not been started or has been
* finished, or if the AAD has been finished.
*/
int mbedtls_chachapoly_update_aad(mbedtls_chachapoly_context *ctx,
const unsigned char *aad,
size_t aad_len);
/**
* \brief Thus function feeds data to be encrypted or decrypted
* into an on-going ChaCha20-Poly1305
* operation.
*
* The direction (encryption or decryption) depends on the
* mode that was given when calling
* \c mbedtls_chachapoly_starts().
*
* You may call this function multiple times to process
* an arbitrary amount of data. It is permitted to call
* this function 0 times, if no data is to be encrypted
* or decrypted.
*
* \warning Decryption with the piecewise API is discouraged, see the
* warning on \c mbedtls_chachapoly_init().
*
* \param ctx The ChaCha20-Poly1305 context to use. This must be initialized.
* \param len The length (in bytes) of the data to encrypt or decrypt.
* \param input The buffer containing the data to encrypt or decrypt.
* This pointer can be \c NULL if `len == 0`.
* \param output The buffer to where the encrypted or decrypted data is
* written. This must be able to hold \p len bytes.
* This pointer can be \c NULL if `len == 0`.
*
* \return \c 0 on success.
* \return #MBEDTLS_ERR_CHACHAPOLY_BAD_STATE
* if the operation has not been started or has been
* finished.
* \return Another negative error code on other kinds of failure.
*/
int mbedtls_chachapoly_update(mbedtls_chachapoly_context *ctx,
size_t len,
const unsigned char *input,
unsigned char *output);
/**
* \brief This function finished the ChaCha20-Poly1305 operation and
* generates the MAC (authentication tag).
*
* \param ctx The ChaCha20-Poly1305 context to use. This must be initialized.
* \param mac The buffer to where the 128-bit (16 bytes) MAC is written.
*
* \warning Decryption with the piecewise API is discouraged, see the
* warning on \c mbedtls_chachapoly_init().
*
* \return \c 0 on success.
* \return #MBEDTLS_ERR_CHACHAPOLY_BAD_STATE
* if the operation has not been started or has been
* finished.
* \return Another negative error code on other kinds of failure.
*/
int mbedtls_chachapoly_finish(mbedtls_chachapoly_context *ctx,
unsigned char mac[16]);
/**
* \brief This function performs a complete ChaCha20-Poly1305
* authenticated encryption with the previously-set key.
*
* \note Before using this function, you must set the key with
* \c mbedtls_chachapoly_setkey().
*
* \warning You must never use the same nonce twice with the same key.
* This would void any confidentiality and authenticity
* guarantees for the messages encrypted with the same nonce
* and key.
*
* \param ctx The ChaCha20-Poly1305 context to use (holds the key).
* This must be initialized.
* \param length The length (in bytes) of the data to encrypt or decrypt.
* \param nonce The 96-bit (12 bytes) nonce/IV to use.
* \param aad The buffer containing the additional authenticated
* data (AAD). This pointer can be \c NULL if `aad_len == 0`.
* \param aad_len The length (in bytes) of the AAD data to process.
* \param input The buffer containing the data to encrypt or decrypt.
* This pointer can be \c NULL if `ilen == 0`.
* \param output The buffer to where the encrypted or decrypted data
* is written. This pointer can be \c NULL if `ilen == 0`.
* \param tag The buffer to where the computed 128-bit (16 bytes) MAC
* is written. This must not be \c NULL.
*
* \return \c 0 on success.
* \return A negative error code on failure.
*/
int mbedtls_chachapoly_encrypt_and_tag(mbedtls_chachapoly_context *ctx,
size_t length,
const unsigned char nonce[12],
const unsigned char *aad,
size_t aad_len,
const unsigned char *input,
unsigned char *output,
unsigned char tag[16]);
/**
* \brief This function performs a complete ChaCha20-Poly1305
* authenticated decryption with the previously-set key.
*
* \note Before using this function, you must set the key with
* \c mbedtls_chachapoly_setkey().
*
* \param ctx The ChaCha20-Poly1305 context to use (holds the key).
* \param length The length (in Bytes) of the data to decrypt.
* \param nonce The \c 96 Bit (\c 12 bytes) nonce/IV to use.
* \param aad The buffer containing the additional authenticated data (AAD).
* This pointer can be \c NULL if `aad_len == 0`.
* \param aad_len The length (in bytes) of the AAD data to process.
* \param tag The buffer holding the authentication tag.
* This must be a readable buffer of length \c 16 Bytes.
* \param input The buffer containing the data to decrypt.
* This pointer can be \c NULL if `ilen == 0`.
* \param output The buffer to where the decrypted data is written.
* This pointer can be \c NULL if `ilen == 0`.
*
* \return \c 0 on success.
* \return #MBEDTLS_ERR_CHACHAPOLY_AUTH_FAILED
* if the data was not authentic.
* \return Another negative error code on other kinds of failure.
*/
int mbedtls_chachapoly_auth_decrypt(mbedtls_chachapoly_context *ctx,
size_t length,
const unsigned char nonce[12],
const unsigned char *aad,
size_t aad_len,
const unsigned char tag[16],
const unsigned char *input,
unsigned char *output);
#if defined(MBEDTLS_SELF_TEST)
/**
* \brief The ChaCha20-Poly1305 checkup routine.
*
* \return \c 0 on success.
* \return \c 1 on failure.
*/
int mbedtls_chachapoly_self_test(int verbose);
#endif /* MBEDTLS_SELF_TEST */
#endif /* MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS */
#ifdef __cplusplus
}
#endif
#endif /* TF_PSA_CRYPTO_MBEDTLS_PRIVATE_CHACHAPOLY_H */
File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More