Merge commit '0344c602eadc0802776b65ff90f0a02c856cf53c' as 'lib/mbedtls/external/mbedtls'

This commit is contained in:
Tom Rini 2024-10-08 13:56:50 -06:00
commit 12f1212e95
1783 changed files with 625440 additions and 0 deletions

View File

@ -0,0 +1,2 @@
# Classify all '.function' files as C for syntax highlighting purposes
*.function linguist-language=C

View File

@ -0,0 +1,35 @@
---
name: Bug report
about: To report a bug, please fill this form.
title: ''
labels: ''
assignees: ''
---
### Summary
### System information
Mbed TLS version (number or commit id):
Operating system and version:
Configuration (if not default, please attach `mbedtls_config.h`):
Compiler and options (if you used a pre-built binary, please indicate how you obtained it):
Additional environment information:
### Expected behavior
### Actual behavior
### Steps to reproduce
### Additional information

View File

@ -0,0 +1,8 @@
blank_issues_enabled: false
contact_links:
- name: Mbed TLS security team
url: mailto:mbed-tls-security@lists.trustedfirmware.org
about: Report a security vulnerability.
- name: Mbed TLS mailing list
url: https://lists.trustedfirmware.org/mailman3/lists/mbed-tls.lists.trustedfirmware.org
about: Mbed TLS community support and general discussion.

View File

@ -0,0 +1,17 @@
---
name: Enhancement request
about: To request an enhancement, please fill this form.
title: ''
labels: ''
assignees: ''
---
### Suggested enhancement
### Justification
Mbed TLS needs this because

View File

@ -0,0 +1,27 @@
## Description
Please write a few sentences describing the overall goals of the pull request's commits.
## PR checklist
Please tick as appropriate and edit the reasons (e.g.: "backport: not needed because this is a new feature")
- [ ] **changelog** provided, or not required
- [ ] **backport** done, or not required
- [ ] **tests** provided, or not required
## Notes for the submitter
Please refer to the [contributing guidelines](https://github.com/Mbed-TLS/mbedtls/blob/development/CONTRIBUTING.md), especially the
checklist for PR contributors.
Help make review efficient:
* Multiple simple commits
- please structure your PR into a series of small commits, each of which does one thing
* Avoid force-push
- please do not force-push to update your PR - just add new commit(s)
* See our [Guidelines for Contributors](https://mbed-tls.readthedocs.io/en/latest/reviews/review-for-contributors/) for more details about the review process.

69
lib/mbedtls/external/mbedtls/.gitignore vendored Normal file
View File

@ -0,0 +1,69 @@
# Random seed file created by test scripts and sample programs
seedfile
# MBEDTLS_PSA_INJECT_ENTROPY seed file created by the test framework
00000000ffffff52.psa_its
# CMake build artifacts:
CMakeCache.txt
CMakeFiles
CTestTestfile.cmake
cmake_install.cmake
Testing
# CMake generates *.dir/ folders for in-tree builds (used by MSVC projects), ignore all of those:
*.dir/
# MSVC files generated by CMake:
/*.sln
/*.vcxproj
/*.filters
# Test coverage build artifacts:
Coverage
*.gcno
*.gcda
coverage-summary.txt
# generated by scripts/memory.sh
massif-*
# Eclipse project files
.cproject
.project
/.settings
# Unix-like build artifacts:
*.o
# MSVC build artifacts:
*.exe
*.pdb
*.ilk
*.lib
# Python build artifacts:
*.pyc
# CMake generates *.dir/ folders for in-tree builds (used by MSVC projects), ignore all of those:
*.dir/
# Microsoft CMake extension for Visual Studio Code generates a build directory by default
/build/
# Generated documentation:
/apidoc
# PSA Crypto compliance test repo, cloned by test_psa_compliance.py
/psa-arch-tests
# Editor navigation files:
/GPATH
/GRTAGS
/GSYMS
/GTAGS
/TAGS
/cscope*.out
/tags
# clangd compilation database
compile_commands.json
# clangd index files
/.cache/clangd/index/

View File

@ -0,0 +1,3 @@
[submodule "framework"]
path = framework
url = https://github.com/Mbed-TLS/mbedtls-framework

View File

@ -0,0 +1,3 @@
default:\
:langmap=c\:.c.h.function:\

View File

@ -0,0 +1,4 @@
[mypy]
mypy_path = scripts
namespace_packages = True
warn_unused_configs = True

80
lib/mbedtls/external/mbedtls/.pylintrc vendored Normal file
View File

@ -0,0 +1,80 @@
[MASTER]
init-hook='import sys; sys.path.append("scripts")'
min-similarity-lines=10
[BASIC]
# We're ok with short funtion argument names.
# [invalid-name]
argument-rgx=[a-z_][a-z0-9_]*$
# Allow filter and map.
# [bad-builtin]
bad-functions=input
# We prefer docstrings, but we don't require them on all functions.
# Require them only on long functions (for some value of long).
# [missing-docstring]
docstring-min-length=10
# No upper limit on method names. Pylint <2.1.0 has an upper limit of 30.
# [invalid-name]
method-rgx=[a-z_][a-z0-9_]{2,}$
# Allow module names containing a dash (but no underscore or uppercase letter).
# They are whole programs, not meant to be included by another module.
# [invalid-name]
module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+)|[a-z][-0-9a-z]+)$
# Some functions don't need docstrings.
# [missing-docstring]
no-docstring-rgx=(run_)?main$
# We're ok with short local or global variable names.
# [invalid-name]
variable-rgx=[a-z_][a-z0-9_]*$
[DESIGN]
# Allow more than the default 7 attributes.
# [too-many-instance-attributes]
max-attributes=15
[FORMAT]
# Allow longer modules than the default recommended maximum.
# [too-many-lines]
max-module-lines=2000
[MESSAGES CONTROL]
# * locally-disabled, locally-enabled: If we disable or enable a message
# locally, it's by design. There's no need to clutter the Pylint output
# with this information.
# * logging-format-interpolation: Pylint warns about things like
# ``log.info('...'.format(...))``. It insists on ``log.info('...', ...)``.
# This is of minor utility (mainly a performance gain when there are
# many messages that use formatting and are below the log level).
# Some versions of Pylint (including 1.8, which is the version on
# Ubuntu 18.04) only recognize old-style format strings using '%',
# and complain about something like ``log.info('{}', foo)`` with
# logging-too-many-args (Pylint supports new-style formatting if
# declared globally with logging_format_style under [LOGGING] but
# this requires Pylint >=2.2).
# * no-else-return: Allow the perfectly reasonable idiom
# if condition1:
# return value1
# else:
# return value2
# * unnecessary-pass: If we take the trouble of adding a line with "pass",
# it's because we think the code is clearer that way.
disable=locally-disabled,locally-enabled,logging-format-interpolation,no-else-return,unnecessary-pass
[REPORTS]
# Don't diplay statistics. Just the facts.
reports=no
[VARIABLES]
# Allow unused variables if their name starts with an underscore.
# [unused-argument]
dummy-variables-rgx=_.*
[SIMILARITIES]
# Ignore imports when computing similarities.
ignore-imports=yes

View File

@ -0,0 +1,37 @@
# .readthedocs.yaml
# Read the Docs configuration file
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
# Required
version: 2
# Include the framework submodule in the build
submodules:
include:
- framework
# Set the version of Python and other tools you might need
build:
os: ubuntu-20.04
tools:
python: "3.9"
jobs:
pre_build:
- ./scripts/apidoc_full.sh
- breathe-apidoc -o docs/api apidoc/xml
post_build:
- |
# Work around Readthedocs bug: Command parsing fails if the 'if' statement is on the first line
if [ "$READTHEDOCS_VERSION" = "development" ]; then
"$READTHEDOCS_VIRTUALENV_PATH/bin/rtd" projects "Mbed TLS API" redirects sync --wet-run -f docs/redirects.yaml
fi
# Build documentation in the docs/ directory with Sphinx
sphinx:
builder: dirhtml
configuration: docs/conf.py
# Optionally declare the Python requirements required to build your docs
python:
install:
- requirements: docs/requirements.txt

View File

@ -0,0 +1,28 @@
# Declare python as our language. This way we get our chosen Python version,
# and pip is available. Gcc and clang are available anyway.
dist: jammy
os: linux
language: python
python: 3.10
cache: ccache
branches:
only:
coverity_scan
install:
- $PYTHON scripts/min_requirements.py
env:
global:
- SEED=1
- secure: "GF/Fde5fkm15T/RNykrjrPV5Uh1KJ70cP308igL6Xkk3eJmqkkmWCe9JqRH12J3TeWw2fu9PYPHt6iFSg6jasgqysfUyg+W03knRT5QNn3h5eHgt36cQJiJr6t3whPrRaiM6U9omE0evm+c0cAwlkA3GGSMw8Z+na4EnKI6OFCo="
addons:
coverity_scan:
project:
name: "ARMmbed/mbedtls"
notification_email: support-mbedtls@arm.com
build_command_prepend:
build_command: make
branch_pattern: coverity_scan

View File

@ -0,0 +1,240 @@
# Configuration options for Uncrustify specifying the Mbed TLS code style.
#
# Note: The code style represented by this file has not yet been introduced
# to Mbed TLS.
#
# Copyright The Mbed TLS Contributors
# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
# Wrap lines at 100 characters
code_width = 100
# Allow splitting long for statements between the condition statements
ls_for_split_full = true
# Allow splitting function calls between arguments
ls_func_split_full = true
input_tab_size = 4
# Spaces-only indentation
indent_with_tabs = 0
indent_columns = 4
# Indent 'case' 1 level from 'switch'
indent_switch_case = indent_columns
# Line-up strings broken by '\'
indent_align_string = true
# Braces on the same line (Egyptian-style braces)
nl_enum_brace = remove
nl_union_brace = remove
nl_struct_brace = remove
nl_do_brace = remove
nl_if_brace = remove
nl_for_brace = remove
nl_else_brace = remove
nl_while_brace = remove
nl_switch_brace = remove
# Braces on same line as keywords that follow them - 'else' and the 'while' in 'do {} while ()';
nl_brace_else = remove
nl_brace_while = remove
# Space before else on the same line
sp_brace_else = add
# If else is on the same line as '{', force exactly 1 space between them
sp_else_brace = force
# Functions are the exception and have braces on the next line
nl_fcall_brace = add
nl_fdef_brace = add
# Force exactly one space between ')' and '{' in statements
sp_sparen_brace = force
# At least 1 space around assignment
sp_assign = add
# Remove spaces around the preprocessor '##' token-concatenate
sp_pp_concat = ignore
# At least 1 space around '||' and '&&'
sp_bool = add
# But no space after the '!' operator
sp_not = remove
# No space after the bitwise-not '~' operator
sp_inv = remove
# No space after the addressof '&' operator
sp_addr = remove
# No space around the member '.' and '->' operators
sp_member = remove
# No space after the dereference '*' operator
sp_deref = remove
# No space after a unary negation '-'
sp_sign = remove
# No space between the '++'/'--' operator and its operand
sp_incdec = remove
# At least 1 space around comparison operators
sp_compare = add
# Remove spaces inside all kinds of parentheses:
# Remove spaces inside parentheses
sp_inside_paren = remove
# No spaces inside statement parentheses
sp_inside_sparen = remove
# No spaces inside cast parentheses '( char )x' -> '(char)x'
sp_inside_paren_cast = remove
# No spaces inside function parentheses
sp_inside_fparen = remove
# (The case where the function has no parameters/arguments)
sp_inside_fparens = remove
# No spaces inside the first parentheses in a function type
sp_inside_tparen = remove
# (Uncrustify >= 0.74.0) No spaces inside parens in for statements
sp_inside_for = remove
# Remove spaces between nested parentheses '( (' -> '(('
sp_paren_paren = remove
# (Uncrustify >= 0.74.0)
sp_sparen_paren = remove
# Remove spaces between ')' and adjacent '('
sp_cparen_oparen = remove
# (Uncrustify >= 0.73.0) space between 'do' and '{'
sp_do_brace_open = force
# (Uncrustify >= 0.73.0) space between '}' and 'while'
sp_brace_close_while = force
# At least 1 space before a '*' pointer star
sp_before_ptr_star = add
# Remove spaces between pointer stars
sp_between_ptr_star = remove
# No space after a pointer star
sp_after_ptr_star = remove
# But allow a space in the case of e.g. char * const x;
sp_after_ptr_star_qualifier = ignore
# Remove space after star in a function return type
sp_after_ptr_star_func = remove
# At least 1 space after a type in variable definition etc
sp_after_type = add
# Force exactly 1 space between a statement keyword (e.g. 'if') and an opening parenthesis
sp_before_sparen = force
# Remove a space before a ';'
sp_before_semi = remove
# (Uncrustify >= 0.73.0) Remove space before a semi in a non-empty for
sp_before_semi_for = remove
# (Uncrustify >= 0.73.0) Remove space in empty first statement of a for
sp_before_semi_for_empty = remove
# (Uncrustify >= 0.74.0) Remove space in empty middle statement of a for
sp_between_semi_for_empty = remove
# Add a space after a ';' (unless a comment follows)
sp_after_semi = add
# (Uncrustify >= 0.73.0) Add a space after a semi in non-empty for statements
sp_after_semi_for = add
# (Uncrustify >= 0.73.0) No space after final semi in empty for statements
sp_after_semi_for_empty = remove
# Remove spaces on the inside of square brackets '[]'
sp_inside_square = remove
# Must have at least 1 space after a comma
sp_after_comma = add
# Must not have a space before a comma
sp_before_comma = remove
# No space before the ':' in a case statement
sp_before_case_colon = remove
# Must have space after a cast - '(char)x' -> '(char) x'
sp_after_cast = add
# No space between 'sizeof' and '('
sp_sizeof_paren = remove
# At least 1 space inside '{ }'
sp_inside_braces = add
# At least 1 space inside '{ }' in an enum
sp_inside_braces_enum = add
# At least 1 space inside '{ }' in a struct
sp_inside_braces_struct = add
# At least 1 space between a function return type and the function name
sp_type_func = add
# No space between a function name and its arguments/parameters
sp_func_proto_paren = remove
sp_func_def_paren = remove
sp_func_call_paren = remove
# No space between '__attribute__' and '('
sp_attribute_paren = remove
# No space between 'defined' and '(' in preprocessor conditions
sp_defined_paren = remove
# At least 1 space between a macro's name and its definition
sp_macro = add
sp_macro_func = add
# Force exactly 1 space between a '}' and the name of a typedef if on the same line
sp_brace_typedef = force
# At least 1 space before a '\' line continuation
sp_before_nl_cont = add
# At least 1 space around '?' and ':' in ternary statements
sp_cond_colon = add
sp_cond_question = add
# Space between #else/#endif and comment afterwards
sp_endif_cmt = add
# Remove newlines at the start of a file
nl_start_of_file = remove
# At least 1 newline at the end of a file
nl_end_of_file = add
nl_end_of_file_min = 1
# Add braces in single-line statements
mod_full_brace_do = add
mod_full_brace_for = add
mod_full_brace_if = add
mod_full_brace_while = add
# Remove parentheses from return statements
mod_paren_on_return = remove
# Disable removal of leading spaces in a multi-line comment if the first and
# last lines are the same length
cmt_multi_check_last = false

View File

@ -0,0 +1 @@
/Makefile

View File

@ -0,0 +1,2 @@
add_subdirectory(everest)
add_subdirectory(p256-m)

View File

@ -0,0 +1,3 @@
THIRDPARTY_DIR := $(dir $(lastword $(MAKEFILE_LIST)))
include $(THIRDPARTY_DIR)/everest/Makefile.inc
include $(THIRDPARTY_DIR)/p256-m/Makefile.inc

View File

@ -0,0 +1 @@
Makefile

View File

@ -0,0 +1,42 @@
set(everest_target "${MBEDTLS_TARGET_PREFIX}everest")
add_library(${everest_target}
library/everest.c
library/x25519.c
library/Hacl_Curve25519_joined.c)
target_include_directories(${everest_target}
PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<BUILD_INTERFACE:${MBEDTLS_DIR}/include>
$<INSTALL_INTERFACE:include>
PRIVATE include/everest
include/everest/kremlib
${MBEDTLS_DIR}/library/)
# Pass-through MBEDTLS_CONFIG_FILE and MBEDTLS_USER_CONFIG_FILE
# This must be duplicated from library/CMakeLists.txt because
# everest is not directly linked against any mbedtls targets
# so does not inherit the compile definitions.
if(MBEDTLS_CONFIG_FILE)
target_compile_definitions(${everest_target}
PUBLIC MBEDTLS_CONFIG_FILE="${MBEDTLS_CONFIG_FILE}")
endif()
if(MBEDTLS_USER_CONFIG_FILE)
target_compile_definitions(${everest_target}
PUBLIC MBEDTLS_USER_CONFIG_FILE="${MBEDTLS_USER_CONFIG_FILE}")
endif()
if(INSTALL_MBEDTLS_HEADERS)
install(DIRECTORY include/everest
DESTINATION include
FILE_PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ
DIRECTORY_PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE
FILES_MATCHING PATTERN "*.h")
endif(INSTALL_MBEDTLS_HEADERS)
install(TARGETS ${everest_target}
EXPORT MbedTLSTargets
DESTINATION ${CMAKE_INSTALL_LIBDIR}
PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ)

View File

@ -0,0 +1,6 @@
THIRDPARTY_INCLUDES+=-I$(THIRDPARTY_DIR)/everest/include -I$(THIRDPARTY_DIR)/everest/include/everest -I$(THIRDPARTY_DIR)/everest/include/everest/kremlib
THIRDPARTY_CRYPTO_OBJECTS+= \
$(THIRDPARTY_DIR)/everest/library/everest.o \
$(THIRDPARTY_DIR)/everest/library/x25519.o \
$(THIRDPARTY_DIR)/everest/library/Hacl_Curve25519_joined.o

View File

@ -0,0 +1,5 @@
The files in this directory stem from [Project Everest](https://project-everest.github.io/) and are distributed under the Apache 2.0 license.
This is a formally verified implementation of Curve25519-based handshakes. The C code is automatically derived from the (verified) [original implementation](https://github.com/project-everest/hacl-star/tree/master/code/curve25519) in the [F* language](https://github.com/fstarlang/fstar) by [KreMLin](https://github.com/fstarlang/kremlin). In addition to the improved safety and security of the implementation, it is also significantly faster than the default implementation of Curve25519 in mbedTLS.
The caveat is that not all platforms are supported, although the version in `everest/library/legacy` should work on most systems. The main issue is that some platforms do not provide a 128-bit integer type and KreMLin therefore has to use additional (also verified) code to simulate them, resulting in less of a performance gain overall. Explicitly supported platforms are currently `x86` and `x86_64` using gcc or clang, and Visual C (2010 and later).

View File

@ -0,0 +1,21 @@
/* Copyright (c) INRIA and Microsoft Corporation. All rights reserved.
Licensed under the Apache 2.0 License. */
/* This file was generated by KreMLin <https://github.com/FStarLang/kremlin>
* KreMLin invocation: /mnt/e/everest/verify/kremlin/krml -fc89 -fparentheses -fno-shadow -header /mnt/e/everest/verify/hdrcLh -minimal -fbuiltin-uint128 -fc89 -fparentheses -fno-shadow -header /mnt/e/everest/verify/hdrcLh -minimal -I /mnt/e/everest/verify/hacl-star/code/lib/kremlin -I /mnt/e/everest/verify/kremlin/kremlib/compat -I /mnt/e/everest/verify/hacl-star/specs -I /mnt/e/everest/verify/hacl-star/specs/old -I . -ccopt -march=native -verbose -ldopt -flto -tmpdir x25519-c -I ../bignum -bundle Hacl.Curve25519=* -minimal -add-include "kremlib.h" -skip-compilation x25519-c/out.krml -o x25519-c/Hacl_Curve25519.c
* F* version: 059db0c8
* KreMLin version: 916c37ac
*/
#ifndef __Hacl_Curve25519_H
#define __Hacl_Curve25519_H
#include "kremlib.h"
void Hacl_Curve25519_crypto_scalarmult(uint8_t *mypublic, uint8_t *secret, uint8_t *basepoint);
#define __Hacl_Curve25519_H_DEFINED
#endif

View File

@ -0,0 +1,234 @@
/*
* Interface to code from Project Everest
*
* Copyright 2016-2018 INRIA and Microsoft Corporation
* SPDX-License-Identifier: Apache-2.0
*
* 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.
*
* This file is part of Mbed TLS (https://tls.mbed.org).
*/
#ifndef MBEDTLS_EVEREST_H
#define MBEDTLS_EVEREST_H
#include "everest/x25519.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* Defines the source of the imported EC key.
*/
typedef enum
{
MBEDTLS_EVEREST_ECDH_OURS, /**< Our key. */
MBEDTLS_EVEREST_ECDH_THEIRS, /**< The key of the peer. */
} mbedtls_everest_ecdh_side;
typedef struct {
mbedtls_x25519_context ctx;
} mbedtls_ecdh_context_everest;
/**
* \brief This function sets up the ECDH context with the information
* given.
*
* This function should be called after mbedtls_ecdh_init() but
* before mbedtls_ecdh_make_params(). There is no need to call
* this function before mbedtls_ecdh_read_params().
*
* This is the first function used by a TLS server for ECDHE
* ciphersuites.
*
* \param ctx The ECDH context to set up.
* \param grp_id The group id of the group to set up the context for.
*
* \return \c 0 on success.
*/
int mbedtls_everest_setup( mbedtls_ecdh_context_everest *ctx, int grp_id );
/**
* \brief This function frees a context.
*
* \param ctx The context to free.
*/
void mbedtls_everest_free( mbedtls_ecdh_context_everest *ctx );
/**
* \brief This function generates a public key and a TLS
* ServerKeyExchange payload.
*
* This is the second function used by a TLS server for ECDHE
* ciphersuites. (It is called after mbedtls_ecdh_setup().)
*
* \note This function assumes that the ECP group (grp) of the
* \p ctx context has already been properly set,
* for example, using mbedtls_ecp_group_load().
*
* \see ecp.h
*
* \param ctx The ECDH context.
* \param olen The number of characters written.
* \param buf The destination buffer.
* \param blen The length of the destination buffer.
* \param f_rng The RNG function.
* \param p_rng The RNG context.
*
* \return \c 0 on success.
* \return An \c MBEDTLS_ERR_ECP_XXX error code on failure.
*/
int mbedtls_everest_make_params( mbedtls_ecdh_context_everest *ctx, size_t *olen,
unsigned char *buf, size_t blen,
int( *f_rng )( void *, unsigned char *, size_t ),
void *p_rng );
/**
* \brief This function parses and processes a TLS ServerKeyExchange
* payload.
*
* This is the first function used by a TLS client for ECDHE
* ciphersuites.
*
* \see ecp.h
*
* \param ctx The ECDH context.
* \param buf The pointer to the start of the input buffer.
* \param end The address for one Byte past the end of the buffer.
*
* \return \c 0 on success.
* \return An \c MBEDTLS_ERR_ECP_XXX error code on failure.
*
*/
int mbedtls_everest_read_params( mbedtls_ecdh_context_everest *ctx,
const unsigned char **buf, const unsigned char *end );
/**
* \brief This function parses and processes a TLS ServerKeyExchange
* payload.
*
* This is the first function used by a TLS client for ECDHE
* ciphersuites.
*
* \see ecp.h
*
* \param ctx The ECDH context.
* \param buf The pointer to the start of the input buffer.
* \param end The address for one Byte past the end of the buffer.
*
* \return \c 0 on success.
* \return An \c MBEDTLS_ERR_ECP_XXX error code on failure.
*
*/
int mbedtls_everest_read_params( mbedtls_ecdh_context_everest *ctx,
const unsigned char **buf, const unsigned char *end );
/**
* \brief This function sets up an ECDH context from an EC key.
*
* It is used by clients and servers in place of the
* ServerKeyEchange for static ECDH, and imports ECDH
* parameters from the EC key information of a certificate.
*
* \see ecp.h
*
* \param ctx The ECDH context to set up.
* \param key The EC key to use.
* \param side Defines the source of the key: 1: Our key, or
* 0: The key of the peer.
*
* \return \c 0 on success.
* \return An \c MBEDTLS_ERR_ECP_XXX error code on failure.
*
*/
int mbedtls_everest_get_params( mbedtls_ecdh_context_everest *ctx, const mbedtls_ecp_keypair *key,
mbedtls_everest_ecdh_side side );
/**
* \brief This function generates a public key and a TLS
* ClientKeyExchange payload.
*
* This is the second function used by a TLS client for ECDH(E)
* ciphersuites.
*
* \see ecp.h
*
* \param ctx The ECDH context.
* \param olen The number of Bytes written.
* \param buf The destination buffer.
* \param blen The size of the destination buffer.
* \param f_rng The RNG function.
* \param p_rng The RNG context.
*
* \return \c 0 on success.
* \return An \c MBEDTLS_ERR_ECP_XXX error code on failure.
*/
int mbedtls_everest_make_public( mbedtls_ecdh_context_everest *ctx, size_t *olen,
unsigned char *buf, size_t blen,
int( *f_rng )( void *, unsigned char *, size_t ),
void *p_rng );
/**
* \brief This function parses and processes a TLS ClientKeyExchange
* payload.
*
* This is the third function used by a TLS server for ECDH(E)
* ciphersuites. (It is called after mbedtls_ecdh_setup() and
* mbedtls_ecdh_make_params().)
*
* \see ecp.h
*
* \param ctx The ECDH context.
* \param buf The start of the input buffer.
* \param blen The length of the input buffer.
*
* \return \c 0 on success.
* \return An \c MBEDTLS_ERR_ECP_XXX error code on failure.
*/
int mbedtls_everest_read_public( mbedtls_ecdh_context_everest *ctx,
const unsigned char *buf, size_t blen );
/**
* \brief This function derives and exports the shared secret.
*
* This is the last function used by both TLS client
* and servers.
*
* \note If \p f_rng is not NULL, it is used to implement
* countermeasures against side-channel attacks.
* For more information, see mbedtls_ecp_mul().
*
* \see ecp.h
*
* \param ctx The ECDH context.
* \param olen The number of Bytes written.
* \param buf The destination buffer.
* \param blen The length of the destination buffer.
* \param f_rng The RNG function.
* \param p_rng The RNG context.
*
* \return \c 0 on success.
* \return An \c MBEDTLS_ERR_ECP_XXX error code on failure.
*/
int mbedtls_everest_calc_secret( mbedtls_ecdh_context_everest *ctx, size_t *olen,
unsigned char *buf, size_t blen,
int( *f_rng )( void *, unsigned char *, size_t ),
void *p_rng );
#ifdef __cplusplus
}
#endif
#endif /* MBEDTLS_EVEREST_H */

View File

@ -0,0 +1,29 @@
/*
* Copyright 2016-2018 INRIA and Microsoft Corporation
*
* SPDX-License-Identifier: Apache-2.0
*
* 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.
*
* This file is part of Mbed TLS (https://tls.mbed.org) and
* originated from Project Everest (https://project-everest.github.io/)
*/
#ifndef __KREMLIB_H
#define __KREMLIB_H
#include "kremlin/internal/target.h"
#include "kremlin/internal/types.h"
#include "kremlin/c_endianness.h"
#endif /* __KREMLIB_H */

View File

@ -0,0 +1,124 @@
/* Copyright (c) INRIA and Microsoft Corporation. All rights reserved.
Licensed under the Apache 2.0 License. */
/* This file was generated by KreMLin <https://github.com/FStarLang/kremlin>
* KreMLin invocation: ../krml -fc89 -fparentheses -fno-shadow -header /mnt/e/everest/verify/hdrB9w -minimal -fparentheses -fcurly-braces -fno-shadow -header copyright-header.txt -minimal -tmpdir dist/uint128 -skip-compilation -extract-uints -add-include <inttypes.h> -add-include <stdbool.h> -add-include "kremlin/internal/types.h" -bundle FStar.UInt128=* extracted/prims.krml extracted/FStar_Pervasives_Native.krml extracted/FStar_Pervasives.krml extracted/FStar_Mul.krml extracted/FStar_Squash.krml extracted/FStar_Classical.krml extracted/FStar_StrongExcludedMiddle.krml extracted/FStar_FunctionalExtensionality.krml extracted/FStar_List_Tot_Base.krml extracted/FStar_List_Tot_Properties.krml extracted/FStar_List_Tot.krml extracted/FStar_Seq_Base.krml extracted/FStar_Seq_Properties.krml extracted/FStar_Seq.krml extracted/FStar_Math_Lib.krml extracted/FStar_Math_Lemmas.krml extracted/FStar_BitVector.krml extracted/FStar_UInt.krml extracted/FStar_UInt32.krml extracted/FStar_Int.krml extracted/FStar_Int16.krml extracted/FStar_Preorder.krml extracted/FStar_Ghost.krml extracted/FStar_ErasedLogic.krml extracted/FStar_UInt64.krml extracted/FStar_Set.krml extracted/FStar_PropositionalExtensionality.krml extracted/FStar_PredicateExtensionality.krml extracted/FStar_TSet.krml extracted/FStar_Monotonic_Heap.krml extracted/FStar_Heap.krml extracted/FStar_Map.krml extracted/FStar_Monotonic_HyperHeap.krml extracted/FStar_Monotonic_HyperStack.krml extracted/FStar_HyperStack.krml extracted/FStar_Monotonic_Witnessed.krml extracted/FStar_HyperStack_ST.krml extracted/FStar_HyperStack_All.krml extracted/FStar_Date.krml extracted/FStar_Universe.krml extracted/FStar_GSet.krml extracted/FStar_ModifiesGen.krml extracted/LowStar_Monotonic_Buffer.krml extracted/LowStar_Buffer.krml extracted/Spec_Loops.krml extracted/LowStar_BufferOps.krml extracted/C_Loops.krml extracted/FStar_UInt8.krml extracted/FStar_Kremlin_Endianness.krml extracted/FStar_UInt63.krml extracted/FStar_Exn.krml extracted/FStar_ST.krml extracted/FStar_All.krml extracted/FStar_Dyn.krml extracted/FStar_Int63.krml extracted/FStar_Int64.krml extracted/FStar_Int32.krml extracted/FStar_Int8.krml extracted/FStar_UInt16.krml extracted/FStar_Int_Cast.krml extracted/FStar_UInt128.krml extracted/C_Endianness.krml extracted/FStar_List.krml extracted/FStar_Float.krml extracted/FStar_IO.krml extracted/C.krml extracted/FStar_Char.krml extracted/FStar_String.krml extracted/LowStar_Modifies.krml extracted/C_String.krml extracted/FStar_Bytes.krml extracted/FStar_HyperStack_IO.krml extracted/C_Failure.krml extracted/TestLib.krml extracted/FStar_Int_Cast_Full.krml
* F* version: 059db0c8
* KreMLin version: 916c37ac
*/
#ifndef __FStar_UInt128_H
#define __FStar_UInt128_H
#include <inttypes.h>
#include <stdbool.h>
#include "kremlin/internal/types.h"
uint64_t FStar_UInt128___proj__Mkuint128__item__low(FStar_UInt128_uint128 projectee);
uint64_t FStar_UInt128___proj__Mkuint128__item__high(FStar_UInt128_uint128 projectee);
typedef FStar_UInt128_uint128 FStar_UInt128_t;
FStar_UInt128_uint128 FStar_UInt128_add(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b);
FStar_UInt128_uint128
FStar_UInt128_add_underspec(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b);
FStar_UInt128_uint128 FStar_UInt128_add_mod(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b);
FStar_UInt128_uint128 FStar_UInt128_sub(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b);
FStar_UInt128_uint128
FStar_UInt128_sub_underspec(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b);
FStar_UInt128_uint128 FStar_UInt128_sub_mod(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b);
FStar_UInt128_uint128 FStar_UInt128_logand(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b);
FStar_UInt128_uint128 FStar_UInt128_logxor(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b);
FStar_UInt128_uint128 FStar_UInt128_logor(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b);
FStar_UInt128_uint128 FStar_UInt128_lognot(FStar_UInt128_uint128 a);
FStar_UInt128_uint128 FStar_UInt128_shift_left(FStar_UInt128_uint128 a, uint32_t s);
FStar_UInt128_uint128 FStar_UInt128_shift_right(FStar_UInt128_uint128 a, uint32_t s);
bool FStar_UInt128_eq(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b);
bool FStar_UInt128_gt(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b);
bool FStar_UInt128_lt(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b);
bool FStar_UInt128_gte(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b);
bool FStar_UInt128_lte(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b);
FStar_UInt128_uint128 FStar_UInt128_eq_mask(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b);
FStar_UInt128_uint128 FStar_UInt128_gte_mask(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b);
FStar_UInt128_uint128 FStar_UInt128_uint64_to_uint128(uint64_t a);
uint64_t FStar_UInt128_uint128_to_uint64(FStar_UInt128_uint128 a);
extern FStar_UInt128_uint128
(*FStar_UInt128_op_Plus_Hat)(FStar_UInt128_uint128 x0, FStar_UInt128_uint128 x1);
extern FStar_UInt128_uint128
(*FStar_UInt128_op_Plus_Question_Hat)(FStar_UInt128_uint128 x0, FStar_UInt128_uint128 x1);
extern FStar_UInt128_uint128
(*FStar_UInt128_op_Plus_Percent_Hat)(FStar_UInt128_uint128 x0, FStar_UInt128_uint128 x1);
extern FStar_UInt128_uint128
(*FStar_UInt128_op_Subtraction_Hat)(FStar_UInt128_uint128 x0, FStar_UInt128_uint128 x1);
extern FStar_UInt128_uint128
(*FStar_UInt128_op_Subtraction_Question_Hat)(
FStar_UInt128_uint128 x0,
FStar_UInt128_uint128 x1
);
extern FStar_UInt128_uint128
(*FStar_UInt128_op_Subtraction_Percent_Hat)(FStar_UInt128_uint128 x0, FStar_UInt128_uint128 x1);
extern FStar_UInt128_uint128
(*FStar_UInt128_op_Amp_Hat)(FStar_UInt128_uint128 x0, FStar_UInt128_uint128 x1);
extern FStar_UInt128_uint128
(*FStar_UInt128_op_Hat_Hat)(FStar_UInt128_uint128 x0, FStar_UInt128_uint128 x1);
extern FStar_UInt128_uint128
(*FStar_UInt128_op_Bar_Hat)(FStar_UInt128_uint128 x0, FStar_UInt128_uint128 x1);
extern FStar_UInt128_uint128
(*FStar_UInt128_op_Less_Less_Hat)(FStar_UInt128_uint128 x0, uint32_t x1);
extern FStar_UInt128_uint128
(*FStar_UInt128_op_Greater_Greater_Hat)(FStar_UInt128_uint128 x0, uint32_t x1);
extern bool (*FStar_UInt128_op_Equals_Hat)(FStar_UInt128_uint128 x0, FStar_UInt128_uint128 x1);
extern bool
(*FStar_UInt128_op_Greater_Hat)(FStar_UInt128_uint128 x0, FStar_UInt128_uint128 x1);
extern bool (*FStar_UInt128_op_Less_Hat)(FStar_UInt128_uint128 x0, FStar_UInt128_uint128 x1);
extern bool
(*FStar_UInt128_op_Greater_Equals_Hat)(FStar_UInt128_uint128 x0, FStar_UInt128_uint128 x1);
extern bool
(*FStar_UInt128_op_Less_Equals_Hat)(FStar_UInt128_uint128 x0, FStar_UInt128_uint128 x1);
FStar_UInt128_uint128 FStar_UInt128_mul32(uint64_t x, uint32_t y);
FStar_UInt128_uint128 FStar_UInt128_mul_wide(uint64_t x, uint64_t y);
#define __FStar_UInt128_H_DEFINED
#endif

View File

@ -0,0 +1,280 @@
/* Copyright (c) INRIA and Microsoft Corporation. All rights reserved.
Licensed under the Apache 2.0 License. */
/* This file was generated by KreMLin <https://github.com/FStarLang/kremlin>
* KreMLin invocation: ../krml -fc89 -fparentheses -fno-shadow -header /mnt/e/everest/verify/hdrB9w -minimal -fparentheses -fcurly-braces -fno-shadow -header copyright-header.txt -minimal -tmpdir dist/minimal -skip-compilation -extract-uints -add-include <inttypes.h> -add-include <stdbool.h> -add-include "kremlin/internal/compat.h" -add-include "kremlin/internal/types.h" -bundle FStar.UInt64+FStar.UInt32+FStar.UInt16+FStar.UInt8=* extracted/prims.krml extracted/FStar_Pervasives_Native.krml extracted/FStar_Pervasives.krml extracted/FStar_Mul.krml extracted/FStar_Squash.krml extracted/FStar_Classical.krml extracted/FStar_StrongExcludedMiddle.krml extracted/FStar_FunctionalExtensionality.krml extracted/FStar_List_Tot_Base.krml extracted/FStar_List_Tot_Properties.krml extracted/FStar_List_Tot.krml extracted/FStar_Seq_Base.krml extracted/FStar_Seq_Properties.krml extracted/FStar_Seq.krml extracted/FStar_Math_Lib.krml extracted/FStar_Math_Lemmas.krml extracted/FStar_BitVector.krml extracted/FStar_UInt.krml extracted/FStar_UInt32.krml extracted/FStar_Int.krml extracted/FStar_Int16.krml extracted/FStar_Preorder.krml extracted/FStar_Ghost.krml extracted/FStar_ErasedLogic.krml extracted/FStar_UInt64.krml extracted/FStar_Set.krml extracted/FStar_PropositionalExtensionality.krml extracted/FStar_PredicateExtensionality.krml extracted/FStar_TSet.krml extracted/FStar_Monotonic_Heap.krml extracted/FStar_Heap.krml extracted/FStar_Map.krml extracted/FStar_Monotonic_HyperHeap.krml extracted/FStar_Monotonic_HyperStack.krml extracted/FStar_HyperStack.krml extracted/FStar_Monotonic_Witnessed.krml extracted/FStar_HyperStack_ST.krml extracted/FStar_HyperStack_All.krml extracted/FStar_Date.krml extracted/FStar_Universe.krml extracted/FStar_GSet.krml extracted/FStar_ModifiesGen.krml extracted/LowStar_Monotonic_Buffer.krml extracted/LowStar_Buffer.krml extracted/Spec_Loops.krml extracted/LowStar_BufferOps.krml extracted/C_Loops.krml extracted/FStar_UInt8.krml extracted/FStar_Kremlin_Endianness.krml extracted/FStar_UInt63.krml extracted/FStar_Exn.krml extracted/FStar_ST.krml extracted/FStar_All.krml extracted/FStar_Dyn.krml extracted/FStar_Int63.krml extracted/FStar_Int64.krml extracted/FStar_Int32.krml extracted/FStar_Int8.krml extracted/FStar_UInt16.krml extracted/FStar_Int_Cast.krml extracted/FStar_UInt128.krml extracted/C_Endianness.krml extracted/FStar_List.krml extracted/FStar_Float.krml extracted/FStar_IO.krml extracted/C.krml extracted/FStar_Char.krml extracted/FStar_String.krml extracted/LowStar_Modifies.krml extracted/C_String.krml extracted/FStar_Bytes.krml extracted/FStar_HyperStack_IO.krml extracted/C_Failure.krml extracted/TestLib.krml extracted/FStar_Int_Cast_Full.krml
* F* version: 059db0c8
* KreMLin version: 916c37ac
*/
#ifndef __FStar_UInt64_FStar_UInt32_FStar_UInt16_FStar_UInt8_H
#define __FStar_UInt64_FStar_UInt32_FStar_UInt16_FStar_UInt8_H
#include <inttypes.h>
#include <stdbool.h>
#include "kremlin/internal/compat.h"
#include "kremlin/internal/types.h"
extern Prims_int FStar_UInt64_n;
extern Prims_int FStar_UInt64_v(uint64_t x0);
extern uint64_t FStar_UInt64_uint_to_t(Prims_int x0);
extern uint64_t FStar_UInt64_add(uint64_t x0, uint64_t x1);
extern uint64_t FStar_UInt64_add_underspec(uint64_t x0, uint64_t x1);
extern uint64_t FStar_UInt64_add_mod(uint64_t x0, uint64_t x1);
extern uint64_t FStar_UInt64_sub(uint64_t x0, uint64_t x1);
extern uint64_t FStar_UInt64_sub_underspec(uint64_t x0, uint64_t x1);
extern uint64_t FStar_UInt64_sub_mod(uint64_t x0, uint64_t x1);
extern uint64_t FStar_UInt64_mul(uint64_t x0, uint64_t x1);
extern uint64_t FStar_UInt64_mul_underspec(uint64_t x0, uint64_t x1);
extern uint64_t FStar_UInt64_mul_mod(uint64_t x0, uint64_t x1);
extern uint64_t FStar_UInt64_mul_div(uint64_t x0, uint64_t x1);
extern uint64_t FStar_UInt64_div(uint64_t x0, uint64_t x1);
extern uint64_t FStar_UInt64_rem(uint64_t x0, uint64_t x1);
extern uint64_t FStar_UInt64_logand(uint64_t x0, uint64_t x1);
extern uint64_t FStar_UInt64_logxor(uint64_t x0, uint64_t x1);
extern uint64_t FStar_UInt64_logor(uint64_t x0, uint64_t x1);
extern uint64_t FStar_UInt64_lognot(uint64_t x0);
extern uint64_t FStar_UInt64_shift_right(uint64_t x0, uint32_t x1);
extern uint64_t FStar_UInt64_shift_left(uint64_t x0, uint32_t x1);
extern bool FStar_UInt64_eq(uint64_t x0, uint64_t x1);
extern bool FStar_UInt64_gt(uint64_t x0, uint64_t x1);
extern bool FStar_UInt64_gte(uint64_t x0, uint64_t x1);
extern bool FStar_UInt64_lt(uint64_t x0, uint64_t x1);
extern bool FStar_UInt64_lte(uint64_t x0, uint64_t x1);
extern uint64_t FStar_UInt64_minus(uint64_t x0);
extern uint32_t FStar_UInt64_n_minus_one;
uint64_t FStar_UInt64_eq_mask(uint64_t a, uint64_t b);
uint64_t FStar_UInt64_gte_mask(uint64_t a, uint64_t b);
extern Prims_string FStar_UInt64_to_string(uint64_t x0);
extern uint64_t FStar_UInt64_of_string(Prims_string x0);
extern Prims_int FStar_UInt32_n;
extern Prims_int FStar_UInt32_v(uint32_t x0);
extern uint32_t FStar_UInt32_uint_to_t(Prims_int x0);
extern uint32_t FStar_UInt32_add(uint32_t x0, uint32_t x1);
extern uint32_t FStar_UInt32_add_underspec(uint32_t x0, uint32_t x1);
extern uint32_t FStar_UInt32_add_mod(uint32_t x0, uint32_t x1);
extern uint32_t FStar_UInt32_sub(uint32_t x0, uint32_t x1);
extern uint32_t FStar_UInt32_sub_underspec(uint32_t x0, uint32_t x1);
extern uint32_t FStar_UInt32_sub_mod(uint32_t x0, uint32_t x1);
extern uint32_t FStar_UInt32_mul(uint32_t x0, uint32_t x1);
extern uint32_t FStar_UInt32_mul_underspec(uint32_t x0, uint32_t x1);
extern uint32_t FStar_UInt32_mul_mod(uint32_t x0, uint32_t x1);
extern uint32_t FStar_UInt32_mul_div(uint32_t x0, uint32_t x1);
extern uint32_t FStar_UInt32_div(uint32_t x0, uint32_t x1);
extern uint32_t FStar_UInt32_rem(uint32_t x0, uint32_t x1);
extern uint32_t FStar_UInt32_logand(uint32_t x0, uint32_t x1);
extern uint32_t FStar_UInt32_logxor(uint32_t x0, uint32_t x1);
extern uint32_t FStar_UInt32_logor(uint32_t x0, uint32_t x1);
extern uint32_t FStar_UInt32_lognot(uint32_t x0);
extern uint32_t FStar_UInt32_shift_right(uint32_t x0, uint32_t x1);
extern uint32_t FStar_UInt32_shift_left(uint32_t x0, uint32_t x1);
extern bool FStar_UInt32_eq(uint32_t x0, uint32_t x1);
extern bool FStar_UInt32_gt(uint32_t x0, uint32_t x1);
extern bool FStar_UInt32_gte(uint32_t x0, uint32_t x1);
extern bool FStar_UInt32_lt(uint32_t x0, uint32_t x1);
extern bool FStar_UInt32_lte(uint32_t x0, uint32_t x1);
extern uint32_t FStar_UInt32_minus(uint32_t x0);
extern uint32_t FStar_UInt32_n_minus_one;
uint32_t FStar_UInt32_eq_mask(uint32_t a, uint32_t b);
uint32_t FStar_UInt32_gte_mask(uint32_t a, uint32_t b);
extern Prims_string FStar_UInt32_to_string(uint32_t x0);
extern uint32_t FStar_UInt32_of_string(Prims_string x0);
extern Prims_int FStar_UInt16_n;
extern Prims_int FStar_UInt16_v(uint16_t x0);
extern uint16_t FStar_UInt16_uint_to_t(Prims_int x0);
extern uint16_t FStar_UInt16_add(uint16_t x0, uint16_t x1);
extern uint16_t FStar_UInt16_add_underspec(uint16_t x0, uint16_t x1);
extern uint16_t FStar_UInt16_add_mod(uint16_t x0, uint16_t x1);
extern uint16_t FStar_UInt16_sub(uint16_t x0, uint16_t x1);
extern uint16_t FStar_UInt16_sub_underspec(uint16_t x0, uint16_t x1);
extern uint16_t FStar_UInt16_sub_mod(uint16_t x0, uint16_t x1);
extern uint16_t FStar_UInt16_mul(uint16_t x0, uint16_t x1);
extern uint16_t FStar_UInt16_mul_underspec(uint16_t x0, uint16_t x1);
extern uint16_t FStar_UInt16_mul_mod(uint16_t x0, uint16_t x1);
extern uint16_t FStar_UInt16_mul_div(uint16_t x0, uint16_t x1);
extern uint16_t FStar_UInt16_div(uint16_t x0, uint16_t x1);
extern uint16_t FStar_UInt16_rem(uint16_t x0, uint16_t x1);
extern uint16_t FStar_UInt16_logand(uint16_t x0, uint16_t x1);
extern uint16_t FStar_UInt16_logxor(uint16_t x0, uint16_t x1);
extern uint16_t FStar_UInt16_logor(uint16_t x0, uint16_t x1);
extern uint16_t FStar_UInt16_lognot(uint16_t x0);
extern uint16_t FStar_UInt16_shift_right(uint16_t x0, uint32_t x1);
extern uint16_t FStar_UInt16_shift_left(uint16_t x0, uint32_t x1);
extern bool FStar_UInt16_eq(uint16_t x0, uint16_t x1);
extern bool FStar_UInt16_gt(uint16_t x0, uint16_t x1);
extern bool FStar_UInt16_gte(uint16_t x0, uint16_t x1);
extern bool FStar_UInt16_lt(uint16_t x0, uint16_t x1);
extern bool FStar_UInt16_lte(uint16_t x0, uint16_t x1);
extern uint16_t FStar_UInt16_minus(uint16_t x0);
extern uint32_t FStar_UInt16_n_minus_one;
uint16_t FStar_UInt16_eq_mask(uint16_t a, uint16_t b);
uint16_t FStar_UInt16_gte_mask(uint16_t a, uint16_t b);
extern Prims_string FStar_UInt16_to_string(uint16_t x0);
extern uint16_t FStar_UInt16_of_string(Prims_string x0);
extern Prims_int FStar_UInt8_n;
extern Prims_int FStar_UInt8_v(uint8_t x0);
extern uint8_t FStar_UInt8_uint_to_t(Prims_int x0);
extern uint8_t FStar_UInt8_add(uint8_t x0, uint8_t x1);
extern uint8_t FStar_UInt8_add_underspec(uint8_t x0, uint8_t x1);
extern uint8_t FStar_UInt8_add_mod(uint8_t x0, uint8_t x1);
extern uint8_t FStar_UInt8_sub(uint8_t x0, uint8_t x1);
extern uint8_t FStar_UInt8_sub_underspec(uint8_t x0, uint8_t x1);
extern uint8_t FStar_UInt8_sub_mod(uint8_t x0, uint8_t x1);
extern uint8_t FStar_UInt8_mul(uint8_t x0, uint8_t x1);
extern uint8_t FStar_UInt8_mul_underspec(uint8_t x0, uint8_t x1);
extern uint8_t FStar_UInt8_mul_mod(uint8_t x0, uint8_t x1);
extern uint8_t FStar_UInt8_mul_div(uint8_t x0, uint8_t x1);
extern uint8_t FStar_UInt8_div(uint8_t x0, uint8_t x1);
extern uint8_t FStar_UInt8_rem(uint8_t x0, uint8_t x1);
extern uint8_t FStar_UInt8_logand(uint8_t x0, uint8_t x1);
extern uint8_t FStar_UInt8_logxor(uint8_t x0, uint8_t x1);
extern uint8_t FStar_UInt8_logor(uint8_t x0, uint8_t x1);
extern uint8_t FStar_UInt8_lognot(uint8_t x0);
extern uint8_t FStar_UInt8_shift_right(uint8_t x0, uint32_t x1);
extern uint8_t FStar_UInt8_shift_left(uint8_t x0, uint32_t x1);
extern bool FStar_UInt8_eq(uint8_t x0, uint8_t x1);
extern bool FStar_UInt8_gt(uint8_t x0, uint8_t x1);
extern bool FStar_UInt8_gte(uint8_t x0, uint8_t x1);
extern bool FStar_UInt8_lt(uint8_t x0, uint8_t x1);
extern bool FStar_UInt8_lte(uint8_t x0, uint8_t x1);
extern uint8_t FStar_UInt8_minus(uint8_t x0);
extern uint32_t FStar_UInt8_n_minus_one;
uint8_t FStar_UInt8_eq_mask(uint8_t a, uint8_t b);
uint8_t FStar_UInt8_gte_mask(uint8_t a, uint8_t b);
extern Prims_string FStar_UInt8_to_string(uint8_t x0);
extern uint8_t FStar_UInt8_of_string(Prims_string x0);
typedef uint8_t FStar_UInt8_byte;
#define __FStar_UInt64_FStar_UInt32_FStar_UInt16_FStar_UInt8_H_DEFINED
#endif

View File

@ -0,0 +1,204 @@
/* Copyright (c) INRIA and Microsoft Corporation. All rights reserved.
Licensed under the Apache 2.0 License. */
#ifndef __KREMLIN_ENDIAN_H
#define __KREMLIN_ENDIAN_H
#include <string.h>
#include <inttypes.h>
/******************************************************************************/
/* Implementing C.fst (part 2: endian-ness macros) */
/******************************************************************************/
/* ... for Linux */
#if defined(__linux__) || defined(__CYGWIN__)
# include <endian.h>
/* ... for OSX */
#elif defined(__APPLE__)
# include <libkern/OSByteOrder.h>
# define htole64(x) OSSwapHostToLittleInt64(x)
# define le64toh(x) OSSwapLittleToHostInt64(x)
# define htobe64(x) OSSwapHostToBigInt64(x)
# define be64toh(x) OSSwapBigToHostInt64(x)
# define htole16(x) OSSwapHostToLittleInt16(x)
# define le16toh(x) OSSwapLittleToHostInt16(x)
# define htobe16(x) OSSwapHostToBigInt16(x)
# define be16toh(x) OSSwapBigToHostInt16(x)
# define htole32(x) OSSwapHostToLittleInt32(x)
# define le32toh(x) OSSwapLittleToHostInt32(x)
# define htobe32(x) OSSwapHostToBigInt32(x)
# define be32toh(x) OSSwapBigToHostInt32(x)
/* ... for Solaris */
#elif defined(__sun__)
# include <sys/byteorder.h>
# define htole64(x) LE_64(x)
# define le64toh(x) LE_64(x)
# define htobe64(x) BE_64(x)
# define be64toh(x) BE_64(x)
# define htole16(x) LE_16(x)
# define le16toh(x) LE_16(x)
# define htobe16(x) BE_16(x)
# define be16toh(x) BE_16(x)
# define htole32(x) LE_32(x)
# define le32toh(x) LE_32(x)
# define htobe32(x) BE_32(x)
# define be32toh(x) BE_32(x)
/* ... for the BSDs */
#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__)
# include <sys/endian.h>
#elif defined(__OpenBSD__)
# include <endian.h>
/* ... for Windows (MSVC)... not targeting XBOX 360! */
#elif defined(_MSC_VER)
# include <stdlib.h>
# define htobe16(x) _byteswap_ushort(x)
# define htole16(x) (x)
# define be16toh(x) _byteswap_ushort(x)
# define le16toh(x) (x)
# define htobe32(x) _byteswap_ulong(x)
# define htole32(x) (x)
# define be32toh(x) _byteswap_ulong(x)
# define le32toh(x) (x)
# define htobe64(x) _byteswap_uint64(x)
# define htole64(x) (x)
# define be64toh(x) _byteswap_uint64(x)
# define le64toh(x) (x)
/* ... for Windows (GCC-like, e.g. mingw or clang) */
#elif (defined(_WIN32) || defined(_WIN64)) && \
(defined(__GNUC__) || defined(__clang__))
# define htobe16(x) __builtin_bswap16(x)
# define htole16(x) (x)
# define be16toh(x) __builtin_bswap16(x)
# define le16toh(x) (x)
# define htobe32(x) __builtin_bswap32(x)
# define htole32(x) (x)
# define be32toh(x) __builtin_bswap32(x)
# define le32toh(x) (x)
# define htobe64(x) __builtin_bswap64(x)
# define htole64(x) (x)
# define be64toh(x) __builtin_bswap64(x)
# define le64toh(x) (x)
/* ... generic big-endian fallback code */
#elif defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
/* byte swapping code inspired by:
* https://github.com/rweather/arduinolibs/blob/master/libraries/Crypto/utility/EndianUtil.h
* */
# define htobe32(x) (x)
# define be32toh(x) (x)
# define htole32(x) \
(__extension__({ \
uint32_t _temp = (x); \
((_temp >> 24) & 0x000000FF) | ((_temp >> 8) & 0x0000FF00) | \
((_temp << 8) & 0x00FF0000) | ((_temp << 24) & 0xFF000000); \
}))
# define le32toh(x) (htole32((x)))
# define htobe64(x) (x)
# define be64toh(x) (x)
# define htole64(x) \
(__extension__({ \
uint64_t __temp = (x); \
uint32_t __low = htobe32((uint32_t)__temp); \
uint32_t __high = htobe32((uint32_t)(__temp >> 32)); \
(((uint64_t)__low) << 32) | __high; \
}))
# define le64toh(x) (htole64((x)))
/* ... generic little-endian fallback code */
#elif defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
# define htole32(x) (x)
# define le32toh(x) (x)
# define htobe32(x) \
(__extension__({ \
uint32_t _temp = (x); \
((_temp >> 24) & 0x000000FF) | ((_temp >> 8) & 0x0000FF00) | \
((_temp << 8) & 0x00FF0000) | ((_temp << 24) & 0xFF000000); \
}))
# define be32toh(x) (htobe32((x)))
# define htole64(x) (x)
# define le64toh(x) (x)
# define htobe64(x) \
(__extension__({ \
uint64_t __temp = (x); \
uint32_t __low = htobe32((uint32_t)__temp); \
uint32_t __high = htobe32((uint32_t)(__temp >> 32)); \
(((uint64_t)__low) << 32) | __high; \
}))
# define be64toh(x) (htobe64((x)))
/* ... couldn't determine endian-ness of the target platform */
#else
# error "Please define __BYTE_ORDER__!"
#endif /* defined(__linux__) || ... */
/* Loads and stores. These avoid undefined behavior due to unaligned memory
* accesses, via memcpy. */
inline static uint16_t load16(uint8_t *b) {
uint16_t x;
memcpy(&x, b, 2);
return x;
}
inline static uint32_t load32(uint8_t *b) {
uint32_t x;
memcpy(&x, b, 4);
return x;
}
inline static uint64_t load64(uint8_t *b) {
uint64_t x;
memcpy(&x, b, 8);
return x;
}
inline static void store16(uint8_t *b, uint16_t i) {
memcpy(b, &i, 2);
}
inline static void store32(uint8_t *b, uint32_t i) {
memcpy(b, &i, 4);
}
inline static void store64(uint8_t *b, uint64_t i) {
memcpy(b, &i, 8);
}
#define load16_le(b) (le16toh(load16(b)))
#define store16_le(b, i) (store16(b, htole16(i)))
#define load16_be(b) (be16toh(load16(b)))
#define store16_be(b, i) (store16(b, htobe16(i)))
#define load32_le(b) (le32toh(load32(b)))
#define store32_le(b, i) (store32(b, htole32(i)))
#define load32_be(b) (be32toh(load32(b)))
#define store32_be(b, i) (store32(b, htobe32(i)))
#define load64_le(b) (le64toh(load64(b)))
#define store64_le(b, i) (store64(b, htole64(i)))
#define load64_be(b) (be64toh(load64(b)))
#define store64_be(b, i) (store64(b, htobe64(i)))
#endif

View File

@ -0,0 +1,16 @@
/* Copyright (c) INRIA and Microsoft Corporation. All rights reserved.
Licensed under the Apache 2.0 License. */
#ifndef __KREMLIN_BUILTIN_H
#define __KREMLIN_BUILTIN_H
/* For alloca, when using KreMLin's -falloca */
#if (defined(_WIN32) || defined(_WIN64))
# include <malloc.h>
#endif
/* If some globals need to be initialized before the main, then kremlin will
* generate and try to link last a function with this type: */
void kremlinit_globals(void);
#endif

View File

@ -0,0 +1,46 @@
/* Copyright (c) INRIA and Microsoft Corporation. All rights reserved.
Licensed under the Apache 2.0 License. */
#ifndef __KREMLIN_CALLCONV_H
#define __KREMLIN_CALLCONV_H
/******************************************************************************/
/* Some macros to ease compatibility */
/******************************************************************************/
/* We want to generate __cdecl safely without worrying about it being undefined.
* When using MSVC, these are always defined. When using MinGW, these are
* defined too. They have no meaning for other platforms, so we define them to
* be empty macros in other situations. */
#ifndef _MSC_VER
#ifndef __cdecl
#define __cdecl
#endif
#ifndef __stdcall
#define __stdcall
#endif
#ifndef __fastcall
#define __fastcall
#endif
#endif
/* Since KreMLin emits the inline keyword unconditionally, we follow the
* guidelines at https://gcc.gnu.org/onlinedocs/gcc/Inline.html and make this
* __inline__ to ensure the code compiles with -std=c90 and earlier. */
#ifdef __GNUC__
# define inline __inline__
#endif
/* GCC-specific attribute syntax; everyone else gets the standard C inline
* attribute. */
#ifdef __GNU_C__
# ifndef __clang__
# define force_inline inline __attribute__((always_inline))
# else
# define force_inline inline
# endif
#else
# define force_inline inline
#endif
#endif

View File

@ -0,0 +1,34 @@
/* Copyright (c) INRIA and Microsoft Corporation. All rights reserved.
Licensed under the Apache 2.0 License. */
#ifndef KRML_COMPAT_H
#define KRML_COMPAT_H
#include <inttypes.h>
/* A series of macros that define C implementations of types that are not Low*,
* to facilitate porting programs to Low*. */
typedef const char *Prims_string;
typedef struct {
uint32_t length;
const char *data;
} FStar_Bytes_bytes;
typedef int32_t Prims_pos, Prims_nat, Prims_nonzero, Prims_int,
krml_checked_int_t;
#define RETURN_OR(x) \
do { \
int64_t __ret = x; \
if (__ret < INT32_MIN || INT32_MAX < __ret) { \
KRML_HOST_PRINTF( \
"Prims.{int,nat,pos} integer overflow at %s:%d\n", __FILE__, \
__LINE__); \
KRML_HOST_EXIT(252); \
} \
return (int32_t)__ret; \
} while (0)
#endif

View File

@ -0,0 +1,57 @@
/* Copyright (c) INRIA and Microsoft Corporation. All rights reserved.
Licensed under the Apache 2.0 License. */
#ifndef __KREMLIN_DEBUG_H
#define __KREMLIN_DEBUG_H
#include <inttypes.h>
#include "kremlin/internal/target.h"
/******************************************************************************/
/* Debugging helpers - intended only for KreMLin developers */
/******************************************************************************/
/* In support of "-wasm -d force-c": we might need this function to be
* forward-declared, because the dependency on WasmSupport appears very late,
* after SimplifyWasm, and sadly, after the topological order has been done. */
void WasmSupport_check_buffer_size(uint32_t s);
/* A series of GCC atrocities to trace function calls (kremlin's [-d c-calls]
* option). Useful when trying to debug, say, Wasm, to compare traces. */
/* clang-format off */
#ifdef __GNUC__
#define KRML_FORMAT(X) _Generic((X), \
uint8_t : "0x%08" PRIx8, \
uint16_t: "0x%08" PRIx16, \
uint32_t: "0x%08" PRIx32, \
uint64_t: "0x%08" PRIx64, \
int8_t : "0x%08" PRIx8, \
int16_t : "0x%08" PRIx16, \
int32_t : "0x%08" PRIx32, \
int64_t : "0x%08" PRIx64, \
default : "%s")
#define KRML_FORMAT_ARG(X) _Generic((X), \
uint8_t : X, \
uint16_t: X, \
uint32_t: X, \
uint64_t: X, \
int8_t : X, \
int16_t : X, \
int32_t : X, \
int64_t : X, \
default : "unknown")
/* clang-format on */
# define KRML_DEBUG_RETURN(X) \
({ \
__auto_type _ret = (X); \
KRML_HOST_PRINTF("returning: "); \
KRML_HOST_PRINTF(KRML_FORMAT(_ret), KRML_FORMAT_ARG(_ret)); \
KRML_HOST_PRINTF(" \n"); \
_ret; \
})
#endif
#endif

View File

@ -0,0 +1,102 @@
/* Copyright (c) INRIA and Microsoft Corporation. All rights reserved.
Licensed under the Apache 2.0 License. */
#ifndef __KREMLIN_TARGET_H
#define __KREMLIN_TARGET_H
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include <inttypes.h>
#include <limits.h>
#include "kremlin/internal/callconv.h"
/******************************************************************************/
/* Macros that KreMLin will generate. */
/******************************************************************************/
/* For "bare" targets that do not have a C stdlib, the user might want to use
* [-add-early-include '"mydefinitions.h"'] and override these. */
#ifndef KRML_HOST_PRINTF
# define KRML_HOST_PRINTF printf
#endif
#if ( \
(defined __STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \
(!(defined KRML_HOST_EPRINTF)))
# define KRML_HOST_EPRINTF(...) fprintf(stderr, __VA_ARGS__)
#endif
#ifndef KRML_HOST_EXIT
# define KRML_HOST_EXIT exit
#endif
#ifndef KRML_HOST_MALLOC
# define KRML_HOST_MALLOC malloc
#endif
#ifndef KRML_HOST_CALLOC
# define KRML_HOST_CALLOC calloc
#endif
#ifndef KRML_HOST_FREE
# define KRML_HOST_FREE free
#endif
#ifndef KRML_HOST_TIME
# include <time.h>
/* Prims_nat not yet in scope */
inline static int32_t krml_time() {
return (int32_t)time(NULL);
}
# define KRML_HOST_TIME krml_time
#endif
/* In statement position, exiting is easy. */
#define KRML_EXIT \
do { \
KRML_HOST_PRINTF("Unimplemented function at %s:%d\n", __FILE__, __LINE__); \
KRML_HOST_EXIT(254); \
} while (0)
/* In expression position, use the comma-operator and a malloc to return an
* expression of the right size. KreMLin passes t as the parameter to the macro.
*/
#define KRML_EABORT(t, msg) \
(KRML_HOST_PRINTF("KreMLin abort at %s:%d\n%s\n", __FILE__, __LINE__, msg), \
KRML_HOST_EXIT(255), *((t *)KRML_HOST_MALLOC(sizeof(t))))
/* In FStar.Buffer.fst, the size of arrays is uint32_t, but it's a number of
* *elements*. Do an ugly, run-time check (some of which KreMLin can eliminate).
*/
#ifdef __GNUC__
# define _KRML_CHECK_SIZE_PRAGMA \
_Pragma("GCC diagnostic ignored \"-Wtype-limits\"")
#else
# define _KRML_CHECK_SIZE_PRAGMA
#endif
#define KRML_CHECK_SIZE(size_elt, sz) \
do { \
_KRML_CHECK_SIZE_PRAGMA \
if (((size_t)(sz)) > ((size_t)(SIZE_MAX / (size_elt)))) { \
KRML_HOST_PRINTF( \
"Maximum allocatable size exceeded, aborting before overflow at " \
"%s:%d\n", \
__FILE__, __LINE__); \
KRML_HOST_EXIT(253); \
} \
} while (0)
#if defined(_MSC_VER) && _MSC_VER < 1900
# define KRML_HOST_SNPRINTF(buf, sz, fmt, arg) _snprintf_s(buf, sz, _TRUNCATE, fmt, arg)
#else
# define KRML_HOST_SNPRINTF(buf, sz, fmt, arg) snprintf(buf, sz, fmt, arg)
#endif
#endif

View File

@ -0,0 +1,61 @@
/* Copyright (c) INRIA and Microsoft Corporation. All rights reserved.
Licensed under the Apache 2.0 License. */
#ifndef KRML_TYPES_H
#define KRML_TYPES_H
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
/* Types which are either abstract, meaning that have to be implemented in C, or
* which are models, meaning that they are swapped out at compile-time for
* hand-written C types (in which case they're marked as noextract). */
typedef uint64_t FStar_UInt64_t, FStar_UInt64_t_;
typedef int64_t FStar_Int64_t, FStar_Int64_t_;
typedef uint32_t FStar_UInt32_t, FStar_UInt32_t_;
typedef int32_t FStar_Int32_t, FStar_Int32_t_;
typedef uint16_t FStar_UInt16_t, FStar_UInt16_t_;
typedef int16_t FStar_Int16_t, FStar_Int16_t_;
typedef uint8_t FStar_UInt8_t, FStar_UInt8_t_;
typedef int8_t FStar_Int8_t, FStar_Int8_t_;
/* Only useful when building Kremlib, because it's in the dependency graph of
* FStar.Int.Cast. */
typedef uint64_t FStar_UInt63_t, FStar_UInt63_t_;
typedef int64_t FStar_Int63_t, FStar_Int63_t_;
typedef double FStar_Float_float;
typedef uint32_t FStar_Char_char;
typedef FILE *FStar_IO_fd_read, *FStar_IO_fd_write;
typedef void *FStar_Dyn_dyn;
typedef const char *C_String_t, *C_String_t_;
typedef int exit_code;
typedef FILE *channel;
typedef unsigned long long TestLib_cycles;
typedef uint64_t FStar_Date_dateTime, FStar_Date_timeSpan;
/* The uint128 type is a special case since we offer several implementations of
* it, depending on the compiler and whether the user wants the verified
* implementation or not. */
#if !defined(KRML_VERIFIED_UINT128) && defined(_MSC_VER) && defined(_M_X64)
# include <emmintrin.h>
typedef __m128i FStar_UInt128_uint128;
#elif !defined(KRML_VERIFIED_UINT128) && !defined(_MSC_VER)
typedef unsigned __int128 FStar_UInt128_uint128;
#else
typedef struct FStar_UInt128_uint128_s {
uint64_t low;
uint64_t high;
} FStar_UInt128_uint128;
#endif
typedef FStar_UInt128_uint128 FStar_UInt128_t, FStar_UInt128_t_, uint128_t;
#endif

View File

@ -0,0 +1,5 @@
/* Copyright (c) INRIA and Microsoft Corporation. All rights reserved.
Licensed under the Apache 2.0 License. */
/* This file is automatically included when compiling with -wasm -d force-c */
#define WasmSupport_check_buffer_size(X)

View File

@ -0,0 +1,21 @@
/* Copyright (c) INRIA and Microsoft Corporation. All rights reserved.
Licensed under the Apache 2.0 License. */
/* This file was generated by KreMLin <https://github.com/FStarLang/kremlin>
* KreMLin invocation: /mnt/e/everest/verify/kremlin/krml -fc89 -fparentheses -fno-shadow -header /mnt/e/everest/verify/hdrcLh -minimal -fc89 -fparentheses -fno-shadow -header /mnt/e/everest/verify/hdrcLh -minimal -I /mnt/e/everest/verify/hacl-star/code/lib/kremlin -I /mnt/e/everest/verify/kremlin/kremlib/compat -I /mnt/e/everest/verify/hacl-star/specs -I /mnt/e/everest/verify/hacl-star/specs/old -I . -ccopt -march=native -verbose -ldopt -flto -tmpdir x25519-c -I ../bignum -bundle Hacl.Curve25519=* -minimal -add-include "kremlib.h" -skip-compilation x25519-c/out.krml -o x25519-c/Hacl_Curve25519.c
* F* version: 059db0c8
* KreMLin version: 916c37ac
*/
#ifndef __Hacl_Curve25519_H
#define __Hacl_Curve25519_H
#include "kremlib.h"
void Hacl_Curve25519_crypto_scalarmult(uint8_t *mypublic, uint8_t *secret, uint8_t *basepoint);
#define __Hacl_Curve25519_H_DEFINED
#endif

View File

@ -0,0 +1,36 @@
/*
* Custom inttypes.h for VS2010 KreMLin requires these definitions,
* but VS2010 doesn't provide them.
*
* Copyright 2016-2018 INRIA and Microsoft Corporation
* SPDX-License-Identifier: Apache-2.0
*
* 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.
*
* This file is part of Mbed TLS (https://tls.mbed.org)
*/
#ifndef _INTTYPES_H_VS2010
#define _INTTYPES_H_VS2010
#include <stdint.h>
#ifdef _MSC_VER
#define inline __inline
#endif
/* VS2010 unsigned long == 8 bytes */
#define PRIu64 "I64u"
#endif

View File

@ -0,0 +1,31 @@
/*
* Custom stdbool.h for VS2010 KreMLin requires these definitions,
* but VS2010 doesn't provide them.
*
* Copyright 2016-2018 INRIA and Microsoft Corporation
* SPDX-License-Identifier: Apache-2.0
*
* 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.
*
* This file is part of Mbed TLS (https://tls.mbed.org)
*/
#ifndef _STDBOOL_H_VS2010
#define _STDBOOL_H_VS2010
typedef int bool;
static bool true = 1;
static bool false = 0;
#endif

View File

@ -0,0 +1,190 @@
/*
* ECDH with curve-optimized implementation multiplexing
*
* Copyright 2016-2018 INRIA and Microsoft Corporation
* SPDX-License-Identifier: Apache-2.0
*
* 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.
*
* This file is part of Mbed TLS (https://tls.mbed.org)
*/
#ifndef MBEDTLS_X25519_H
#define MBEDTLS_X25519_H
#ifdef __cplusplus
extern "C" {
#endif
#define MBEDTLS_ECP_TLS_CURVE25519 0x1d
#define MBEDTLS_X25519_KEY_SIZE_BYTES 32
/**
* Defines the source of the imported EC key.
*/
typedef enum
{
MBEDTLS_X25519_ECDH_OURS, /**< Our key. */
MBEDTLS_X25519_ECDH_THEIRS, /**< The key of the peer. */
} mbedtls_x25519_ecdh_side;
/**
* \brief The x25519 context structure.
*/
typedef struct
{
unsigned char our_secret[MBEDTLS_X25519_KEY_SIZE_BYTES];
unsigned char peer_point[MBEDTLS_X25519_KEY_SIZE_BYTES];
} mbedtls_x25519_context;
/**
* \brief This function initializes an x25519 context.
*
* \param ctx The x25519 context to initialize.
*/
void mbedtls_x25519_init( mbedtls_x25519_context *ctx );
/**
* \brief This function frees a context.
*
* \param ctx The context to free.
*/
void mbedtls_x25519_free( mbedtls_x25519_context *ctx );
/**
* \brief This function generates a public key and a TLS
* ServerKeyExchange payload.
*
* This is the first function used by a TLS server for x25519.
*
*
* \param ctx The x25519 context.
* \param olen The number of characters written.
* \param buf The destination buffer.
* \param blen The length of the destination buffer.
* \param f_rng The RNG function.
* \param p_rng The RNG context.
*
* \return \c 0 on success.
* \return An \c MBEDTLS_ERR_ECP_XXX error code on failure.
*/
int mbedtls_x25519_make_params( mbedtls_x25519_context *ctx, size_t *olen,
unsigned char *buf, size_t blen,
int( *f_rng )(void *, unsigned char *, size_t),
void *p_rng );
/**
* \brief This function parses and processes a TLS ServerKeyExchange
* payload.
*
*
* \param ctx The x25519 context.
* \param buf The pointer to the start of the input buffer.
* \param end The address for one Byte past the end of the buffer.
*
* \return \c 0 on success.
* \return An \c MBEDTLS_ERR_ECP_XXX error code on failure.
*
*/
int mbedtls_x25519_read_params( mbedtls_x25519_context *ctx,
const unsigned char **buf, const unsigned char *end );
/**
* \brief This function sets up an x25519 context from an EC key.
*
* It is used by clients and servers in place of the
* ServerKeyEchange for static ECDH, and imports ECDH
* parameters from the EC key information of a certificate.
*
* \see ecp.h
*
* \param ctx The x25519 context to set up.
* \param key The EC key to use.
* \param side Defines the source of the key: 1: Our key, or
* 0: The key of the peer.
*
* \return \c 0 on success.
* \return An \c MBEDTLS_ERR_ECP_XXX error code on failure.
*
*/
int mbedtls_x25519_get_params( mbedtls_x25519_context *ctx, const mbedtls_ecp_keypair *key,
mbedtls_x25519_ecdh_side side );
/**
* \brief This function derives and exports the shared secret.
*
* This is the last function used by both TLS client
* and servers.
*
*
* \param ctx The x25519 context.
* \param olen The number of Bytes written.
* \param buf The destination buffer.
* \param blen The length of the destination buffer.
* \param f_rng The RNG function.
* \param p_rng The RNG context.
*
* \return \c 0 on success.
* \return An \c MBEDTLS_ERR_ECP_XXX error code on failure.
*/
int mbedtls_x25519_calc_secret( mbedtls_x25519_context *ctx, size_t *olen,
unsigned char *buf, size_t blen,
int( *f_rng )(void *, unsigned char *, size_t),
void *p_rng );
/**
* \brief This function generates a public key and a TLS
* ClientKeyExchange payload.
*
* This is the second function used by a TLS client for x25519.
*
* \see ecp.h
*
* \param ctx The x25519 context.
* \param olen The number of Bytes written.
* \param buf The destination buffer.
* \param blen The size of the destination buffer.
* \param f_rng The RNG function.
* \param p_rng The RNG context.
*
* \return \c 0 on success.
* \return An \c MBEDTLS_ERR_ECP_XXX error code on failure.
*/
int mbedtls_x25519_make_public( mbedtls_x25519_context *ctx, size_t *olen,
unsigned char *buf, size_t blen,
int( *f_rng )(void *, unsigned char *, size_t),
void *p_rng );
/**
* \brief This function parses and processes a TLS ClientKeyExchange
* payload.
*
* This is the second function used by a TLS server for x25519.
*
* \see ecp.h
*
* \param ctx The x25519 context.
* \param buf The start of the input buffer.
* \param blen The length of the input buffer.
*
* \return \c 0 on success.
* \return An \c MBEDTLS_ERR_ECP_XXX error code on failure.
*/
int mbedtls_x25519_read_public( mbedtls_x25519_context *ctx,
const unsigned char *buf, size_t blen );
#ifdef __cplusplus
}
#endif
#endif /* x25519.h */

View File

@ -0,0 +1,760 @@
/* Copyright (c) INRIA and Microsoft Corporation. All rights reserved.
Licensed under the Apache 2.0 License. */
/* This file was generated by KreMLin <https://github.com/FStarLang/kremlin>
* KreMLin invocation: /mnt/e/everest/verify/kremlin/krml -fc89 -fparentheses -fno-shadow -header /mnt/e/everest/verify/hdrcLh -minimal -fbuiltin-uint128 -fc89 -fparentheses -fno-shadow -header /mnt/e/everest/verify/hdrcLh -minimal -I /mnt/e/everest/verify/hacl-star/code/lib/kremlin -I /mnt/e/everest/verify/kremlin/kremlib/compat -I /mnt/e/everest/verify/hacl-star/specs -I /mnt/e/everest/verify/hacl-star/specs/old -I . -ccopt -march=native -verbose -ldopt -flto -tmpdir x25519-c -I ../bignum -bundle Hacl.Curve25519=* -minimal -add-include "kremlib.h" -skip-compilation x25519-c/out.krml -o x25519-c/Hacl_Curve25519.c
* F* version: 059db0c8
* KreMLin version: 916c37ac
*/
#include "Hacl_Curve25519.h"
extern uint64_t FStar_UInt64_eq_mask(uint64_t x0, uint64_t x1);
extern uint64_t FStar_UInt64_gte_mask(uint64_t x0, uint64_t x1);
extern uint128_t FStar_UInt128_add(uint128_t x0, uint128_t x1);
extern uint128_t FStar_UInt128_add_mod(uint128_t x0, uint128_t x1);
extern uint128_t FStar_UInt128_logand(uint128_t x0, uint128_t x1);
extern uint128_t FStar_UInt128_shift_right(uint128_t x0, uint32_t x1);
extern uint128_t FStar_UInt128_uint64_to_uint128(uint64_t x0);
extern uint64_t FStar_UInt128_uint128_to_uint64(uint128_t x0);
extern uint128_t FStar_UInt128_mul_wide(uint64_t x0, uint64_t x1);
static void Hacl_Bignum_Modulo_carry_top(uint64_t *b)
{
uint64_t b4 = b[4U];
uint64_t b0 = b[0U];
uint64_t b4_ = b4 & (uint64_t)0x7ffffffffffffU;
uint64_t b0_ = b0 + (uint64_t)19U * (b4 >> (uint32_t)51U);
b[4U] = b4_;
b[0U] = b0_;
}
inline static void Hacl_Bignum_Fproduct_copy_from_wide_(uint64_t *output, uint128_t *input)
{
uint32_t i;
for (i = (uint32_t)0U; i < (uint32_t)5U; i = i + (uint32_t)1U)
{
uint128_t xi = input[i];
output[i] = (uint64_t)xi;
}
}
inline static void
Hacl_Bignum_Fproduct_sum_scalar_multiplication_(uint128_t *output, uint64_t *input, uint64_t s)
{
uint32_t i;
for (i = (uint32_t)0U; i < (uint32_t)5U; i = i + (uint32_t)1U)
{
uint128_t xi = output[i];
uint64_t yi = input[i];
output[i] = xi + (uint128_t)yi * s;
}
}
inline static void Hacl_Bignum_Fproduct_carry_wide_(uint128_t *tmp)
{
uint32_t i;
for (i = (uint32_t)0U; i < (uint32_t)4U; i = i + (uint32_t)1U)
{
uint32_t ctr = i;
uint128_t tctr = tmp[ctr];
uint128_t tctrp1 = tmp[ctr + (uint32_t)1U];
uint64_t r0 = (uint64_t)tctr & (uint64_t)0x7ffffffffffffU;
uint128_t c = tctr >> (uint32_t)51U;
tmp[ctr] = (uint128_t)r0;
tmp[ctr + (uint32_t)1U] = tctrp1 + c;
}
}
inline static void Hacl_Bignum_Fmul_shift_reduce(uint64_t *output)
{
uint64_t tmp = output[4U];
uint64_t b0;
{
uint32_t i;
for (i = (uint32_t)0U; i < (uint32_t)4U; i = i + (uint32_t)1U)
{
uint32_t ctr = (uint32_t)5U - i - (uint32_t)1U;
uint64_t z = output[ctr - (uint32_t)1U];
output[ctr] = z;
}
}
output[0U] = tmp;
b0 = output[0U];
output[0U] = (uint64_t)19U * b0;
}
static void
Hacl_Bignum_Fmul_mul_shift_reduce_(uint128_t *output, uint64_t *input, uint64_t *input2)
{
uint32_t i;
uint64_t input2i;
{
uint32_t i0;
for (i0 = (uint32_t)0U; i0 < (uint32_t)4U; i0 = i0 + (uint32_t)1U)
{
uint64_t input2i0 = input2[i0];
Hacl_Bignum_Fproduct_sum_scalar_multiplication_(output, input, input2i0);
Hacl_Bignum_Fmul_shift_reduce(input);
}
}
i = (uint32_t)4U;
input2i = input2[i];
Hacl_Bignum_Fproduct_sum_scalar_multiplication_(output, input, input2i);
}
inline static void Hacl_Bignum_Fmul_fmul(uint64_t *output, uint64_t *input, uint64_t *input2)
{
uint64_t tmp[5U] = { 0U };
memcpy(tmp, input, (uint32_t)5U * sizeof input[0U]);
KRML_CHECK_SIZE(sizeof (uint128_t), (uint32_t)5U);
{
uint128_t t[5U];
{
uint32_t _i;
for (_i = 0U; _i < (uint32_t)5U; ++_i)
t[_i] = (uint128_t)(uint64_t)0U;
}
{
uint128_t b4;
uint128_t b0;
uint128_t b4_;
uint128_t b0_;
uint64_t i0;
uint64_t i1;
uint64_t i0_;
uint64_t i1_;
Hacl_Bignum_Fmul_mul_shift_reduce_(t, tmp, input2);
Hacl_Bignum_Fproduct_carry_wide_(t);
b4 = t[4U];
b0 = t[0U];
b4_ = b4 & (uint128_t)(uint64_t)0x7ffffffffffffU;
b0_ = b0 + (uint128_t)(uint64_t)19U * (uint64_t)(b4 >> (uint32_t)51U);
t[4U] = b4_;
t[0U] = b0_;
Hacl_Bignum_Fproduct_copy_from_wide_(output, t);
i0 = output[0U];
i1 = output[1U];
i0_ = i0 & (uint64_t)0x7ffffffffffffU;
i1_ = i1 + (i0 >> (uint32_t)51U);
output[0U] = i0_;
output[1U] = i1_;
}
}
}
inline static void Hacl_Bignum_Fsquare_fsquare__(uint128_t *tmp, uint64_t *output)
{
uint64_t r0 = output[0U];
uint64_t r1 = output[1U];
uint64_t r2 = output[2U];
uint64_t r3 = output[3U];
uint64_t r4 = output[4U];
uint64_t d0 = r0 * (uint64_t)2U;
uint64_t d1 = r1 * (uint64_t)2U;
uint64_t d2 = r2 * (uint64_t)2U * (uint64_t)19U;
uint64_t d419 = r4 * (uint64_t)19U;
uint64_t d4 = d419 * (uint64_t)2U;
uint128_t s0 = (uint128_t)r0 * r0 + (uint128_t)d4 * r1 + (uint128_t)d2 * r3;
uint128_t s1 = (uint128_t)d0 * r1 + (uint128_t)d4 * r2 + (uint128_t)(r3 * (uint64_t)19U) * r3;
uint128_t s2 = (uint128_t)d0 * r2 + (uint128_t)r1 * r1 + (uint128_t)d4 * r3;
uint128_t s3 = (uint128_t)d0 * r3 + (uint128_t)d1 * r2 + (uint128_t)r4 * d419;
uint128_t s4 = (uint128_t)d0 * r4 + (uint128_t)d1 * r3 + (uint128_t)r2 * r2;
tmp[0U] = s0;
tmp[1U] = s1;
tmp[2U] = s2;
tmp[3U] = s3;
tmp[4U] = s4;
}
inline static void Hacl_Bignum_Fsquare_fsquare_(uint128_t *tmp, uint64_t *output)
{
uint128_t b4;
uint128_t b0;
uint128_t b4_;
uint128_t b0_;
uint64_t i0;
uint64_t i1;
uint64_t i0_;
uint64_t i1_;
Hacl_Bignum_Fsquare_fsquare__(tmp, output);
Hacl_Bignum_Fproduct_carry_wide_(tmp);
b4 = tmp[4U];
b0 = tmp[0U];
b4_ = b4 & (uint128_t)(uint64_t)0x7ffffffffffffU;
b0_ = b0 + (uint128_t)(uint64_t)19U * (uint64_t)(b4 >> (uint32_t)51U);
tmp[4U] = b4_;
tmp[0U] = b0_;
Hacl_Bignum_Fproduct_copy_from_wide_(output, tmp);
i0 = output[0U];
i1 = output[1U];
i0_ = i0 & (uint64_t)0x7ffffffffffffU;
i1_ = i1 + (i0 >> (uint32_t)51U);
output[0U] = i0_;
output[1U] = i1_;
}
static void
Hacl_Bignum_Fsquare_fsquare_times_(uint64_t *input, uint128_t *tmp, uint32_t count1)
{
uint32_t i;
Hacl_Bignum_Fsquare_fsquare_(tmp, input);
for (i = (uint32_t)1U; i < count1; i = i + (uint32_t)1U)
Hacl_Bignum_Fsquare_fsquare_(tmp, input);
}
inline static void
Hacl_Bignum_Fsquare_fsquare_times(uint64_t *output, uint64_t *input, uint32_t count1)
{
KRML_CHECK_SIZE(sizeof (uint128_t), (uint32_t)5U);
{
uint128_t t[5U];
{
uint32_t _i;
for (_i = 0U; _i < (uint32_t)5U; ++_i)
t[_i] = (uint128_t)(uint64_t)0U;
}
memcpy(output, input, (uint32_t)5U * sizeof input[0U]);
Hacl_Bignum_Fsquare_fsquare_times_(output, t, count1);
}
}
inline static void Hacl_Bignum_Fsquare_fsquare_times_inplace(uint64_t *output, uint32_t count1)
{
KRML_CHECK_SIZE(sizeof (uint128_t), (uint32_t)5U);
{
uint128_t t[5U];
{
uint32_t _i;
for (_i = 0U; _i < (uint32_t)5U; ++_i)
t[_i] = (uint128_t)(uint64_t)0U;
}
Hacl_Bignum_Fsquare_fsquare_times_(output, t, count1);
}
}
inline static void Hacl_Bignum_Crecip_crecip(uint64_t *out, uint64_t *z)
{
uint64_t buf[20U] = { 0U };
uint64_t *a0 = buf;
uint64_t *t00 = buf + (uint32_t)5U;
uint64_t *b0 = buf + (uint32_t)10U;
uint64_t *t01;
uint64_t *b1;
uint64_t *c0;
uint64_t *a;
uint64_t *t0;
uint64_t *b;
uint64_t *c;
Hacl_Bignum_Fsquare_fsquare_times(a0, z, (uint32_t)1U);
Hacl_Bignum_Fsquare_fsquare_times(t00, a0, (uint32_t)2U);
Hacl_Bignum_Fmul_fmul(b0, t00, z);
Hacl_Bignum_Fmul_fmul(a0, b0, a0);
Hacl_Bignum_Fsquare_fsquare_times(t00, a0, (uint32_t)1U);
Hacl_Bignum_Fmul_fmul(b0, t00, b0);
Hacl_Bignum_Fsquare_fsquare_times(t00, b0, (uint32_t)5U);
t01 = buf + (uint32_t)5U;
b1 = buf + (uint32_t)10U;
c0 = buf + (uint32_t)15U;
Hacl_Bignum_Fmul_fmul(b1, t01, b1);
Hacl_Bignum_Fsquare_fsquare_times(t01, b1, (uint32_t)10U);
Hacl_Bignum_Fmul_fmul(c0, t01, b1);
Hacl_Bignum_Fsquare_fsquare_times(t01, c0, (uint32_t)20U);
Hacl_Bignum_Fmul_fmul(t01, t01, c0);
Hacl_Bignum_Fsquare_fsquare_times_inplace(t01, (uint32_t)10U);
Hacl_Bignum_Fmul_fmul(b1, t01, b1);
Hacl_Bignum_Fsquare_fsquare_times(t01, b1, (uint32_t)50U);
a = buf;
t0 = buf + (uint32_t)5U;
b = buf + (uint32_t)10U;
c = buf + (uint32_t)15U;
Hacl_Bignum_Fmul_fmul(c, t0, b);
Hacl_Bignum_Fsquare_fsquare_times(t0, c, (uint32_t)100U);
Hacl_Bignum_Fmul_fmul(t0, t0, c);
Hacl_Bignum_Fsquare_fsquare_times_inplace(t0, (uint32_t)50U);
Hacl_Bignum_Fmul_fmul(t0, t0, b);
Hacl_Bignum_Fsquare_fsquare_times_inplace(t0, (uint32_t)5U);
Hacl_Bignum_Fmul_fmul(out, t0, a);
}
inline static void Hacl_Bignum_fsum(uint64_t *a, uint64_t *b)
{
uint32_t i;
for (i = (uint32_t)0U; i < (uint32_t)5U; i = i + (uint32_t)1U)
{
uint64_t xi = a[i];
uint64_t yi = b[i];
a[i] = xi + yi;
}
}
inline static void Hacl_Bignum_fdifference(uint64_t *a, uint64_t *b)
{
uint64_t tmp[5U] = { 0U };
uint64_t b0;
uint64_t b1;
uint64_t b2;
uint64_t b3;
uint64_t b4;
memcpy(tmp, b, (uint32_t)5U * sizeof b[0U]);
b0 = tmp[0U];
b1 = tmp[1U];
b2 = tmp[2U];
b3 = tmp[3U];
b4 = tmp[4U];
tmp[0U] = b0 + (uint64_t)0x3fffffffffff68U;
tmp[1U] = b1 + (uint64_t)0x3ffffffffffff8U;
tmp[2U] = b2 + (uint64_t)0x3ffffffffffff8U;
tmp[3U] = b3 + (uint64_t)0x3ffffffffffff8U;
tmp[4U] = b4 + (uint64_t)0x3ffffffffffff8U;
{
uint32_t i;
for (i = (uint32_t)0U; i < (uint32_t)5U; i = i + (uint32_t)1U)
{
uint64_t xi = a[i];
uint64_t yi = tmp[i];
a[i] = yi - xi;
}
}
}
inline static void Hacl_Bignum_fscalar(uint64_t *output, uint64_t *b, uint64_t s)
{
KRML_CHECK_SIZE(sizeof (uint128_t), (uint32_t)5U);
{
uint128_t tmp[5U];
{
uint32_t _i;
for (_i = 0U; _i < (uint32_t)5U; ++_i)
tmp[_i] = (uint128_t)(uint64_t)0U;
}
{
uint128_t b4;
uint128_t b0;
uint128_t b4_;
uint128_t b0_;
{
uint32_t i;
for (i = (uint32_t)0U; i < (uint32_t)5U; i = i + (uint32_t)1U)
{
uint64_t xi = b[i];
tmp[i] = (uint128_t)xi * s;
}
}
Hacl_Bignum_Fproduct_carry_wide_(tmp);
b4 = tmp[4U];
b0 = tmp[0U];
b4_ = b4 & (uint128_t)(uint64_t)0x7ffffffffffffU;
b0_ = b0 + (uint128_t)(uint64_t)19U * (uint64_t)(b4 >> (uint32_t)51U);
tmp[4U] = b4_;
tmp[0U] = b0_;
Hacl_Bignum_Fproduct_copy_from_wide_(output, tmp);
}
}
}
inline static void Hacl_Bignum_fmul(uint64_t *output, uint64_t *a, uint64_t *b)
{
Hacl_Bignum_Fmul_fmul(output, a, b);
}
inline static void Hacl_Bignum_crecip(uint64_t *output, uint64_t *input)
{
Hacl_Bignum_Crecip_crecip(output, input);
}
static void
Hacl_EC_Point_swap_conditional_step(uint64_t *a, uint64_t *b, uint64_t swap1, uint32_t ctr)
{
uint32_t i = ctr - (uint32_t)1U;
uint64_t ai = a[i];
uint64_t bi = b[i];
uint64_t x = swap1 & (ai ^ bi);
uint64_t ai1 = ai ^ x;
uint64_t bi1 = bi ^ x;
a[i] = ai1;
b[i] = bi1;
}
static void
Hacl_EC_Point_swap_conditional_(uint64_t *a, uint64_t *b, uint64_t swap1, uint32_t ctr)
{
if (!(ctr == (uint32_t)0U))
{
uint32_t i;
Hacl_EC_Point_swap_conditional_step(a, b, swap1, ctr);
i = ctr - (uint32_t)1U;
Hacl_EC_Point_swap_conditional_(a, b, swap1, i);
}
}
static void Hacl_EC_Point_swap_conditional(uint64_t *a, uint64_t *b, uint64_t iswap)
{
uint64_t swap1 = (uint64_t)0U - iswap;
Hacl_EC_Point_swap_conditional_(a, b, swap1, (uint32_t)5U);
Hacl_EC_Point_swap_conditional_(a + (uint32_t)5U, b + (uint32_t)5U, swap1, (uint32_t)5U);
}
static void Hacl_EC_Point_copy(uint64_t *output, uint64_t *input)
{
memcpy(output, input, (uint32_t)5U * sizeof input[0U]);
memcpy(output + (uint32_t)5U,
input + (uint32_t)5U,
(uint32_t)5U * sizeof (input + (uint32_t)5U)[0U]);
}
static void Hacl_EC_Format_fexpand(uint64_t *output, uint8_t *input)
{
uint64_t i0 = load64_le(input);
uint8_t *x00 = input + (uint32_t)6U;
uint64_t i1 = load64_le(x00);
uint8_t *x01 = input + (uint32_t)12U;
uint64_t i2 = load64_le(x01);
uint8_t *x02 = input + (uint32_t)19U;
uint64_t i3 = load64_le(x02);
uint8_t *x0 = input + (uint32_t)24U;
uint64_t i4 = load64_le(x0);
uint64_t output0 = i0 & (uint64_t)0x7ffffffffffffU;
uint64_t output1 = i1 >> (uint32_t)3U & (uint64_t)0x7ffffffffffffU;
uint64_t output2 = i2 >> (uint32_t)6U & (uint64_t)0x7ffffffffffffU;
uint64_t output3 = i3 >> (uint32_t)1U & (uint64_t)0x7ffffffffffffU;
uint64_t output4 = i4 >> (uint32_t)12U & (uint64_t)0x7ffffffffffffU;
output[0U] = output0;
output[1U] = output1;
output[2U] = output2;
output[3U] = output3;
output[4U] = output4;
}
static void Hacl_EC_Format_fcontract_first_carry_pass(uint64_t *input)
{
uint64_t t0 = input[0U];
uint64_t t1 = input[1U];
uint64_t t2 = input[2U];
uint64_t t3 = input[3U];
uint64_t t4 = input[4U];
uint64_t t1_ = t1 + (t0 >> (uint32_t)51U);
uint64_t t0_ = t0 & (uint64_t)0x7ffffffffffffU;
uint64_t t2_ = t2 + (t1_ >> (uint32_t)51U);
uint64_t t1__ = t1_ & (uint64_t)0x7ffffffffffffU;
uint64_t t3_ = t3 + (t2_ >> (uint32_t)51U);
uint64_t t2__ = t2_ & (uint64_t)0x7ffffffffffffU;
uint64_t t4_ = t4 + (t3_ >> (uint32_t)51U);
uint64_t t3__ = t3_ & (uint64_t)0x7ffffffffffffU;
input[0U] = t0_;
input[1U] = t1__;
input[2U] = t2__;
input[3U] = t3__;
input[4U] = t4_;
}
static void Hacl_EC_Format_fcontract_first_carry_full(uint64_t *input)
{
Hacl_EC_Format_fcontract_first_carry_pass(input);
Hacl_Bignum_Modulo_carry_top(input);
}
static void Hacl_EC_Format_fcontract_second_carry_pass(uint64_t *input)
{
uint64_t t0 = input[0U];
uint64_t t1 = input[1U];
uint64_t t2 = input[2U];
uint64_t t3 = input[3U];
uint64_t t4 = input[4U];
uint64_t t1_ = t1 + (t0 >> (uint32_t)51U);
uint64_t t0_ = t0 & (uint64_t)0x7ffffffffffffU;
uint64_t t2_ = t2 + (t1_ >> (uint32_t)51U);
uint64_t t1__ = t1_ & (uint64_t)0x7ffffffffffffU;
uint64_t t3_ = t3 + (t2_ >> (uint32_t)51U);
uint64_t t2__ = t2_ & (uint64_t)0x7ffffffffffffU;
uint64_t t4_ = t4 + (t3_ >> (uint32_t)51U);
uint64_t t3__ = t3_ & (uint64_t)0x7ffffffffffffU;
input[0U] = t0_;
input[1U] = t1__;
input[2U] = t2__;
input[3U] = t3__;
input[4U] = t4_;
}
static void Hacl_EC_Format_fcontract_second_carry_full(uint64_t *input)
{
uint64_t i0;
uint64_t i1;
uint64_t i0_;
uint64_t i1_;
Hacl_EC_Format_fcontract_second_carry_pass(input);
Hacl_Bignum_Modulo_carry_top(input);
i0 = input[0U];
i1 = input[1U];
i0_ = i0 & (uint64_t)0x7ffffffffffffU;
i1_ = i1 + (i0 >> (uint32_t)51U);
input[0U] = i0_;
input[1U] = i1_;
}
static void Hacl_EC_Format_fcontract_trim(uint64_t *input)
{
uint64_t a0 = input[0U];
uint64_t a1 = input[1U];
uint64_t a2 = input[2U];
uint64_t a3 = input[3U];
uint64_t a4 = input[4U];
uint64_t mask0 = FStar_UInt64_gte_mask(a0, (uint64_t)0x7ffffffffffedU);
uint64_t mask1 = FStar_UInt64_eq_mask(a1, (uint64_t)0x7ffffffffffffU);
uint64_t mask2 = FStar_UInt64_eq_mask(a2, (uint64_t)0x7ffffffffffffU);
uint64_t mask3 = FStar_UInt64_eq_mask(a3, (uint64_t)0x7ffffffffffffU);
uint64_t mask4 = FStar_UInt64_eq_mask(a4, (uint64_t)0x7ffffffffffffU);
uint64_t mask = (((mask0 & mask1) & mask2) & mask3) & mask4;
uint64_t a0_ = a0 - ((uint64_t)0x7ffffffffffedU & mask);
uint64_t a1_ = a1 - ((uint64_t)0x7ffffffffffffU & mask);
uint64_t a2_ = a2 - ((uint64_t)0x7ffffffffffffU & mask);
uint64_t a3_ = a3 - ((uint64_t)0x7ffffffffffffU & mask);
uint64_t a4_ = a4 - ((uint64_t)0x7ffffffffffffU & mask);
input[0U] = a0_;
input[1U] = a1_;
input[2U] = a2_;
input[3U] = a3_;
input[4U] = a4_;
}
static void Hacl_EC_Format_fcontract_store(uint8_t *output, uint64_t *input)
{
uint64_t t0 = input[0U];
uint64_t t1 = input[1U];
uint64_t t2 = input[2U];
uint64_t t3 = input[3U];
uint64_t t4 = input[4U];
uint64_t o0 = t1 << (uint32_t)51U | t0;
uint64_t o1 = t2 << (uint32_t)38U | t1 >> (uint32_t)13U;
uint64_t o2 = t3 << (uint32_t)25U | t2 >> (uint32_t)26U;
uint64_t o3 = t4 << (uint32_t)12U | t3 >> (uint32_t)39U;
uint8_t *b0 = output;
uint8_t *b1 = output + (uint32_t)8U;
uint8_t *b2 = output + (uint32_t)16U;
uint8_t *b3 = output + (uint32_t)24U;
store64_le(b0, o0);
store64_le(b1, o1);
store64_le(b2, o2);
store64_le(b3, o3);
}
static void Hacl_EC_Format_fcontract(uint8_t *output, uint64_t *input)
{
Hacl_EC_Format_fcontract_first_carry_full(input);
Hacl_EC_Format_fcontract_second_carry_full(input);
Hacl_EC_Format_fcontract_trim(input);
Hacl_EC_Format_fcontract_store(output, input);
}
static void Hacl_EC_Format_scalar_of_point(uint8_t *scalar, uint64_t *point)
{
uint64_t *x = point;
uint64_t *z = point + (uint32_t)5U;
uint64_t buf[10U] = { 0U };
uint64_t *zmone = buf;
uint64_t *sc = buf + (uint32_t)5U;
Hacl_Bignum_crecip(zmone, z);
Hacl_Bignum_fmul(sc, x, zmone);
Hacl_EC_Format_fcontract(scalar, sc);
}
static void
Hacl_EC_AddAndDouble_fmonty(
uint64_t *pp,
uint64_t *ppq,
uint64_t *p,
uint64_t *pq,
uint64_t *qmqp
)
{
uint64_t *qx = qmqp;
uint64_t *x2 = pp;
uint64_t *z2 = pp + (uint32_t)5U;
uint64_t *x3 = ppq;
uint64_t *z3 = ppq + (uint32_t)5U;
uint64_t *x = p;
uint64_t *z = p + (uint32_t)5U;
uint64_t *xprime = pq;
uint64_t *zprime = pq + (uint32_t)5U;
uint64_t buf[40U] = { 0U };
uint64_t *origx = buf;
uint64_t *origxprime0 = buf + (uint32_t)5U;
uint64_t *xxprime0 = buf + (uint32_t)25U;
uint64_t *zzprime0 = buf + (uint32_t)30U;
uint64_t *origxprime;
uint64_t *xx0;
uint64_t *zz0;
uint64_t *xxprime;
uint64_t *zzprime;
uint64_t *zzzprime;
uint64_t *zzz;
uint64_t *xx;
uint64_t *zz;
uint64_t scalar;
memcpy(origx, x, (uint32_t)5U * sizeof x[0U]);
Hacl_Bignum_fsum(x, z);
Hacl_Bignum_fdifference(z, origx);
memcpy(origxprime0, xprime, (uint32_t)5U * sizeof xprime[0U]);
Hacl_Bignum_fsum(xprime, zprime);
Hacl_Bignum_fdifference(zprime, origxprime0);
Hacl_Bignum_fmul(xxprime0, xprime, z);
Hacl_Bignum_fmul(zzprime0, x, zprime);
origxprime = buf + (uint32_t)5U;
xx0 = buf + (uint32_t)15U;
zz0 = buf + (uint32_t)20U;
xxprime = buf + (uint32_t)25U;
zzprime = buf + (uint32_t)30U;
zzzprime = buf + (uint32_t)35U;
memcpy(origxprime, xxprime, (uint32_t)5U * sizeof xxprime[0U]);
Hacl_Bignum_fsum(xxprime, zzprime);
Hacl_Bignum_fdifference(zzprime, origxprime);
Hacl_Bignum_Fsquare_fsquare_times(x3, xxprime, (uint32_t)1U);
Hacl_Bignum_Fsquare_fsquare_times(zzzprime, zzprime, (uint32_t)1U);
Hacl_Bignum_fmul(z3, zzzprime, qx);
Hacl_Bignum_Fsquare_fsquare_times(xx0, x, (uint32_t)1U);
Hacl_Bignum_Fsquare_fsquare_times(zz0, z, (uint32_t)1U);
zzz = buf + (uint32_t)10U;
xx = buf + (uint32_t)15U;
zz = buf + (uint32_t)20U;
Hacl_Bignum_fmul(x2, xx, zz);
Hacl_Bignum_fdifference(zz, xx);
scalar = (uint64_t)121665U;
Hacl_Bignum_fscalar(zzz, zz, scalar);
Hacl_Bignum_fsum(zzz, xx);
Hacl_Bignum_fmul(z2, zzz, zz);
}
static void
Hacl_EC_Ladder_SmallLoop_cmult_small_loop_step(
uint64_t *nq,
uint64_t *nqpq,
uint64_t *nq2,
uint64_t *nqpq2,
uint64_t *q,
uint8_t byt
)
{
uint64_t bit0 = (uint64_t)(byt >> (uint32_t)7U);
uint64_t bit;
Hacl_EC_Point_swap_conditional(nq, nqpq, bit0);
Hacl_EC_AddAndDouble_fmonty(nq2, nqpq2, nq, nqpq, q);
bit = (uint64_t)(byt >> (uint32_t)7U);
Hacl_EC_Point_swap_conditional(nq2, nqpq2, bit);
}
static void
Hacl_EC_Ladder_SmallLoop_cmult_small_loop_double_step(
uint64_t *nq,
uint64_t *nqpq,
uint64_t *nq2,
uint64_t *nqpq2,
uint64_t *q,
uint8_t byt
)
{
uint8_t byt1;
Hacl_EC_Ladder_SmallLoop_cmult_small_loop_step(nq, nqpq, nq2, nqpq2, q, byt);
byt1 = byt << (uint32_t)1U;
Hacl_EC_Ladder_SmallLoop_cmult_small_loop_step(nq2, nqpq2, nq, nqpq, q, byt1);
}
static void
Hacl_EC_Ladder_SmallLoop_cmult_small_loop(
uint64_t *nq,
uint64_t *nqpq,
uint64_t *nq2,
uint64_t *nqpq2,
uint64_t *q,
uint8_t byt,
uint32_t i
)
{
if (!(i == (uint32_t)0U))
{
uint32_t i_ = i - (uint32_t)1U;
uint8_t byt_;
Hacl_EC_Ladder_SmallLoop_cmult_small_loop_double_step(nq, nqpq, nq2, nqpq2, q, byt);
byt_ = byt << (uint32_t)2U;
Hacl_EC_Ladder_SmallLoop_cmult_small_loop(nq, nqpq, nq2, nqpq2, q, byt_, i_);
}
}
static void
Hacl_EC_Ladder_BigLoop_cmult_big_loop(
uint8_t *n1,
uint64_t *nq,
uint64_t *nqpq,
uint64_t *nq2,
uint64_t *nqpq2,
uint64_t *q,
uint32_t i
)
{
if (!(i == (uint32_t)0U))
{
uint32_t i1 = i - (uint32_t)1U;
uint8_t byte = n1[i1];
Hacl_EC_Ladder_SmallLoop_cmult_small_loop(nq, nqpq, nq2, nqpq2, q, byte, (uint32_t)4U);
Hacl_EC_Ladder_BigLoop_cmult_big_loop(n1, nq, nqpq, nq2, nqpq2, q, i1);
}
}
static void Hacl_EC_Ladder_cmult(uint64_t *result, uint8_t *n1, uint64_t *q)
{
uint64_t point_buf[40U] = { 0U };
uint64_t *nq = point_buf;
uint64_t *nqpq = point_buf + (uint32_t)10U;
uint64_t *nq2 = point_buf + (uint32_t)20U;
uint64_t *nqpq2 = point_buf + (uint32_t)30U;
Hacl_EC_Point_copy(nqpq, q);
nq[0U] = (uint64_t)1U;
Hacl_EC_Ladder_BigLoop_cmult_big_loop(n1, nq, nqpq, nq2, nqpq2, q, (uint32_t)32U);
Hacl_EC_Point_copy(result, nq);
}
void Hacl_Curve25519_crypto_scalarmult(uint8_t *mypublic, uint8_t *secret, uint8_t *basepoint)
{
uint64_t buf0[10U] = { 0U };
uint64_t *x0 = buf0;
uint64_t *z = buf0 + (uint32_t)5U;
uint64_t *q;
Hacl_EC_Format_fexpand(x0, basepoint);
z[0U] = (uint64_t)1U;
q = buf0;
{
uint8_t e[32U] = { 0U };
uint8_t e0;
uint8_t e31;
uint8_t e01;
uint8_t e311;
uint8_t e312;
uint8_t *scalar;
memcpy(e, secret, (uint32_t)32U * sizeof secret[0U]);
e0 = e[0U];
e31 = e[31U];
e01 = e0 & (uint8_t)248U;
e311 = e31 & (uint8_t)127U;
e312 = e311 | (uint8_t)64U;
e[0U] = e01;
e[31U] = e312;
scalar = e;
{
uint64_t buf[15U] = { 0U };
uint64_t *nq = buf;
uint64_t *x = nq;
x[0U] = (uint64_t)1U;
Hacl_EC_Ladder_cmult(nq, scalar, q);
Hacl_EC_Format_scalar_of_point(mypublic, nq);
}
}
}

View File

@ -0,0 +1,50 @@
/*
* Interface to code from Project Everest
*
* Copyright 2016-2018 INRIA and Microsoft Corporation
* SPDX-License-Identifier: Apache-2.0
*
* 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.
*
* This file is part of Mbed TLS (https://tls.mbed.org)
*/
#ifndef _BSD_SOURCE
/* Required to get htole64() from gcc/glibc's endian.h (older systems)
* when we compile with -std=c99 */
#define _BSD_SOURCE
#endif
#ifndef _DEFAULT_SOURCE
/* (modern version of _BSD_SOURCE) */
#define _DEFAULT_SOURCE
#endif
#include "common.h"
#if defined(MBEDTLS_ECDH_VARIANT_EVEREST_ENABLED)
#if defined(__SIZEOF_INT128__) && (__SIZEOF_INT128__ == 16)
#define MBEDTLS_HAVE_INT128
#endif
#if defined(MBEDTLS_HAVE_INT128)
#include "Hacl_Curve25519.c"
#else
#define KRML_VERIFIED_UINT128
#include "kremlib/FStar_UInt128_extracted.c"
#include "legacy/Hacl_Curve25519.c"
#endif
#include "kremlib/FStar_UInt64_FStar_UInt32_FStar_UInt16_FStar_UInt8.c"
#endif /* defined(MBEDTLS_ECDH_VARIANT_EVEREST_ENABLED) */

View File

@ -0,0 +1,102 @@
/*
* Interface to code from Project Everest
*
* Copyright 2016-2018 INRIA and Microsoft Corporation
* SPDX-License-Identifier: Apache-2.0
*
* 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.
*
* This file is part of Mbed TLS (https://tls.mbed.org).
*/
#include "common.h"
#include <string.h>
#include "mbedtls/ecdh.h"
#include "everest/x25519.h"
#include "everest/everest.h"
#include "mbedtls/platform.h"
#if defined(MBEDTLS_ECDH_VARIANT_EVEREST_ENABLED)
int mbedtls_everest_setup( mbedtls_ecdh_context_everest *ctx, int grp_id )
{
if( grp_id != MBEDTLS_ECP_DP_CURVE25519 )
return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
mbedtls_x25519_init( &ctx->ctx );
return 0;
}
void mbedtls_everest_free( mbedtls_ecdh_context_everest *ctx )
{
mbedtls_x25519_free( &ctx->ctx );
}
int mbedtls_everest_make_params( mbedtls_ecdh_context_everest *ctx, size_t *olen,
unsigned char *buf, size_t blen,
int( *f_rng )( void *, unsigned char *, size_t ),
void *p_rng )
{
mbedtls_x25519_context *x25519_ctx = &ctx->ctx;
return mbedtls_x25519_make_params( x25519_ctx, olen, buf, blen, f_rng, p_rng );
}
int mbedtls_everest_read_params( mbedtls_ecdh_context_everest *ctx,
const unsigned char **buf,
const unsigned char *end )
{
mbedtls_x25519_context *x25519_ctx = &ctx->ctx;
return mbedtls_x25519_read_params( x25519_ctx, buf, end );
}
int mbedtls_everest_get_params( mbedtls_ecdh_context_everest *ctx,
const mbedtls_ecp_keypair *key,
mbedtls_everest_ecdh_side side )
{
mbedtls_x25519_context *x25519_ctx = &ctx->ctx;
mbedtls_x25519_ecdh_side s = side == MBEDTLS_EVEREST_ECDH_OURS ?
MBEDTLS_X25519_ECDH_OURS :
MBEDTLS_X25519_ECDH_THEIRS;
return mbedtls_x25519_get_params( x25519_ctx, key, s );
}
int mbedtls_everest_make_public( mbedtls_ecdh_context_everest *ctx, size_t *olen,
unsigned char *buf, size_t blen,
int( *f_rng )( void *, unsigned char *, size_t ),
void *p_rng )
{
mbedtls_x25519_context *x25519_ctx = &ctx->ctx;
return mbedtls_x25519_make_public( x25519_ctx, olen, buf, blen, f_rng, p_rng );
}
int mbedtls_everest_read_public( mbedtls_ecdh_context_everest *ctx,
const unsigned char *buf, size_t blen )
{
mbedtls_x25519_context *x25519_ctx = &ctx->ctx;
return mbedtls_x25519_read_public ( x25519_ctx, buf, blen );
}
int mbedtls_everest_calc_secret( mbedtls_ecdh_context_everest *ctx, size_t *olen,
unsigned char *buf, size_t blen,
int( *f_rng )( void *, unsigned char *, size_t ),
void *p_rng )
{
mbedtls_x25519_context *x25519_ctx = &ctx->ctx;
return mbedtls_x25519_calc_secret( x25519_ctx, olen, buf, blen, f_rng, p_rng );
}
#endif /* MBEDTLS_ECDH_VARIANT_EVEREST_ENABLED */

View File

@ -0,0 +1,413 @@
/* Copyright (c) INRIA and Microsoft Corporation. All rights reserved.
Licensed under the Apache 2.0 License. */
/* This file was generated by KreMLin <https://github.com/FStarLang/kremlin>
* KreMLin invocation: ../krml -fc89 -fparentheses -fno-shadow -header /mnt/e/everest/verify/hdrB9w -minimal -fparentheses -fcurly-braces -fno-shadow -header copyright-header.txt -minimal -tmpdir extracted -warn-error +9+11 -skip-compilation -extract-uints -add-include <inttypes.h> -add-include "kremlib.h" -add-include "kremlin/internal/compat.h" extracted/prims.krml extracted/FStar_Pervasives_Native.krml extracted/FStar_Pervasives.krml extracted/FStar_Mul.krml extracted/FStar_Squash.krml extracted/FStar_Classical.krml extracted/FStar_StrongExcludedMiddle.krml extracted/FStar_FunctionalExtensionality.krml extracted/FStar_List_Tot_Base.krml extracted/FStar_List_Tot_Properties.krml extracted/FStar_List_Tot.krml extracted/FStar_Seq_Base.krml extracted/FStar_Seq_Properties.krml extracted/FStar_Seq.krml extracted/FStar_Math_Lib.krml extracted/FStar_Math_Lemmas.krml extracted/FStar_BitVector.krml extracted/FStar_UInt.krml extracted/FStar_UInt32.krml extracted/FStar_Int.krml extracted/FStar_Int16.krml extracted/FStar_Preorder.krml extracted/FStar_Ghost.krml extracted/FStar_ErasedLogic.krml extracted/FStar_UInt64.krml extracted/FStar_Set.krml extracted/FStar_PropositionalExtensionality.krml extracted/FStar_PredicateExtensionality.krml extracted/FStar_TSet.krml extracted/FStar_Monotonic_Heap.krml extracted/FStar_Heap.krml extracted/FStar_Map.krml extracted/FStar_Monotonic_HyperHeap.krml extracted/FStar_Monotonic_HyperStack.krml extracted/FStar_HyperStack.krml extracted/FStar_Monotonic_Witnessed.krml extracted/FStar_HyperStack_ST.krml extracted/FStar_HyperStack_All.krml extracted/FStar_Date.krml extracted/FStar_Universe.krml extracted/FStar_GSet.krml extracted/FStar_ModifiesGen.krml extracted/LowStar_Monotonic_Buffer.krml extracted/LowStar_Buffer.krml extracted/Spec_Loops.krml extracted/LowStar_BufferOps.krml extracted/C_Loops.krml extracted/FStar_UInt8.krml extracted/FStar_Kremlin_Endianness.krml extracted/FStar_UInt63.krml extracted/FStar_Exn.krml extracted/FStar_ST.krml extracted/FStar_All.krml extracted/FStar_Dyn.krml extracted/FStar_Int63.krml extracted/FStar_Int64.krml extracted/FStar_Int32.krml extracted/FStar_Int8.krml extracted/FStar_UInt16.krml extracted/FStar_Int_Cast.krml extracted/FStar_UInt128.krml extracted/C_Endianness.krml extracted/FStar_List.krml extracted/FStar_Float.krml extracted/FStar_IO.krml extracted/C.krml extracted/FStar_Char.krml extracted/FStar_String.krml extracted/LowStar_Modifies.krml extracted/C_String.krml extracted/FStar_Bytes.krml extracted/FStar_HyperStack_IO.krml extracted/C_Failure.krml extracted/TestLib.krml extracted/FStar_Int_Cast_Full.krml
* F* version: 059db0c8
* KreMLin version: 916c37ac
*/
#include "FStar_UInt128.h"
#include "kremlin/c_endianness.h"
#include "FStar_UInt64_FStar_UInt32_FStar_UInt16_FStar_UInt8.h"
uint64_t FStar_UInt128___proj__Mkuint128__item__low(FStar_UInt128_uint128 projectee)
{
return projectee.low;
}
uint64_t FStar_UInt128___proj__Mkuint128__item__high(FStar_UInt128_uint128 projectee)
{
return projectee.high;
}
static uint64_t FStar_UInt128_constant_time_carry(uint64_t a, uint64_t b)
{
return (a ^ ((a ^ b) | ((a - b) ^ b))) >> (uint32_t)63U;
}
static uint64_t FStar_UInt128_carry(uint64_t a, uint64_t b)
{
return FStar_UInt128_constant_time_carry(a, b);
}
FStar_UInt128_uint128 FStar_UInt128_add(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b)
{
FStar_UInt128_uint128
flat = { a.low + b.low, a.high + b.high + FStar_UInt128_carry(a.low + b.low, b.low) };
return flat;
}
FStar_UInt128_uint128
FStar_UInt128_add_underspec(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b)
{
FStar_UInt128_uint128
flat = { a.low + b.low, a.high + b.high + FStar_UInt128_carry(a.low + b.low, b.low) };
return flat;
}
FStar_UInt128_uint128 FStar_UInt128_add_mod(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b)
{
FStar_UInt128_uint128
flat = { a.low + b.low, a.high + b.high + FStar_UInt128_carry(a.low + b.low, b.low) };
return flat;
}
FStar_UInt128_uint128 FStar_UInt128_sub(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b)
{
FStar_UInt128_uint128
flat = { a.low - b.low, a.high - b.high - FStar_UInt128_carry(a.low, a.low - b.low) };
return flat;
}
FStar_UInt128_uint128
FStar_UInt128_sub_underspec(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b)
{
FStar_UInt128_uint128
flat = { a.low - b.low, a.high - b.high - FStar_UInt128_carry(a.low, a.low - b.low) };
return flat;
}
static FStar_UInt128_uint128
FStar_UInt128_sub_mod_impl(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b)
{
FStar_UInt128_uint128
flat = { a.low - b.low, a.high - b.high - FStar_UInt128_carry(a.low, a.low - b.low) };
return flat;
}
FStar_UInt128_uint128 FStar_UInt128_sub_mod(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b)
{
return FStar_UInt128_sub_mod_impl(a, b);
}
FStar_UInt128_uint128 FStar_UInt128_logand(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b)
{
FStar_UInt128_uint128 flat = { a.low & b.low, a.high & b.high };
return flat;
}
FStar_UInt128_uint128 FStar_UInt128_logxor(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b)
{
FStar_UInt128_uint128 flat = { a.low ^ b.low, a.high ^ b.high };
return flat;
}
FStar_UInt128_uint128 FStar_UInt128_logor(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b)
{
FStar_UInt128_uint128 flat = { a.low | b.low, a.high | b.high };
return flat;
}
FStar_UInt128_uint128 FStar_UInt128_lognot(FStar_UInt128_uint128 a)
{
FStar_UInt128_uint128 flat = { ~a.low, ~a.high };
return flat;
}
static uint32_t FStar_UInt128_u32_64 = (uint32_t)64U;
static uint64_t FStar_UInt128_add_u64_shift_left(uint64_t hi, uint64_t lo, uint32_t s)
{
return (hi << s) + (lo >> (FStar_UInt128_u32_64 - s));
}
static uint64_t FStar_UInt128_add_u64_shift_left_respec(uint64_t hi, uint64_t lo, uint32_t s)
{
return FStar_UInt128_add_u64_shift_left(hi, lo, s);
}
static FStar_UInt128_uint128
FStar_UInt128_shift_left_small(FStar_UInt128_uint128 a, uint32_t s)
{
if (s == (uint32_t)0U)
{
return a;
}
else
{
FStar_UInt128_uint128
flat = { a.low << s, FStar_UInt128_add_u64_shift_left_respec(a.high, a.low, s) };
return flat;
}
}
static FStar_UInt128_uint128
FStar_UInt128_shift_left_large(FStar_UInt128_uint128 a, uint32_t s)
{
FStar_UInt128_uint128 flat = { (uint64_t)0U, a.low << (s - FStar_UInt128_u32_64) };
return flat;
}
FStar_UInt128_uint128 FStar_UInt128_shift_left(FStar_UInt128_uint128 a, uint32_t s)
{
if (s < FStar_UInt128_u32_64)
{
return FStar_UInt128_shift_left_small(a, s);
}
else
{
return FStar_UInt128_shift_left_large(a, s);
}
}
static uint64_t FStar_UInt128_add_u64_shift_right(uint64_t hi, uint64_t lo, uint32_t s)
{
return (lo >> s) + (hi << (FStar_UInt128_u32_64 - s));
}
static uint64_t FStar_UInt128_add_u64_shift_right_respec(uint64_t hi, uint64_t lo, uint32_t s)
{
return FStar_UInt128_add_u64_shift_right(hi, lo, s);
}
static FStar_UInt128_uint128
FStar_UInt128_shift_right_small(FStar_UInt128_uint128 a, uint32_t s)
{
if (s == (uint32_t)0U)
{
return a;
}
else
{
FStar_UInt128_uint128
flat = { FStar_UInt128_add_u64_shift_right_respec(a.high, a.low, s), a.high >> s };
return flat;
}
}
static FStar_UInt128_uint128
FStar_UInt128_shift_right_large(FStar_UInt128_uint128 a, uint32_t s)
{
FStar_UInt128_uint128 flat = { a.high >> (s - FStar_UInt128_u32_64), (uint64_t)0U };
return flat;
}
FStar_UInt128_uint128 FStar_UInt128_shift_right(FStar_UInt128_uint128 a, uint32_t s)
{
if (s < FStar_UInt128_u32_64)
{
return FStar_UInt128_shift_right_small(a, s);
}
else
{
return FStar_UInt128_shift_right_large(a, s);
}
}
bool FStar_UInt128_eq(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b)
{
return a.low == b.low && a.high == b.high;
}
bool FStar_UInt128_gt(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b)
{
return a.high > b.high || (a.high == b.high && a.low > b.low);
}
bool FStar_UInt128_lt(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b)
{
return a.high < b.high || (a.high == b.high && a.low < b.low);
}
bool FStar_UInt128_gte(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b)
{
return a.high > b.high || (a.high == b.high && a.low >= b.low);
}
bool FStar_UInt128_lte(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b)
{
return a.high < b.high || (a.high == b.high && a.low <= b.low);
}
FStar_UInt128_uint128 FStar_UInt128_eq_mask(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b)
{
FStar_UInt128_uint128
flat =
{
FStar_UInt64_eq_mask(a.low,
b.low)
& FStar_UInt64_eq_mask(a.high, b.high),
FStar_UInt64_eq_mask(a.low,
b.low)
& FStar_UInt64_eq_mask(a.high, b.high)
};
return flat;
}
FStar_UInt128_uint128 FStar_UInt128_gte_mask(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b)
{
FStar_UInt128_uint128
flat =
{
(FStar_UInt64_gte_mask(a.high, b.high) & ~FStar_UInt64_eq_mask(a.high, b.high))
| (FStar_UInt64_eq_mask(a.high, b.high) & FStar_UInt64_gte_mask(a.low, b.low)),
(FStar_UInt64_gte_mask(a.high, b.high) & ~FStar_UInt64_eq_mask(a.high, b.high))
| (FStar_UInt64_eq_mask(a.high, b.high) & FStar_UInt64_gte_mask(a.low, b.low))
};
return flat;
}
FStar_UInt128_uint128 FStar_UInt128_uint64_to_uint128(uint64_t a)
{
FStar_UInt128_uint128 flat = { a, (uint64_t)0U };
return flat;
}
uint64_t FStar_UInt128_uint128_to_uint64(FStar_UInt128_uint128 a)
{
return a.low;
}
FStar_UInt128_uint128
(*FStar_UInt128_op_Plus_Hat)(FStar_UInt128_uint128 x0, FStar_UInt128_uint128 x1) =
FStar_UInt128_add;
FStar_UInt128_uint128
(*FStar_UInt128_op_Plus_Question_Hat)(FStar_UInt128_uint128 x0, FStar_UInt128_uint128 x1) =
FStar_UInt128_add_underspec;
FStar_UInt128_uint128
(*FStar_UInt128_op_Plus_Percent_Hat)(FStar_UInt128_uint128 x0, FStar_UInt128_uint128 x1) =
FStar_UInt128_add_mod;
FStar_UInt128_uint128
(*FStar_UInt128_op_Subtraction_Hat)(FStar_UInt128_uint128 x0, FStar_UInt128_uint128 x1) =
FStar_UInt128_sub;
FStar_UInt128_uint128
(*FStar_UInt128_op_Subtraction_Question_Hat)(
FStar_UInt128_uint128 x0,
FStar_UInt128_uint128 x1
) = FStar_UInt128_sub_underspec;
FStar_UInt128_uint128
(*FStar_UInt128_op_Subtraction_Percent_Hat)(FStar_UInt128_uint128 x0, FStar_UInt128_uint128 x1) =
FStar_UInt128_sub_mod;
FStar_UInt128_uint128
(*FStar_UInt128_op_Amp_Hat)(FStar_UInt128_uint128 x0, FStar_UInt128_uint128 x1) =
FStar_UInt128_logand;
FStar_UInt128_uint128
(*FStar_UInt128_op_Hat_Hat)(FStar_UInt128_uint128 x0, FStar_UInt128_uint128 x1) =
FStar_UInt128_logxor;
FStar_UInt128_uint128
(*FStar_UInt128_op_Bar_Hat)(FStar_UInt128_uint128 x0, FStar_UInt128_uint128 x1) =
FStar_UInt128_logor;
FStar_UInt128_uint128
(*FStar_UInt128_op_Less_Less_Hat)(FStar_UInt128_uint128 x0, uint32_t x1) =
FStar_UInt128_shift_left;
FStar_UInt128_uint128
(*FStar_UInt128_op_Greater_Greater_Hat)(FStar_UInt128_uint128 x0, uint32_t x1) =
FStar_UInt128_shift_right;
bool
(*FStar_UInt128_op_Equals_Hat)(FStar_UInt128_uint128 x0, FStar_UInt128_uint128 x1) =
FStar_UInt128_eq;
bool
(*FStar_UInt128_op_Greater_Hat)(FStar_UInt128_uint128 x0, FStar_UInt128_uint128 x1) =
FStar_UInt128_gt;
bool
(*FStar_UInt128_op_Less_Hat)(FStar_UInt128_uint128 x0, FStar_UInt128_uint128 x1) =
FStar_UInt128_lt;
bool
(*FStar_UInt128_op_Greater_Equals_Hat)(FStar_UInt128_uint128 x0, FStar_UInt128_uint128 x1) =
FStar_UInt128_gte;
bool
(*FStar_UInt128_op_Less_Equals_Hat)(FStar_UInt128_uint128 x0, FStar_UInt128_uint128 x1) =
FStar_UInt128_lte;
static uint64_t FStar_UInt128_u64_mod_32(uint64_t a)
{
return a & (uint64_t)0xffffffffU;
}
static uint32_t FStar_UInt128_u32_32 = (uint32_t)32U;
static uint64_t FStar_UInt128_u32_combine(uint64_t hi, uint64_t lo)
{
return lo + (hi << FStar_UInt128_u32_32);
}
FStar_UInt128_uint128 FStar_UInt128_mul32(uint64_t x, uint32_t y)
{
FStar_UInt128_uint128
flat =
{
FStar_UInt128_u32_combine((x >> FStar_UInt128_u32_32)
* (uint64_t)y
+ (FStar_UInt128_u64_mod_32(x) * (uint64_t)y >> FStar_UInt128_u32_32),
FStar_UInt128_u64_mod_32(FStar_UInt128_u64_mod_32(x) * (uint64_t)y)),
((x >> FStar_UInt128_u32_32)
* (uint64_t)y
+ (FStar_UInt128_u64_mod_32(x) * (uint64_t)y >> FStar_UInt128_u32_32))
>> FStar_UInt128_u32_32
};
return flat;
}
typedef struct K___uint64_t_uint64_t_uint64_t_uint64_t_s
{
uint64_t fst;
uint64_t snd;
uint64_t thd;
uint64_t f3;
}
K___uint64_t_uint64_t_uint64_t_uint64_t;
static K___uint64_t_uint64_t_uint64_t_uint64_t
FStar_UInt128_mul_wide_impl_t_(uint64_t x, uint64_t y)
{
K___uint64_t_uint64_t_uint64_t_uint64_t
flat =
{
FStar_UInt128_u64_mod_32(x),
FStar_UInt128_u64_mod_32(FStar_UInt128_u64_mod_32(x) * FStar_UInt128_u64_mod_32(y)),
x
>> FStar_UInt128_u32_32,
(x >> FStar_UInt128_u32_32)
* FStar_UInt128_u64_mod_32(y)
+ (FStar_UInt128_u64_mod_32(x) * FStar_UInt128_u64_mod_32(y) >> FStar_UInt128_u32_32)
};
return flat;
}
static uint64_t FStar_UInt128_u32_combine_(uint64_t hi, uint64_t lo)
{
return lo + (hi << FStar_UInt128_u32_32);
}
static FStar_UInt128_uint128 FStar_UInt128_mul_wide_impl(uint64_t x, uint64_t y)
{
K___uint64_t_uint64_t_uint64_t_uint64_t scrut = FStar_UInt128_mul_wide_impl_t_(x, y);
uint64_t u1 = scrut.fst;
uint64_t w3 = scrut.snd;
uint64_t x_ = scrut.thd;
uint64_t t_ = scrut.f3;
FStar_UInt128_uint128
flat =
{
FStar_UInt128_u32_combine_(u1 * (y >> FStar_UInt128_u32_32) + FStar_UInt128_u64_mod_32(t_),
w3),
x_
* (y >> FStar_UInt128_u32_32)
+ (t_ >> FStar_UInt128_u32_32)
+ ((u1 * (y >> FStar_UInt128_u32_32) + FStar_UInt128_u64_mod_32(t_)) >> FStar_UInt128_u32_32)
};
return flat;
}
FStar_UInt128_uint128 FStar_UInt128_mul_wide(uint64_t x, uint64_t y)
{
return FStar_UInt128_mul_wide_impl(x, y);
}

View File

@ -0,0 +1,100 @@
/* Copyright (c) INRIA and Microsoft Corporation. All rights reserved.
Licensed under the Apache 2.0 License. */
/* This file was generated by KreMLin <https://github.com/FStarLang/kremlin>
* KreMLin invocation: ../krml -fc89 -fparentheses -fno-shadow -header /mnt/e/everest/verify/hdrB9w -minimal -fparentheses -fcurly-braces -fno-shadow -header copyright-header.txt -minimal -tmpdir dist/minimal -skip-compilation -extract-uints -add-include <inttypes.h> -add-include <stdbool.h> -add-include "kremlin/internal/compat.h" -add-include "kremlin/internal/types.h" -bundle FStar.UInt64+FStar.UInt32+FStar.UInt16+FStar.UInt8=* extracted/prims.krml extracted/FStar_Pervasives_Native.krml extracted/FStar_Pervasives.krml extracted/FStar_Mul.krml extracted/FStar_Squash.krml extracted/FStar_Classical.krml extracted/FStar_StrongExcludedMiddle.krml extracted/FStar_FunctionalExtensionality.krml extracted/FStar_List_Tot_Base.krml extracted/FStar_List_Tot_Properties.krml extracted/FStar_List_Tot.krml extracted/FStar_Seq_Base.krml extracted/FStar_Seq_Properties.krml extracted/FStar_Seq.krml extracted/FStar_Math_Lib.krml extracted/FStar_Math_Lemmas.krml extracted/FStar_BitVector.krml extracted/FStar_UInt.krml extracted/FStar_UInt32.krml extracted/FStar_Int.krml extracted/FStar_Int16.krml extracted/FStar_Preorder.krml extracted/FStar_Ghost.krml extracted/FStar_ErasedLogic.krml extracted/FStar_UInt64.krml extracted/FStar_Set.krml extracted/FStar_PropositionalExtensionality.krml extracted/FStar_PredicateExtensionality.krml extracted/FStar_TSet.krml extracted/FStar_Monotonic_Heap.krml extracted/FStar_Heap.krml extracted/FStar_Map.krml extracted/FStar_Monotonic_HyperHeap.krml extracted/FStar_Monotonic_HyperStack.krml extracted/FStar_HyperStack.krml extracted/FStar_Monotonic_Witnessed.krml extracted/FStar_HyperStack_ST.krml extracted/FStar_HyperStack_All.krml extracted/FStar_Date.krml extracted/FStar_Universe.krml extracted/FStar_GSet.krml extracted/FStar_ModifiesGen.krml extracted/LowStar_Monotonic_Buffer.krml extracted/LowStar_Buffer.krml extracted/Spec_Loops.krml extracted/LowStar_BufferOps.krml extracted/C_Loops.krml extracted/FStar_UInt8.krml extracted/FStar_Kremlin_Endianness.krml extracted/FStar_UInt63.krml extracted/FStar_Exn.krml extracted/FStar_ST.krml extracted/FStar_All.krml extracted/FStar_Dyn.krml extracted/FStar_Int63.krml extracted/FStar_Int64.krml extracted/FStar_Int32.krml extracted/FStar_Int8.krml extracted/FStar_UInt16.krml extracted/FStar_Int_Cast.krml extracted/FStar_UInt128.krml extracted/C_Endianness.krml extracted/FStar_List.krml extracted/FStar_Float.krml extracted/FStar_IO.krml extracted/C.krml extracted/FStar_Char.krml extracted/FStar_String.krml extracted/LowStar_Modifies.krml extracted/C_String.krml extracted/FStar_Bytes.krml extracted/FStar_HyperStack_IO.krml extracted/C_Failure.krml extracted/TestLib.krml extracted/FStar_Int_Cast_Full.krml
* F* version: 059db0c8
* KreMLin version: 916c37ac
*/
#include "FStar_UInt64_FStar_UInt32_FStar_UInt16_FStar_UInt8.h"
uint64_t FStar_UInt64_eq_mask(uint64_t a, uint64_t b)
{
uint64_t x = a ^ b;
uint64_t minus_x = ~x + (uint64_t)1U;
uint64_t x_or_minus_x = x | minus_x;
uint64_t xnx = x_or_minus_x >> (uint32_t)63U;
return xnx - (uint64_t)1U;
}
uint64_t FStar_UInt64_gte_mask(uint64_t a, uint64_t b)
{
uint64_t x = a;
uint64_t y = b;
uint64_t x_xor_y = x ^ y;
uint64_t x_sub_y = x - y;
uint64_t x_sub_y_xor_y = x_sub_y ^ y;
uint64_t q = x_xor_y | x_sub_y_xor_y;
uint64_t x_xor_q = x ^ q;
uint64_t x_xor_q_ = x_xor_q >> (uint32_t)63U;
return x_xor_q_ - (uint64_t)1U;
}
uint32_t FStar_UInt32_eq_mask(uint32_t a, uint32_t b)
{
uint32_t x = a ^ b;
uint32_t minus_x = ~x + (uint32_t)1U;
uint32_t x_or_minus_x = x | minus_x;
uint32_t xnx = x_or_minus_x >> (uint32_t)31U;
return xnx - (uint32_t)1U;
}
uint32_t FStar_UInt32_gte_mask(uint32_t a, uint32_t b)
{
uint32_t x = a;
uint32_t y = b;
uint32_t x_xor_y = x ^ y;
uint32_t x_sub_y = x - y;
uint32_t x_sub_y_xor_y = x_sub_y ^ y;
uint32_t q = x_xor_y | x_sub_y_xor_y;
uint32_t x_xor_q = x ^ q;
uint32_t x_xor_q_ = x_xor_q >> (uint32_t)31U;
return x_xor_q_ - (uint32_t)1U;
}
uint16_t FStar_UInt16_eq_mask(uint16_t a, uint16_t b)
{
uint16_t x = a ^ b;
uint16_t minus_x = ~x + (uint16_t)1U;
uint16_t x_or_minus_x = x | minus_x;
uint16_t xnx = x_or_minus_x >> (uint32_t)15U;
return xnx - (uint16_t)1U;
}
uint16_t FStar_UInt16_gte_mask(uint16_t a, uint16_t b)
{
uint16_t x = a;
uint16_t y = b;
uint16_t x_xor_y = x ^ y;
uint16_t x_sub_y = x - y;
uint16_t x_sub_y_xor_y = x_sub_y ^ y;
uint16_t q = x_xor_y | x_sub_y_xor_y;
uint16_t x_xor_q = x ^ q;
uint16_t x_xor_q_ = x_xor_q >> (uint32_t)15U;
return x_xor_q_ - (uint16_t)1U;
}
uint8_t FStar_UInt8_eq_mask(uint8_t a, uint8_t b)
{
uint8_t x = a ^ b;
uint8_t minus_x = ~x + (uint8_t)1U;
uint8_t x_or_minus_x = x | minus_x;
uint8_t xnx = x_or_minus_x >> (uint32_t)7U;
return xnx - (uint8_t)1U;
}
uint8_t FStar_UInt8_gte_mask(uint8_t a, uint8_t b)
{
uint8_t x = a;
uint8_t y = b;
uint8_t x_xor_y = x ^ y;
uint8_t x_sub_y = x - y;
uint8_t x_sub_y_xor_y = x_sub_y ^ y;
uint8_t q = x_xor_y | x_sub_y_xor_y;
uint8_t x_xor_q = x ^ q;
uint8_t x_xor_q_ = x_xor_q >> (uint32_t)7U;
return x_xor_q_ - (uint8_t)1U;
}

View File

@ -0,0 +1,805 @@
/* Copyright (c) INRIA and Microsoft Corporation. All rights reserved.
Licensed under the Apache 2.0 License. */
/* This file was generated by KreMLin <https://github.com/FStarLang/kremlin>
* KreMLin invocation: /mnt/e/everest/verify/kremlin/krml -fc89 -fparentheses -fno-shadow -header /mnt/e/everest/verify/hdrcLh -minimal -fc89 -fparentheses -fno-shadow -header /mnt/e/everest/verify/hdrcLh -minimal -I /mnt/e/everest/verify/hacl-star/code/lib/kremlin -I /mnt/e/everest/verify/kremlin/kremlib/compat -I /mnt/e/everest/verify/hacl-star/specs -I /mnt/e/everest/verify/hacl-star/specs/old -I . -ccopt -march=native -verbose -ldopt -flto -tmpdir x25519-c -I ../bignum -bundle Hacl.Curve25519=* -minimal -add-include "kremlib.h" -skip-compilation x25519-c/out.krml -o x25519-c/Hacl_Curve25519.c
* F* version: 059db0c8
* KreMLin version: 916c37ac
*/
#include "Hacl_Curve25519.h"
extern uint64_t FStar_UInt64_eq_mask(uint64_t x0, uint64_t x1);
extern uint64_t FStar_UInt64_gte_mask(uint64_t x0, uint64_t x1);
extern FStar_UInt128_uint128
FStar_UInt128_add(FStar_UInt128_uint128 x0, FStar_UInt128_uint128 x1);
extern FStar_UInt128_uint128
FStar_UInt128_add_mod(FStar_UInt128_uint128 x0, FStar_UInt128_uint128 x1);
extern FStar_UInt128_uint128
FStar_UInt128_logand(FStar_UInt128_uint128 x0, FStar_UInt128_uint128 x1);
extern FStar_UInt128_uint128 FStar_UInt128_shift_right(FStar_UInt128_uint128 x0, uint32_t x1);
extern FStar_UInt128_uint128 FStar_UInt128_uint64_to_uint128(uint64_t x0);
extern uint64_t FStar_UInt128_uint128_to_uint64(FStar_UInt128_uint128 x0);
extern FStar_UInt128_uint128 FStar_UInt128_mul_wide(uint64_t x0, uint64_t x1);
static void Hacl_Bignum_Modulo_carry_top(uint64_t *b)
{
uint64_t b4 = b[4U];
uint64_t b0 = b[0U];
uint64_t b4_ = b4 & (uint64_t)0x7ffffffffffffU;
uint64_t b0_ = b0 + (uint64_t)19U * (b4 >> (uint32_t)51U);
b[4U] = b4_;
b[0U] = b0_;
}
inline static void
Hacl_Bignum_Fproduct_copy_from_wide_(uint64_t *output, FStar_UInt128_uint128 *input)
{
uint32_t i;
for (i = (uint32_t)0U; i < (uint32_t)5U; i = i + (uint32_t)1U)
{
FStar_UInt128_uint128 xi = input[i];
output[i] = FStar_UInt128_uint128_to_uint64(xi);
}
}
inline static void
Hacl_Bignum_Fproduct_sum_scalar_multiplication_(
FStar_UInt128_uint128 *output,
uint64_t *input,
uint64_t s
)
{
uint32_t i;
for (i = (uint32_t)0U; i < (uint32_t)5U; i = i + (uint32_t)1U)
{
FStar_UInt128_uint128 xi = output[i];
uint64_t yi = input[i];
output[i] = FStar_UInt128_add_mod(xi, FStar_UInt128_mul_wide(yi, s));
}
}
inline static void Hacl_Bignum_Fproduct_carry_wide_(FStar_UInt128_uint128 *tmp)
{
uint32_t i;
for (i = (uint32_t)0U; i < (uint32_t)4U; i = i + (uint32_t)1U)
{
uint32_t ctr = i;
FStar_UInt128_uint128 tctr = tmp[ctr];
FStar_UInt128_uint128 tctrp1 = tmp[ctr + (uint32_t)1U];
uint64_t r0 = FStar_UInt128_uint128_to_uint64(tctr) & (uint64_t)0x7ffffffffffffU;
FStar_UInt128_uint128 c = FStar_UInt128_shift_right(tctr, (uint32_t)51U);
tmp[ctr] = FStar_UInt128_uint64_to_uint128(r0);
tmp[ctr + (uint32_t)1U] = FStar_UInt128_add(tctrp1, c);
}
}
inline static void Hacl_Bignum_Fmul_shift_reduce(uint64_t *output)
{
uint64_t tmp = output[4U];
uint64_t b0;
{
uint32_t i;
for (i = (uint32_t)0U; i < (uint32_t)4U; i = i + (uint32_t)1U)
{
uint32_t ctr = (uint32_t)5U - i - (uint32_t)1U;
uint64_t z = output[ctr - (uint32_t)1U];
output[ctr] = z;
}
}
output[0U] = tmp;
b0 = output[0U];
output[0U] = (uint64_t)19U * b0;
}
static void
Hacl_Bignum_Fmul_mul_shift_reduce_(
FStar_UInt128_uint128 *output,
uint64_t *input,
uint64_t *input2
)
{
uint32_t i;
uint64_t input2i;
{
uint32_t i0;
for (i0 = (uint32_t)0U; i0 < (uint32_t)4U; i0 = i0 + (uint32_t)1U)
{
uint64_t input2i0 = input2[i0];
Hacl_Bignum_Fproduct_sum_scalar_multiplication_(output, input, input2i0);
Hacl_Bignum_Fmul_shift_reduce(input);
}
}
i = (uint32_t)4U;
input2i = input2[i];
Hacl_Bignum_Fproduct_sum_scalar_multiplication_(output, input, input2i);
}
inline static void Hacl_Bignum_Fmul_fmul(uint64_t *output, uint64_t *input, uint64_t *input2)
{
uint64_t tmp[5U] = { 0U };
memcpy(tmp, input, (uint32_t)5U * sizeof input[0U]);
KRML_CHECK_SIZE(sizeof (FStar_UInt128_uint128), (uint32_t)5U);
{
FStar_UInt128_uint128 t[5U];
{
uint32_t _i;
for (_i = 0U; _i < (uint32_t)5U; ++_i)
t[_i] = FStar_UInt128_uint64_to_uint128((uint64_t)0U);
}
{
FStar_UInt128_uint128 b4;
FStar_UInt128_uint128 b0;
FStar_UInt128_uint128 b4_;
FStar_UInt128_uint128 b0_;
uint64_t i0;
uint64_t i1;
uint64_t i0_;
uint64_t i1_;
Hacl_Bignum_Fmul_mul_shift_reduce_(t, tmp, input2);
Hacl_Bignum_Fproduct_carry_wide_(t);
b4 = t[4U];
b0 = t[0U];
b4_ = FStar_UInt128_logand(b4, FStar_UInt128_uint64_to_uint128((uint64_t)0x7ffffffffffffU));
b0_ =
FStar_UInt128_add(b0,
FStar_UInt128_mul_wide((uint64_t)19U,
FStar_UInt128_uint128_to_uint64(FStar_UInt128_shift_right(b4, (uint32_t)51U))));
t[4U] = b4_;
t[0U] = b0_;
Hacl_Bignum_Fproduct_copy_from_wide_(output, t);
i0 = output[0U];
i1 = output[1U];
i0_ = i0 & (uint64_t)0x7ffffffffffffU;
i1_ = i1 + (i0 >> (uint32_t)51U);
output[0U] = i0_;
output[1U] = i1_;
}
}
}
inline static void Hacl_Bignum_Fsquare_fsquare__(FStar_UInt128_uint128 *tmp, uint64_t *output)
{
uint64_t r0 = output[0U];
uint64_t r1 = output[1U];
uint64_t r2 = output[2U];
uint64_t r3 = output[3U];
uint64_t r4 = output[4U];
uint64_t d0 = r0 * (uint64_t)2U;
uint64_t d1 = r1 * (uint64_t)2U;
uint64_t d2 = r2 * (uint64_t)2U * (uint64_t)19U;
uint64_t d419 = r4 * (uint64_t)19U;
uint64_t d4 = d419 * (uint64_t)2U;
FStar_UInt128_uint128
s0 =
FStar_UInt128_add(FStar_UInt128_add(FStar_UInt128_mul_wide(r0, r0),
FStar_UInt128_mul_wide(d4, r1)),
FStar_UInt128_mul_wide(d2, r3));
FStar_UInt128_uint128
s1 =
FStar_UInt128_add(FStar_UInt128_add(FStar_UInt128_mul_wide(d0, r1),
FStar_UInt128_mul_wide(d4, r2)),
FStar_UInt128_mul_wide(r3 * (uint64_t)19U, r3));
FStar_UInt128_uint128
s2 =
FStar_UInt128_add(FStar_UInt128_add(FStar_UInt128_mul_wide(d0, r2),
FStar_UInt128_mul_wide(r1, r1)),
FStar_UInt128_mul_wide(d4, r3));
FStar_UInt128_uint128
s3 =
FStar_UInt128_add(FStar_UInt128_add(FStar_UInt128_mul_wide(d0, r3),
FStar_UInt128_mul_wide(d1, r2)),
FStar_UInt128_mul_wide(r4, d419));
FStar_UInt128_uint128
s4 =
FStar_UInt128_add(FStar_UInt128_add(FStar_UInt128_mul_wide(d0, r4),
FStar_UInt128_mul_wide(d1, r3)),
FStar_UInt128_mul_wide(r2, r2));
tmp[0U] = s0;
tmp[1U] = s1;
tmp[2U] = s2;
tmp[3U] = s3;
tmp[4U] = s4;
}
inline static void Hacl_Bignum_Fsquare_fsquare_(FStar_UInt128_uint128 *tmp, uint64_t *output)
{
FStar_UInt128_uint128 b4;
FStar_UInt128_uint128 b0;
FStar_UInt128_uint128 b4_;
FStar_UInt128_uint128 b0_;
uint64_t i0;
uint64_t i1;
uint64_t i0_;
uint64_t i1_;
Hacl_Bignum_Fsquare_fsquare__(tmp, output);
Hacl_Bignum_Fproduct_carry_wide_(tmp);
b4 = tmp[4U];
b0 = tmp[0U];
b4_ = FStar_UInt128_logand(b4, FStar_UInt128_uint64_to_uint128((uint64_t)0x7ffffffffffffU));
b0_ =
FStar_UInt128_add(b0,
FStar_UInt128_mul_wide((uint64_t)19U,
FStar_UInt128_uint128_to_uint64(FStar_UInt128_shift_right(b4, (uint32_t)51U))));
tmp[4U] = b4_;
tmp[0U] = b0_;
Hacl_Bignum_Fproduct_copy_from_wide_(output, tmp);
i0 = output[0U];
i1 = output[1U];
i0_ = i0 & (uint64_t)0x7ffffffffffffU;
i1_ = i1 + (i0 >> (uint32_t)51U);
output[0U] = i0_;
output[1U] = i1_;
}
static void
Hacl_Bignum_Fsquare_fsquare_times_(
uint64_t *input,
FStar_UInt128_uint128 *tmp,
uint32_t count1
)
{
uint32_t i;
Hacl_Bignum_Fsquare_fsquare_(tmp, input);
for (i = (uint32_t)1U; i < count1; i = i + (uint32_t)1U)
Hacl_Bignum_Fsquare_fsquare_(tmp, input);
}
inline static void
Hacl_Bignum_Fsquare_fsquare_times(uint64_t *output, uint64_t *input, uint32_t count1)
{
KRML_CHECK_SIZE(sizeof (FStar_UInt128_uint128), (uint32_t)5U);
{
FStar_UInt128_uint128 t[5U];
{
uint32_t _i;
for (_i = 0U; _i < (uint32_t)5U; ++_i)
t[_i] = FStar_UInt128_uint64_to_uint128((uint64_t)0U);
}
memcpy(output, input, (uint32_t)5U * sizeof input[0U]);
Hacl_Bignum_Fsquare_fsquare_times_(output, t, count1);
}
}
inline static void Hacl_Bignum_Fsquare_fsquare_times_inplace(uint64_t *output, uint32_t count1)
{
KRML_CHECK_SIZE(sizeof (FStar_UInt128_uint128), (uint32_t)5U);
{
FStar_UInt128_uint128 t[5U];
{
uint32_t _i;
for (_i = 0U; _i < (uint32_t)5U; ++_i)
t[_i] = FStar_UInt128_uint64_to_uint128((uint64_t)0U);
}
Hacl_Bignum_Fsquare_fsquare_times_(output, t, count1);
}
}
inline static void Hacl_Bignum_Crecip_crecip(uint64_t *out, uint64_t *z)
{
uint64_t buf[20U] = { 0U };
uint64_t *a0 = buf;
uint64_t *t00 = buf + (uint32_t)5U;
uint64_t *b0 = buf + (uint32_t)10U;
uint64_t *t01;
uint64_t *b1;
uint64_t *c0;
uint64_t *a;
uint64_t *t0;
uint64_t *b;
uint64_t *c;
Hacl_Bignum_Fsquare_fsquare_times(a0, z, (uint32_t)1U);
Hacl_Bignum_Fsquare_fsquare_times(t00, a0, (uint32_t)2U);
Hacl_Bignum_Fmul_fmul(b0, t00, z);
Hacl_Bignum_Fmul_fmul(a0, b0, a0);
Hacl_Bignum_Fsquare_fsquare_times(t00, a0, (uint32_t)1U);
Hacl_Bignum_Fmul_fmul(b0, t00, b0);
Hacl_Bignum_Fsquare_fsquare_times(t00, b0, (uint32_t)5U);
t01 = buf + (uint32_t)5U;
b1 = buf + (uint32_t)10U;
c0 = buf + (uint32_t)15U;
Hacl_Bignum_Fmul_fmul(b1, t01, b1);
Hacl_Bignum_Fsquare_fsquare_times(t01, b1, (uint32_t)10U);
Hacl_Bignum_Fmul_fmul(c0, t01, b1);
Hacl_Bignum_Fsquare_fsquare_times(t01, c0, (uint32_t)20U);
Hacl_Bignum_Fmul_fmul(t01, t01, c0);
Hacl_Bignum_Fsquare_fsquare_times_inplace(t01, (uint32_t)10U);
Hacl_Bignum_Fmul_fmul(b1, t01, b1);
Hacl_Bignum_Fsquare_fsquare_times(t01, b1, (uint32_t)50U);
a = buf;
t0 = buf + (uint32_t)5U;
b = buf + (uint32_t)10U;
c = buf + (uint32_t)15U;
Hacl_Bignum_Fmul_fmul(c, t0, b);
Hacl_Bignum_Fsquare_fsquare_times(t0, c, (uint32_t)100U);
Hacl_Bignum_Fmul_fmul(t0, t0, c);
Hacl_Bignum_Fsquare_fsquare_times_inplace(t0, (uint32_t)50U);
Hacl_Bignum_Fmul_fmul(t0, t0, b);
Hacl_Bignum_Fsquare_fsquare_times_inplace(t0, (uint32_t)5U);
Hacl_Bignum_Fmul_fmul(out, t0, a);
}
inline static void Hacl_Bignum_fsum(uint64_t *a, uint64_t *b)
{
uint32_t i;
for (i = (uint32_t)0U; i < (uint32_t)5U; i = i + (uint32_t)1U)
{
uint64_t xi = a[i];
uint64_t yi = b[i];
a[i] = xi + yi;
}
}
inline static void Hacl_Bignum_fdifference(uint64_t *a, uint64_t *b)
{
uint64_t tmp[5U] = { 0U };
uint64_t b0;
uint64_t b1;
uint64_t b2;
uint64_t b3;
uint64_t b4;
memcpy(tmp, b, (uint32_t)5U * sizeof b[0U]);
b0 = tmp[0U];
b1 = tmp[1U];
b2 = tmp[2U];
b3 = tmp[3U];
b4 = tmp[4U];
tmp[0U] = b0 + (uint64_t)0x3fffffffffff68U;
tmp[1U] = b1 + (uint64_t)0x3ffffffffffff8U;
tmp[2U] = b2 + (uint64_t)0x3ffffffffffff8U;
tmp[3U] = b3 + (uint64_t)0x3ffffffffffff8U;
tmp[4U] = b4 + (uint64_t)0x3ffffffffffff8U;
{
uint32_t i;
for (i = (uint32_t)0U; i < (uint32_t)5U; i = i + (uint32_t)1U)
{
uint64_t xi = a[i];
uint64_t yi = tmp[i];
a[i] = yi - xi;
}
}
}
inline static void Hacl_Bignum_fscalar(uint64_t *output, uint64_t *b, uint64_t s)
{
KRML_CHECK_SIZE(sizeof (FStar_UInt128_uint128), (uint32_t)5U);
{
FStar_UInt128_uint128 tmp[5U];
{
uint32_t _i;
for (_i = 0U; _i < (uint32_t)5U; ++_i)
tmp[_i] = FStar_UInt128_uint64_to_uint128((uint64_t)0U);
}
{
FStar_UInt128_uint128 b4;
FStar_UInt128_uint128 b0;
FStar_UInt128_uint128 b4_;
FStar_UInt128_uint128 b0_;
{
uint32_t i;
for (i = (uint32_t)0U; i < (uint32_t)5U; i = i + (uint32_t)1U)
{
uint64_t xi = b[i];
tmp[i] = FStar_UInt128_mul_wide(xi, s);
}
}
Hacl_Bignum_Fproduct_carry_wide_(tmp);
b4 = tmp[4U];
b0 = tmp[0U];
b4_ = FStar_UInt128_logand(b4, FStar_UInt128_uint64_to_uint128((uint64_t)0x7ffffffffffffU));
b0_ =
FStar_UInt128_add(b0,
FStar_UInt128_mul_wide((uint64_t)19U,
FStar_UInt128_uint128_to_uint64(FStar_UInt128_shift_right(b4, (uint32_t)51U))));
tmp[4U] = b4_;
tmp[0U] = b0_;
Hacl_Bignum_Fproduct_copy_from_wide_(output, tmp);
}
}
}
inline static void Hacl_Bignum_fmul(uint64_t *output, uint64_t *a, uint64_t *b)
{
Hacl_Bignum_Fmul_fmul(output, a, b);
}
inline static void Hacl_Bignum_crecip(uint64_t *output, uint64_t *input)
{
Hacl_Bignum_Crecip_crecip(output, input);
}
static void
Hacl_EC_Point_swap_conditional_step(uint64_t *a, uint64_t *b, uint64_t swap1, uint32_t ctr)
{
uint32_t i = ctr - (uint32_t)1U;
uint64_t ai = a[i];
uint64_t bi = b[i];
uint64_t x = swap1 & (ai ^ bi);
uint64_t ai1 = ai ^ x;
uint64_t bi1 = bi ^ x;
a[i] = ai1;
b[i] = bi1;
}
static void
Hacl_EC_Point_swap_conditional_(uint64_t *a, uint64_t *b, uint64_t swap1, uint32_t ctr)
{
if (!(ctr == (uint32_t)0U))
{
uint32_t i;
Hacl_EC_Point_swap_conditional_step(a, b, swap1, ctr);
i = ctr - (uint32_t)1U;
Hacl_EC_Point_swap_conditional_(a, b, swap1, i);
}
}
static void Hacl_EC_Point_swap_conditional(uint64_t *a, uint64_t *b, uint64_t iswap)
{
uint64_t swap1 = (uint64_t)0U - iswap;
Hacl_EC_Point_swap_conditional_(a, b, swap1, (uint32_t)5U);
Hacl_EC_Point_swap_conditional_(a + (uint32_t)5U, b + (uint32_t)5U, swap1, (uint32_t)5U);
}
static void Hacl_EC_Point_copy(uint64_t *output, uint64_t *input)
{
memcpy(output, input, (uint32_t)5U * sizeof input[0U]);
memcpy(output + (uint32_t)5U,
input + (uint32_t)5U,
(uint32_t)5U * sizeof (input + (uint32_t)5U)[0U]);
}
static void Hacl_EC_Format_fexpand(uint64_t *output, uint8_t *input)
{
uint64_t i0 = load64_le(input);
uint8_t *x00 = input + (uint32_t)6U;
uint64_t i1 = load64_le(x00);
uint8_t *x01 = input + (uint32_t)12U;
uint64_t i2 = load64_le(x01);
uint8_t *x02 = input + (uint32_t)19U;
uint64_t i3 = load64_le(x02);
uint8_t *x0 = input + (uint32_t)24U;
uint64_t i4 = load64_le(x0);
uint64_t output0 = i0 & (uint64_t)0x7ffffffffffffU;
uint64_t output1 = i1 >> (uint32_t)3U & (uint64_t)0x7ffffffffffffU;
uint64_t output2 = i2 >> (uint32_t)6U & (uint64_t)0x7ffffffffffffU;
uint64_t output3 = i3 >> (uint32_t)1U & (uint64_t)0x7ffffffffffffU;
uint64_t output4 = i4 >> (uint32_t)12U & (uint64_t)0x7ffffffffffffU;
output[0U] = output0;
output[1U] = output1;
output[2U] = output2;
output[3U] = output3;
output[4U] = output4;
}
static void Hacl_EC_Format_fcontract_first_carry_pass(uint64_t *input)
{
uint64_t t0 = input[0U];
uint64_t t1 = input[1U];
uint64_t t2 = input[2U];
uint64_t t3 = input[3U];
uint64_t t4 = input[4U];
uint64_t t1_ = t1 + (t0 >> (uint32_t)51U);
uint64_t t0_ = t0 & (uint64_t)0x7ffffffffffffU;
uint64_t t2_ = t2 + (t1_ >> (uint32_t)51U);
uint64_t t1__ = t1_ & (uint64_t)0x7ffffffffffffU;
uint64_t t3_ = t3 + (t2_ >> (uint32_t)51U);
uint64_t t2__ = t2_ & (uint64_t)0x7ffffffffffffU;
uint64_t t4_ = t4 + (t3_ >> (uint32_t)51U);
uint64_t t3__ = t3_ & (uint64_t)0x7ffffffffffffU;
input[0U] = t0_;
input[1U] = t1__;
input[2U] = t2__;
input[3U] = t3__;
input[4U] = t4_;
}
static void Hacl_EC_Format_fcontract_first_carry_full(uint64_t *input)
{
Hacl_EC_Format_fcontract_first_carry_pass(input);
Hacl_Bignum_Modulo_carry_top(input);
}
static void Hacl_EC_Format_fcontract_second_carry_pass(uint64_t *input)
{
uint64_t t0 = input[0U];
uint64_t t1 = input[1U];
uint64_t t2 = input[2U];
uint64_t t3 = input[3U];
uint64_t t4 = input[4U];
uint64_t t1_ = t1 + (t0 >> (uint32_t)51U);
uint64_t t0_ = t0 & (uint64_t)0x7ffffffffffffU;
uint64_t t2_ = t2 + (t1_ >> (uint32_t)51U);
uint64_t t1__ = t1_ & (uint64_t)0x7ffffffffffffU;
uint64_t t3_ = t3 + (t2_ >> (uint32_t)51U);
uint64_t t2__ = t2_ & (uint64_t)0x7ffffffffffffU;
uint64_t t4_ = t4 + (t3_ >> (uint32_t)51U);
uint64_t t3__ = t3_ & (uint64_t)0x7ffffffffffffU;
input[0U] = t0_;
input[1U] = t1__;
input[2U] = t2__;
input[3U] = t3__;
input[4U] = t4_;
}
static void Hacl_EC_Format_fcontract_second_carry_full(uint64_t *input)
{
uint64_t i0;
uint64_t i1;
uint64_t i0_;
uint64_t i1_;
Hacl_EC_Format_fcontract_second_carry_pass(input);
Hacl_Bignum_Modulo_carry_top(input);
i0 = input[0U];
i1 = input[1U];
i0_ = i0 & (uint64_t)0x7ffffffffffffU;
i1_ = i1 + (i0 >> (uint32_t)51U);
input[0U] = i0_;
input[1U] = i1_;
}
static void Hacl_EC_Format_fcontract_trim(uint64_t *input)
{
uint64_t a0 = input[0U];
uint64_t a1 = input[1U];
uint64_t a2 = input[2U];
uint64_t a3 = input[3U];
uint64_t a4 = input[4U];
uint64_t mask0 = FStar_UInt64_gte_mask(a0, (uint64_t)0x7ffffffffffedU);
uint64_t mask1 = FStar_UInt64_eq_mask(a1, (uint64_t)0x7ffffffffffffU);
uint64_t mask2 = FStar_UInt64_eq_mask(a2, (uint64_t)0x7ffffffffffffU);
uint64_t mask3 = FStar_UInt64_eq_mask(a3, (uint64_t)0x7ffffffffffffU);
uint64_t mask4 = FStar_UInt64_eq_mask(a4, (uint64_t)0x7ffffffffffffU);
uint64_t mask = (((mask0 & mask1) & mask2) & mask3) & mask4;
uint64_t a0_ = a0 - ((uint64_t)0x7ffffffffffedU & mask);
uint64_t a1_ = a1 - ((uint64_t)0x7ffffffffffffU & mask);
uint64_t a2_ = a2 - ((uint64_t)0x7ffffffffffffU & mask);
uint64_t a3_ = a3 - ((uint64_t)0x7ffffffffffffU & mask);
uint64_t a4_ = a4 - ((uint64_t)0x7ffffffffffffU & mask);
input[0U] = a0_;
input[1U] = a1_;
input[2U] = a2_;
input[3U] = a3_;
input[4U] = a4_;
}
static void Hacl_EC_Format_fcontract_store(uint8_t *output, uint64_t *input)
{
uint64_t t0 = input[0U];
uint64_t t1 = input[1U];
uint64_t t2 = input[2U];
uint64_t t3 = input[3U];
uint64_t t4 = input[4U];
uint64_t o0 = t1 << (uint32_t)51U | t0;
uint64_t o1 = t2 << (uint32_t)38U | t1 >> (uint32_t)13U;
uint64_t o2 = t3 << (uint32_t)25U | t2 >> (uint32_t)26U;
uint64_t o3 = t4 << (uint32_t)12U | t3 >> (uint32_t)39U;
uint8_t *b0 = output;
uint8_t *b1 = output + (uint32_t)8U;
uint8_t *b2 = output + (uint32_t)16U;
uint8_t *b3 = output + (uint32_t)24U;
store64_le(b0, o0);
store64_le(b1, o1);
store64_le(b2, o2);
store64_le(b3, o3);
}
static void Hacl_EC_Format_fcontract(uint8_t *output, uint64_t *input)
{
Hacl_EC_Format_fcontract_first_carry_full(input);
Hacl_EC_Format_fcontract_second_carry_full(input);
Hacl_EC_Format_fcontract_trim(input);
Hacl_EC_Format_fcontract_store(output, input);
}
static void Hacl_EC_Format_scalar_of_point(uint8_t *scalar, uint64_t *point)
{
uint64_t *x = point;
uint64_t *z = point + (uint32_t)5U;
uint64_t buf[10U] = { 0U };
uint64_t *zmone = buf;
uint64_t *sc = buf + (uint32_t)5U;
Hacl_Bignum_crecip(zmone, z);
Hacl_Bignum_fmul(sc, x, zmone);
Hacl_EC_Format_fcontract(scalar, sc);
}
static void
Hacl_EC_AddAndDouble_fmonty(
uint64_t *pp,
uint64_t *ppq,
uint64_t *p,
uint64_t *pq,
uint64_t *qmqp
)
{
uint64_t *qx = qmqp;
uint64_t *x2 = pp;
uint64_t *z2 = pp + (uint32_t)5U;
uint64_t *x3 = ppq;
uint64_t *z3 = ppq + (uint32_t)5U;
uint64_t *x = p;
uint64_t *z = p + (uint32_t)5U;
uint64_t *xprime = pq;
uint64_t *zprime = pq + (uint32_t)5U;
uint64_t buf[40U] = { 0U };
uint64_t *origx = buf;
uint64_t *origxprime0 = buf + (uint32_t)5U;
uint64_t *xxprime0 = buf + (uint32_t)25U;
uint64_t *zzprime0 = buf + (uint32_t)30U;
uint64_t *origxprime;
uint64_t *xx0;
uint64_t *zz0;
uint64_t *xxprime;
uint64_t *zzprime;
uint64_t *zzzprime;
uint64_t *zzz;
uint64_t *xx;
uint64_t *zz;
uint64_t scalar;
memcpy(origx, x, (uint32_t)5U * sizeof x[0U]);
Hacl_Bignum_fsum(x, z);
Hacl_Bignum_fdifference(z, origx);
memcpy(origxprime0, xprime, (uint32_t)5U * sizeof xprime[0U]);
Hacl_Bignum_fsum(xprime, zprime);
Hacl_Bignum_fdifference(zprime, origxprime0);
Hacl_Bignum_fmul(xxprime0, xprime, z);
Hacl_Bignum_fmul(zzprime0, x, zprime);
origxprime = buf + (uint32_t)5U;
xx0 = buf + (uint32_t)15U;
zz0 = buf + (uint32_t)20U;
xxprime = buf + (uint32_t)25U;
zzprime = buf + (uint32_t)30U;
zzzprime = buf + (uint32_t)35U;
memcpy(origxprime, xxprime, (uint32_t)5U * sizeof xxprime[0U]);
Hacl_Bignum_fsum(xxprime, zzprime);
Hacl_Bignum_fdifference(zzprime, origxprime);
Hacl_Bignum_Fsquare_fsquare_times(x3, xxprime, (uint32_t)1U);
Hacl_Bignum_Fsquare_fsquare_times(zzzprime, zzprime, (uint32_t)1U);
Hacl_Bignum_fmul(z3, zzzprime, qx);
Hacl_Bignum_Fsquare_fsquare_times(xx0, x, (uint32_t)1U);
Hacl_Bignum_Fsquare_fsquare_times(zz0, z, (uint32_t)1U);
zzz = buf + (uint32_t)10U;
xx = buf + (uint32_t)15U;
zz = buf + (uint32_t)20U;
Hacl_Bignum_fmul(x2, xx, zz);
Hacl_Bignum_fdifference(zz, xx);
scalar = (uint64_t)121665U;
Hacl_Bignum_fscalar(zzz, zz, scalar);
Hacl_Bignum_fsum(zzz, xx);
Hacl_Bignum_fmul(z2, zzz, zz);
}
static void
Hacl_EC_Ladder_SmallLoop_cmult_small_loop_step(
uint64_t *nq,
uint64_t *nqpq,
uint64_t *nq2,
uint64_t *nqpq2,
uint64_t *q,
uint8_t byt
)
{
uint64_t bit0 = (uint64_t)(byt >> (uint32_t)7U);
uint64_t bit;
Hacl_EC_Point_swap_conditional(nq, nqpq, bit0);
Hacl_EC_AddAndDouble_fmonty(nq2, nqpq2, nq, nqpq, q);
bit = (uint64_t)(byt >> (uint32_t)7U);
Hacl_EC_Point_swap_conditional(nq2, nqpq2, bit);
}
static void
Hacl_EC_Ladder_SmallLoop_cmult_small_loop_double_step(
uint64_t *nq,
uint64_t *nqpq,
uint64_t *nq2,
uint64_t *nqpq2,
uint64_t *q,
uint8_t byt
)
{
uint8_t byt1;
Hacl_EC_Ladder_SmallLoop_cmult_small_loop_step(nq, nqpq, nq2, nqpq2, q, byt);
byt1 = byt << (uint32_t)1U;
Hacl_EC_Ladder_SmallLoop_cmult_small_loop_step(nq2, nqpq2, nq, nqpq, q, byt1);
}
static void
Hacl_EC_Ladder_SmallLoop_cmult_small_loop(
uint64_t *nq,
uint64_t *nqpq,
uint64_t *nq2,
uint64_t *nqpq2,
uint64_t *q,
uint8_t byt,
uint32_t i
)
{
if (!(i == (uint32_t)0U))
{
uint32_t i_ = i - (uint32_t)1U;
uint8_t byt_;
Hacl_EC_Ladder_SmallLoop_cmult_small_loop_double_step(nq, nqpq, nq2, nqpq2, q, byt);
byt_ = byt << (uint32_t)2U;
Hacl_EC_Ladder_SmallLoop_cmult_small_loop(nq, nqpq, nq2, nqpq2, q, byt_, i_);
}
}
static void
Hacl_EC_Ladder_BigLoop_cmult_big_loop(
uint8_t *n1,
uint64_t *nq,
uint64_t *nqpq,
uint64_t *nq2,
uint64_t *nqpq2,
uint64_t *q,
uint32_t i
)
{
if (!(i == (uint32_t)0U))
{
uint32_t i1 = i - (uint32_t)1U;
uint8_t byte = n1[i1];
Hacl_EC_Ladder_SmallLoop_cmult_small_loop(nq, nqpq, nq2, nqpq2, q, byte, (uint32_t)4U);
Hacl_EC_Ladder_BigLoop_cmult_big_loop(n1, nq, nqpq, nq2, nqpq2, q, i1);
}
}
static void Hacl_EC_Ladder_cmult(uint64_t *result, uint8_t *n1, uint64_t *q)
{
uint64_t point_buf[40U] = { 0U };
uint64_t *nq = point_buf;
uint64_t *nqpq = point_buf + (uint32_t)10U;
uint64_t *nq2 = point_buf + (uint32_t)20U;
uint64_t *nqpq2 = point_buf + (uint32_t)30U;
Hacl_EC_Point_copy(nqpq, q);
nq[0U] = (uint64_t)1U;
Hacl_EC_Ladder_BigLoop_cmult_big_loop(n1, nq, nqpq, nq2, nqpq2, q, (uint32_t)32U);
Hacl_EC_Point_copy(result, nq);
}
void Hacl_Curve25519_crypto_scalarmult(uint8_t *mypublic, uint8_t *secret, uint8_t *basepoint)
{
uint64_t buf0[10U] = { 0U };
uint64_t *x0 = buf0;
uint64_t *z = buf0 + (uint32_t)5U;
uint64_t *q;
Hacl_EC_Format_fexpand(x0, basepoint);
z[0U] = (uint64_t)1U;
q = buf0;
{
uint8_t e[32U] = { 0U };
uint8_t e0;
uint8_t e31;
uint8_t e01;
uint8_t e311;
uint8_t e312;
uint8_t *scalar;
memcpy(e, secret, (uint32_t)32U * sizeof secret[0U]);
e0 = e[0U];
e31 = e[31U];
e01 = e0 & (uint8_t)248U;
e311 = e31 & (uint8_t)127U;
e312 = e311 | (uint8_t)64U;
e[0U] = e01;
e[31U] = e312;
scalar = e;
{
uint64_t buf[15U] = { 0U };
uint64_t *nq = buf;
uint64_t *x = nq;
x[0U] = (uint64_t)1U;
Hacl_EC_Ladder_cmult(nq, scalar, q);
Hacl_EC_Format_scalar_of_point(mypublic, nq);
}
}
}

View File

@ -0,0 +1,186 @@
/*
* ECDH with curve-optimized implementation multiplexing
*
* Copyright 2016-2018 INRIA and Microsoft Corporation
* SPDX-License-Identifier: Apache-2.0
*
* 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.
*
* This file is part of Mbed TLS (https://tls.mbed.org)
*/
#include "common.h"
#if defined(MBEDTLS_ECDH_C) && defined(MBEDTLS_ECDH_VARIANT_EVEREST_ENABLED)
#include <mbedtls/ecdh.h>
#if !(defined(__SIZEOF_INT128__) && (__SIZEOF_INT128__ == 16))
#define KRML_VERIFIED_UINT128
#endif
#include <Hacl_Curve25519.h>
#include <mbedtls/platform_util.h>
#include "x25519.h"
#include <string.h>
/*
* Initialize context
*/
void mbedtls_x25519_init( mbedtls_x25519_context *ctx )
{
mbedtls_platform_zeroize( ctx, sizeof( mbedtls_x25519_context ) );
}
/*
* Free context
*/
void mbedtls_x25519_free( mbedtls_x25519_context *ctx )
{
if( ctx == NULL )
return;
mbedtls_platform_zeroize( ctx->our_secret, MBEDTLS_X25519_KEY_SIZE_BYTES );
mbedtls_platform_zeroize( ctx->peer_point, MBEDTLS_X25519_KEY_SIZE_BYTES );
}
int mbedtls_x25519_make_params( mbedtls_x25519_context *ctx, size_t *olen,
unsigned char *buf, size_t blen,
int( *f_rng )(void *, unsigned char *, size_t),
void *p_rng )
{
int ret = 0;
uint8_t base[MBEDTLS_X25519_KEY_SIZE_BYTES] = {0};
if( ( ret = f_rng( p_rng, ctx->our_secret, MBEDTLS_X25519_KEY_SIZE_BYTES ) ) != 0 )
return ret;
*olen = MBEDTLS_X25519_KEY_SIZE_BYTES + 4;
if( blen < *olen )
return( MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL );
*buf++ = MBEDTLS_ECP_TLS_NAMED_CURVE;
*buf++ = MBEDTLS_ECP_TLS_CURVE25519 >> 8;
*buf++ = MBEDTLS_ECP_TLS_CURVE25519 & 0xFF;
*buf++ = MBEDTLS_X25519_KEY_SIZE_BYTES;
base[0] = 9;
Hacl_Curve25519_crypto_scalarmult( buf, ctx->our_secret, base );
base[0] = 0;
if( memcmp( buf, base, MBEDTLS_X25519_KEY_SIZE_BYTES) == 0 )
return MBEDTLS_ERR_ECP_RANDOM_FAILED;
return( 0 );
}
int mbedtls_x25519_read_params( mbedtls_x25519_context *ctx,
const unsigned char **buf, const unsigned char *end )
{
if( end - *buf < MBEDTLS_X25519_KEY_SIZE_BYTES + 1 )
return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
if( ( *(*buf)++ != MBEDTLS_X25519_KEY_SIZE_BYTES ) )
return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
memcpy( ctx->peer_point, *buf, MBEDTLS_X25519_KEY_SIZE_BYTES );
*buf += MBEDTLS_X25519_KEY_SIZE_BYTES;
return( 0 );
}
int mbedtls_x25519_get_params( mbedtls_x25519_context *ctx, const mbedtls_ecp_keypair *key,
mbedtls_x25519_ecdh_side side )
{
size_t olen = 0;
switch( side ) {
case MBEDTLS_X25519_ECDH_THEIRS:
return mbedtls_ecp_point_write_binary( &key->grp, &key->Q, MBEDTLS_ECP_PF_COMPRESSED, &olen, ctx->peer_point, MBEDTLS_X25519_KEY_SIZE_BYTES );
case MBEDTLS_X25519_ECDH_OURS:
return mbedtls_mpi_write_binary_le( &key->d, ctx->our_secret, MBEDTLS_X25519_KEY_SIZE_BYTES );
default:
return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
}
}
int mbedtls_x25519_calc_secret( mbedtls_x25519_context *ctx, size_t *olen,
unsigned char *buf, size_t blen,
int( *f_rng )(void *, unsigned char *, size_t),
void *p_rng )
{
/* f_rng and p_rng are not used here because this implementation does not
need blinding since it has constant trace. */
(( void )f_rng);
(( void )p_rng);
*olen = MBEDTLS_X25519_KEY_SIZE_BYTES;
if( blen < *olen )
return( MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL );
Hacl_Curve25519_crypto_scalarmult( buf, ctx->our_secret, ctx->peer_point);
/* Wipe the DH secret and don't let the peer chose a small subgroup point */
mbedtls_platform_zeroize( ctx->our_secret, MBEDTLS_X25519_KEY_SIZE_BYTES );
if( memcmp( buf, ctx->our_secret, MBEDTLS_X25519_KEY_SIZE_BYTES) == 0 )
return MBEDTLS_ERR_ECP_RANDOM_FAILED;
return( 0 );
}
int mbedtls_x25519_make_public( mbedtls_x25519_context *ctx, size_t *olen,
unsigned char *buf, size_t blen,
int( *f_rng )(void *, unsigned char *, size_t),
void *p_rng )
{
int ret = 0;
unsigned char base[MBEDTLS_X25519_KEY_SIZE_BYTES] = { 0 };
if( ctx == NULL )
return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
if( ( ret = f_rng( p_rng, ctx->our_secret, MBEDTLS_X25519_KEY_SIZE_BYTES ) ) != 0 )
return ret;
*olen = MBEDTLS_X25519_KEY_SIZE_BYTES + 1;
if( blen < *olen )
return(MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL);
*buf++ = MBEDTLS_X25519_KEY_SIZE_BYTES;
base[0] = 9;
Hacl_Curve25519_crypto_scalarmult( buf, ctx->our_secret, base );
base[0] = 0;
if( memcmp( buf, base, MBEDTLS_X25519_KEY_SIZE_BYTES ) == 0 )
return MBEDTLS_ERR_ECP_RANDOM_FAILED;
return( ret );
}
int mbedtls_x25519_read_public( mbedtls_x25519_context *ctx,
const unsigned char *buf, size_t blen )
{
if( blen < MBEDTLS_X25519_KEY_SIZE_BYTES + 1 )
return(MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL);
if( (*buf++ != MBEDTLS_X25519_KEY_SIZE_BYTES) )
return(MBEDTLS_ERR_ECP_BAD_INPUT_DATA);
memcpy( ctx->peer_point, buf, MBEDTLS_X25519_KEY_SIZE_BYTES );
return( 0 );
}
#endif /* MBEDTLS_ECDH_C && MBEDTLS_ECDH_VARIANT_EVEREST_ENABLED */

View File

@ -0,0 +1,40 @@
set(p256m_target ${MBEDTLS_TARGET_PREFIX}p256m)
add_library(${p256m_target}
p256-m_driver_entrypoints.c
p256-m/p256-m.c)
target_include_directories(${p256m_target}
PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/p256-m>
$<BUILD_INTERFACE:${MBEDTLS_DIR}/include>
$<INSTALL_INTERFACE:include>
PRIVATE ${MBEDTLS_DIR}/library/)
# Pass-through MBEDTLS_CONFIG_FILE and MBEDTLS_USER_CONFIG_FILE
# This must be duplicated from library/CMakeLists.txt because
# p256m is not directly linked against any mbedtls targets
# so does not inherit the compile definitions.
if(MBEDTLS_CONFIG_FILE)
target_compile_definitions(${p256m_target}
PUBLIC MBEDTLS_CONFIG_FILE="${MBEDTLS_CONFIG_FILE}")
endif()
if(MBEDTLS_USER_CONFIG_FILE)
target_compile_definitions(${p256m_target}
PUBLIC MBEDTLS_USER_CONFIG_FILE="${MBEDTLS_USER_CONFIG_FILE}")
endif()
if(INSTALL_MBEDTLS_HEADERS)
install(DIRECTORY :${CMAKE_CURRENT_SOURCE_DIR}
DESTINATION include
FILE_PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ
DIRECTORY_PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE
FILES_MATCHING PATTERN "*.h")
endif(INSTALL_MBEDTLS_HEADERS)
install(TARGETS ${p256m_target}
EXPORT MbedTLSTargets
DESTINATION ${CMAKE_INSTALL_LIBDIR}
PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ)

View File

@ -0,0 +1,5 @@
THIRDPARTY_INCLUDES+=-I$(THIRDPARTY_DIR)/p256-m/p256-m/include -I$(THIRDPARTY_DIR)/p256-m/p256-m/include/p256-m -I$(THIRDPARTY_DIR)/p256-m/p256-m_driver_interface
THIRDPARTY_CRYPTO_OBJECTS+= \
$(THIRDPARTY_DIR)/p256-m//p256-m_driver_entrypoints.o \
$(THIRDPARTY_DIR)/p256-m//p256-m/p256-m.o

View File

@ -0,0 +1,4 @@
The files within the `p256-m/` subdirectory originate from the [p256-m GitHub repository](https://github.com/mpg/p256-m). They are distributed here under a dual Apache-2.0 OR GPL-2.0-or-later license. They are authored by Manuel Pégourié-Gonnard. p256-m is a minimalistic implementation of ECDH and ECDSA on NIST P-256, especially suited to constrained 32-bit environments. Mbed TLS documentation for integrating drivers uses p256-m as an example of a software accelerator, and describes how it can be integrated alongside Mbed TLS. It should be noted that p256-m files in the Mbed TLS repo will not be updated regularly, so they may not have fixes and improvements present in the upstream project.
The files `p256-m.c`, `p256-m.h` and `README.md` have been taken from the `p256-m` repository.
It should be noted that p256-m deliberately does not supply its own cryptographically secure RNG function. As a result, the PSA RNG is used, with `p256_generate_random()` wrapping `psa_generate_random()`.

View File

@ -0,0 +1,544 @@
*This is the original README for the p256-m repository. Please note that as
only a subset of p256-m's files are present in Mbed TLS, this README may refer
to files that are not present/relevant here.*
p256-m is a minimalistic implementation of ECDH and ECDSA on NIST P-256,
especially suited to constrained 32-bit environments. It's written in standard
C, with optional bits of assembly for Arm Cortex-M and Cortex-A CPUs.
Its design is guided by the following goals in this order:
1. correctness & security;
2. low code size & RAM usage;
3. runtime performance.
Most cryptographic implementations care more about speed than footprint, and
some might even risk weakening security for more speed. p256-m was written
because I wanted to see what happened when reversing the usual emphasis.
The result is a full implementation of ECDH and ECDSA in **less than 3KiB of
code**, using **less than 768 bytes of RAM**, with comparable performance
to existing implementations (see below) - in less than 700 LOC.
_Contents of this Readme:_
- [Correctness](#correctness)
- [Security](#security)
- [Code size](#code-size)
- [RAM usage](#ram-usage)
- [Runtime performance](#runtime-performance)
- [Comparison with other implementations](#comparison-with-other-implementations)
- [Design overview](#design-overview)
- [Notes about other curves](#notes-about-other-curves)
- [Notes about other platforms](#notes-about-other-platforms)
## Correctness
**API design:**
- The API is minimal: only 4 public functions.
- Each public function fully validates its inputs and returns specific errors.
- The API uses arrays of octets for all input and output.
**Testing:**
- p256-m is validated against multiple test vectors from various RFCs and
NIST.
- In addition, crafted inputs are used for negative testing and to reach
corner cases.
- Two test suites are provided: one for closed-box testing (using only the
public API), one for open-box testing (for unit-testing internal functions,
and reaching more error cases by exploiting knowledge of how the RNG is used).
- The resulting branch coverage is maximal: closed-box testing reaches all
branches except four; three of them are reached by open-box testing using a
rigged RNG; the last branch could only be reached by computing a discrete log
on P-256... See `coverage.sh`.
- Testing also uses dynamic analysis: valgrind, ASan, MemSan, UBSan.
**Code quality:**
- The code is standard C99; it builds without warnings with `clang
-Weverything` and `gcc -Wall -Wextra -pedantic`.
- The code is small and well documented, including internal APIs: with the
header file, it's less than 700 lines of code, and more lines of comments
than of code.
- However it _has not been reviewed_ independently so far, as this is a
personal project.
**Short Weierstrass pitfalls:**
Its has been [pointed out](https://safecurves.cr.yp.to/) that the NIST curves,
and indeed all Short Weierstrass curves, have a number of pitfalls including
risk for the implementation to:
- "produce incorrect results for some rare curve points" - this is avoided by
carefully checking the validity domain of formulas used throughout the code;
- "leak secret data when the input isn't a curve point" - this is avoided by
validating that points lie on the curve every time a point is deserialized.
## Security
In addition to the above correctness claims, p256-m has the following
properties:
- it has no branch depending (even indirectly) on secret data;
- it has no memory access depending (even indirectly) on secret data.
These properties are checked using valgrind and MemSan with the ideas
behind [ctgrind](https://github.com/agl/ctgrind), see `consttime.sh`.
In addition to avoiding branches and memory accesses depending on secret data,
p256-m also avoid instructions (or library functions) whose execution time
depends on the value of operands on cores of interest. Namely, it never uses
integer division, and for multiplication by default it only uses 16x16->32 bit
unsigned multiplication. On cores which have a constant-time 32x32->64 bit
unsigned multiplication instruction, the symbol `MUL64_IS_CONSTANT_TIME` can
be defined by the user at compile-time to take advantage of it in order to
improve performance and code size. (On Cortex-M and Cortex-A cores wtih GCC or
Clang this is not necessary, since inline assembly is used instead.)
As a result, p256-m should be secure against the following classes of attackers:
1. attackers who can only manipulate the input and observe the output;
2. attackers who can also measure the total computation time of the operation;
3. attackers who can also observe and manipulate micro-architectural features
such as the cache or branch predictor with arbitrary precision.
However, p256-m makes no attempt to protect against:
4. passive physical attackers who can record traces of physical emissions
(power, EM, sound) of the CPU while it manipulates secrets;
5. active physical attackers who can also inject faults in the computation.
(Note: p256-m should actually be secure against SPA, by virtue of being fully
constant-flow, but is not expected to resist any other physical attack.)
**Warning:** p256-m requires an externally-provided RNG function. If that
function is not cryptographically secure, then neither is p256-m's key
generation or ECDSA signature generation.
_Note:_ p256-m also follows best practices such as securely erasing secret
data on the stack before returning.
## Code size
Compiled with
[ARM-GCC 9](https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-rm/downloads),
with `-mthumb -Os`, here are samples of code sizes reached on selected cores:
- Cortex-M0: 2988 bytes
- Cortex-M4: 2900 bytes
- Cortex-A7: 2924 bytes
Clang was also tried but tends to generate larger code (by about 10%). For
details, see `sizes.sh`.
**What's included:**
- Full input validation and (de)serialisation of input/outputs to/from bytes.
- Cleaning up secret values from the stack before returning from a function.
- The code has no dependency on libc functions or the toolchain's runtime
library (such as helpers for long multiply); this can be checked for the
Arm-GCC toolchain with the `deps.sh` script.
**What's excluded:**
- A secure RNG function needs to be provided externally, see
`p256_generate_random()` in `p256-m.h`.
## RAM usage
p256-m doesn't use any dynamic memory (on the heap), only the stack. Here's
how much stack is used by each of its 4 public functions on selected cores:
| Function | Cortex-M0 | Cortex-M4 | Cortex-A7 |
| ------------------------- | --------: | --------: | --------: |
| `p256_gen_keypair` | 608 | 564 | 564 |
| `p256_ecdh_shared_secret` | 640 | 596 | 596 |
| `p256_ecdsa_sign` | 664 | 604 | 604 |
| `p256_ecdsa_verify` | 752 | 700 | 700 |
For details, see `stack.sh`, `wcs.py` and `libc.msu` (the above figures assume
that the externally-provided RNG function uses at most 384 bytes of stack).
## Runtime performance
Here are the timings of each public function in milliseconds measured on
platforms based on a selection of cores:
- Cortex-M0 at 48 MHz: STM32F091 board running Mbed OS 6
- Cortex-M4 at 100 MHz: STM32F411 board running Mbed OS 6
- Cortex-A7 at 900 MHz: Raspberry Pi 2B running Raspbian Buster
| Function | Cortex-M0 | Cortex-M4 | Cortex-A7 |
| ------------------------- | --------: | --------: | --------: |
| `p256_gen_keypair` | 921 | 145 | 11 |
| `p256_ecdh_shared_secret` | 922 | 144 | 11 |
| `p256_ecdsa_sign` | 990 | 155 | 12 |
| `p256_ecdsa_verify` | 1976 | 309 | 24 |
| Sum of the above | 4809 | 753 | 59 |
The sum of these operations corresponds to a TLS handshake using ECDHE-ECDSA
with mutual authentication based on raw public keys or directly-trusted
certificates (otherwise, add one 'verify' for each link in the peer's
certificate chain).
_Note_: the above figures where obtained by compiling with GCC, which is able
to use inline assembly. Without that inline assembly (22 lines for Cortex-M0,
1 line for Cortex-M4), the code would be roughly 2 times slower on those
platforms. (The effect is much less important on the Cortex-A7 core.)
For details, see `bench.sh`, `benchmark.c` and `on-target-benchmark/`.
## Comparison with other implementations
The most relevant/convenient implementation for comparisons is
[TinyCrypt](https://github.com/intel/tinycrypt), as it's also a standalone
implementation of ECDH and ECDSA on P-256 only, that also targets constrained
devices. Other implementations tend to implement many curves and build on a
shared bignum/MPI module (possibly also supporting RSA), which makes fair
comparisons less convenient.
The scripts used for TinyCrypt measurements are available in [this
branch](https://github.com/mpg/tinycrypt/tree/measurements), based on version
0.2.8.
**Code size**
| Core | p256-m | TinyCrypt |
| --------- | -----: | --------: |
| Cortex-M0 | 2988 | 6134 |
| Cortex-M4 | 2900 | 5934 |
| Cortex-A7 | 2924 | 5934 |
**RAM usage**
TinyCrypto also uses no heap, only the stack. Here's the RAM used by each
operation on a Cortex-M0 core:
| operation | p256-m | TinyCrypt |
| ------------------ | -----: | --------: |
| key generation | 608 | 824 |
| ECDH shared secret | 640 | 728 |
| ECDSA sign | 664 | 880 |
| ECDSA verify | 752 | 824 |
On a Cortex-M4 or Cortex-A7 core (identical numbers):
| operation | p256-m | TinyCrypt |
| ------------------ | -----: | --------: |
| key generation | 564 | 796 |
| ECDH shared secret | 596 | 700 |
| ECDSA sign | 604 | 844 |
| ECDSA verify | 700 | 808 |
**Runtime performance**
Here are the timings of each operation in milliseconds measured on
platforms based on a selection of cores:
_Cortex-M0_ at 48 MHz: STM32F091 board running Mbed OS 6
| Operation | p256-m | TinyCrypt |
| ------------------ | -----: | --------: |
| Key generation | 921 | 979 |
| ECDH shared secret | 922 | 975 |
| ECDSA sign | 990 | 1009 |
| ECDSA verify | 1976 | 1130 |
| Sum of those 4 | 4809 | 4093 |
_Cortex-M4_ at 100 MHz: STM32F411 board running Mbed OS 6
| Operation | p256-m | TinyCrypt |
| ------------------ | -----: | --------: |
| Key generation | 145 | 178 |
| ECDH shared secret | 144 | 177 |
| ECDSA sign | 155 | 188 |
| ECDSA verify | 309 | 210 |
| Sum of those 4 | 753 | 753 |
_Cortex-A7_ at 900 MHz: Raspberry Pi 2B running Raspbian Buster
| Operation | p256-m | TinyCrypt |
| ------------------ | -----: | --------: |
| Key generation | 11 | 13 |
| ECDH shared secret | 11 | 13 |
| ECDSA sign | 12 | 14 |
| ECDSA verify | 24 | 15 |
| Sum of those 4 | 59 | 55 |
_64-bit Intel_ (i7-6500U at 2.50GHz) laptop running Ubuntu 20.04
Note: results in microseconds (previous benchmarks in milliseconds)
| Operation | p256-m | TinyCrypt |
| ------------------ | -----: | --------: |
| Key generation | 1060 | 1627 |
| ECDH shared secret | 1060 | 1611 |
| ECDSA sign | 1136 | 1712 |
| ECDSA verify | 2279 | 1888 |
| Sum of those 4 | 5535 | 6838 |
**Other differences**
- While p256-m fully validates all inputs, Tinycrypt's ECDH shared secret
function doesn't include validation of the peer's public key, which should be
done separately by the user for static ECDH (there are attacks [when users
forget](https://link.springer.com/chapter/10.1007/978-3-319-24174-6_21)).
- The two implementations have slightly different security characteristics:
p256-m is fully constant-time from the ground up so should be more robust
than TinyCrypt against powerful local attackers (such as an untrusted OS
attacking a secure enclave); on the other hand TinyCrypt includes coordinate
randomisation which protects against some passive physical attacks (such as
DPA, see Table 3, column C9 of [this
paper](https://www.esat.kuleuven.be/cosic/publications/article-2293.pdf#page=12)),
which p256-m completely ignores.
- TinyCrypt's code looks like it could easily be expanded to support other
curves, while p256-m has much more hard-coded to minimize code size (see
"Notes about other curves" below).
- TinyCrypt uses a specialised routine for reduction modulo the curve prime,
exploiting its structure as a Solinas prime, which should be faster than the
generic Montgomery reduction used by p256-m, but other factors appear to
compensate for that.
- TinyCrypt uses Co-Z Jacobian formulas for point operation, which should be
faster (though a bit larger) than the mixed affine-Jacobian formulas
used by p256-m, but again other factors appear to compensate for that.
- p256-m uses bits of inline assembly for 64-bit multiplication on the
platforms used for benchmarking, while TinyCrypt uses only C (and the
compiler's runtime library).
- TinyCrypt uses a specialised routine based on Shamir's trick for
ECDSA verification, which gives much better performance than the generic
code that p256-m uses in order to minimize code size.
## Design overview
The implementation is contained in a single file to keep most functions static
and allow for more optimisations. It is organized in multiple layers:
- Fixed-width multi-precision arithmetic
- Fixed-width modular arithmetic
- Operations on curve points
- Operations with scalars
- The public API
**Multi-precision arithmetic.**
Large integers are represented as arrays of `uint32_t` limbs. When carries may
occur, casts to `uint64_t` are used to nudge the compiler towards using the
CPU's carry flag. When overflow may occur, functions return a carry flag.
This layer contains optional assembly for Cortex-M and Cortex-A cores, for the
internal `u32_muladd64()` function, as well as two pure C versions of this
function, depending on whether `MUL64_IS_CONSTANT_TIME`.
This layer's API consists of:
- addition, subtraction;
- multiply-and-add, shift by one limb (for Montgomery multiplication);
- conditional assignment, assignment of a small value;
- comparison of two values for equality, comparison to 0 for equality;
- (de)serialization as big-endian arrays of bytes.
**Modular arithmetic.**
All modular operations are done in the Montgomery domain, that is x is
represented by `x * 2^256 mod m`; integers need to be converted to that domain
before computations, and back from it afterwards. Montgomery constants
associated to the curve's p and n are pre-computed and stored in static
structures.
Modular inversion is computed using Fermat's little theorem to get
constant-time behaviour with respect to the value being inverted.
This layer's API consists of:
- the curve's constants p and n (and associated Montgomery constants);
- modular addition, subtraction, multiplication, and inversion;
- assignment of a small value;
- conversion to/from Montgomery domain;
- (de)serialization to/from bytes with integrated range checking and
Montgomery domain conversion.
**Operations on curve points.**
Curve points are represented using either affine or Jacobian coordinates;
affine coordinates are extended to represent 0 as (0,0). Individual
coordinates are always in the Montgomery domain.
Not all formulas associated with affine or Jacobian coordinates are complete;
great care is taken to document and satisfy each function's pre-conditions.
This layer's API consists of:
- curve constants: b from the equation, the base point's coordinates;
- point validity check (on the curve and not 0);
- Jacobian to affine coordinate conversion;
- point doubling in Jacobian coordinates (complete formulas);
- point addition in mixed affine-Jacobian coordinates (P not in {0, Q, -Q});
- point addition-or-doubling in affine coordinates (leaky version, only used
for ECDSA verify where all data is public);
- (de)serialization to/from bytes with integrated validity checking
**Scalar operations.**
The crucial function here is scalar multiplication. It uses a signed binary
ladder, which is a variant of the good old double-and-add algorithm where an
addition/subtraction is performed at each step. Again, care is taken to make
sure the pre-conditions for the addition formulas are always satisfied. The
signed binary ladder only works if the scalar is odd; this is ensured by
negating both the scalar (mod n) and the input point if necessary.
This layer's API consists of:
- scalar multiplication
- de-serialization from bytes with integrated range checking
- generation of a scalar and its associated public key
**Public API.**
This layer builds on the others, but unlike them, all inputs and outputs are
byte arrays. Key generation and ECDH shared secret computation are thin
wrappers around internal functions, just taking care of format conversions and
errors. The ECDSA functions have more non-trivial logic.
This layer's API consists of:
- key-pair generation
- ECDH shared secret computation
- ECDSA signature creation
- ECDSA signature verification
**Testing.**
A self-contained, straightforward, pure-Python implementation was first
produced as a warm-up and to help check intermediate values. Test vectors from
various sources are embedded and used to validate the implementation.
This implementation, `p256.py`, is used by a second Python script,
`gen-test-data.py`, to generate additional data for both positive and negative
testing, available from a C header file, that is then used by the closed-box
and open-box test programs.
p256-m can be compiled with extra instrumentation to mark secret data and
allow either valgrind or MemSan to check that no branch or memory access
depends on it (even indirectly). Macros are defined for this purpose near the
top of the file.
**Tested platforms.**
There are 4 versions of the internal function `u32_muladd64`: two assembly
versions, for Cortex-M/A cores with or without the DSP extension, and two
pure-C versions, depending on whether `MUL64_IS_CONSTANT_TIME`.
Tests are run on the following platforms:
- `make` on x64 tests the pure-C version without `MUL64_IS_CONSTANT_TIME`
(with Clang).
- `./consttime.sh` on x64 tests both pure-C versions (with Clang).
- `make` on Arm v7-A (Raspberry Pi 2) tests the Arm-DSP assembly version (with
Clang).
- `on-target-*box` on boards based on Cortex-M0 and M4 cores test both
assembly versions (with GCC).
In addition:
- `sizes.sh` builds the code for three Arm cores with GCC and Clang.
- `deps.sh` checks for external dependencies with GCC.
## Notes about other curves
It should be clear that minimal code size can only be reached by specializing
the implementation to the curve at hand. Here's a list of things in the
implementation that are specific to the NIST P-256 curve, and how the
implementation could be changed to expand to other curves, layer by layer (see
"Design Overview" above).
**Fixed-width multi-precision arithmetic:**
- The number of limbs is hard-coded to 8. For other 256-bit curves, nothing to
change. For a curve of another size, hard-code to another value. For multiple
curves of various sizes, add a parameter to each function specifying the
number of limbs; when declaring arrays, always use the maximum number of
limbs.
**Fixed-width modular arithmetic:**
- The values of the curve's constant p and n, and their associated Montgomery
constants, are hard-coded. For another curve, just hard-code the new constants.
For multiple other curves, define all the constants, and from this layer's API
only keep the functions that already accept a `mod` parameter (that is, remove
convenience functions `m256_xxx_p()`).
- The number of limbs is again hard-coded to 8. See above, but it order to
support multiple sizes there is no need to add a new parameter to functions
in this layer: the existing `mod` parameter can include the number of limbs as
well.
**Operations on curve points:**
- The values of the curve's constants b (constant term from the equation) and
gx, gy (coordinates of the base point) are hard-coded. For another curve,
hard-code the other values. For multiple curves, define each curve's value and
add a "curve id" parameter to all functions in this layer.
- The value of the curve's constant a is implicitly hard-coded to `-3` by using
a standard optimisation to save one multiplication in the first step of
`point_double()`. For curves that don't have a == -3, replace that with the
normal computation.
- The fact that b != 0 in the curve equation is used indirectly, to ensure
that (0, 0) is not a point on the curve and re-use that value to represent
the point 0. As far as I know, all Short Weierstrass curves standardized so
far have b != 0.
- The shape of the curve is assumed to be Short Weierstrass. For other curve
shapes (Montgomery, (twisted) Edwards), this layer would probably look very
different (both implementation and API).
**Scalar operations:**
- If multiple curves are to be supported, all function in this layer need to
gain a new "curve id" parameter.
- This layer assumes that the bit size of the curve's order n is the same as
that of the modulus p. This is true of most curves standardized so far, the
only exception being secp224k1. If that curve were to be supported, the
representation of `n` and scalars would need adapting to allow for an extra
limb.
- The bit size of the curve's order is hard-coded in `scalar_mult()`. For
multiple curves, this should be deduced from the "curve id" parameter.
- The `scalar_mult()` function exploits the fact that the second least
significant bit of the curve's order n is set in order to avoid a special
case. For curve orders that don't meet this criterion, we can just handle that
special case (multiplication by +-2) separately (always compute that and
conditionally assign it to the result).
- The shape of the curve is again assumed to be Short Weierstrass. For other curve
shapes (Montgomery, (twisted) Edwards), this layer would probably have a
very different implementation.
**Public API:**
- For multiple curves, all functions in this layer would need to gain a "curve
id" parameter and handle variable-sized input/output.
- The shape of the curve is again assumed to be Short Weierstrass. For other curve
shapes (Montgomery, (twisted) Edwards), the ECDH API would probably look
quite similar (with differences in the size of public keys), but the ECDSA API
wouldn't apply and an EdDSA API would look pretty different.
## Notes about other platforms
While p256-m is standard C99, it is written with constrained 32-bit platforms
in mind and makes a few assumptions about the platform:
- The types `uint8_t`, `uint16_t`, `uint32_t` and `uint64_t` exist.
- 32-bit unsigned addition and subtraction with carry are constant time.
- 16x16->32-bit unsigned multiplication is available and constant time.
Also, on platforms on which 64-bit addition and subtraction with carry, or
even 64x64->128-bit multiplication, are available, p256-m makes no use of
them, though they could significantly improve performance.
This could be improved by replacing uses of arrays of `uint32_t` with a
defined type throughout the internal APIs, and then on 64-bit platforms define
that type to be an array of `uint64_t` instead, and making the obvious
adaptations in the multi-precision arithmetic layer.
Finally, the optional assembly code (which boosts performance by a factor 2 on
tested Cortex-M CPUs, while slightly reducing code size and stack usage) is
currently only available with compilers that support GCC's extended asm
syntax (which includes GCC and Clang).

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,135 @@
/*
* Interface of curve P-256 (ECDH and ECDSA)
*
* Copyright The Mbed TLS Contributors
* Author: Manuel Pégourié-Gonnard.
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
*/
#ifndef P256_M_H
#define P256_M_H
#include <stdint.h>
#include <stddef.h>
/* Status codes */
#define P256_SUCCESS 0
#define P256_RANDOM_FAILED -1
#define P256_INVALID_PUBKEY -2
#define P256_INVALID_PRIVKEY -3
#define P256_INVALID_SIGNATURE -4
#ifdef __cplusplus
extern "C" {
#endif
/*
* RNG function - must be provided externally and be cryptographically secure.
*
* in: output - must point to a writable buffer of at least output_size bytes.
* output_size - the number of random bytes to write to output.
* out: output is filled with output_size random bytes.
* return 0 on success, non-zero on errors.
*/
extern int p256_generate_random(uint8_t * output, unsigned output_size);
/*
* ECDH/ECDSA generate key pair
*
* [in] draws from p256_generate_random()
* [out] priv: on success, holds the private key, as a big-endian integer
* [out] pub: on success, holds the public key, as two big-endian integers
*
* return: P256_SUCCESS on success
* P256_RANDOM_FAILED on failure
*/
int p256_gen_keypair(uint8_t priv[32], uint8_t pub[64]);
/*
* ECDH compute shared secret
*
* [out] secret: on success, holds the shared secret, as a big-endian integer
* [in] priv: our private key as a big-endian integer
* [in] pub: the peer's public key, as two big-endian integers
*
* return: P256_SUCCESS on success
* P256_INVALID_PRIVKEY if priv is invalid
* P256_INVALID_PUBKEY if pub is invalid
*/
int p256_ecdh_shared_secret(uint8_t secret[32],
const uint8_t priv[32], const uint8_t pub[64]);
/*
* ECDSA sign
*
* [in] draws from p256_generate_random()
* [out] sig: on success, holds the signature, as two big-endian integers
* [in] priv: our private key as a big-endian integer
* [in] hash: the hash of the message to be signed
* [in] hlen: the size of hash in bytes
*
* return: P256_SUCCESS on success
* P256_RANDOM_FAILED on failure
* P256_INVALID_PRIVKEY if priv is invalid
*/
int p256_ecdsa_sign(uint8_t sig[64], const uint8_t priv[32],
const uint8_t *hash, size_t hlen);
/*
* ECDSA verify
*
* [in] sig: the signature to be verified, as two big-endian integers
* [in] pub: the associated public key, as two big-endian integers
* [in] hash: the hash of the message that was signed
* [in] hlen: the size of hash in bytes
*
* return: P256_SUCCESS on success - the signature was verified as valid
* P256_INVALID_PUBKEY if pub is invalid
* P256_INVALID_SIGNATURE if the signature was found to be invalid
*/
int p256_ecdsa_verify(const uint8_t sig[64], const uint8_t pub[64],
const uint8_t *hash, size_t hlen);
/*
* Public key validation
*
* Note: you never need to call this function, as all other functions always
* validate their input; however it's availabe if you want to validate the key
* without performing an operation.
*
* [in] pub: the public key, as two big-endian integers
*
* return: P256_SUCCESS if the key is valid
* P256_INVALID_PUBKEY if pub is invalid
*/
int p256_validate_pubkey(const uint8_t pub[64]);
/*
* Private key validation
*
* Note: you never need to call this function, as all other functions always
* validate their input; however it's availabe if you want to validate the key
* without performing an operation.
*
* [in] priv: the private key, as a big-endian integer
*
* return: P256_SUCCESS if the key is valid
* P256_INVALID_PRIVKEY if priv is invalid
*/
int p256_validate_privkey(const uint8_t priv[32]);
/*
* Compute public key from private key
*
* [out] pub: the associated public key, as two big-endian integers
* [in] priv: the private key, as a big-endian integer
*
* return: P256_SUCCESS on success
* P256_INVALID_PRIVKEY if priv is invalid
*/
int p256_public_from_private(uint8_t pub[64], const uint8_t priv[32]);
#ifdef __cplusplus
}
#endif
#endif /* P256_M_H */

View File

@ -0,0 +1,312 @@
/*
* Driver entry points for p256-m
*/
/*
* Copyright The Mbed TLS Contributors
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
*/
#include "mbedtls/platform.h"
#include "p256-m_driver_entrypoints.h"
#include "p256-m/p256-m.h"
#include "psa/crypto.h"
#include <stddef.h>
#include <string.h>
#include "psa_crypto_driver_wrappers_no_static.h"
#if defined(MBEDTLS_PSA_P256M_DRIVER_ENABLED)
/* INFORMATION ON PSA KEY EXPORT FORMATS:
*
* PSA exports SECP256R1 keys in two formats:
* 1. Keypair format: 32 byte string which is just the private key (public key
* can be calculated from the private key)
* 2. Public Key format: A leading byte 0x04 (indicating uncompressed format),
* followed by the 64 byte public key. This results in a
* total of 65 bytes.
*
* p256-m's internal format for private keys matches PSA. Its format for public
* keys is only 64 bytes: the same as PSA but without the leading byte (0x04).
* Hence, when passing public keys from PSA to p256-m, the leading byte is
* removed.
*
* Shared secret and signature have the same format between PSA and p256-m.
*/
#define PSA_PUBKEY_SIZE 65
#define PSA_PUBKEY_HEADER_BYTE 0x04
#define P256_PUBKEY_SIZE 64
#define PRIVKEY_SIZE 32
#define SHARED_SECRET_SIZE 32
#define SIGNATURE_SIZE 64
#define CURVE_BITS 256
/* Convert between p256-m and PSA error codes */
static psa_status_t p256_to_psa_error(int ret)
{
switch (ret) {
case P256_SUCCESS:
return PSA_SUCCESS;
case P256_INVALID_PUBKEY:
case P256_INVALID_PRIVKEY:
return PSA_ERROR_INVALID_ARGUMENT;
case P256_INVALID_SIGNATURE:
return PSA_ERROR_INVALID_SIGNATURE;
case P256_RANDOM_FAILED:
default:
return PSA_ERROR_GENERIC_ERROR;
}
}
psa_status_t p256_transparent_import_key(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)
{
/* Check the key size */
if (*bits != 0 && *bits != CURVE_BITS) {
return PSA_ERROR_NOT_SUPPORTED;
}
/* Validate the key (and its type and size) */
psa_key_type_t type = psa_get_key_type(attributes);
if (type == PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1)) {
if (data_length != PSA_PUBKEY_SIZE) {
return *bits == 0 ? PSA_ERROR_NOT_SUPPORTED : PSA_ERROR_INVALID_ARGUMENT;
}
/* See INFORMATION ON PSA KEY EXPORT FORMATS near top of file */
if (p256_validate_pubkey(data + 1) != P256_SUCCESS) {
return PSA_ERROR_INVALID_ARGUMENT;
}
} else if (type == PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1)) {
if (data_length != PRIVKEY_SIZE) {
return *bits == 0 ? PSA_ERROR_NOT_SUPPORTED : PSA_ERROR_INVALID_ARGUMENT;
}
if (p256_validate_privkey(data) != P256_SUCCESS) {
return PSA_ERROR_INVALID_ARGUMENT;
}
} else {
return PSA_ERROR_NOT_SUPPORTED;
}
*bits = CURVE_BITS;
/* We only support the export format for input, so just copy. */
if (key_buffer_size < data_length) {
return PSA_ERROR_BUFFER_TOO_SMALL;
}
memcpy(key_buffer, data, data_length);
*key_buffer_length = data_length;
return PSA_SUCCESS;
}
psa_status_t p256_transparent_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)
{
/* Is this the right curve? */
size_t bits = psa_get_key_bits(attributes);
psa_key_type_t type = psa_get_key_type(attributes);
if (bits != CURVE_BITS || type != PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1)) {
return PSA_ERROR_NOT_SUPPORTED;
}
/* Validate sizes, as p256-m expects fixed-size buffers */
if (key_buffer_size != PRIVKEY_SIZE) {
return PSA_ERROR_INVALID_ARGUMENT;
}
if (data_size < PSA_PUBKEY_SIZE) {
return PSA_ERROR_BUFFER_TOO_SMALL;
}
/* See INFORMATION ON PSA KEY EXPORT FORMATS near top of file */
data[0] = PSA_PUBKEY_HEADER_BYTE;
int ret = p256_public_from_private(data + 1, key_buffer);
if (ret == P256_SUCCESS) {
*data_length = PSA_PUBKEY_SIZE;
}
return p256_to_psa_error(ret);
}
psa_status_t p256_transparent_generate_key(
const psa_key_attributes_t *attributes,
uint8_t *key_buffer,
size_t key_buffer_size,
size_t *key_buffer_length)
{
/* We don't use this argument, but the specification mandates the signature
* of driver entry-points. (void) used to avoid compiler warning. */
(void) attributes;
/* Validate sizes, as p256-m expects fixed-size buffers */
if (key_buffer_size != PRIVKEY_SIZE) {
return PSA_ERROR_BUFFER_TOO_SMALL;
}
/*
* p256-m's keypair generation function outputs both public and private
* keys. Allocate a buffer to which the public key will be written. The
* private key will be written to key_buffer, which is passed to this
* function as an argument. */
uint8_t public_key_buffer[P256_PUBKEY_SIZE];
int ret = p256_gen_keypair(key_buffer, public_key_buffer);
if (ret == P256_SUCCESS) {
*key_buffer_length = PRIVKEY_SIZE;
}
return p256_to_psa_error(ret);
}
psa_status_t p256_transparent_key_agreement(
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)
{
/* We don't use these arguments, but the specification mandates the
* sginature of driver entry-points. (void) used to avoid compiler
* warning. */
(void) attributes;
(void) alg;
/* Validate sizes, as p256-m expects fixed-size buffers */
if (key_buffer_size != PRIVKEY_SIZE || peer_key_length != PSA_PUBKEY_SIZE) {
return PSA_ERROR_INVALID_ARGUMENT;
}
if (shared_secret_size < SHARED_SECRET_SIZE) {
return PSA_ERROR_BUFFER_TOO_SMALL;
}
/* See INFORMATION ON PSA KEY EXPORT FORMATS near top of file */
const uint8_t *peer_key_p256m = peer_key + 1;
int ret = p256_ecdh_shared_secret(shared_secret, key_buffer, peer_key_p256m);
if (ret == P256_SUCCESS) {
*shared_secret_length = SHARED_SECRET_SIZE;
}
return p256_to_psa_error(ret);
}
psa_status_t p256_transparent_sign_hash(
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)
{
/* We don't use these arguments, but the specification mandates the
* sginature of driver entry-points. (void) used to avoid compiler
* warning. */
(void) attributes;
(void) alg;
/* Validate sizes, as p256-m expects fixed-size buffers */
if (key_buffer_size != PRIVKEY_SIZE) {
return PSA_ERROR_INVALID_ARGUMENT;
}
if (signature_size < SIGNATURE_SIZE) {
return PSA_ERROR_BUFFER_TOO_SMALL;
}
int ret = p256_ecdsa_sign(signature, key_buffer, hash, hash_length);
if (ret == P256_SUCCESS) {
*signature_length = SIGNATURE_SIZE;
}
return p256_to_psa_error(ret);
}
/* This function expects the key buffer to contain a PSA public key,
* as exported by psa_export_public_key() */
static psa_status_t p256_verify_hash_with_public_key(
const uint8_t *key_buffer,
size_t key_buffer_size,
const uint8_t *hash,
size_t hash_length,
const uint8_t *signature,
size_t signature_length)
{
/* Validate sizes, as p256-m expects fixed-size buffers */
if (key_buffer_size != PSA_PUBKEY_SIZE || *key_buffer != PSA_PUBKEY_HEADER_BYTE) {
return PSA_ERROR_INVALID_ARGUMENT;
}
if (signature_length != SIGNATURE_SIZE) {
return PSA_ERROR_INVALID_SIGNATURE;
}
/* See INFORMATION ON PSA KEY EXPORT FORMATS near top of file */
const uint8_t *public_key_p256m = key_buffer + 1;
int ret = p256_ecdsa_verify(signature, public_key_p256m, hash, hash_length);
return p256_to_psa_error(ret);
}
psa_status_t p256_transparent_verify_hash(
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)
{
/* We don't use this argument, but the specification mandates the signature
* of driver entry-points. (void) used to avoid compiler warning. */
(void) alg;
psa_status_t status;
uint8_t public_key_buffer[PSA_PUBKEY_SIZE];
size_t public_key_buffer_size = PSA_PUBKEY_SIZE;
size_t public_key_length = PSA_PUBKEY_SIZE;
/* As p256-m doesn't require dynamic allocation, we want to avoid it in
* the entrypoint functions as well. psa_driver_wrapper_export_public_key()
* requires size_t*, so we use a pointer to a stack variable. */
size_t *public_key_length_ptr = &public_key_length;
/* The contents of key_buffer may either be the 32 byte private key
* (keypair format), or 0x04 followed by the 64 byte public key (public
* key format). To ensure the key is in the latter format, the public key
* is exported. */
status = psa_driver_wrapper_export_public_key(
attributes,
key_buffer,
key_buffer_size,
public_key_buffer,
public_key_buffer_size,
public_key_length_ptr);
if (status != PSA_SUCCESS) {
goto exit;
}
status = p256_verify_hash_with_public_key(
public_key_buffer,
public_key_buffer_size,
hash,
hash_length,
signature,
signature_length);
exit:
return status;
}
#endif /* MBEDTLS_PSA_P256M_DRIVER_ENABLED */

View File

@ -0,0 +1,219 @@
/*
* Driver entry points for p256-m
*/
/*
* Copyright The Mbed TLS Contributors
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
*/
#ifndef P256M_DRIVER_ENTRYPOINTS_H
#define P256M_DRIVER_ENTRYPOINTS_H
#if defined(MBEDTLS_PSA_P256M_DRIVER_ENABLED)
#ifndef PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT
#define PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT
#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */
#endif /* MBEDTLS_PSA_P256M_DRIVER_ENABLED */
#include "psa/crypto_types.h"
/** Import SECP256R1 key.
*
* \param[in] attributes The attributes of the key to use for the
* operation.
* \param[in] data The raw key material. For private keys
* this must be a big-endian integer of 32
* bytes; for public key this must be an
* uncompressed ECPoint (65 bytes).
* \param[in] data_length The size of the raw key material.
* \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.
* \param[out] key_buffer_length The length of the data written in \p
* key_buffer in bytes.
* \param[out] bits The bitsize of the key.
*
* \retval #PSA_SUCCESS
* Success. Keypair generated and stored in buffer.
* \retval #PSA_ERROR_NOT_SUPPORTED
* The input is not supported by this driver (not SECP256R1).
* \retval #PSA_ERROR_INVALID_ARGUMENT
* The input is invalid.
* \retval #PSA_ERROR_BUFFER_TOO_SMALL
* \p key_buffer_size is too small.
*/
psa_status_t p256_transparent_import_key(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 SECP256R1 public key, from the private key.
*
* \param[in] attributes The attributes of the key to use for the
* operation.
* \param[in] key_buffer The private key in the export format.
* \param[in] key_buffer_size The size of the private key in bytes.
* \param[out] data The buffer to contain the public key in
* the export format upon successful return.
* \param[in] data_size The size of the \p data buffer in bytes.
* \param[out] data_length The length written to \p data in bytes.
*
* \retval #PSA_SUCCESS
* Success. Keypair generated and stored in buffer.
* \retval #PSA_ERROR_NOT_SUPPORTED
* The input is not supported by this driver (not SECP256R1).
* \retval #PSA_ERROR_INVALID_ARGUMENT
* The input is invalid.
* \retval #PSA_ERROR_BUFFER_TOO_SMALL
* \p key_buffer_size is too small.
*/
psa_status_t p256_transparent_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);
/** Generate SECP256R1 ECC Key Pair.
* Interface function which calls the p256-m key generation function and
* places it in the key buffer provided by the caller (Mbed TLS) in the
* correct format. For a SECP256R1 curve this is the 32 bit private key.
*
* \param[in] attributes The attributes of the key to use for the
* operation.
* \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.
* \param[out] key_buffer_length The length of the data written in \p
* key_buffer in bytes.
*
* \retval #PSA_SUCCESS
* Success. Keypair generated and stored in buffer.
* \retval #PSA_ERROR_BUFFER_TOO_SMALL
* \p key_buffer_size is too small.
* \retval #PSA_ERROR_GENERIC_ERROR
* The internal RNG failed.
*/
psa_status_t p256_transparent_generate_key(
const psa_key_attributes_t *attributes,
uint8_t *key_buffer,
size_t key_buffer_size,
size_t *key_buffer_length);
/** Perform raw key agreement using p256-m's ECDH implementation
* \param[in] attributes The attributes of the key to use for the
* operation.
* \param[in] key_buffer The buffer containing the private key
* in the format specified by PSA.
* \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 peer's public
* key in format specified by PSA.
* \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_ARGUMENT
* The input is invalid.
* \retval #PSA_ERROR_BUFFER_TOO_SMALL
* \p shared_secret_size is too small.
*/
psa_status_t p256_transparent_key_agreement(
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);
/** Sign an already-calculated hash with a private key using p256-m's ECDSA
* implementation
* \param[in] attributes The attributes of the key to use for the
* operation.
* \param[in] key_buffer The buffer containing the private key
* in the format specified by PSA.
* \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 to sign.
* \param[in] hash_length Size of the \p hash buffer in bytes.
* \param[out] signature Buffer where 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
* Success. Hash was signed successfully.
* \retval #PSA_ERROR_INVALID_ARGUMENT
* The input is invalid.
* \retval #PSA_ERROR_BUFFER_TOO_SMALL
* \p signature_size is too small.
* \retval #PSA_ERROR_GENERIC_ERROR
* The internal RNG failed.
*/
psa_status_t p256_transparent_sign_hash(
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);
/** Verify the signature of a hash using a SECP256R1 public key using p256-m's
* ECDSA implementation.
*
* \note p256-m expects a 64 byte public key, but the contents of the key
buffer may be the 32 byte keypair representation or the 65 byte
public key representation. As a result, this function calls
psa_driver_wrapper_export_public_key() to ensure the public key
can be passed to p256-m.
*
* \param[in] attributes The attributes of the key to use for the
* operation.
*
* \param[in] key_buffer The buffer containing the key
* in the format specified by PSA.
* \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[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_INVALID_ARGUMENT
* The input is invalid.
*/
psa_status_t p256_transparent_verify_hash(
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);
#endif /* P256M_DRIVER_ENTRYPOINTS_H */

115
lib/mbedtls/external/mbedtls/BRANCHES.md vendored Normal file
View File

@ -0,0 +1,115 @@
# Maintained branches
At any point in time, we have a number of maintained branches, currently consisting of:
- The [`main`](https://github.com/Mbed-TLS/mbedtls/tree/main) branch:
this always contains the latest release, including all publicly available
security fixes.
- The [`development`](https://github.com/Mbed-TLS/mbedtls/tree/development) branch:
this is where the next major version of Mbed TLS (version 4.0) is being
prepared. It has API changes that make it incompatible with Mbed TLS 3.x,
as well as all the new features and bug fixes and security fixes.
- One or more long-time support (LTS) branches: these only get bug fixes and
security fixes. Currently, the supported LTS branches are:
- [`mbedtls-2.28`](https://github.com/Mbed-TLS/mbedtls/tree/mbedtls-2.28).
- [`mbedtls-3.6`](https://github.com/Mbed-TLS/mbedtls/tree/mbedtls-3.6).
We retain a number of historical branches, whose names are prefixed by `archive/`,
such as [`archive/mbedtls-2.7`](https://github.com/Mbed-TLS/mbedtls/tree/archive/mbedtls-2.7).
These branches will not receive any changes or updates.
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 3.(x+1) is backward compatible with 3.x). We only break API
compatibility on major version changes (e.g. from 3.x to 4.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. On this basis, 3.6 LTS (released March 2024) will be
supported until March 2027. The next LTS release will be a 4.x release, which is
planned for September 2025.
## Backwards Compatibility for application code
We maintain API compatibility in released versions of Mbed TLS. If you have
code that's working and secure with Mbed TLS 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 (`mbedtls/mbedtls_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 Mbed TLS may extend the API. Here are some
examples of changes that are common in minor releases of Mbed TLS, 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 Mbed TLS (for example, all Mbed TLS 3.y versions will be able to read
keys written under any Mbed TLS 3.x with x <= y).
Mbed TLS 3.x can also read keys written by Mbed TLS 2.25.0 through 2.28.x
LTS, but future major version upgrades (for example from 2.28.x/3.x to 4.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/mbedtls/tree/main)
- [`development`](https://github.com/Mbed-TLS/mbedtls/)
- [`mbedtls-3.6`](https://github.com/Mbed-TLS/mbedtls/tree/mbedtls-3.6)
maintained until March 2027, see
<https://github.com/Mbed-TLS/mbedtls/releases/tag/v3.6.0>.
- [`mbedtls-2.28`](https://github.com/Mbed-TLS/mbedtls/tree/mbedtls-2.28)
maintained until the end of 2024, see
<https://github.com/Mbed-TLS/mbedtls/releases/tag/v2.28.8>.
Users are urged to always use the latest version of a maintained branch.

20
lib/mbedtls/external/mbedtls/BUGS.md vendored Normal file
View File

@ -0,0 +1,20 @@
## Known issues
Known issues in Mbed TLS are [tracked on GitHub](https://github.com/Mbed-TLS/mbedtls/issues).
## Reporting a bug
If you think you've found a bug in Mbed TLS, 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/mbedtls/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 on GitHub](https://github.com/Mbed-TLS/mbedtls/issues).
Please do not use GitHub for support questions. If you want to know
how to do something with Mbed TLS, please see [`SUPPORT.md`](SUPPORT.md) for available documentation and support channels.

View File

@ -0,0 +1,429 @@
#
# 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.
# - MBEDTLS_TARGET_PREFIX: CMake targets are designed to be alterable by calling
# CMake in order to avoid target name clashes, via the use of
# MBEDTLS_TARGET_PREFIX. The value of this variable is prefixed to the
# mbedtls, mbedx509, mbedcrypto and apidoc targets.
#
# We specify a minimum requirement of 3.10.2, but for now use 3.5.1 here
# until our infrastructure catches up.
cmake_minimum_required(VERSION 3.5.1)
include(CMakePackageConfigHelpers)
# 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)
if(TEST_CPP)
project("Mbed TLS"
LANGUAGES C CXX
VERSION 3.6.0
)
else()
project("Mbed TLS"
LANGUAGES C
VERSION 3.6.0
)
endif()
include(GNUInstallDirs)
# Determine if Mbed TLS is being built as a subproject using add_subdirectory()
if(NOT DEFINED MBEDTLS_AS_SUBPROJECT)
set(MBEDTLS_AS_SUBPROJECT ON)
if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
set(MBEDTLS_AS_SUBPROJECT OFF)
endif()
endif()
# Set the project root directory.
set(MBEDTLS_DIR ${CMAKE_CURRENT_SOURCE_DIR})
option(ENABLE_PROGRAMS "Build Mbed TLS programs." ON)
option(UNSAFE_BUILD "Allow unsafe builds. These builds ARE NOT SECURE." OFF)
option(MBEDTLS_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" OFF)
endif()
option(DISABLE_PACKAGE_CONFIG_AND_INSTALL "Disable package configuration, target export and installation" ${MBEDTLS_AS_SUBPROJECT})
string(REGEX MATCH "Clang" CMAKE_COMPILER_IS_CLANG "${CMAKE_C_COMPILER_ID}")
string(REGEX MATCH "GNU" CMAKE_COMPILER_IS_GNU "${CMAKE_C_COMPILER_ID}")
string(REGEX MATCH "IAR" CMAKE_COMPILER_IS_IAR "${CMAKE_C_COMPILER_ID}")
string(REGEX MATCH "MSVC" CMAKE_COMPILER_IS_MSVC "${CMAKE_C_COMPILER_ID}")
# the test suites currently have compile errors with MSVC
if(CMAKE_COMPILER_IS_MSVC)
option(ENABLE_TESTING "Build Mbed TLS tests." OFF)
else()
option(ENABLE_TESTING "Build Mbed TLS tests." ON)
endif()
# Warning string - created as a list for compatibility with CMake 2.8
set(CTR_DRBG_128_BIT_KEY_WARN_L1 "**** WARNING! MBEDTLS_CTR_DRBG_USE_128_BIT_KEY defined!\n")
set(CTR_DRBG_128_BIT_KEY_WARN_L2 "**** Using 128-bit keys for CTR_DRBG limits the security of generated\n")
set(CTR_DRBG_128_BIT_KEY_WARN_L3 "**** keys and operations that use random values generated to 128-bit security\n")
set(CTR_DRBG_128_BIT_KEY_WARNING "${WARNING_BORDER}"
"${CTR_DRBG_128_BIT_KEY_WARN_L1}"
"${CTR_DRBG_128_BIT_KEY_WARN_L2}"
"${CTR_DRBG_128_BIT_KEY_WARN_L3}"
"${WARNING_BORDER}")
# 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(MBEDTLS_PYTHON_EXECUTABLE ${Python3_EXECUTABLE})
endif()
else()
find_package(PythonInterp 3)
if(PYTHONINTERP_FOUND)
set(MBEDTLS_PYTHON_EXECUTABLE ${PYTHON_EXECUTABLE})
endif()
endif()
if(MBEDTLS_PYTHON_EXECUTABLE)
# If 128-bit keys are configured for CTR_DRBG, display an appropriate warning
execute_process(COMMAND ${MBEDTLS_PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/scripts/config.py -f ${CMAKE_CURRENT_SOURCE_DIR}/include/mbedtls/mbedtls_config.h get MBEDTLS_CTR_DRBG_USE_128_BIT_KEY
RESULT_VARIABLE result)
if(${result} EQUAL 0)
message(WARNING ${CTR_DRBG_128_BIT_KEY_WARNING})
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(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
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 MBEDTLS_CONFIG_FILE and MBEDTLS_USER_CONFIG_FILE into PATHs
set(MBEDTLS_CONFIG_FILE "" CACHE FILEPATH "Mbed TLS config file (overrides default).")
set(MBEDTLS_USER_CONFIG_FILE "" CACHE FILEPATH "Mbed TLS user config file (appended to default).")
# 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(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(link_to_source)
# Get the filename without the final extension (i.e. convert "a.b.c" to "a.b")
function(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(get_name_without_last_ext)
string(REGEX MATCH "Clang" CMAKE_COMPILER_IS_CLANG "${CMAKE_C_COMPILER_ID}")
include(CheckCCompilerFlag)
set(CMAKE_C_EXTENSIONS OFF)
set(CMAKE_C_STANDARD 99)
if(CMAKE_COMPILER_IS_GNU)
# 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)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wwrite-strings")
if (GCC_VERSION VERSION_GREATER 3.0 OR GCC_VERSION VERSION_EQUAL 3.0)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wformat=2 -Wno-format-nonliteral")
endif()
if (GCC_VERSION VERSION_GREATER 4.3 OR GCC_VERSION VERSION_EQUAL 4.3)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wvla")
endif()
if (GCC_VERSION VERSION_GREATER 4.5 OR GCC_VERSION VERSION_EQUAL 4.5)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wlogical-op")
endif()
if (GCC_VERSION VERSION_GREATER 4.8 OR GCC_VERSION VERSION_EQUAL 4.8)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -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)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wformat-signedness")
endif()
endif()
if (GCC_VERSION VERSION_GREATER 7.0 OR GCC_VERSION VERSION_EQUAL 7.0)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wformat-overflow=2 -Wformat-truncation")
endif()
set(CMAKE_C_FLAGS_RELEASE "-O2")
set(CMAKE_C_FLAGS_DEBUG "-O0 -g3")
set(CMAKE_C_FLAGS_COVERAGE "-O0 -g3 --coverage")
set(CMAKE_C_FLAGS_ASAN "-fsanitize=address -fno-common -fsanitize=undefined -fno-sanitize-recover=all -O3")
set(CMAKE_C_FLAGS_ASANDBG "-fsanitize=address -fno-common -fsanitize=undefined -fno-sanitize-recover=all -O1 -g3 -fno-omit-frame-pointer -fno-optimize-sibling-calls")
set(CMAKE_C_FLAGS_TSAN "-fsanitize=thread -O3")
set(CMAKE_C_FLAGS_TSANDBG "-fsanitize=thread -O1 -g3 -fno-omit-frame-pointer -fno-optimize-sibling-calls")
set(CMAKE_C_FLAGS_CHECK "-Os")
set(CMAKE_C_FLAGS_CHECKFULL "${CMAKE_C_FLAGS_CHECK} -Wcast-qual")
endif(CMAKE_COMPILER_IS_GNU)
if(CMAKE_COMPILER_IS_CLANG)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wwrite-strings -Wpointer-arith -Wimplicit-fallthrough -Wshadow -Wvla -Wformat=2 -Wno-format-nonliteral")
set(CMAKE_C_FLAGS_RELEASE "-O2")
set(CMAKE_C_FLAGS_DEBUG "-O0 -g3")
set(CMAKE_C_FLAGS_COVERAGE "-O0 -g3 --coverage")
set(CMAKE_C_FLAGS_ASAN "-fsanitize=address -fno-common -fsanitize=undefined -fno-sanitize-recover=all -O3")
set(CMAKE_C_FLAGS_ASANDBG "-fsanitize=address -fno-common -fsanitize=undefined -fno-sanitize-recover=all -O1 -g3 -fno-omit-frame-pointer -fno-optimize-sibling-calls")
set(CMAKE_C_FLAGS_MEMSAN "-fsanitize=memory -O3")
set(CMAKE_C_FLAGS_MEMSANDBG "-fsanitize=memory -O1 -g3 -fno-omit-frame-pointer -fno-optimize-sibling-calls -fsanitize-memory-track-origins=2")
set(CMAKE_C_FLAGS_TSAN "-fsanitize=thread -O3")
set(CMAKE_C_FLAGS_TSANDBG "-fsanitize=thread -O1 -g3 -fno-omit-frame-pointer -fno-optimize-sibling-calls")
set(CMAKE_C_FLAGS_CHECK "-Os")
endif(CMAKE_COMPILER_IS_CLANG)
if(CMAKE_COMPILER_IS_IAR)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} --warn_about_c_style_casts")
set(CMAKE_C_FLAGS_RELEASE "-Ohz")
set(CMAKE_C_FLAGS_DEBUG "--debug -On")
endif(CMAKE_COMPILER_IS_IAR)
if(CMAKE_COMPILER_IS_MSVC)
# Strictest warnings, UTF-8 source and execution charset
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /W3 /utf-8")
endif(CMAKE_COMPILER_IS_MSVC)
if(MBEDTLS_FATAL_WARNINGS)
if(CMAKE_COMPILER_IS_MSVC)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /WX")
endif(CMAKE_COMPILER_IS_MSVC)
if(CMAKE_COMPILER_IS_CLANG OR CMAKE_COMPILER_IS_GNU)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror")
if(UNSAFE_BUILD)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-error=cpp")
set(CMAKE_C_FLAGS_ASAN "${CMAKE_C_FLAGS_ASAN} -Wno-error=cpp")
set(CMAKE_C_FLAGS_ASANDBG "${CMAKE_C_FLAGS_ASANDBG} -Wno-error=cpp")
endif(UNSAFE_BUILD)
endif(CMAKE_COMPILER_IS_CLANG OR CMAKE_COMPILER_IS_GNU)
if (CMAKE_COMPILER_IS_IAR)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} --warnings_are_errors")
endif(CMAKE_COMPILER_IS_IAR)
endif(MBEDTLS_FATAL_WARNINGS)
if(CMAKE_BUILD_TYPE STREQUAL "Coverage")
if(CMAKE_COMPILER_IS_GNU OR CMAKE_COMPILER_IS_CLANG)
set(CMAKE_SHARED_LINKER_FLAGS "--coverage")
endif(CMAKE_COMPILER_IS_GNU OR CMAKE_COMPILER_IS_CLANG)
endif(CMAKE_BUILD_TYPE STREQUAL "Coverage")
if(LIB_INSTALL_DIR)
set(CMAKE_INSTALL_LIBDIR "${LIB_INSTALL_DIR}")
endif()
if (NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/framework/CMakeLists.txt")
message(FATAL_ERROR "${CMAKE_CURRENT_SOURCE_DIR}/framework/CMakeLists.txt not found. Run `git submodule update --init` from the source tree to fetch the submodule contents.")
endif()
add_subdirectory(framework)
add_subdirectory(include)
add_subdirectory(3rdparty)
add_subdirectory(library)
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 mbedcrypto, mbedx509 and mbedtls libraries.
# The reason is that such library is expected to have mutual dependencies with
# the aforementioned libraries and that there is as of today no portable way of
# handling such dependencies (only toolchain specific solutions).
#
# Thus the below definition of the `mbedtls_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 MBEDTLS_TEST_FILES
${CMAKE_CURRENT_SOURCE_DIR}/tests/src/*.c
${CMAKE_CURRENT_SOURCE_DIR}/tests/src/drivers/*.c)
add_library(mbedtls_test OBJECT ${MBEDTLS_TEST_FILES})
target_include_directories(mbedtls_test
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/tests/include
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/library)
# Request C11, needed for memory poisoning tests
set_target_properties(mbedtls_test PROPERTIES C_STANDARD 11)
file(GLOB MBEDTLS_TEST_HELPER_FILES
${CMAKE_CURRENT_SOURCE_DIR}/tests/src/test_helpers/*.c)
add_library(mbedtls_test_helpers OBJECT ${MBEDTLS_TEST_HELPER_FILES})
target_include_directories(mbedtls_test_helpers
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/tests/include
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/library
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/everest/include)
# Pass-through MBEDTLS_CONFIG_FILE and MBEDTLS_USER_CONFIG_FILE
if(MBEDTLS_CONFIG_FILE)
target_compile_definitions(mbedtls_test
PUBLIC MBEDTLS_CONFIG_FILE="${MBEDTLS_CONFIG_FILE}")
target_compile_definitions(mbedtls_test_helpers
PUBLIC MBEDTLS_CONFIG_FILE="${MBEDTLS_CONFIG_FILE}")
endif()
if(MBEDTLS_USER_CONFIG_FILE)
target_compile_definitions(mbedtls_test
PUBLIC MBEDTLS_USER_CONFIG_FILE="${MBEDTLS_USER_CONFIG_FILE}")
target_compile_definitions(mbedtls_test_helpers
PUBLIC MBEDTLS_USER_CONFIG_FILE="${MBEDTLS_USER_CONFIG_FILE}")
endif()
endif()
if(ENABLE_PROGRAMS)
add_subdirectory(programs)
endif()
ADD_CUSTOM_TARGET(${MBEDTLS_TARGET_PREFIX}apidoc
COMMAND doxygen mbedtls.doxyfile
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/doxygen)
if(ENABLE_TESTING)
enable_testing()
add_subdirectory(tests)
# additional convenience targets for Unix only
if(UNIX)
# 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 scripts/lcov.sh to generate an HTML report.
ADD_CUSTOM_TARGET(lcov
COMMAND 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(UNIX)
# Make scripts needed for testing available in an out-of-source build.
if (NOT ${CMAKE_CURRENT_BINARY_DIR} STREQUAL ${CMAKE_CURRENT_SOURCE_DIR})
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/MbedTLSConfig.cmake.in"
"cmake/MbedTLSConfig.cmake"
INSTALL_DESTINATION "cmake")
write_basic_package_version_file(
"cmake/MbedTLSConfigVersion.cmake"
COMPATIBILITY SameMajorVersion
VERSION 3.6.0)
install(
FILES "${CMAKE_CURRENT_BINARY_DIR}/cmake/MbedTLSConfig.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/cmake/MbedTLSConfigVersion.cmake"
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/MbedTLS")
export(
EXPORT MbedTLSTargets
NAMESPACE MbedTLS::
FILE "cmake/MbedTLSTargets.cmake")
install(
EXPORT MbedTLSTargets
NAMESPACE MbedTLS::
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/MbedTLS"
FILE "MbedTLSTargets.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 MbedTLS)
endif()
endif()

View File

@ -0,0 +1,97 @@
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/mbedtls/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 [Mbed TLS repository on GitHub](https://github.com/Mbed-TLS/mbedtls) to start making your changes. As a general rule, you should use the ["development" branch](https://github.com/Mbed-TLS/mbedtls/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 Mbed TLS 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
--------------------------
Mbed TLS maintains several LTS (Long Term Support) branches, which are maintained continuously for a given period. 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/mbedtls/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.
Mbed TLS 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_rsa.c`). These files are generated from a `function file` (e.g. `suites/test_suite_rsa.function`) and a `data file` (e.g. `suites/test_suite_rsa.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.
It is advised to enable the [githooks scripts](https://github.com/Mbed-TLS/mbedtls/tree/development/tests/git-scripts) prior to pushing your changes, for catching some of the issues as early as possible.
Documentation
-------------
Mbed TLS 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/mbedtls/blob/development/ChangeLog.d/00README.md) entry should be added for this contribution.
License and Copyright
---------------------
Unless specifically indicated otherwise in a file, Mbed TLS 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.

6108
lib/mbedtls/external/mbedtls/ChangeLog vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,91 @@
# 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.
Until Mbed TLS 2.24.0, we required changelog entries in more cases.
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 an
Mbed TLS 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.

View File

@ -0,0 +1,4 @@
Site: localhost
BuildName: Mbed TLS-test
CoverageCommand: /usr/bin/gcov
MemoryCheckCommand: /usr/bin/valgrind

553
lib/mbedtls/external/mbedtls/LICENSE vendored Normal file
View File

@ -0,0 +1,553 @@
Mbed TLS 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.

217
lib/mbedtls/external/mbedtls/Makefile vendored Normal file
View File

@ -0,0 +1,217 @@
DESTDIR=/usr/local
PREFIX=mbedtls_
PERL ?= perl
ifneq (,$(filter-out lib library/%,$(or $(MAKECMDGOALS),all)))
ifeq (,$(wildcard framework/exported.make))
# Use the define keyword to get a multi-line message.
# GNU make appends ". Stop.", so tweak the ending of our message accordingly.
define error_message
$(MBEDTLS_PATH)/framework/exported.make not found.
Run `git submodule update --init` to fetch the submodule contents.
This is a fatal error
endef
$(error $(error_message))
endif
include framework/exported.make
endif
.SILENT:
.PHONY: all no_test programs lib tests install uninstall clean test check lcov apidoc apidoc_clean
all: programs tests
$(MAKE) post_build
no_test: programs
programs: lib mbedtls_test
$(MAKE) -C programs
lib:
$(MAKE) -C library
tests: lib mbedtls_test
$(MAKE) -C tests
mbedtls_test:
$(MAKE) -C tests mbedtls_test
library/%:
$(MAKE) -C library $*
programs/%:
$(MAKE) -C programs $*
tests/%:
$(MAKE) -C tests $*
.PHONY: generated_files
generated_files: library/generated_files
generated_files: programs/generated_files
generated_files: tests/generated_files
generated_files: visualc_files
# Set GEN_FILES to the empty string to disable dependencies on generated
# source files. Then `make generated_files` will only build files that
# are missing, it will not rebuilt files that are present but out of date.
# This is useful, for example, if you have a source tree where
# `make generated_files` has already run and file timestamps reflect the
# time the files were copied or extracted, and you are now in an environment
# that lacks some of the necessary tools to re-generate the files.
# If $(GEN_FILES) is non-empty, the generated source files' dependencies
# are treated ordinarily, based on file timestamps.
GEN_FILES ?=
# In dependencies where the target is a configuration-independent generated
# file, use `TARGET: $(gen_file_dep) DEPENDENCY1 DEPENDENCY2 ...`
# rather than directly `TARGET: DEPENDENCY1 DEPENDENCY2 ...`. This
# enables the re-generation to be turned off when GEN_FILES is disabled.
ifdef GEN_FILES
gen_file_dep =
else
# Order-only dependency: generate the target if it's absent, but don't
# re-generate it if it's present but older than its dependencies.
gen_file_dep = |
endif
.PHONY: visualc_files
VISUALC_FILES = visualc/VS2017/mbedTLS.sln visualc/VS2017/mbedTLS.vcxproj
# TODO: $(app).vcxproj for each $(app) in programs/
visualc_files: $(VISUALC_FILES)
# Ensure that the .c files that generate_visualc_files.pl enumerates are
# present before it runs. It doesn't matter if the files aren't up-to-date,
# they just need to be present.
$(VISUALC_FILES): | library/generated_files
$(VISUALC_FILES): $(gen_file_dep) scripts/generate_visualc_files.pl
$(VISUALC_FILES): $(gen_file_dep) scripts/data_files/vs2017-app-template.vcxproj
$(VISUALC_FILES): $(gen_file_dep) scripts/data_files/vs2017-main-template.vcxproj
$(VISUALC_FILES): $(gen_file_dep) scripts/data_files/vs2017-sln-template.sln
# TODO: also the list of .c and .h source files, but not their content
$(VISUALC_FILES):
echo " Gen $@ ..."
$(PERL) scripts/generate_visualc_files.pl
ifndef WINDOWS
install: no_test
mkdir -p $(DESTDIR)/include/mbedtls
cp -rp include/mbedtls $(DESTDIR)/include
mkdir -p $(DESTDIR)/include/psa
cp -rp include/psa $(DESTDIR)/include
mkdir -p $(DESTDIR)/lib
cp -RP library/libmbedtls.* $(DESTDIR)/lib
cp -RP library/libmbedx509.* $(DESTDIR)/lib
cp -RP library/libmbedcrypto.* $(DESTDIR)/lib
mkdir -p $(DESTDIR)/bin
for p in programs/*/* ; do \
if [ -x $$p ] && [ ! -d $$p ] ; \
then \
f=$(PREFIX)`basename $$p` ; \
cp $$p $(DESTDIR)/bin/$$f ; \
fi \
done
uninstall:
rm -rf $(DESTDIR)/include/mbedtls
rm -rf $(DESTDIR)/include/psa
rm -f $(DESTDIR)/lib/libmbedtls.*
rm -f $(DESTDIR)/lib/libmbedx509.*
rm -f $(DESTDIR)/lib/libmbedcrypto.*
for p in programs/*/* ; do \
if [ -x $$p ] && [ ! -d $$p ] ; \
then \
f=$(PREFIX)`basename $$p` ; \
rm -f $(DESTDIR)/bin/$$f ; \
fi \
done
endif
WARNING_BORDER_LONG =**********************************************************************************\n
CTR_DRBG_128_BIT_KEY_WARN_L1=**** WARNING! MBEDTLS_CTR_DRBG_USE_128_BIT_KEY defined! ****\n
CTR_DRBG_128_BIT_KEY_WARN_L2=**** Using 128-bit keys for CTR_DRBG limits the security of generated ****\n
CTR_DRBG_128_BIT_KEY_WARN_L3=**** keys and operations that use random values generated to 128-bit security ****\n
CTR_DRBG_128_BIT_KEY_WARNING=\n$(WARNING_BORDER_LONG)$(CTR_DRBG_128_BIT_KEY_WARN_L1)$(CTR_DRBG_128_BIT_KEY_WARN_L2)$(CTR_DRBG_128_BIT_KEY_WARN_L3)$(WARNING_BORDER_LONG)
# Post build steps
post_build:
ifndef WINDOWS
# If 128-bit keys are configured for CTR_DRBG, display an appropriate warning
-scripts/config.py get MBEDTLS_CTR_DRBG_USE_128_BIT_KEY && ([ $$? -eq 0 ]) && \
echo '$(CTR_DRBG_128_BIT_KEY_WARNING)'
endif
clean: clean_more_on_top
$(MAKE) -C library clean
$(MAKE) -C programs clean
$(MAKE) -C tests clean
clean_more_on_top:
ifndef WINDOWS
find . \( -name \*.gcno -o -name \*.gcda -o -name \*.info \) -exec rm {} +
endif
neat: clean_more_on_top
$(MAKE) -C library neat
$(MAKE) -C programs neat
$(MAKE) -C tests neat
ifndef WINDOWS
rm -f visualc/VS2017/*.vcxproj visualc/VS2017/mbedTLS.sln
else
if exist visualc\VS2017\*.vcxproj del /Q /F visualc\VS2017\*.vcxproj
if exist visualc\VS2017\mbedTLS.sln del /Q /F visualc\VS2017\mbedTLS.sln
endif
check: lib tests
$(MAKE) -C tests check
test: check
ifndef WINDOWS
# For coverage testing:
# 1. Build with:
# make CFLAGS='--coverage -g3 -O0' LDFLAGS='--coverage'
# 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 scripts/lcov.sh to generate an HTML report.
lcov:
scripts/lcov.sh
apidoc:
mkdir -p apidoc
cd doxygen && doxygen mbedtls.doxyfile
apidoc_clean:
rm -rf apidoc
endif
## Editor navigation files
C_SOURCE_FILES = $(wildcard \
3rdparty/*/include/*/*.h 3rdparty/*/include/*/*/*.h 3rdparty/*/include/*/*/*/*.h \
3rdparty/*/*.c 3rdparty/*/*/*.c 3rdparty/*/*/*/*.c 3rdparty/*/*/*/*/*.c \
include/*/*.h \
library/*.[hc] \
programs/*/*.[hc] \
tests/include/*/*.h tests/include/*/*/*.h \
tests/src/*.c tests/src/*/*.c \
tests/suites/*.function \
)
# Exuberant-ctags invocation. Other ctags implementations may require different options.
CTAGS = ctags --langmap=c:+.h.function --line-directives=no -o
tags: $(C_SOURCE_FILES)
$(CTAGS) $@ $(C_SOURCE_FILES)
TAGS: $(C_SOURCE_FILES)
etags --no-line-directive -o $@ $(C_SOURCE_FILES)
global: GPATH GRTAGS GSYMS GTAGS
GPATH GRTAGS GSYMS GTAGS: $(C_SOURCE_FILES)
ls $(C_SOURCE_FILES) | gtags -f - --gtagsconf .globalrc
cscope: cscope.in.out cscope.po.out cscope.out
cscope.in.out cscope.po.out cscope.out: $(C_SOURCE_FILES)
cscope -bq -u -Iinclude -Ilibrary $(patsubst %,-I%,$(wildcard 3rdparty/*/include)) -Itests/include $(C_SOURCE_FILES)
.PHONY: cscope global

333
lib/mbedtls/external/mbedtls/README.md vendored Normal file
View File

@ -0,0 +1,333 @@
README for Mbed TLS
===================
Mbed TLS is a C library that implements cryptographic primitives, X.509 certificate manipulation and the SSL/TLS and DTLS protocols. Its small code footprint makes it suitable for embedded systems.
Mbed TLS includes a reference implementation of the [PSA Cryptography API](#psa-cryptography-api). This is currently a preview for evaluation purposes only.
Configuration
-------------
Mbed TLS should build out of the box on most systems. Some platform specific options are available in the fully documented configuration file `include/mbedtls/mbedtls_config.h`, which is also the place where features can be selected. This file can be edited manually, or in a more programmatic way using the Python 3 script `scripts/config.py` (use `--help` for usage instructions).
Compiler options can be set using conventional environment variables such as `CC` and `CFLAGS` when using the Make and CMake build system (see below).
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
-------------
The main Mbed TLS documentation is available via [ReadTheDocs](https://mbed-tls.readthedocs.io/).
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, tailored to your compile-time configuration:
1. Make sure that [Doxygen](http://www.doxygen.nl/) is installed.
1. Run `make apidoc`.
1. Browse `apidoc/index.html` or `apidoc/modules.html`.
For other sources of documentation, see the [SUPPORT](SUPPORT.md) document.
Compiling
---------
There are currently three active build systems used within Mbed TLS releases:
- GNU Make
- CMake
- Microsoft Visual Studio
The main systems used for development are CMake and GNU Make. Those systems are always complete and up-to-date. The others should reflect all changes present in the CMake and Make build system, although features may not be ported there automatically.
The Make and CMake build systems create three libraries: libmbedcrypto, libmbedx509, and libmbedtls. Note that libmbedtls depends on libmbedx509 and libmbedcrypto, and libmbedx509 depends on libmbedcrypto. As a result, some linkers will expect flags to be in a specific order, for example the GNU linker wants `-lmbedtls -lmbedx509 -lmbedcrypto`.
### Tool versions
You need the following tools to build the library with the provided makefiles:
* GNU Make 3.82 or a build tool that CMake supports.
* A C99 toolchain (compiler, linker, archiver). We actively test with GCC 5.4, Clang 3.8, Arm Compiler 6, IAR 8 and Visual Studio 2017. More recent versions should work. Slightly older versions may work.
* Python 3.8 to generate the test code. Python is also needed to integrate PSA drivers and to build the development branch (see next section).
* Perl to run the tests, and to generate some source files in the development branch.
* CMake 3.10.2 or later (if using CMake).
* Microsoft Visual Studio 2017 or later (if using Visual Studio).
* Doxygen 1.8.11 or later (if building the documentation; slightly older versions should work).
### Git usage
The `development` branch and the `mbedtls-3.6` long-term support branch of Mbed TLS use a [Git submodule](https://git-scm.com/book/en/v2/Git-Tools-Submodules#_cloning_submodules) ([framework](https://github.com/Mbed-TLS/mbedtls-framework)). This is not needed to merely compile the library at a release tag. This is not needed to consume a release archive (zip or tar).
### Generated source files in the development branch
The source code of Mbed TLS includes some files that are automatically generated by scripts and whose content depends only on the Mbed TLS source, not on the platform or on the library configuration. These files are not included in the development branch of Mbed TLS, 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:
* Perl, for some library source files and for Visual Studio build files.
* Python 3.8 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, omit the `--user` option.
* A C compiler for the host platform, for some test data.
If you are cross-compiling, you must set the `CC` environment variable to a C compiler for the host platform when generating the configuration-independent files.
Any of the following methods are available to generate the configuration-independent files:
* If not cross-compiling, running `make` with any target, or just `make`, will automatically generate required files.
* On non-Windows systems, when not cross-compiling, CMake will generate the required files automatically.
* Run `make generated_files` to generate all the configuration-independent files.
* On Unix/POSIX systems, run `tests/scripts/check-generated-files.sh -u` to generate all the configuration-independent files.
* On Windows, run `scripts\make_generated_files.bat` to generate all the configuration-independent files.
### Make
We require GNU Make. To build the library and the sample programs, GNU Make and a C compiler are sufficient. Some of the more advanced build targets require some Unix/Linux tools.
We intentionally only use a minimum of functionality in the makefiles in order to keep them as simple and independent of different toolchains as possible, to allow users to more easily move between different platforms. Users who need more features are recommended to use CMake.
In order to build from the source code using GNU Make, just enter at the command line:
make
In order to run the tests, enter:
make check
The tests need Python to be built and Perl to be run. If you don't have one of them installed, you can skip building the tests with:
make no_test
You'll still be able to run a much smaller set of tests with:
programs/test/selftest
In order to build for a Windows platform, you should use `WINDOWS_BUILD=1` if the target is Windows but the build environment is Unix-like (for instance when cross-compiling, or compiling from an MSYS shell), and `WINDOWS=1` if the build environment is a Windows shell (for instance using mingw32-make) (in that case some targets will not be available).
Setting the variable `SHARED` in your environment will build shared libraries in addition to the static libraries. Setting `DEBUG` gives you a debug build. You can override `CFLAGS` and `LDFLAGS` by setting them in your environment or on the make command line; compiler warning options may be overridden separately using `WARNING_CFLAGS`. Some directory-specific options (for example, `-I` directives) are still preserved.
Please note that setting `CFLAGS` overrides its default value of `-O2` and setting `WARNING_CFLAGS` overrides its default value (starting with `-Wall -Wextra`), so if you just want to add some warning options to the default ones, you can do so by setting `CFLAGS=-O2 -Werror` for example. Setting `WARNING_CFLAGS` is useful when you want to get rid of its default content (for example because your compiler doesn't accept `-Wall` as an option). Directory-specific options cannot be overridden from the command line.
Depending on your platform, you might run into some issues. Please check the Makefiles in `library/`, `programs/` and `tests/` for options to manually add or remove for specific platforms. You can also check [the Mbed TLS Knowledge Base](https://mbed-tls.readthedocs.io/en/latest/kb/) for articles on your platform or issue.
In case you find that you need to do something else as well, please let us know what, so we can add it to the [Mbed TLS Knowledge Base](https://mbed-tls.readthedocs.io/en/latest/kb/).
### 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/mbedtls_source
cmake --build .
In order to run the tests, enter:
ctest
The test suites need Python to be built and Perl to be executed. If you don't have one of these installed, you'll want to disable the test suites with:
cmake -DENABLE_TESTING=Off /path/to/mbedtls_source
If you disabled the test suites, but kept the programs enabled, you can still run a much smaller set of tests with:
programs/test/selftest
To configure CMake for building shared libraries, use:
cmake -DUSE_SHARED_MBEDTLS_LIBRARY=On /path/to/mbedtls_source
There are many different build modes available within the CMake buildsystem. 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.
- `Coverage`. This generates code coverage information in addition to debug information.
- `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.
Switching build modes in CMake is simple. For debug mode, enter at the command line:
cmake -D CMAKE_BUILD_TYPE=Debug /path/to/mbedtls_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/mbedtls_source
If you already invoked cmake and want to change those settings, you need to
remove the build directory and create it again.
Note that it is possible to build in-place; this will however overwrite the
provided Makefiles (see `scripts/tmp_ignore_makefiles.sh` if you want to
prevent `git status` from showing them as modified). In order to do so, from
the Mbed TLS source directory, use:
cmake .
make
If you want to change `CC` or `CFLAGS` afterwards, you will need to remove the
CMake cache. This can be done with the following command using GNU find:
find . -iname '*cmake*' -not -name CMakeLists.txt -exec rm -rf {} +
You can now make the desired change:
CC=your_cc cmake .
make
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 Mbed TLS
Mbed TLS provides a package config file for consumption as a dependency in other
CMake projects. You can include Mbed TLS's CMake targets yourself with:
find_package(MbedTLS)
If prompted, set `MbedTLS_DIR` to `${YOUR_MBEDTLS_INSTALL_DIR}/cmake`. This
creates the following targets:
- `MbedTLS::mbedcrypto` (Crypto library)
- `MbedTLS::mbedtls` (TLS library)
- `MbedTLS::mbedx509` (X509 library)
You can then use these directly through `target_link_libraries()`:
add_executable(xyz)
target_link_libraries(xyz
PUBLIC MbedTLS::mbedtls
MbedTLS::mbedcrypto
MbedTLS::mbedx509)
This will link the Mbed TLS libraries to your library or application, and add
its include directories to your target (transitively, in the case of `PUBLIC` or
`INTERFACE` link libraries).
#### Mbed TLS as a subproject
Mbed TLS supports being built as a CMake subproject. One can
use `add_subdirectory()` from a parent CMake project to include Mbed TLS as a
subproject.
### Microsoft Visual Studio
The build files for Microsoft Visual Studio are generated for Visual Studio 2017.
The solution file `mbedTLS.sln` contains all the basic projects needed to build the library and all the programs. The files in tests are not generated and compiled, as these need Python and perl environments as well. However, the selftest program in `programs/test/` is still available.
In the development branch of Mbed TLS, the Visual Studio solution files need to be generated first as described in [“Generated source files in the development branch”](#generated-source-files-in-the-development-branch).
Example programs
----------------
We've included example programs for a lot of 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
-----
Mbed TLS includes an elaborate test suite in `tests/` that initially requires Python to generate the tests files (e.g. `test\_suite\_mpi.c`). These files are generated from a `function file` (e.g. `suites/test\_suite\_mpi.function`) and a `data file` (e.g. `suites/test\_suite\_mpi.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.
For machines with a Unix shell and OpenSSL (and optionally GnuTLS) installed, additional test scripts are available:
- `tests/ssl-opt.sh` runs integration tests for various TLS options (renegotiation, resumption, etc.) and tests interoperability of these options with other implementations.
- `tests/compat.sh` tests interoperability of every ciphersuite with other implementations.
- `tests/scripts/test-ref-configs.pl` test builds in various reduced configurations.
- `tests/scripts/depends.py` test builds in configurations with a single curve, key exchange, hash, cipher, or pkalg on.
- `tests/scripts/all.sh` runs a combination of the above tests, plus some more, with various build options (such as ASan, full `mbedtls_config.h`, etc).
Instead of manually installing the required versions of all tools required for testing, it is possible to use the Docker images from our CI systems, as explained in [our testing infrastructure repository](https://github.com/Mbed-TLS/mbedtls-test/blob/main/README.md#quick-start).
Porting Mbed TLS
----------------
Mbed TLS 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/)
Mbed TLS 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.
PSA cryptography API
--------------------
### PSA API
Arm's [Platform Security Architecture (PSA)](https://developer.arm.com/architectures/security-architectures/platform-security-architecture) is a holistic set of threat models, security analyses, hardware and firmware architecture specifications, and an open source firmware reference implementation. PSA provides a recipe, based on industry best practice, that allows security to be consistently designed in, at both a hardware and firmware level.
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.
Arm 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 implementation in Mbed TLS
Mbed TLS includes a reference implementation of the PSA Cryptography API.
However, it does not aim to implement the whole specification; in particular it does not implement all the algorithms.
The X.509 and TLS code can use PSA cryptography for most operations. To enable this support, activate the compilation option `MBEDTLS_USE_PSA_CRYPTO` in `mbedtls_config.h`. Note that TLS 1.3 uses PSA cryptography for most operations regardless of this option. See `docs/use-psa-crypto.md` for details.
### PSA drivers
Mbed TLS 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 Crypto API), but the code of the drivers may have to change in future minor releases of Mbed TLS.
Please see the [PSA driver example and guide](docs/psa-driver-example-and-guide.md) for information on writing a driver.
When using drivers, you will generally want to enable two compilation options (see the reference manual for more information):
* `MBEDTLS_USE_PSA_CRYPTO` is necessary so that the X.509 and TLS code calls the PSA drivers rather than the built-in software implementation.
* `MBEDTLS_PSA_CRYPTO_CONFIG` allows you to enable PSA cryptographic mechanisms without including the code of the corresponding software implementation. This is not yet supported for all mechanisms.
License
-------
Unless specifically indicated otherwise in a file, Mbed TLS 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, and [the 'License and Copyright' section in the contributing guidelines](CONTRIBUTING.md#License-and-Copyright) for more information.
### Third-party code included in Mbed TLS
This project contains code from other projects. This code is located within the `3rdparty/` 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:
* `3rdparty/everest/`: Files stem from [Project Everest](https://project-everest.github.io/) and are distributed under the Apache 2.0 license.
* `3rdparty/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 Mbed TLS 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 Mbed TLS, 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 Mbed TLS, please [file an issue on GitHub](https://github.com/Mbed-TLS/mbedtls/issues/new/choose).
* Please see [`SUPPORT.md`](SUPPORT.md) for other channels for discussion and support about Mbed TLS.

146
lib/mbedtls/external/mbedtls/SECURITY.md vendored Normal file
View File

@ -0,0 +1,146 @@
## Reporting Vulnerabilities
If you think you have found an Mbed TLS security vulnerability, 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.
Mbed TLS aims to fully protect against remote attacks and to enable the user
application in providing full protection against remote attacks. Said
protection is limited to providing security guarantees offered by the protocol
being implemented. (For example Mbed TLS alone won't guarantee that the
messages will arrive without delay, as the TLS protocol doesn't guarantee that
either.)
**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 Mbed TLS
assets such as memory and files.
#### Timing attacks
The attacker is able to observe the timing of instructions executed by Mbed TLS
by leveraging shared hardware that both Mbed TLS and the attacker have access
to. Typical attack vectors include cache timings, memory bus contention and
branch prediction.
Mbed TLS 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 Mbed TLS is
limited. We are only aiming to provide protection against **publicly
documented attack techniques**.
As attacks keep improving, so does Mbed TLS's protection. Mbed TLS 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 Mbed TLS 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.
Mbed TLS 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.
Mbed TLS 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 Mbed TLS is running on and/or can alter the physical state
of the hardware (e.g. power analysis, radio emissions or fault injection).
Mbed TLS 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
Mbed TLS has evolved organically and a well defined threat model hasn't always
been present. Therefore, Mbed TLS might have countermeasures against attacks
outside the above defined threat model.
The presence of such countermeasures don't mean that Mbed TLS 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 Mbed TLS: AES, CAMELLIA, ARIA and
DES. The pure software implementation in Mbed TLS implementation uses lookup
tables, which are vulnerable to timing attacks.
These timing attacks can be physical, local or depending on network latency
even a 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
`MBEDTLS_AESCE_C`, `MBEDTLS_AESNI_C` and `MBEDTLS_PADLOCK_C` for details.
- Add a secure alternative implementation (typically hardware acceleration) for
the vulnerable cipher. See the [Alternative Implementations
Guide](docs/architecture/alternative-implementations.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
lib/mbedtls/external/mbedtls/SUPPORT.md vendored Normal file
View File

@ -0,0 +1,16 @@
## Documentation
Here are some useful sources of information about using Mbed TLS:
- [ReadTheDocs](https://mbed-tls.readthedocs.io/);
- API documentation, see the [Documentation section of the
README](README.md#documentation);
- the `docs` directory in the source tree;
- 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).

View File

@ -0,0 +1,3 @@
@PACKAGE_INIT@
include("${CMAKE_CURRENT_LIST_DIR}/MbedTLSTargets.cmake")

View File

@ -0,0 +1,24 @@
This directory contains example configuration files.
The examples are generally focused on a particular usage case (eg, support for
a restricted number of ciphersuites) 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 mbedtls_config.h. To use one of
them, you can pick one of the following methods:
1. Replace the default file include/mbedtls/mbedtls_config.h with the chosen one.
2. Define MBEDTLS_CONFIG_FILE and adjust the include path accordingly.
For example, using make:
CFLAGS="-I$PWD/configs -DMBEDTLS_CONFIG_FILE='<foo.h>'" make
Or, using cmake:
find . -iname '*cmake*' -not -name CMakeLists.txt -exec rm -rf {} +
CFLAGS="-I$PWD/configs -DMBEDTLS_CONFIG_FILE='<foo.h>'" cmake .
make
Note that the second method also works if you want to keep your custom
configuration file outside the Mbed TLS tree.

View File

@ -0,0 +1,92 @@
/**
* \file config-ccm-psk-dtls1_2.h
*
* \brief Small configuration for DTLS 1.2 with PSK and AES-CCM ciphersuites
*/
/*
* Copyright The Mbed TLS Contributors
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
*/
/*
* Minimal configuration for DTLS 1.2 with PSK and AES-CCM ciphersuites
*
* Distinguishing features:
* - Optimized for small code size, low bandwidth (on an unreliable transport),
* and low RAM usage.
* - No asymmetric cryptography (no certificates, no Diffie-Hellman key
* exchange).
* - Fully modern and secure (provided the pre-shared keys are generated and
* stored securely).
* - Very low record overhead with CCM-8.
* - Includes several optional DTLS features typically used in IoT.
*
* See README.txt for usage instructions.
*/
/* System support */
//#define MBEDTLS_HAVE_TIME /* Optionally used in Hello messages */
/* Other MBEDTLS_HAVE_XXX flags irrelevant for this configuration */
/* Mbed TLS modules */
#define MBEDTLS_AES_C
#define MBEDTLS_CCM_C
#define MBEDTLS_CIPHER_C
#define MBEDTLS_CTR_DRBG_C
#define MBEDTLS_ENTROPY_C
#define MBEDTLS_MD_C
#define MBEDTLS_NET_C
#define MBEDTLS_SHA256_C
#define MBEDTLS_SSL_CLI_C
#define MBEDTLS_SSL_COOKIE_C
#define MBEDTLS_SSL_SRV_C
#define MBEDTLS_SSL_TLS_C
#define MBEDTLS_TIMING_C
/* TLS protocol feature support */
#define MBEDTLS_KEY_EXCHANGE_PSK_ENABLED
#define MBEDTLS_SSL_PROTO_TLS1_2
#define MBEDTLS_SSL_PROTO_DTLS
#define MBEDTLS_SSL_DTLS_ANTI_REPLAY
#define MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE
#define MBEDTLS_SSL_DTLS_CONNECTION_ID
#define MBEDTLS_SSL_DTLS_HELLO_VERIFY
#define MBEDTLS_SSL_MAX_FRAGMENT_LENGTH
/*
* Use only CCM_8 ciphersuites, and
* save ROM and a few bytes of RAM by specifying our own ciphersuite list
*/
#define MBEDTLS_SSL_CIPHERSUITES \
MBEDTLS_TLS_PSK_WITH_AES_256_CCM_8, \
MBEDTLS_TLS_PSK_WITH_AES_128_CCM_8
/*
* Save RAM at the expense of interoperability: do this only if you control
* both ends of the connection! (See comments in "mbedtls/ssl.h".)
* The optimal size here depends on the typical size of records.
*/
#define MBEDTLS_SSL_IN_CONTENT_LEN 256
#define MBEDTLS_SSL_OUT_CONTENT_LEN 256
/* Save RAM at the expense of ROM */
#define MBEDTLS_AES_ROM_TABLES
/* Save some RAM by adjusting to your exact needs */
#define MBEDTLS_PSK_MAX_LEN 16 /* 128-bits keys are generally enough */
/*
* You should adjust this to the exact number of sources you're using: default
* is the "platform_entropy_poll" source, but you may want to add other ones
* Minimum is 2 for the entropy test suite.
*/
#define MBEDTLS_ENTROPY_MAX_SOURCES 2
/* These defines are present so that the config modifying scripts can enable
* them during tests/scripts/test-ref-configs.pl */
//#define MBEDTLS_USE_PSA_CRYPTO
//#define MBEDTLS_PSA_CRYPTO_C
/* Error messages and TLS debugging traces
* (huge code size increase, needed for tests/ssl-opt.sh) */
//#define MBEDTLS_DEBUG_C
//#define MBEDTLS_ERROR_C

View File

@ -0,0 +1,83 @@
/**
* \file config-ccm-psk-tls1_2.h
*
* \brief Minimal configuration for TLS 1.2 with PSK and AES-CCM ciphersuites
*/
/*
* Copyright The Mbed TLS Contributors
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
*/
/*
* Minimal configuration for TLS 1.2 with PSK and AES-CCM ciphersuites
*
* Distinguishing features:
* - Optimized for small code size, low bandwidth (on a reliable transport),
* and low RAM usage.
* - No asymmetric cryptography (no certificates, no Diffie-Hellman key
* exchange).
* - Fully modern and secure (provided the pre-shared keys are generated and
* stored securely).
* - Very low record overhead with CCM-8.
*
* See README.txt for usage instructions.
*/
/* System support */
//#define MBEDTLS_HAVE_TIME /* Optionally used in Hello messages */
/* Other MBEDTLS_HAVE_XXX flags irrelevant for this configuration */
/* Mbed TLS modules */
#define MBEDTLS_AES_C
#define MBEDTLS_CCM_C
#define MBEDTLS_CIPHER_C
#define MBEDTLS_CTR_DRBG_C
#define MBEDTLS_ENTROPY_C
#define MBEDTLS_MD_C
#define MBEDTLS_NET_C
#define MBEDTLS_SHA256_C
#define MBEDTLS_SSL_CLI_C
#define MBEDTLS_SSL_SRV_C
#define MBEDTLS_SSL_TLS_C
/* TLS protocol feature support */
#define MBEDTLS_KEY_EXCHANGE_PSK_ENABLED
#define MBEDTLS_SSL_PROTO_TLS1_2
/*
* Use only CCM_8 ciphersuites, and
* save ROM and a few bytes of RAM by specifying our own ciphersuite list
*/
#define MBEDTLS_SSL_CIPHERSUITES \
MBEDTLS_TLS_PSK_WITH_AES_256_CCM_8, \
MBEDTLS_TLS_PSK_WITH_AES_128_CCM_8
/*
* Save RAM at the expense of interoperability: do this only if you control
* both ends of the connection! (See comments in "mbedtls/ssl.h".)
* The optimal size here depends on the typical size of records.
*/
#define MBEDTLS_SSL_IN_CONTENT_LEN 1024
#define MBEDTLS_SSL_OUT_CONTENT_LEN 1024
/* Save RAM at the expense of ROM */
#define MBEDTLS_AES_ROM_TABLES
/* Save some RAM by adjusting to your exact needs */
#define MBEDTLS_PSK_MAX_LEN 16 /* 128-bits keys are generally enough */
/*
* You should adjust this to the exact number of sources you're using: default
* is the "platform_entropy_poll" source, but you may want to add other ones
* Minimum is 2 for the entropy test suite.
*/
#define MBEDTLS_ENTROPY_MAX_SOURCES 2
/* These defines are present so that the config modifying scripts can enable
* them during tests/scripts/test-ref-configs.pl */
//#define MBEDTLS_USE_PSA_CRYPTO
//#define MBEDTLS_PSA_CRYPTO_C
/* Error messages and TLS debugging traces
* (huge code size increase, needed for tests/ssl-opt.sh) */
//#define MBEDTLS_DEBUG_C
//#define MBEDTLS_ERROR_C

View File

@ -0,0 +1,73 @@
/**
* \file config-no-entropy.h
*
* \brief Minimal configuration of features that do not require an entropy source
*/
/*
* Copyright The Mbed TLS Contributors
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
*/
/*
* Minimal configuration of features that do not require an entropy source
* Distinguishing features:
* - no entropy module
* - no TLS protocol implementation available due to absence of an entropy
* source
*
* See README.txt for usage instructions.
*/
/* System support */
#define MBEDTLS_HAVE_ASM
#define MBEDTLS_HAVE_TIME
/* Mbed TLS feature support */
#define MBEDTLS_CIPHER_MODE_CBC
#define MBEDTLS_CIPHER_PADDING_PKCS7
#define MBEDTLS_ECP_DP_SECP256R1_ENABLED
#define MBEDTLS_ECP_DP_SECP384R1_ENABLED
#define MBEDTLS_ECP_DP_CURVE25519_ENABLED
#define MBEDTLS_ECP_NIST_OPTIM
#define MBEDTLS_ECDSA_DETERMINISTIC
#define MBEDTLS_PK_RSA_ALT_SUPPORT
#define MBEDTLS_PKCS1_V15
#define MBEDTLS_PKCS1_V21
#define MBEDTLS_SELF_TEST
#define MBEDTLS_VERSION_FEATURES
/* Mbed TLS modules */
#define MBEDTLS_AES_C
#define MBEDTLS_ASN1_PARSE_C
#define MBEDTLS_ASN1_WRITE_C
#define MBEDTLS_BASE64_C
#define MBEDTLS_BIGNUM_C
#define MBEDTLS_CCM_C
#define MBEDTLS_CIPHER_C
#define MBEDTLS_ECDSA_C
#define MBEDTLS_ECP_C
#define MBEDTLS_ERROR_C
#define MBEDTLS_GCM_C
#define MBEDTLS_HMAC_DRBG_C
#define MBEDTLS_MD_C
#define MBEDTLS_OID_C
#define MBEDTLS_PEM_PARSE_C
#define MBEDTLS_PK_C
#define MBEDTLS_PK_PARSE_C
#define MBEDTLS_PK_WRITE_C
#define MBEDTLS_PLATFORM_C
#define MBEDTLS_RSA_C
/* The library does not currently support enabling SHA-224 without SHA-256.
* A future version of the library will have this option disabled
* by default. */
#define MBEDTLS_SHA224_C
#define MBEDTLS_SHA256_C
#define MBEDTLS_SHA384_C
#define MBEDTLS_SHA512_C
#define MBEDTLS_VERSION_C
#define MBEDTLS_X509_USE_C
#define MBEDTLS_X509_CRT_PARSE_C
#define MBEDTLS_X509_CRL_PARSE_C
//#define MBEDTLS_CMAC_C
/* Miscellaneous options */
#define MBEDTLS_AES_ROM_TABLES

View File

@ -0,0 +1,106 @@
/**
* \file config-suite-b.h
*
* \brief Minimal configuration for TLS NSA Suite B Profile (RFC 6460)
*/
/*
* Copyright The Mbed TLS Contributors
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
*/
/*
* Minimal configuration for TLS NSA Suite B Profile (RFC 6460)
*
* Distinguishing features:
* - no RSA or classic DH, fully based on ECC
* - optimized for low RAM usage
*
* Possible improvements:
* - if 128-bit security is enough, disable secp384r1 and SHA-512
* - use embedded certs in DER format and disable PEM_PARSE_C and BASE64_C
*
* See README.txt for usage instructions.
*/
/* System support */
#define MBEDTLS_HAVE_ASM
#define MBEDTLS_HAVE_TIME
/* Mbed TLS feature support */
#define MBEDTLS_ECP_DP_SECP256R1_ENABLED
#define MBEDTLS_ECP_DP_SECP384R1_ENABLED
#define MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
#define MBEDTLS_SSL_PROTO_TLS1_2
/* Mbed TLS modules */
#define MBEDTLS_AES_C
#define MBEDTLS_ASN1_PARSE_C
#define MBEDTLS_ASN1_WRITE_C
#define MBEDTLS_BIGNUM_C
#define MBEDTLS_CIPHER_C
#define MBEDTLS_CTR_DRBG_C
#define MBEDTLS_ECDH_C
#define MBEDTLS_ECDSA_C
#define MBEDTLS_ECP_C
#define MBEDTLS_ENTROPY_C
#define MBEDTLS_GCM_C
#define MBEDTLS_MD_C
#define MBEDTLS_NET_C
#define MBEDTLS_OID_C
#define MBEDTLS_PK_C
#define MBEDTLS_PK_PARSE_C
#define MBEDTLS_SHA256_C
#define MBEDTLS_SHA384_C
#define MBEDTLS_SHA512_C
#define MBEDTLS_SSL_CLI_C
#define MBEDTLS_SSL_SRV_C
#define MBEDTLS_SSL_TLS_C
#define MBEDTLS_X509_CRT_PARSE_C
#define MBEDTLS_X509_USE_C
/* For test certificates */
#define MBEDTLS_BASE64_C
#define MBEDTLS_PEM_PARSE_C
/* Save RAM at the expense of ROM */
#define MBEDTLS_AES_ROM_TABLES
/* Save RAM by adjusting to our exact needs */
#define MBEDTLS_MPI_MAX_SIZE 48 // 384-bit EC curve = 48 bytes
/* Save RAM at the expense of speed, see ecp.h */
#define MBEDTLS_ECP_WINDOW_SIZE 2
#define MBEDTLS_ECP_FIXED_POINT_OPTIM 0
/* Significant speed benefit at the expense of some ROM */
#define MBEDTLS_ECP_NIST_OPTIM
/*
* You should adjust this to the exact number of sources you're using: default
* is the "mbedtls_platform_entropy_poll" source, but you may want to add other ones.
* Minimum is 2 for the entropy test suite.
*/
#define MBEDTLS_ENTROPY_MAX_SOURCES 2
/* Save ROM and a few bytes of RAM by specifying our own ciphersuite list */
#define MBEDTLS_SSL_CIPHERSUITES \
MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, \
MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
/*
* Save RAM at the expense of interoperability: do this only if you control
* both ends of the connection! (See comments in "mbedtls/ssl.h".)
* The minimum size here depends on the certificate chain used as well as the
* typical size of records.
*/
#define MBEDTLS_SSL_IN_CONTENT_LEN 1024
#define MBEDTLS_SSL_OUT_CONTENT_LEN 1024
/* These defines are present so that the config modifying scripts can enable
* them during tests/scripts/test-ref-configs.pl */
//#define MBEDTLS_USE_PSA_CRYPTO
//#define MBEDTLS_PSA_CRYPTO_C
/* Error messages and TLS debugging traces
* (huge code size increase, needed for tests/ssl-opt.sh) */
//#define MBEDTLS_DEBUG_C
//#define MBEDTLS_ERROR_C

View File

@ -0,0 +1,77 @@
/**
* \file config-symmetric-only.h
*
* \brief Configuration without any asymmetric cryptography.
*/
/*
* Copyright The Mbed TLS Contributors
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
*/
/* System support */
//#define MBEDTLS_HAVE_ASM
#define MBEDTLS_HAVE_TIME
#define MBEDTLS_HAVE_TIME_DATE
/* Mbed TLS feature support */
#define MBEDTLS_CIPHER_MODE_CBC
#define MBEDTLS_CIPHER_MODE_CFB
#define MBEDTLS_CIPHER_MODE_CTR
#define MBEDTLS_CIPHER_MODE_OFB
#define MBEDTLS_CIPHER_MODE_XTS
#define MBEDTLS_CIPHER_PADDING_PKCS7
#define MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS
#define MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN
#define MBEDTLS_CIPHER_PADDING_ZEROS
#define MBEDTLS_ERROR_STRERROR_DUMMY
#define MBEDTLS_FS_IO
#define MBEDTLS_ENTROPY_NV_SEED
#define MBEDTLS_SELF_TEST
#define MBEDTLS_USE_PSA_CRYPTO
#define MBEDTLS_VERSION_FEATURES
/* Mbed TLS modules */
#define MBEDTLS_AES_C
#define MBEDTLS_ASN1_PARSE_C
#define MBEDTLS_ASN1_WRITE_C
#define MBEDTLS_BASE64_C
#define MBEDTLS_CAMELLIA_C
#define MBEDTLS_ARIA_C
#define MBEDTLS_CCM_C
#define MBEDTLS_CHACHA20_C
#define MBEDTLS_CHACHAPOLY_C
#define MBEDTLS_CIPHER_C
#define MBEDTLS_CMAC_C
#define MBEDTLS_CTR_DRBG_C
#define MBEDTLS_DES_C
#define MBEDTLS_ENTROPY_C
#define MBEDTLS_ERROR_C
#define MBEDTLS_GCM_C
#define MBEDTLS_HKDF_C
#define MBEDTLS_HMAC_DRBG_C
#define MBEDTLS_NIST_KW_C
#define MBEDTLS_MD_C
#define MBEDTLS_MD5_C
#define MBEDTLS_OID_C
#define MBEDTLS_PEM_PARSE_C
#define MBEDTLS_PEM_WRITE_C
#define MBEDTLS_PKCS5_C
#define MBEDTLS_PKCS12_C
#define MBEDTLS_PLATFORM_C
#define MBEDTLS_POLY1305_C
#define MBEDTLS_PSA_CRYPTO_C
#define MBEDTLS_PSA_CRYPTO_SE_C
#define MBEDTLS_PSA_CRYPTO_STORAGE_C
#define MBEDTLS_PSA_ITS_FILE_C
#define MBEDTLS_RIPEMD160_C
#define MBEDTLS_SHA1_C
/* The library does not currently support enabling SHA-224 without SHA-256.
* A future version of the library will have this option disabled
* by default. */
#define MBEDTLS_SHA224_C
#define MBEDTLS_SHA256_C
#define MBEDTLS_SHA384_C
#define MBEDTLS_SHA512_C
//#define MBEDTLS_THREADING_C
#define MBEDTLS_TIMING_C
#define MBEDTLS_VERSION_C

View File

@ -0,0 +1,68 @@
/**
* \file config-tfm.h
*
* \brief TF-M medium profile, adapted to work on other platforms.
*/
/*
* Copyright The Mbed TLS Contributors
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
*/
/* TF-M medium profile: mbedtls legacy configuration */
#include "../configs/ext/tfm_mbedcrypto_config_profile_medium.h"
/* TF-M medium profile: PSA crypto configuration */
#define MBEDTLS_PSA_CRYPTO_CONFIG_FILE "../configs/ext/crypto_config_profile_medium.h"
/***********************************************************/
/* 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
// 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
/*
* In order to get an example config that works cleanly out-of-the-box
* for both baremetal and non-baremetal builds, we detect baremetal builds
* (either IAR, Arm compiler or __ARM_EABI__ defined), and adjust some
* variables accordingly.
*/
#if defined(__IAR_SYSTEMS_ICC__) || defined(__ARMCC_VERSION) || defined(__ARM_EABI__)
#define MBEDTLS_NO_PLATFORM_ENTROPY
#else
/* Use built-in platform entropy functions (TF-M provides its own). */
#undef MBEDTLS_NO_PLATFORM_ENTROPY
#endif
/***********************************************************************
* Local changes to crypto config below this delimiter
**********************************************************************/
// We expect TF-M to pick this up soon
#define MBEDTLS_BLOCK_CIPHER_NO_DECRYPT
/* CCM is the only cipher/AEAD enabled in TF-M configuration files, but it
* does not need CIPHER_C to be enabled, so we can disable it in order
* to reduce code size further. */
#undef MBEDTLS_CIPHER_C

View File

@ -0,0 +1,76 @@
/**
* \file config-thread.h
*
* \brief Minimal configuration for using TLS as part of Thread
*/
/*
* Copyright The Mbed TLS Contributors
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
*/
/*
* Minimal configuration for using TLS a part of Thread
* http://threadgroup.org/
*
* Distinguishing features:
* - no RSA or classic DH, fully based on ECC
* - no X.509
* - support for experimental EC J-PAKE key exchange
*
* See README.txt for usage instructions.
*/
/* System support */
#define MBEDTLS_HAVE_ASM
/* Mbed TLS feature support */
#define MBEDTLS_AES_ROM_TABLES
#define MBEDTLS_ECP_DP_SECP256R1_ENABLED
#define MBEDTLS_ECP_NIST_OPTIM
#define MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED
#define MBEDTLS_SSL_MAX_FRAGMENT_LENGTH
#define MBEDTLS_SSL_PROTO_TLS1_2
#define MBEDTLS_SSL_PROTO_DTLS
#define MBEDTLS_SSL_DTLS_ANTI_REPLAY
#define MBEDTLS_SSL_DTLS_HELLO_VERIFY
/* Mbed TLS modules */
#define MBEDTLS_AES_C
#define MBEDTLS_ASN1_PARSE_C
#define MBEDTLS_ASN1_WRITE_C
#define MBEDTLS_BIGNUM_C
#define MBEDTLS_CCM_C
#define MBEDTLS_CIPHER_C
#define MBEDTLS_CTR_DRBG_C
#define MBEDTLS_CMAC_C
#define MBEDTLS_ECJPAKE_C
#define MBEDTLS_ECP_C
#define MBEDTLS_ENTROPY_C
#define MBEDTLS_HMAC_DRBG_C
#define MBEDTLS_MD_C
#define MBEDTLS_OID_C
#define MBEDTLS_PK_C
#define MBEDTLS_PK_PARSE_C
#define MBEDTLS_SHA256_C
#define MBEDTLS_SSL_COOKIE_C
#define MBEDTLS_SSL_CLI_C
#define MBEDTLS_SSL_SRV_C
#define MBEDTLS_SSL_TLS_C
/* For tests using ssl-opt.sh */
#define MBEDTLS_NET_C
#define MBEDTLS_TIMING_C
/* Save RAM at the expense of ROM */
#define MBEDTLS_AES_ROM_TABLES
/* Save RAM by adjusting to our exact needs */
#define MBEDTLS_MPI_MAX_SIZE 32 // 256-bit EC curve = 32 bytes
/* Save ROM and a few bytes of RAM by specifying our own ciphersuite list */
#define MBEDTLS_SSL_CIPHERSUITES MBEDTLS_TLS_ECJPAKE_WITH_AES_128_CCM_8
/* These defines are present so that the config modifying scripts can enable
* them during tests/scripts/test-ref-configs.pl */
//#define MBEDTLS_USE_PSA_CRYPTO
//#define MBEDTLS_PSA_CRYPTO_C

View File

@ -0,0 +1,25 @@
/**
* \file configs/crypto-config-ccm-aes-sha256.h
*
* \brief PSA crypto configuration with only symmetric cryptography: CCM-AES,
* SHA-256, HMAC and key derivation
*/
/*
* 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_HMAC 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_HMAC 1
#define PSA_WANT_KEY_TYPE_AES 1
#define PSA_WANT_KEY_TYPE_RAW_DATA 1
#endif /* PSA_CRYPTO_CONFIG_H */

View File

@ -0,0 +1,25 @@
Summary
-------
The two files:
* crypto_config_profile_medium.h
* tfm_mbedcrypto_config_profile_medium.h
are copyright The Mbed TLS Contributors, and are distributed under the license normally
used by Mbed TLS: a dual Apache 2.0 or GPLv2-or-later license.
Background
----------
The two files crypto_config_profile_medium.h and tfm_mbedcrypto_config_profile_medium.h
are taken verbatim from the TF-M source code here:
https://git.trustedfirmware.org/TF-M/trusted-firmware-m.git/tree/lib/ext/mbedcrypto/mbedcrypto_config
In TF-M, they 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, they are 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.
We only retain the note at the top of the files because we are taking the files verbatim, for ease of
maintenance.

View File

@ -0,0 +1,13 @@
/*
* Empty placeholder
*
* Copyright The Mbed TLS Contributors
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
*/
/*
* This file is intentionally empty.
*
* Having an empty file here allows us to build the TF-M config, which references this file,
* without making any changes to the TF-M config.
*/

View File

@ -0,0 +1,132 @@
/*
* 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)
*
*/
#if defined(MBEDTLS_PSA_CRYPTO_CONFIG)
/**
* When #MBEDTLS_PSA_CRYPTO_CONFIG is enabled in mbedtls_config.h,
* this file determines which cryptographic mechanisms are enabled
* through the PSA Cryptography API (\c psa_xxx() functions).
*
* To enable a cryptographic mechanism, uncomment the definition of
* the corresponding \c PSA_WANT_xxx preprocessor symbol.
* To disable a cryptographic mechanism, comment out the definition of
* the corresponding \c PSA_WANT_xxx preprocessor symbol.
* The names of cryptographic mechanisms correspond to values
* defined in psa/crypto_values.h, with the prefix \c PSA_WANT_ instead
* of \c PSA_.
*
* Note that many cryptographic mechanisms involve two symbols: one for
* the key type (\c PSA_WANT_KEY_TYPE_xxx) and one for the algorithm
* (\c PSA_WANT_ALG_xxx). Mechanisms with additional parameters may involve
* additional symbols.
*/
#else
/**
* When \c MBEDTLS_PSA_CRYPTO_CONFIG is disabled in mbedtls_config.h,
* this file is not used, and cryptographic mechanisms are supported
* through the PSA API if and only if they are supported through the
* mbedtls_xxx API.
*/
#endif
#ifndef PROFILE_M_PSA_CRYPTO_CONFIG_H
#define PROFILE_M_PSA_CRYPTO_CONFIG_H
/*
* 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_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_ECDSA 1
//#define PSA_WANT_ALG_GCM 1
#define PSA_WANT_ALG_HKDF 1
#define PSA_WANT_ALG_HMAC 1
//#define PSA_WANT_ALG_MD5 1
//#define PSA_WANT_ALG_OFB 1
/* PBKDF2-HMAC is not yet supported via the PSA API in Mbed TLS.
* Note: when adding support, also adjust include/mbedtls/config_psa.h */
//#define PSA_WANT_ALG_PBKDF2_HMAC 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_STREAM_CIPHER 1
#define PSA_WANT_ALG_TLS12_PRF 1
#define PSA_WANT_ALG_TLS12_PSK_TO_MS 1
/* PBKDF2-HMAC is not yet supported via the PSA API in Mbed TLS.
* Note: when adding support, also adjust include/mbedtls/config_psa.h */
//#define PSA_WANT_ALG_XTS 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_192 1
/*
* SECP224K1 is buggy via the PSA API in Mbed TLS
* (https://github.com/Mbed-TLS/mbedtls/issues/3541). Thus, do not enable it by
* default.
*/
//#define PSA_WANT_ECC_SECP_K1_224 1
//#define PSA_WANT_ECC_SECP_K1_256 1
//#define PSA_WANT_ECC_SECP_R1_192 1
//#define PSA_WANT_ECC_SECP_R1_224 1
#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_KEY_TYPE_DERIVE 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_DES 1
//#define PSA_WANT_KEY_TYPE_ECC_KEY_PAIR 1 /* Deprecated */
#define PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY 1
#define PSA_WANT_KEY_TYPE_RAW_DATA 1
//#define PSA_WANT_KEY_TYPE_RSA_KEY_PAIR 1 /* Deprecated */
//#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
#ifdef CRYPTO_HW_ACCELERATOR
#include "crypto_accelerator_config.h"
#endif
#endif /* PROFILE_M_PSA_CRYPTO_CONFIG_H */

View File

@ -0,0 +1,13 @@
/*
* Empty placeholder
*
* Copyright The Mbed TLS Contributors
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
*/
/*
* This file is intentionally empty.
*
* Having an empty file here allows us to build the TF-M config, which references this file,
* without making any changes to the TF-M config.
*/

View File

@ -0,0 +1,573 @@
/**
* \file config.h
*
* \brief Configuration options (set of defines)
*
* This set of compile-time options may be used to enable
* or disable features selectively, and reduce the global
* memory footprint.
*/
/*
* Copyright (C) 2006-2023, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* 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.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
#ifndef PROFILE_M_MBEDTLS_CONFIG_H
#define PROFILE_M_MBEDTLS_CONFIG_H
#include "config_tfm.h"
#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_DEPRECATE)
#define _CRT_SECURE_NO_DEPRECATE 1
#endif
/**
* \name SECTION: System support
*
* This section sets system specific settings.
* \{
*/
/**
* \def MBEDTLS_HAVE_ASM
*
* The compiler has support for asm().
*
* Requires support for asm() in compiler.
*
* Used in:
* library/aria.c
* library/timing.c
* include/mbedtls/bn_mul.h
*
* Required by:
* MBEDTLS_AESNI_C
* MBEDTLS_PADLOCK_C
*
* Comment to disable the use of assembly code.
*/
#define MBEDTLS_HAVE_ASM
/**
* \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.
*
* Requires: MBEDTLS_PLATFORM_C
*
* Enable this layer to allow use of alternative memory allocators.
*/
#define MBEDTLS_PLATFORM_MEMORY
/* \} name SECTION: System support */
/**
* \name SECTION: mbed TLS feature support
*
* This section sets support for features that are or are not needed
* within the modules that are enabled.
* \{
*/
/**
* \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_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_NO_PLATFORM_ENTROPY
*
* Do not use built-in platform entropy functions.
* This is useful if your platform does not support
* standards like the /dev/urandom or Windows CryptoAPI.
*
* Uncomment this macro to disable the built-in platform entropy functions.
*/
#define MBEDTLS_NO_PLATFORM_ENTROPY
/**
* \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_ENTROPY_C, 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_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).
*
* Module: library/psa_crypto.c
* Requires: MBEDTLS_PSA_CRYPTO_C
*
*/
#define MBEDTLS_PSA_CRYPTO_SPM
/**
* \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 reasonnable 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
/**
* \def MBEDTLS_PSA_CRYPTO_CONFIG
*
* This setting allows support for cryptographic mechanisms through the PSA
* API to be configured separately from support through the mbedtls API.
*
* When this option is disabled, the PSA API exposes the cryptographic
* mechanisms that can be implemented on top of the `mbedtls_xxx` API
* configured with `MBEDTLS_XXX` symbols.
*
* When this option is enabled, the PSA API exposes the cryptographic
* mechanisms requested by the `PSA_WANT_XXX` symbols defined in
* include/psa/crypto_config.h. The corresponding `MBEDTLS_XXX` settings are
* automatically enabled if required (i.e. if no PSA driver provides the
* mechanism). You may still freely enable additional `MBEDTLS_XXX` symbols
* in mbedtls_config.h.
*
* If the symbol #MBEDTLS_PSA_CRYPTO_CONFIG_FILE is defined, it specifies
* an alternative header to include instead of include/psa/crypto_config.h.
*
* This feature is still experimental and is not ready for production since
* it is not completed.
*/
#define MBEDTLS_PSA_CRYPTO_CONFIG
/* \} name SECTION: mbed TLS feature support */
/**
* \name SECTION: mbed TLS modules
*
* This section enables or disables entire modules in mbed TLS
* \{
*/
/**
* \def MBEDTLS_AES_C
*
* Enable the AES block cipher.
*
* Module: library/aes.c
* Caller: library/cipher.c
* library/pem.c
* library/ctr_drbg.c
*
* This module is required to support the TLS ciphersuites that use the AES
* cipher.
*
* PEM_PARSE uses AES for decrypting encrypted keys.
*/
#define MBEDTLS_AES_C
/**
* \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: library/aes.c
*
* Requires: MBEDTLS_AES_C
*/
#define MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH
/**
* \def MBEDTLS_CIPHER_C
*
* Enable the generic cipher layer.
*
* Module: library/cipher.c
*
* Uncomment to enable generic cipher wrappers.
*/
#define MBEDTLS_CIPHER_C
/**
* \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, enable MBEDTLS_CTR_DRBG_USE_128_BIT_KEY below.
*
* Module: library/ctr_drbg.c
* Caller:
*
* Requires: MBEDTLS_AES_C
*
* This module provides the CTR_DRBG AES random number generator.
*/
#define MBEDTLS_CTR_DRBG_C
/**
* \def MBEDTLS_ENTROPY_C
*
* Enable the platform-specific entropy code.
*
* Module: library/entropy.c
* Caller:
*
* Requires: MBEDTLS_SHA512_C or MBEDTLS_SHA256_C
*
* This module provides a generic entropy pool
*/
#define MBEDTLS_ENTROPY_C
/**
* \def MBEDTLS_HKDF_C
*
* Enable the HKDF algorithm (RFC 5869).
*
* Module: library/hkdf.c
* Caller:
*
* Requires: MBEDTLS_MD_C
*
* This module adds support for the Hashed Message Authentication Code
* (HMAC)-based key derivation function (HKDF).
*/
//#define MBEDTLS_HKDF_C /* Used for HUK deriviation */
/**
* \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: library/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 module rely on it for a fixed snprintf implementation.
*
* Module: library/platform.c
* Caller: Most other .c files
*
* This module enables abstraction of common (libc) functions.
*/
#define MBEDTLS_PLATFORM_C
#define MBEDTLS_PLATFORM_NO_STD_FUNCTIONS
#define MBEDTLS_PLATFORM_STD_MEM_HDR <stdlib.h>
#include <stdio.h>
#define MBEDTLS_PLATFORM_SNPRINTF_MACRO snprintf
#define MBEDTLS_PLATFORM_PRINTF_ALT
#define MBEDTLS_PLATFORM_STD_EXIT_SUCCESS EXIT_SUCCESS
#define MBEDTLS_PLATFORM_STD_EXIT_FAILURE EXIT_FAILURE
/**
* \def MBEDTLS_PSA_CRYPTO_C
*
* Enable the Platform Security Architecture cryptography API.
*
* Module: library/psa_crypto.c
*
* Requires: MBEDTLS_CTR_DRBG_C, MBEDTLS_ENTROPY_C
*
*/
#define MBEDTLS_PSA_CRYPTO_C
/**
* \def MBEDTLS_PSA_CRYPTO_STORAGE_C
*
* Enable the Platform Security Architecture persistent key storage.
*
* Module: library/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
/* \} name SECTION: mbed TLS modules */
/**
* \name SECTION: General configuration options
*
* This section contains Mbed TLS build settings that are not associated
* with a particular module.
*
* \{
*/
/**
* \def MBEDTLS_CONFIG_FILE
*
* If defined, this is a header which will be included instead of
* `"mbedtls/mbedtls_config.h"`.
* This header file specifies the compile-time configuration of Mbed TLS.
* Unlike other configuration options, this one must be defined on the
* compiler command line: a definition in `mbedtls_config.h` would have
* no effect.
*
* This macro is expanded after an <tt>\#include</tt> directive. This is a popular but
* non-standard feature of the C language, so this feature is only available
* with compilers that perform macro expansion on an <tt>\#include</tt> line.
*
* The value of this symbol is typically a path in double quotes, either
* absolute or relative to a directory on the include search path.
*/
//#define MBEDTLS_CONFIG_FILE "mbedtls/mbedtls_config.h"
/**
* \def MBEDTLS_USER_CONFIG_FILE
*
* If defined, this is a header which will be included after
* `"mbedtls/mbedtls_config.h"` or #MBEDTLS_CONFIG_FILE.
* This allows you to modify the default configuration, including the ability
* to undefine options that are enabled by default.
*
* This macro is expanded after an <tt>\#include</tt> directive. This is a popular but
* non-standard feature of the C language, so this feature is only available
* with compilers that perform macro expansion on an <tt>\#include</tt> line.
*
* The value of this symbol is typically a path in double quotes, either
* absolute or relative to a directory on the include search path.
*/
//#define MBEDTLS_USER_CONFIG_FILE "/dev/null"
/**
* \def MBEDTLS_PSA_CRYPTO_CONFIG_FILE
*
* If defined, this is a header which will be included instead of
* `"psa/crypto_config.h"`.
* This header file specifies which cryptographic mechanisms are available
* through the PSA API when #MBEDTLS_PSA_CRYPTO_CONFIG is enabled, and
* is not used when #MBEDTLS_PSA_CRYPTO_CONFIG is disabled.
*
* This macro is expanded after an <tt>\#include</tt> directive. This is a popular but
* non-standard feature of the C language, so this feature is only available
* with compilers that perform macro expansion on an <tt>\#include</tt> line.
*
* The value of this symbol is typically a path in double quotes, either
* absolute or relative to a directory on the include search path.
*/
//#define MBEDTLS_PSA_CRYPTO_CONFIG_FILE "psa/crypto_config.h"
/**
* \def MBEDTLS_PSA_CRYPTO_USER_CONFIG_FILE
*
* If defined, this is a header which will be included after
* `"psa/crypto_config.h"` or #MBEDTLS_PSA_CRYPTO_CONFIG_FILE.
* This allows you to modify the default configuration, including the ability
* to undefine options that are enabled by default.
*
* This macro is expanded after an <tt>\#include</tt> directive. This is a popular but
* non-standard feature of the C language, so this feature is only available
* with compilers that perform macro expansion on an <tt>\#include</tt> line.
*
* The value of this symbol is typically a path in double quotes, either
* absolute or relative to a directory on the include search path.
*/
//#define MBEDTLS_PSA_CRYPTO_USER_CONFIG_FILE "/dev/null"
/** \} name SECTION: General configuration options */
/**
* \name SECTION: Module configuration options
*
* This section allows for the setting of module specific sizes and
* configuration options. The default values are already present in the
* relevant header files and should suffice for the regular use cases.
*
* Our advice is to enable options and change their values here
* only if you have a good reason and know the consequences.
*
* Please check the respective header file for documentation on these
* parameters (to prevent duplicate documentation).
* \{
*/
/* ECP options */
#define MBEDTLS_ECP_FIXED_POINT_OPTIM 0 /**< Disable fixed-point speed-up */
/**
* 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
* when #MBEDTLS_USE_PSA_CRYPTO is enabled.
* - 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 and #MBEDTLS_PSA_CRYPTO_CONFIG for PSA-based
* configuration;
* - #MBEDTLS_USE_PSA_CRYPTO if you want to use p256-m from PK, X.509 or TLS;
* - #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
/* \} name SECTION: Customisation configuration options */
#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 "mbedtls_accelerator_config.h"
#endif
#endif /* PROFILE_M_MBEDTLS_CONFIG_H */

37
lib/mbedtls/external/mbedtls/dco.txt vendored Normal file
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.

View File

@ -0,0 +1,4 @@
*.html
*.pdf
_build/
api/

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,40 @@
# Minimal makefile for Sphinx documentation
#
# You can set these variables from the command line, and also
# from the environment for the first two.
SPHINXOPTS ?=
SPHINXBUILD ?= sphinx-build
SOURCEDIR = .
BUILDDIR = _build
# Put it first so that "make" without argument is like "make help".
help:
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
.PHONY: help clean apidoc breathe_apidoc Makefile
# Intercept the 'clean' target so we can do the right thing for apidoc as well
clean:
@# Clean the apidoc
$(MAKE) -C .. apidoc_clean
@# Clean the breathe-apidoc generated files
rm -rf ./api
@# Clean the sphinx docs
@$(SPHINXBUILD) -M clean "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
apidoc:
@# Generate doxygen from source using the main Makefile
$(MAKE) -C .. apidoc
breathe_apidoc: apidoc
@# Remove existing files - breathe-apidoc skips them if they're present
rm -rf ./api
@# Generate RST file structure with breathe-apidoc
breathe-apidoc -o ./api ../apidoc/xml
# Catch-all target: route all unknown targets to Sphinx using the new
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
%: Makefile breathe_apidoc
@# Build the relevant target with sphinx
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)

View File

@ -0,0 +1,21 @@
PANDOC = pandoc
default: all
all_markdown = $(wildcard *.md */*.md)
html: $(all_markdown:.md=.html)
pdf: $(all_markdown:.md=.pdf)
all: html pdf
.SUFFIXES:
.SUFFIXES: .md .html .pdf
.md.html:
$(PANDOC) -o $@ $<
.md.pdf:
$(PANDOC) -o $@ $<
clean:
rm -f *.html *.pdf
rm -f testing/*.html testing/*.pdf

View File

@ -0,0 +1,91 @@
Alternative implementations of Mbed TLS functionality
=====================================================
This document describes how parts of the Mbed TLS functionality can be replaced at compile time to integrate the library on a platform.
This document is an overview. It is not exhaustive. Please consult the documentation of individual modules and read the library header files for more details.
## Platform integration
Mbed TLS works out of the box on Unix/Linux/POSIX-like systems and on Windows. On embedded platforms, you may need to customize some aspects of how Mbed TLS interacts with the underlying platform. This section discusses the main areas that can be configured.
The platform module (`include/mbedtls/platform.h`) controls how Mbed TLS accesses standard library features such as memory management (`calloc`, `free`), `printf`, `exit`. You can define custom functions instead of the ones from the C standard library through `MBEDTLS_PLATFORM_XXX` options in the configuration file. Many options have two mechanisms: either define `MBEDTLS_PLATFORM_XXX_MACRO` to the name of a function to call instead of the standard function `xxx`, or define `MBEDTLS_PLATFORM_XXX_ALT` and [register an alternative implementation during the platform setup](#alternative-implementations-of-platform-functions).
The storage of the non-volatile seed for random generation, enabled with `MBEDTLS_ENTROPY_NV_SEED`, is also controlled via the platform module.
For timing functions, you can [declare an alternative implementation of the timing module](#module-alternative-implementations).
On multithreaded platforms, [declare an alternative implementation of the threading module](#module-alternative-implementations).
To configure entropy sources (hardware random generators), see the `MBEDTLS_ENTROPY_XXX` options in the configuration file.
For networking, the `net_sockets` module does not currently support alternative implementations. If this module does not work on your platform, disable `MBEDTLS_NET_C` and use custom functions for TLS.
If your platform has a cryptographic accelerator, you can use it via a [PSA driver](#psa-cryptography-drivers) or declare an [alternative implementation of the corresponding module(s)](#module-alternative-implementations) or [of specific functions](#function-alternative-implementations). PSA drivers will ultimately replace the alternative implementation mechanism, but alternative implementation will remain supported in at least all Mbed TLS versions of the form 3.x. The interface of PSA drivers is currently still experimental and subject to change.
## PSA cryptography drivers
On platforms where a hardware cryptographic engine is present, you can implement a driver for this engine in the PSA interface. Drivers are supported for cryptographic operations with transparent keys (keys available in cleartext), for cryptographic operations with opaque keys (keys that are only available inside the cryptographic engine), and for random generation. Calls to `psa_xxx` functions that perform cryptographic operations are directed to drivers instead of the built-in code as applicable. See the [PSA cryptography driver interface specification](docs/proposed/psa-driver-interface.md), the [Mbed TLS PSA driver developer guide](docs/proposed/psa-driver-developer-guide.md) and the [Mbed TLS PSA driver integration guide](docs/proposed/psa-driver-integration-guide.md) for more information.
As of Mbed TLS 3.0, this interface is still experimental and subject to change, and not all operations support drivers yet. The configuration option `MBEDTLS_USE_PSA_CRYPTO` causes parts of the `mbedtls_xxx` API to use PSA crypto and therefore to support drivers, however it is not yet compatible with all drivers.
## Module alternative implementations
You can replace the code of some modules of Mbed TLS at compile time by a custom implementation. This is possible for low-level cryptography modules (symmetric algorithms, DHM, RSA, ECP, ECJPAKE) and for some platform-related modules (threading, timing). Such custom implementations are called “alternative implementations”, or “ALT implementations” for short.
The general principle of an alternative implementation is:
* Enable `MBEDTLS_XXX_ALT` in the compile-time configuration where XXX is the module name. For example, `MBEDTLS_AES_ALT` for an implementation of the AES module. This is in addition to enabling `MBEDTLS_XXX_C`.
* Create a header file `xxx_alt.h` that defines the context type(s) used by the module. For example, `mbedtls_aes_context` for AES.
* Implement all the functions from the module, i.e. the functions declared in `include/mbedtls/xxx.h`.
See https://mbed-tls.readthedocs.io/en/latest/kb/development/hw_acc_guidelines for a more detailed guide.
### Constraints on context types
Generally, alternative implementations can define their context types to any C type except incomplete and array types (although they would normally be `struct` types). This section lists some known limitations where the context type needs to be a structure with certain fields.
Where a context type needs to have a certain field, the field must have the same type and semantics as in the built-in implementation, but does not need to be at the same position in the structure. Furthermore, unless otherwise indicated, only read access is necessary: the field can be `const`, and modifications to it do not need to be supported. For example, if an alternative implementation of asymmetric cryptography uses a different representation of large integers, it is sufficient to provide a read-only copy of the fields listed here of type `mbedtls_mpi`.
* AES: if `MBEDTLS_AESNI_C` or `MBEDTLS_PADLOCK_C` is enabled, `mbedtls_aes_context` must have the fields `nr` and `rk`.
* DHM: if `MBEDTLS_DEBUG_C` is enabled, `mbedtls_dhm_context` must have the fields `P`, `Q`, `G`, `GX`, `GY` and `K`.
* ECP: `mbedtls_ecp_group` must have the fields `id`, `P`, `A`, `B`, `G`, `N`, `pbits` and `nbits`.
* If `MBEDTLS_PK_PARSE_EC_EXTENDED` is enabled, those fields must be writable, and `mbedtls_ecp_point_read_binary()` must support a group structure where only `P`, `pbits`, `A` and `B` are set.
It must be possible to move a context object in memory (except during the execution of a library function that takes this context as an argument). (This is necessary, for example, to support applications that populate a context on the stack of an inner function and then copy the context upwards through the call chain, or applications written in a language with automatic memory management that can move objects on the heap.) That is, call sequences like the following must work:
```
mbedtls_xxx_context ctx1, ctx2;
mbedtls_xxx_init(&ctx1);
mbedtls_xxx_setup(&ctx1, …);
ctx2 = ctx1;
memset(&ctx1, 0, sizeof(ctx1));
mbedtls_xxx_do_stuff(&ctx2, …);
mbedtls_xxx_free(&ctx2);
```
In practice, this means that a pointer to a context or to a part of a context does not remain valid across function calls. Alternative implementations do not need to support copying of contexts: contexts can only be cloned through explicit `clone()` functions.
## Function alternative implementations
In some cases, it is possible to replace a single function or a small set of functions instead of [providing an alternative implementation of the whole module](#module-alternative-implementations).
### Alternative implementations of cryptographic functions
Options to replace individual functions of cryptographic modules generally have a name obtained by upper-casing the function name and appending `_ALT`. If the function name contains `_internal`, `_ext` or `_ret`, this is removed in the `_ALT` symbol. When the corresponding option is enabled, the built-in implementation of the function will not be compiled, and you must provide an alternative implementation at link time.
For example, enable `MBEDTLS_AES_ENCRYPT_ALT` at compile time and provide your own implementation of `mbedtls_aes_encrypt()` to provide an accelerated implementation of AES encryption that is compatible with the built-in key schedule. If you wish to implement key schedule differently, you can also enable `MBEDTLS_AES_SETKEY_ENC_ALT` and implement `mbedtls_aes_setkey_enc()`.
Another example: enable `MBEDTLS_SHA256_PROCESS_ALT` and implement `mbedtls_internal_sha256_process()` to provide an accelerated implementation of SHA-256 and SHA-224.
Note that since alternative implementations of individual functions cooperate with the built-in implementation of other functions, you must use the same layout for context objects as the built-in implementation. If you want to use different context types, you need to [provide an alternative implementation of the whole module](#module-alternative-implementations).
### Alternative implementations of platform functions
Several platform functions can be reconfigured dynamically by following the process described here. To reconfigure how Mbed TLS calls the standard library function `xxx()`:
* Define the symbol `MBEDTLS_PLATFORM_XXX_ALT` at compile time.
* During the initialization of your application, set the global variable `mbedtls_xxx` to an alternative implementation of `xxx()`.
For example, to provide a custom `printf` function at run time, enable `MBEDTLS_PLATFORM_PRINTF_ALT` at compile time and assign to `mbedtls_printf` during the initialization of your application.
Merely enabling `MBEDTLS_PLATFORM_XXX_ALT` does not change the behavior: by default, `mbedtls_xxx` points to the standard function `xxx`.
Note that there are variations on the naming pattern. For example, some configurable functions are activated in pairs, such as `mbedtls_calloc` and `mbedtls_free` via `MBEDTLS_PLATFORM_MEMORY`. Consult the documentation of individual configuration options and of the platform module for details.

View File

@ -0,0 +1,467 @@
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.

View File

@ -0,0 +1,175 @@
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/include/test/drivers/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)
* [ ] `scripts/mbedtls_dev/crypto_knowledge.py`, `scripts/mbedtls_dev/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:
* If `MBEDTLS_PSA_CRYPTO_CONFIG` is disabled: based on the available mechanisms in Mbed TLS, deduced from `mbedtls/mbedtls_config.h` by code in `include/mbedtls/config_psa.h`.
* if `MBEDTLS_PSA_CRYPTO_CONFIG` is enabled: 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/include/test/drivers/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 `tests/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:
* `scripts/mbedtls_dev/crypto_knowledge.py` contains knowledge about the compatibility of key types, key sizes and algorithms.
* `scripts/mbedtls_dev/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.

View File

@ -0,0 +1,616 @@
PSA migration strategy for hashes and ciphers
=============================================
## Introduction
This document discusses a migration strategy for code that is not subject to `MBEDTLS_USE_PSA_CRYPTO`, is currently using legacy cryptography APIs, and should transition to PSA, without a major version change.
### Relationship with the main strategy document
This is complementary to the main [strategy document](strategy.html) and is intended as a refinement. However, at this stage, there may be contradictions between the strategy proposed here and some of the earlier strategy.
A difference between the original strategy and the current one is that in this work, we are not treating PSA as a black box. We can change experimental features, and we can call internal interfaces.
## Requirements
### User stories
#### Backward compatibility user story
As a developer of an application that uses Mbed TLS's interfaces (including legacy crypto),
I want Mbed TLS to preserve backward compatibility,
so that my code keeps working in new minor versions of Mbed TLS.
#### Interface design user story
As a developer of library code that uses Mbed TLS to perform cryptographic operations,
I want to know which functions to call and which feature macros to check,
so that my code works in all Mbed TLS configurations.
Note: this is the same problem we face in X.509 and TLS.
#### Hardware accelerator vendor user stories
As a vendor of a platform with hardware acceleration for some crypto,
I want to build Mbed TLS in a way that uses my hardware wherever relevant,
so that my customers maximally benefit from my hardware.
As a vendor of a platform with hardware acceleration for some crypto,
I want to build Mbed TLS without software that replicates what my hardware does,
to minimize the code size.
#### Maintainer user stories
As a maintainer of Mbed TLS,
I want to have clear rules for when to use which interface,
to avoid bugs in “unusual” configurations.
As a maintainer of Mbed TLS,
I want to avoid duplicating code,
because this is inefficient and error-prone.
### Use PSA more
In the long term, all code using cryptography should use PSA interfaces, to benefit from PSA drivers, allow eliminating legacy interfaces (less code size, less maintenance). However, this can't be done without breaking [backward compatibility](#backward-compatibility).
The goal of this work is to arrange for more non-PSA interfaces to use PSA interfaces under the hood, without breaking code in the cases where this doesn't work. Using PSA interfaces has two benefits:
* Where a PSA driver is available, it likely has better performance, and sometimes better security, than the built-in software implementation.
* In many scenarios, where a PSA driver is available, this allows removing the software implementation altogether.
* We may be able to get rid of some redundancies, for example the duplication between the implementations of HMAC in `md.c` and in `psa_crypto_mac.c`, and HKDF in `hkdf.c` and `psa_crypto.c`.
### Correct dependencies
Traditionally, to determine whether a cryptographic mechanism was available, you had to check whether the corresponding Mbed TLS module or submodule was present: `MBEDTLS_SHA256_C` for SHA256, `MBEDTLS_AES_C && MBEDTLS_CIPHER_MODE_CBC` for AES-CBC, etc. In code that uses the PSA interfaces, this needs to change to `PSA_WANT_xxx` symbols.
### Backward compatibility
All documented behavior must be preserved, except for interfaces currently described as experimental or unstable. Those interfaces can change, but we should minimize disruption by providing a transition path for reasonable use cases.
#### Changeable configuration options
The following configuration options are described as experimental, and are likely to change at least marginally:
* `MBEDTLS_PSA_CRYPTO_CLIENT`: “This interface is experimental and may change or be removed without notice.” In practice we don't want to remove this, but we may constrain how it's used.
* `MBEDTLS_PSA_CRYPTO_DRIVERS`: “This interface is experimental. We intend to maintain backward compatibility with application code that relies on drivers, but the driver interfaces may change without notice.” In practice, this may mean constraints not only on how to write drivers, but also on how to integrate drivers into code that is platform code more than application code.
* `MBEDTLS_PSA_CRYPTO_CONFIG`: “This feature is still experimental and is not ready for production since it is not completed.” We may want to change this, for example, to automatically enable more mechanisms (although this wouldn't be considered a backward compatibility break anyway, since we don't promise that you will not get a feature if you don't enable its `PSA_WANT_xxx`).
### Non-goals
It is not a goal at this stage to make more code directly call `psa_xxx` functions. Rather, the goal is to make more code call PSA drivers where available. How dispatch is done is secondary.
## Problem analysis
### Scope analysis
#### Limitations of `MBEDTLS_USE_PSA_CRYPTO`
The option `MBEDTLS_USE_PSA_CRYPTO` causes parts of the library to call the PSA API instead of legacy APIs for cryptographic calculations. `MBEDTLS_USE_PSA_CRYPTO` only applies to `pk.h`, X.509 and TLS. When this option is enabled, applications must call `psa_crypto_init()` before calling any of the functions in these modules.
In this work, we want two things:
* Make non-covered modules call PSA, but only [when this will actually work](#why-psa-is-not-always-possible). This effectively brings those modules to a partial use-PSA behavior (benefiting from PSA accelerators when they're usable) regardless of whether the option is enabled.
* Call PSA when a covered module calls a non-covered module which calls another module, for example X.509 calling pk for PSS verification which calls RSA which calculates a hash ([see issue \#6497](https://github.com/Mbed-TLS/mbedtls/issues/6497)). This effectively extends the option to modules that aren't directly covered.
#### Classification of callers
We can classify code that implements or uses cryptographic mechanisms into several groups:
* Software implementations of primitive cryptographic mechanisms. These are not expected to change.
* Software implementations of constructed cryptographic mechanisms (e.g. HMAC, CTR_DRBG, RSA (calling a hash for PSS/OAEP, and needing to know the hash length in PKCS1v1.5 sign/verify), …). These need to keep working whenever a legacy implementation of the auxiliary mechanism is available, regardless of whether a PSA implementation is also available.
* Code implementing the PSA crypto interface. This is not expected to change, except perhaps to expose some internal functionality to overhauled glue code.
* Code that's subject to `MBEDTLS_USE_PSA_CRYPTO`: `pk.h`, X.509, TLS (excluding parts specific TLS 1.3).
* Code that always uses PSA for crypto: TLS 1.3 (except things common with 1.2), LMS.
For the purposes of this work, three domains emerge:
* **Legacy domain**: does not interact with PSA. Implementations of hashes, of cipher primitives, of arithmetic.
* **Mixed domain**: does not currently use PSA, but should [when possible](#why-psa-is-not-always-possible). This consists of the constructed cryptographic primitives (except LMS), as well as pk, X.509 and TLS when `MBEDTLS_USE_PSA_CRYPTO` is disabled.
* **PSA domain**: includes pk, X.509 and TLS when `MBEDTLS_USE_PSA_CRYPTO` is enabled. Also TLS 1.3, LMS.
#### Non-use-PSA modules
The following modules in Mbed TLS call another module to perform cryptographic operations which, in the long term, will be provided through a PSA interface, but cannot make any PSA-related assumption.
Hashes and HMAC (after the work on driver-only hashes):
* entropy (hashes via MD-light)
* ECDSA (HMAC\_DRBG; `md.h` exposed through API)
* ECJPAKE (hashes via MD-light; `md.h` exposed through API)
* MD (hashes and HMAC)
* HKDF (HMAC via `md.h`; `md.h` exposed through API)
* HMAC\_DRBG (hashes and HMAC via `md.h`; `md.h` exposed through API)
* PKCS12 (hashes via MD-light)
* PKCS5 (HMAC via `md.h`; `md.h` exposed through API)
* PKCS7 (hashes via MD)
* RSA (hash via MD-light for PSS and OAEP; `md.h` exposed through API)
* PEM (MD5 hash via MD-light)
Symmetric ciphers and AEADs (before work on driver-only cipher):
* PEM:
* AES, DES or 3DES in CBC mode without padding, decrypt only (!).
* Currently using low-level non-generic APIs.
* No hard dependency, features guarded by `AES_C` resp. `DES_C`.
* Functions called: `setkey_dec()` + `crypt_cbc()`.
* PKCS12:
* In practice: 2DES or 3DES in CBC mode with PKCS7 padding, decrypt only
(when called from pkparse).
* In principle: any cipher-mode (default padding), passed an
`mbedtls_cipher_type_t` as an argument, no documented restriction.
* Cipher, generically, selected from ASN.1 or function parameters;
no documented restriction but in practice TODO (inc. padding and
en/decrypt, look at standards and tests)
* Unconditional dependency on `CIPHER_C` in `check_config.h`.
* Note: `cipher.h` exposed through API.
* Functions called: `setup`, `setkey`, `set_iv`, `reset`, `update`, `finish` (in sequence, once).
* PKCS5 (PBES2, `mbedtls_pkcs5_pbes2()`):
* 3DES or DES in CBC mode with PKCS7 padding, both encrypt and decrypt.
* Note: could also be AES in the future, see #7038.
* Unconditional dependency on `CIPHER_C` in `check_config.h`.
* Functions called: `setup`, `setkey`, `crypt`.
* CTR\_DRBG:
* AES in ECB mode, encrypt only.
* Currently using low-level non-generic API (`aes.h`).
* Unconditional dependency on `AES_C` in `check_config.h`.
* Functions called: `setkey_enc`, `crypt_ecb`.
* CCM:
* AES, Camellia or Aria in ECB mode, encrypt only.
* Unconditional dependency on `AES_C || CAMELLIA_C || ARIA_C` in `check_config.h`.
* Unconditional dependency on `CIPHER_C` in `check_config.h`.
* Note: also called by `cipher.c` if enabled.
* Functions called: `info`, `setup`, `setkey`, `update` (several times) - (never finish)
* CMAC:
* AES or DES in ECB mode, encrypt only.
* Unconditional dependency on `AES_C || DES_C` in `check_config.h`.
* Unconditional dependency on `CIPHER_C` in `check_config.h`.
* Note: also called by `cipher.c` if enabled.
* Functions called: `info`, `setup`, `setkey`, `update` (several times) - (never finish)
* GCM:
* AES, Camellia or Aria in ECB mode, encrypt only.
* Unconditional dependency on `AES_C || CAMELLIA_C || ARIA_C` in `check_config.h`.
* Unconditional dependency on `CIPHER_C` in `check_config.h`.
* Note: also called by `cipher.c` if enabled.
* Functions called: `info`, `setup`, `setkey`, `update` (several times) - (never finish)
* NIST\_KW:
* AES in ECB mode, both encryt and decrypt.
* Unconditional dependency on `AES_C || DES_C` in `check_config.h`.
* Unconditional dependency on `CIPHER_C` in `check_config.h`.
* Note: also called by `cipher.c` if enabled.
* Note: `cipher.h` exposed through API.
* Functions called: `info`, `setup`, `setkey`, `update` (several times) - (never finish)
* Cipher:
* potentially any cipher/AEAD in any mode and any direction
Note: PSA cipher is built on Cipher, but PSA AEAD directly calls the underlying AEAD modules (GCM, CCM, ChachaPoly).
### Difficulties
#### Why PSA is not always possible
Here are some reasons why calling `psa_xxx()` to perform a hash or cipher calculation might not be desirable in some circumstances, explaining why the application would arrange to call the legacy software implementation instead.
* `MBEDTLS_PSA_CRYPTO_C` is disabled.
* There is a PSA driver which has not been initialized (this happens in `psa_crypto_init()`).
* For ciphers, the keystore is not initialized yet, and Mbed TLS uses a custom implementation of PSA ITS where the file system is not accessible yet (because something else needs to happen first, and the application takes care that it happens before it calls `psa_crypto_init()`). A possible workaround may be to dispatch to the internal functions that are called after the keystore lookup, rather than to the PSA API functions (but this is incompatible with `MBEDTLS_PSA_CRYPTO_CLIENT`).
* The requested mechanism is enabled in the legacy interface but not in the PSA interface. This was not really intended, but is possible, for example, if you enable `MBEDTLS_MD5_C` for PEM decoding with PBKDF1 but don't want `PSA_ALG_WANT_MD5` because it isn't supported for `PSA_ALG_RSA_PSS` and `PSA_ALG_DETERMINISTIC_ECDSA`.
* `MBEDTLS_PSA_CRYPTO_CLIENT` is enabled, and the client has not yet activated the connection to the server (this happens in `psa_crypto_init()`).
* `MBEDTLS_PSA_CRYPTO_CLIENT` is enabled, but the operation is part of the implementation of an encrypted communication with the crypto service, or the local implementation is faster because it avoids a costly remote procedure call.
#### Indirect knowledge
Consider for example the code in `rsa.c` to perform an RSA-PSS signature. It needs to calculate a hash. If `mbedtls_rsa_rsassa_pss_sign()` is called directly by application code, it is supposed to call the built-in implementation: calling a PSA accelerator would be a behavior change, acceptable only if this does not add a risk of failure or performance degradation ([PSA is impossible or undesirable in some circumstances](#why-psa-is-not-always-possible)). Note that this holds regardless of the state of `MBEDTLS_USE_PSA_CRYPTO`, since `rsa.h` is outside the scope of `MBEDTLS_USE_PSA_CRYPTO`. On the other hand, if `mbedtls_rsa_rsassa_pss_sign()` is called from X.509 code, it should use PSA to calculate hashes. It doesn't, currently, which is [bug \#6497](https://github.com/Mbed-TLS/mbedtls/issues/6497).
Generally speaking, modules in the mixed domain:
* must call PSA if called by a module in the PSA domain;
* must not call PSA (or must have a fallback) if their caller is not in the PSA domain and the PSA call is not guaranteed to work.
#### Non-support guarantees: requirements
Generally speaking, just because some feature is not enabled in `mbedtls_config.h` or `psa_config.h` doesn't guarantee that it won't be enabled in the build. We can enable additional features through `build_info.h`.
If `PSA_WANT_xxx` is disabled, this should guarantee that attempting xxx through the PSA API will fail. This is generally guaranteed by the test suite `test_suite_psa_crypto_not_supported` with automatically enumerated test cases, so it would be inconvenient to carve out an exception.
### Technical requirements
Based on the preceding analysis, the core of the problem is: for code in the mixed domain (see [“Classification of callers”](#classification-of-callers)), how do we handle a cryptographic mechanism? This has several related subproblems:
* How the mechanism is encoded (e.g. `mbedtls_md_type_t` vs `const *mbedtls_md_info_t` vs `psa_algorithm_t` for hashes).
* How to decide whether a specific algorithm or key type is supported (eventually based on `MBEDTLS_xxx_C` vs `PSA_WANT_xxx`).
* How to obtain metadata about algorithms (e.g. hash/MAC/tag size, key size).
* How to perform the operation (context type, which functions to call).
We need a way to decide this based on the available information:
* Who's the ultimate caller — see [indirect knowledge](#indirect-knowledge) — which is not actually available.
* Some parameter indicating which algorithm to use.
* The available cryptographic implementations, based on preprocessor symbols (`MBEDTLS_xxx_C`, `PSA_WANT_xxx`, `MBEDTLS_PSA_ACCEL_xxx`, etc.).
* Possibly additional runtime state (for example, we might check whether `psa_crypto_init` has been called).
And we need to take care of the [the cases where PSA is not possible](#why-psa-is-not-always-possible): either make sure the current behavior is preserved, or (where allowed by backward compatibility) document a behavior change and, preferably, a workaround.
### Working through an example: RSA-PSS
Let us work through the example of RSA-PSS which calculates a hash, as in [see issue \#6497](https://github.com/Mbed-TLS/mbedtls/issues/6497).
RSA is in the [mixed domain](#classification-of-callers). So:
* When called from `psa_sign_hash` and other PSA functions, it must call the PSA hash accelerator if there is one.
* When called from user code, it must call the built-in hash implementation if PSA is not available (regardless of whether this is because `MBEDTLS_PSA_CRYPTO_C` is disabled, or because `PSA_WANT_ALG_xxx` is disabled for this hash, or because there is an accelerator driver which has not been initialized yet).
RSA knows which hash algorithm to use based on a parameter of type `mbedtls_md_type_t`. (More generally, all mixed-domain modules that take an algorithm specification as a parameter take it via a numerical type, except HMAC\_DRBG and HKDF which take a `const mbedtls_md_info_t*` instead, and CMAC which takes a `const mbedtls_cipher_info_t *`.)
#### Double encoding solution
A natural solution is to double up the encoding of hashes in `mbedtls_md_type_t`. Pass `MBEDTLS_MD_SHA256` and `md` will dispatch to the legacy code, pass a new constant `MBEDTLS_MD_SHA256_USE_PSA` and `md` will dispatch through PSA.
This maximally preserves backward compatibility, but then no non-PSA code benefits from PSA accelerators, and there's little potential for removing the software implementation.
#### Availability of hashes in RSA-PSS
Here we try to answer the question: As a caller of RSA-PSS via `rsa.h`, how do I know whether it can use a certain hash?
* For a caller in the legacy domain: if e.g. `MBEDTLS_SHA256_C` is enabled, then I want RSA-PSS to support SHA-256. I don't care about negative support. So `MBEDTLS_SHA256_C` must imply support for RSA-PSS-SHA-256. It must work at all times, regardless of the state of PSA (e.g. drivers not initialized).
* For a caller in the PSA domain: if e.g. `PSA_WANT_ALG_SHA_256` is enabled, then I want RSA-PSS to support SHA-256, provided that `psa_crypto_init()` has been called. In some limited cases, such as `test_suite_psa_crypto_not_supported` when PSA implements RSA-PSS in software, we care about negative support: if `PSA_WANT_ALG_SHA_256` is disabled then `psa_verify_hash` must reject `PSA_WANT_ALG_SHA_256`. This can be done at the level of PSA before it calls the RSA module, though, so it doesn't have any implication on the RSA module. As far as `rsa.c` is concerned, what matters is that `PSA_WANT_ALG_SHA_256` implies that SHA-256 is supported after `psa_crypto_init()` has been called.
* For a caller in the mixed domain: requirements depend on the caller. Whatever solution RSA has to determine the availability of algorithms will apply to its caller as well.
Conclusion so far: RSA must be able to do SHA-256 if either `MBEDTLS_SHA256_C` or `PSA_WANT_ALG_SHA_256` is enabled. If only `PSA_WANT_ALG_SHA_256` and not `MBEDTLS_SHA256_C` is enabled (which implies that PSA's SHA-256 comes from an accelerator driver), then SHA-256 only needs to work if `psa_crypto_init()` has been called.
#### More in-depth discussion of compile-time availability determination
The following combinations of compile-time support are possible:
* `MBEDTLS_PSA_CRYPTO_CLIENT`. Then calling PSA may or may not be desirable for performance. There are plausible use cases where only the server has access to an accelerator so it's best to call the server, and plausible use cases where calling the server has overhead that negates the savings from using acceleration, if there are savings at all. In any case, calling PSA only works if the connection to the server has been established, meaning `psa_crypto_init` has been called successfully. In the rest of this case enumeration, assume `MBEDTLS_PSA_CRYPTO_CLIENT` is disabled.
* No PSA accelerator. Then just call `mbedtls_sha256`, it's all there is, and it doesn't matter (from an API perspective) exactly what call chain leads to it.
* PSA accelerator, no software implementation. Then we might as well call the accelerator, unless it's important that the call fails. At the time of writing, I can't think of a case where we would want to guarantee that if `MBEDTLS_xxx_C` is not enabled, but xxx is enabled through PSA, then a request to use algorithm xxx through some legacy interface must fail.
* Both PSA acceleration and the built-in implementation. In this case, we would prefer PSA for the acceleration, but we can only do this if the accelerator driver is working. For hashes, it's enough to assume the driver is initialized; we've [considered requiring hash drivers to work without initialization](https://github.com/Mbed-TLS/mbedtls/pull/6470). For ciphers, this is more complicated because the cipher functions require the keystore, and plausibly a cipher accelerator might want entropy (for side channel countermeasures) which might not be available at boot time.
Note that it's a bit tricky to determine which algorithms are available. In the case where there is a PSA accelerator but no software implementation, we don't want the preprocessor symbols to indicate that the algorithm is available through the legacy domain, only through the PSA domain. What does this mean for the interfaces in the mixed domain? They can't guarantee the availability of the algorithm, but they must try if requested.
### Designing an interface for hashes
In this section, we specify a hash metadata and calculation for the [mixed domain](#classification-of-callers), i.e. code that can be called both from legacy code and from PSA code.
#### Availability of hashes
Generalizing the analysis in [“Availability of hashes in RSA-PSS”](#availability-of-hashes-in-RSA-PSS):
A hash is available through the mixed-domain interface iff either of the following conditions is true:
* A legacy hash interface is available and the hash algorithm is implemented in software.
* PSA crypto is enabled and the hash algorithm is implemented via PSA.
We could go further and make PSA accelerators available to legacy callers that call any legacy hash interface, e.g. `md.h` or `shaX.h`. There is little point in doing this, however: callers should just use the mixed-domain interface.
#### Implications between legacy availability and PSA availability
* When `MBEDTLS_PSA_CRYPTO_CONFIG` is disabled, all legacy mechanisms are automatically enabled through PSA. Users can manually enable PSA mechanisms that are available through accelerators but not through legacy, but this is not officially supported (users are not supposed to manually define PSA configuration symbols when `MBEDTLS_PSA_CRYPTO_CONFIG` is disabled).
* When `MBEDTLS_PSA_CRYPTO_CONFIG` is enabled, there is no mandatory relationship between PSA support and legacy support for a mechanism. Users can configure legacy support and PSA support independently. Legacy support is automatically enabled if PSA support is requested, but only if there is no accelerator.
It is strongly desirable to allow mechanisms available through PSA but not legacy: this allows saving code size when an accelerator is present.
There is no strong reason to allow mechanisms available through legacy but not PSA when `MBEDTLS_PSA_CRYPTO_C` is enabled. This would only save at best a very small amount of code size in the PSA dispatch code. This may be more desirable when `MBEDTLS_PSA_CRYPTO_CLIENT` is enabled (having a mechanism available only locally and not in the crypto service), but we do not have an explicit request for this and it would be entirely reasonable to forbid it.
In this analysis, we have not found a compelling reason to require all legacy mechanisms to also be available through PSA. However, this can simplify both the implementation and the use of dispatch code thanks to some simplifying properties:
* Mixed-domain code can call PSA code if it knows that `psa_crypto_init()` has been called, without having to inspect the specifics of algorithm support.
* Mixed-domain code can assume that PSA buffer calculations work correctly for all algorithms that it supports.
#### Shape of the mixed-domain hash interface
We now need to create an abstraction for mixed-domain hash calculation. (We could not create an abstraction, but that would require every piece of mixed-domain code to replicate the logic here. We went that route in Mbed TLS 3.3, but it made it effectively impossible to get something that works correctly.)
Requirements: given a hash algorithm,
* Obtain some metadata about it (size, block size).
* Calculate the hash.
* Set up a multipart operation to calculate the hash. The operation must support update, finish, reset, abort, clone.
The existing interface in `md.h` is close to what we want, but not perfect. What's wrong with it?
* It has an extra step of converting from `mbedtls_md_type_t` to `const mbedtls_md_info_t *`.
* It includes extra fluff such as names and HMAC. This costs code size.
* The md module has some legacy baggage dating from when it was more open, which we don't care about anymore. This may cost code size.
These problems are easily solvable.
* `mbedtls_md_info_t` can become a very thin type. We can't remove the extra function call from the source code of callers, but we can make it a very thin abstraction that compilers can often optimize.
* We can make names and HMAC optional. The mixed-domain hash interface won't be the full `MBEDTLS_MD_C` but a subset.
* We can optimize `md.c` without making API changes to `md.h`.
### Scope reductions and priorities for 3.x
This section documents things that we chose to temporarily exclude from the scope in the 3.x branch (which will eventually be in scope again after 4.0) as well as things we chose to prioritize if we don't have time to support everything.
#### Don't support PK, X.509 and TLS without `MBEDTLS_USE_PSA_CRYPTO`
We do not need to support driver-only hashes and ciphers in PK. X.509 and TLS without `MBEDTLS_USE_PSA_CRYPTO`. Users who want to take full advantage of drivers will need to enabled this macro.
Note that this applies to TLS 1.3 as well, as some uses of hashes and all uses of ciphers there are common with TLS 1.2, hence governed by `MBEDTLS_USE_PSA_CRYPTO`, see [this macro's extended documentation](../../docs/use-psa-crypto.html).
This will go away naturally in 4.0 when this macros is not longer an option (because it's always on).
#### Don't support for `MBEDTLS_PSA_CRYPTO_CLIENT` without `MBEDTLS_PSA_CRYPTO_C`
We generally don't really support builds with `MBEDTLS_PSA_CRYPTO_CLIENT` without `MBEDTLS_PSA_CRYPTO_C`. For example, both `MBEDTLS_USE_PSA_CRYPTO` and `MBEDTLS_SSL_PROTO_TLS1_3` require `MBEDTLS_PSA_CRYPTO_C`, while in principle they should only require `MBEDTLS_PSA_CRYPTO_CLIENT`.
Considering this existing restriction which we do not plan to lift before 4.0, it is acceptable driver-only hashes and cipher support to have the same restriction in 3.x.
It is however desirable for the design to keep support for `MBEDTLS_PSA_CRYPTO_CLIENT` in mind, in order to avoid making it more difficult to add in the future.
#### For cipher: prioritize constrained devices and modern TLS
The primary target is a configuration like TF-M's medium profile, plus TLS with only AEAD ciphersuites.
This excludes things like:
- Support for encrypted PEM, PKCS5 and PKCS12 encryption, and PKCS8 encrypted keys in PK parse. (Not widely used on highly constrained devices.)
- Support for NIST-KW. (Same justification.)
- Support for CMAC. (Same justification, plus can be directly accelerated.)
- Support for CBC ciphersuites in TLS. (They've been recommended against for a while now.)
### Dual-dispatch for block cipher primitives
Considering the priorities stated above, initially we want to support GCM, CCM and CTR-DRBG. All three of them use the block cipher primitive only in the encrypt direction. Currently, GCM and CCM use the Cipher layer in order to work with AES, Aria and Camellia (DES is excluded by the standards due to its smaller block size) and CTR-DRBG directly uses the low-level API from `aes.h`. In all cases, access to the "block cipher primitive" is done by using "ECB mode" (which for both Cipher and `aes.h` only allows a single block, contrary to PSA which implements actual ECB mode).
The two AEAD modes, GCM and CCM, have very similar needs and positions in the stack, strongly suggesting using the same design for both. On the other hand, there are a number of differences between CTR-DRBG and them.
- CTR-DRBG only uses AES (and there is no plan to extend it to other block ciphers at the moment), while GCM and CCM need to work with 3 block ciphers already.
- CTR-DRBG holds a special position in the stack: most users don't care about it per se, they only care about getting random numbers - in fact PSA users don't even need to know what DRBG is used. In particular, no part of the stack is asking questions like "is CTR-DRBG-AES available?" - an RNG needs to be available and that's it - contrary to similar questions about AES-GCM etc. which are asked for example by TLS.
So, it makes sense to use different designs for CTR-DRBG on one hand, and GCM/CCM on the other hand:
- CTR-DRBG can just check if `AES_C` is present and "fall back" to PSA if not.
- GCM and CCM need an common abstraction layer that allows:
- Using AES, Aria or Camellia in a uniform way.
- Dispatching to built-in or driver.
The abstraction layer used by GCM and CCM may either be a new internal module, or a subset of the existing Cipher API, extended with the ability to dispatch to a PSA driver.
Reasons for making this layer's API a subset of the existing Cipher API:
- No need to design, implement and test a new module. (Will need to test the new subset though, as well as the extended behaviour.)
- No code change in GCM and CCM - only need to update dependencies.
- No risk for code duplication between a potential new module and Cipher: source-level, and in in particular in builds that still have `CIPHER_C` enabled. (Compiled-code duplication could be avoided by excluding the new module in such builds, though.)
- If want to support other users of Cipher later (such as NIST-KW, CMAC, PKCS5 and PKCS12), we can just extend dual-dispatch support to other modes/operations in Cipher and keep those extra modules unchanged as well.
Possible costs of re-using (a subset of) the existing Cipher API instead of defining a new one:
- We carry over costs associated with `cipher_info_t` structures. (Currently the info structure is used for 3 things: (1) to check if the cipher is supported, (2) to check its block size, (3) because `setup()` requires it).
- We carry over questionable implementation decisions, like dynamic allocation of context.
Those costs could be avoided by refactoring (parts of) Cipher, but that would probably mean either:
- significant differences in how the `cipher.h` API is implemented between builds with the full Cipher or only a subset;
- or more work to apply the simplifications to all of Cipher.
Prototyping both approaches showed better code size savings and cleaner code with a new internal module (see section "Internal "block cipher" abstraction (Cipher light)" below).
## Specification
### MD light
#### Definition of MD light
MD light is a subset of `md.h` that implements the hash calculation interface described in ”[Designing an interface for hashes](#designing-an-interface-for-hashes)”. It is activated by `MBEDTLS_MD_LIGHT` in `mbedtls_config.h`.
The following things enable MD light automatically in `build_info.h`:
* A [mixed-domain](#classification-of-callers) module that needs to calculate hashes is enabled.
* `MBEDTLS_MD_C` is enabled.
MD light includes the following types:
* `mbedtls_md_type_t`
* `mbedtls_md_info_t`
* `mbedtls_md_context_t`
MD light includes the following functions:
* `mbedtls_md_info_from_type`
* `mbedtls_md_init`
* `mbedtls_md_free`
* `mbedtls_md_setup` — but `hmac` must be 0 if `MBEDTLS_MD_C` is disabled.
* `mbedtls_md_clone`
* `mbedtls_md_get_size`
* `mbedtls_md_get_type`
* `mbedtls_md_starts`
* `mbedtls_md_update`
* `mbedtls_md_finish`
* `mbedtls_md`
Unlike the full MD, MD light does not support null pointers as `mbedtls_md_context_t *`. At least some functions still need to support null pointers as `const mbedtls_md_info_t *` because this arises when you try to use an unsupported algorithm (`mbedtls_md_info_from_type` returns `NULL`).
#### MD algorithm support macros
For each hash algorithm, `md.h` defines a macro `MBEDTLS_MD_CAN_xxx` whenever the corresponding hash is available through MD light. These macros are only defined when `MBEDTLS_MD_LIGHT` is enabled. Per “[Availability of hashes](#availability-of-hashes)”, `MBEDTLS_MD_CAN_xxx` is enabled if:
* the corresponding `MBEDTLS_xxx_C` is defined; or
* one of `MBEDTLS_PSA_CRYPTO_C` or `MBEDTLS_PSA_CRYPTO_CLIENT` is enabled, and the corresponding `PSA_WANT_ALG_xxx` is enabled.
Note that some algorithms have different spellings in legacy and PSA. Since MD is a legacy interface, we'll use the legacy names. Thus, for example:
```
#if defined(MBEDTLS_MD_LIGHT)
#if defined(MBEDTLS_SHA256_C) || \
(defined(MBEDTLS_PSA_CRYPTO_C) && PSA_WANT_ALG_SHA_256)
#define MBEDTLS_MD_CAN_SHA256
#endif
#endif
```
Note: in the future, we may want to replace `defined(MBEDTLS_PSA_CRYPTO_C)`
with `defined(MBEDTLS_PSA_CRYTO_C) || defined(MBEDTLS_PSA_CRYPTO_CLIENT)` but
for now this is out of scope.
#### MD light internal support macros
* If at least one hash has a PSA driver, define `MBEDTLS_MD_SOME_PSA`.
* If at least one hash has a legacy implementation, defined `MBEDTLS_MD_SOME_LEGACY`.
#### Support for PSA in the MD context
An MD context needs to contain either a legacy module's context (or a pointer to one, as is the case now), or a PSA context (or a pointer to one).
I am inclined to remove the pointer indirection, but this means that an MD context would always be as large as the largest supported hash context. So for the time being, this specification keeps a pointer. For uniformity, PSA will also have a pointer (we may simplify this later).
```
enum {
MBEDTLS_MD_ENGINE_LEGACY,
MBEDTLS_MD_ENGINE_PSA,
} mbedtls_md_engine_t; // private type
typedef struct mbedtls_md_context_t {
mbedtls_md_type_t type;
#if defined(MBEDTLS_MD_SOME_PSA)
mbedtls_md_engine_t engine;
#endif
void *md_ctx; // mbedtls_xxx_context or psa_hash_operation
#if defined(MBEDTLS_MD_C)
void *hmac_ctx;
#endif
} mbedtls_md_context_t;
```
All fields are private.
The `engine` field is almost redundant with knowledge about `type`. However, when an algorithm is available both via a legacy module and a PSA accelerator, we will choose based on the runtime availability of the accelerator when the context is set up. This choice needs to be recorded in the context structure.
#### Inclusion of MD info structures
MD light needs to support hashes that are only enabled through PSA. Therefore the `mbedtls_md_info_t` structures must be included based on `MBEDTLS_MD_CAN_xxx` instead of just the legacy module.
The same criterion applies in `mbedtls_md_info_from_type`.
#### Conversion to PSA encoding
The implementation needs to convert from a legacy type encoding to a PSA encoding.
```
static inline psa_algorithm_t psa_alg_of_md_info(
const mbedtls_md_info_t *md_info );
```
#### Determination of PSA support at runtime
```
int psa_can_do_hash(psa_algorithm_t hash_alg);
```
The job of this private function is to return 1 if `hash_alg` can be performed through PSA now, and 0 otherwise. It is only defined on algorithms that are enabled via PSA.
As a starting point, return 1 if PSA crypto's driver subsystem has been initialized.
Usage note: for algorithms that are not enabled via PSA, calling `psa_can_do_hash` is generally safe: whether it returns 0 or 1, you can call a PSA hash function on the algorithm and it will return `PSA_ERROR_NOT_SUPPORTED`.
#### Support for PSA dispatch in hash operations
Each function that performs some hash operation or context management needs to know whether to dispatch via PSA or legacy.
If given an established context, use its `engine` field.
If given an algorithm as an `mbedtls_md_type_t type` (possibly being the `type` field of a `const mbedtls_md_info_t *`):
* If there is a PSA accelerator for this hash and `psa_can_do_hash(alg)`, call the corresponding PSA function, and if applicable set the engine to `MBEDTLS_MD_ENGINE_PSA`. (Skip this is `MBEDTLS_MD_SOME_PSA` is not defined.)
* Otherwise dispatch to the legacy module based on the type as currently done. (Skip this is `MBEDTLS_MD_SOME_LEGACY` is not defined.)
* If no dispatch is possible, return `MBEDTLS_ERR_MD_FEATURE_UNAVAILABLE`.
Note that this assumes that an operation that has been started via PSA can be completed. This implies that `mbedtls_psa_crypto_free` must not be called while an operation using PSA is in progress. Document this.
#### Error code conversion
After calling a PSA function, MD light calls `mbedtls_md_error_from_psa` to convert its status code.
### Support all legacy algorithms in PSA
As discussed in [“Implications between legacy availability and PSA availability”](#implications-between-legacy-availability-and-psa-availability), we require the following property:
> If an algorithm has a legacy implementation, it is also available through PSA.
When `MBEDTLS_PSA_CRYPTO_CONFIG` is disabled, this is already the case. When is enabled, we will now make it so as well. Change `include/mbedtls/config_psa.h` accordingly.
### MD light optimizations
This section is not necessary to implement MD light, but will cut down its code size.
#### Split names out of MD light
Remove hash names from `mbedtls_md_info_t`. Use a simple switch-case or a separate list to implement `mbedtls_md_info_from_string` and `mbedtls_md_get_name`.
#### Remove metadata from the info structure
In `mbedtls_md_get_size` and in modules that want a hash's block size, instead of looking up hash metadata in the info structure, call the PSA macros.
#### Optimize type conversions
To allow optimizing conversions between `mbedtls_md_type_t` and `psa_algorithm_t`, renumber the `mbedtls_md_type_t` enum so that the values are the 8 lower bits of the PSA encoding.
With this optimization,
```
static inline psa_algorithm_t psa_alg_of_md_info(
const mbedtls_md_info_t *md_info )
{
if( md_info == NULL )
return( PSA_ALG_NONE );
return( PSA_ALG_CATEGORY_HASH | md_info->type );
}
```
Work in progress on this conversion is at https://github.com/gilles-peskine-arm/mbedtls/tree/hash-unify-ids-wip-1
#### Unify HMAC with PSA
PSA has its own HMAC implementation. In builds with both `MBEDTLS_MD_C` and `PSA_WANT_ALG_HMAC` not fully provided by drivers, we should have a single implementation. Replace the one in `md.h` by calls to the PSA driver interface. This will also give mixed-domain modules access to HMAC accelerated directly by a PSA driver (eliminating the need to a HMAC interface in software if all supported hashes have an accelerator that includes HMAC support).
### Improving support for `MBEDTLS_PSA_CRYPTO_CLIENT`
So far, MD light only dispatches to PSA if an algorithm is available via `MBEDTLS_PSA_CRYPTO_C`, not if it's available via `MBEDTLS_PSA_CRYPTO_CLIENT`. This is acceptable because `MBEDTLS_USE_PSA_CRYPTO` requires `MBEDTLS_PSA_CRYPTO_C`, hence mixed-domain code never invokes PSA.
The architecture can be extended to support `MBEDTLS_PSA_CRYPTO_CLIENT` with a little extra work. Here is an overview of the task breakdown, which should be fleshed up after we've done the first [migration](#migration-to-md-light):
* Compile-time dependencies: instead of checking `defined(MBEDTLS_PSA_CRYPTO_C)`, check `defined(MBEDTLS_PSA_CRYPTO_C) || defined(MBEDTLS_PSA_CRYPTO_CLIENT)`.
* Implementers of `MBEDTLS_PSA_CRYPTO_CLIENT` will need to provide `psa_can_do_hash()` (or a more general function `psa_can_do`) alongside `psa_crypto_init()`. Note that at this point, it will become a public interface, hence we won't be able to change it at a whim.
### Internal "block cipher" abstraction (previously known as "Cipher light")
#### Definition
The new module is automatically enabled in `config_adjust_legacy_crypto.h` by modules that need
it (namely: CCM, GCM) only when `CIPHER_C` is not available, or the new module
is needed for PSA dispatch (see next section). Note: CCM and GCM currently
depend on the full `CIPHER_C` (enforced by `check_config.h`); this hard
dependency would be replaced by the above auto-enablement.
The following API functions are offered:
```
void mbedtls_block_cipher_init(mbedtls_block_cipher_context_t *ctx);
void mbedtls_block_cipher_free(mbedtls_block_cipher_context_t *ctx);
int mbedtls_block_cipher_setup(mbedtls_block_cipher_context_t *ctx,
mbedtls_cipher_id_t cipher_id);
int mbedtls_block_cipher_setkey(mbedtls_block_cipher_context_t *ctx,
const unsigned char *key,
unsigned key_bitlen);
int mbedtls_block_cipher_encrypt(mbedtls_block_cipher_context_t *ctx,
const unsigned char input[16],
unsigned char output[16]);
```
The only supported ciphers are AES, ARIA and Camellia. They are identified by
an `mbedtls_cipher_id_t` in the `setup()` function, because that's how they're
identifed by callers (GCM/CCM).
#### Block cipher dual dispatch
Support for dual dispatch in the new internal module `block_cipher` is extremely similar to that in MD light.
A block cipher context contains either a legacy module's context (AES, ARIA, Camellia) or a PSA key identifier; it has a field indicating which one is in use. All fields are private.
The `engine` field is almost redundant with knowledge about `type`. However, when an algorithm is available both via a legacy module and a PSA accelerator, we will choose based on the runtime availability of the accelerator when the context is set up. This choice needs to be recorded in the context structure.
Support is determined at runtime using the new internal function
```
int psa_can_do_cipher(psa_key_type_t key_type, psa_algorithm_t cipher_alg);
```
The job of this private function is to return 1 if `hash_alg` can be performed through PSA now, and 0 otherwise. It is only defined on algorithms that are enabled via PSA. As a starting point, return 1 if PSA crypto's driver subsystem has been initialized.
Each function in the module needs to know whether to dispatch via PSA or legacy. All functions consult the context's `engine` field, except `setup()` which will set it according to the key type and the return value of `psa_can_do_cipher()` as discussed above.
Note that this assumes that an operation that has been started via PSA can be completed. This implies that `mbedtls_psa_crypto_free` must not be called while an operation using PSA is in progress.
After calling a PSA function, `block_cipher` functions call `mbedtls_cipher_error_from_psa` to convert its status code.

View File

@ -0,0 +1,140 @@
#!/bin/sh
# This script runs tests before and after a PR and analyzes the results in
# order to highlight any difference in the set of tests skipped.
#
# It can be used to check the first testing criterion mentioned in strategy.md,
# end of section "Supporting builds with drivers without the software
# implementation", namely: the sets of tests skipped in the default config and
# the full config must be the same before and after the PR.
#
# USAGE:
# - First, commit any uncommited changes. (Also, see warning below.)
# - Then launch --> [SKIP_SSL_OPT=1] docs/architecture/psa-migration/outcome-analysis.sh
# - SKIP_SSL_OPT=1 can optionally be set to skip ssl-opt.sh tests
#
# WARNING: this script checks out a commit other than the head of the current
# branch; it checks out the current branch again when running successfully,
# but while the script is running, or if it terminates early in error, you
# should be aware that you might be at a different commit than expected.
#
# NOTE: you can comment out parts that don't need to be re-done when
# re-running this script (for example "get numbers before this PR").
set -eu
: ${SKIP_SSL_OPT:=0}
cleanup() {
make clean
git checkout -- include/mbedtls/mbedtls_config.h include/psa/crypto_config.h
}
record() {
export MBEDTLS_TEST_OUTCOME_FILE="$PWD/outcome-$1.csv"
rm -f $MBEDTLS_TEST_OUTCOME_FILE
make check
if [ $SKIP_SSL_OPT -eq 0 ]; then
make -C programs ssl/ssl_server2 ssl/ssl_client2 \
test/udp_proxy test/query_compile_time_config
tests/ssl-opt.sh
fi
}
# save current HEAD.
# Note: this can optionally be updated to
# HEAD=$(git branch --show-current)
# when using a Git version above 2.22
HEAD=$(git rev-parse --abbrev-ref HEAD)
# get the numbers before this PR for default and full
cleanup
git checkout $(git merge-base HEAD development)
record "before-default"
cleanup
scripts/config.py full
record "before-full"
# get the numbers now for default and full
cleanup
git checkout $HEAD
record "after-default"
cleanup
scripts/config.py full
record "after-full"
cleanup
# analysis
populate_suites () {
SUITES=''
make generated_files >/dev/null
data_files=$(cd tests/suites && echo *.data)
for data in $data_files; do
suite=${data%.data}
SUITES="$SUITES $suite"
done
make neat
if [ $SKIP_SSL_OPT -eq 0 ]; then
SUITES="$SUITES ssl-opt"
extra_files=$(cd tests/opt-testcases && echo *.sh)
for extra in $extra_files; do
suite=${extra%.sh}
SUITES="$SUITES $suite"
done
fi
}
compare_suite () {
ref="outcome-$1.csv"
new="outcome-$2.csv"
suite="$3"
pattern_suite=";$suite;"
total=$(grep -c "$pattern_suite" "$ref")
sed_cmd="s/^.*$pattern_suite\(.*\);SKIP.*/\1/p"
sed -n "$sed_cmd" "$ref" > skipped-ref
sed -n "$sed_cmd" "$new" > skipped-new
nb_ref=$(wc -l <skipped-ref)
nb_new=$(wc -l <skipped-new)
name=${suite#test_suite_}
printf "%40s: total %4d; skipped %4d -> %4d\n" \
$name $total $nb_ref $nb_new
if diff skipped-ref skipped-new | grep '^> '; then
ret=1
else
ret=0
fi
rm skipped-ref skipped-new
return $ret
}
compare_builds () {
printf "\n*** Comparing $1 -> $2 ***\n"
failed=''
for suite in $SUITES; do
if compare_suite "$1" "$2" "$suite"; then :; else
failed="$failed $suite"
fi
done
if [ -z "$failed" ]; then
printf "No coverage gap found.\n"
else
printf "Suites with less coverage:%s\n" "$failed"
fi
}
populate_suites
compare_builds before-default after-default
compare_builds before-full after-full

View File

@ -0,0 +1,344 @@
Bridges between legacy and PSA crypto APIs
==========================================
## Introduction
### Goal of this document
This document explores the needs of applications that use both Mbed TLS legacy crypto interfaces and PSA crypto interfaces. Based on [requirements](#requirements), we [analyze gaps](#gap-analysis) and [API design](#api-design).
This is a design document. The target audience is library maintainers. See the companion document [“Transitioning to the PSA API”](../../psa-transition.md) for a user focus on the same topic.
### Keywords
* [TODO] A part of the analysis that isn't finished.
* [OPEN] Open question: a specific aspect of the design where there are several plausible decisions.
* [ACTION] A finalized part of the design that will need to be carried out.
### Context
Mbed TLS 3.x supports two cryptographic APIs:
* The legacy API `mbedtls_xxx` is inherited from PolarSSL.
* The PSA API `psa_xxx` was introduced in Mbed TLS 2.17.
Mbed TLS is gradually shifting from the legacy API to the PSA API. Mbed TLS 4.0 will be the first version where the PSA API is considered the main API, and large parts of the legacy API will be removed.
In Mbed TLS 4.0, the cryptography will be provided by a separate project [TF-PSA-Crypto](https://github.com/Mbed-TLS/TF-PSA-Crypto). For simplicity, in this document, we just refer to the whole as “Mbed TLS”.
### Document history
This document was originally written when preparing Mbed TLS 3.6. Mbed TLS 3.6 includes both PSA and legacy APIs covering largely overlapping ground. Many legacy APIs will be removed in Mbed TLS 4.0.
## Requirements
### Why mix APIs?
There is functionality that is tied to one API and is not directly available in the other API:
* Only PSA fully supports PSA accelerators and secure element integration.
* Only PSA supports isolating cryptographic material in a secure service.
* The legacy API has features that are not present (yet) in PSA, notably parsing and formatting asymmetric keys.
The legacy API can partially leverage PSA features via `MBEDTLS_USE_PSA_CRYPTO`, but this has limited scope.
In addition, many applications cannot be migrated in a single go. For large projects, it is impractical to rewrite a significant part of the code all at once. (For example, Mbed TLS itself will have taken more than 6 years to transition.) Projects that use one or more library in addition to Mbed TLS must follow the evolution of these libraries, each of which might have its own pace.
### Where mixing happens
Mbed TLS can be, and normally is, built with support for both APIs. Therefore no special effort is necessary to allow an application to use both APIs.
Special effort is necessary to use both APIs as part of the implementation of the same feature. From an informal analysis of typical application requirements, we identify four parts of the use of cryptography which can be provided by different APIs:
* Metadata manipulation: parsing and producing encrypted or signed files, finding mutually supported algorithms in a network protocol negotiation, etc.
* Key management: parsing, generating, deriving and formatting cryptographic keys.
* Data manipulation other than keys. In practice, most data formats within the scope of the legacy crypto APIs are trivial (ciphertexts, hashes, MACs, shared secrets). The one exception is ECDSA signatures.
* Cryptographic operations: hash, sign, encrypt, etc.
From this, we deduce the following requirements:
* Convert between PSA and legacy metadata.
* Creating a key with the legacy API and consuming it in the PSA API.
* Creating a key with the PSA API and consuming it in the legacy API.
* Manipulating data formats, other than keys, where the PSA API is lacking.
### Scope limitations
The goal of this document is to bridge the legacy API and the PSA API. The goal is not to provide a PSA way to do everything that is currently possible with the legacy API. The PSA API is less flexible in some regards, and extending it is out of scope in the present study.
With respect to the legacy API, we do not consider functionality of low-level modules for individual algorithms. Our focus is on applications that use high-level legacy crypto modules (md, cipher, pk) and need to combine that with uses of the PSA APIs.
## Gap analysis
The document [“Transitioning to the PSA API”](../../psa-transition.md) enumerates the public header files in Mbed TLS 3.4 and the API elements (especially enums and functions) that they provide, listing PSA equivalents where they exist. There are gaps in two cases:
* Where the PSA equivalents do not provide the same functionality. A typical example is parsing and formatting asymmetric keys.
* To convert between data representations used by legacy APIs and data representations used by PSA APIs.
Based on “[Where mixing happens](#where-mixing-happens)”, we focus the gap analysis on two topics: metadata and keys. This chapter explores the gaps in each family of cryptographic mechanisms.
### Generic metadata gaps
#### Need for error code conversion
Do we need public functions to convert between `MBEDTLS_ERR_xxx` error codes and `PSA_ERROR_xxx` error codes? We have such functions for internal use.
Mbed TLS needs these conversions because it has many functions that expose one API (legacy/API) but are implemented on top of the other API. Most applications would convert legacy and PSA error code to their own error codes, and converting between `MBEDTLS_ERR_xxx` error codes and `PSA_ERROR_xxx` is not particularly helpful for that. Application code might need such conversion functions when implementing an X.509 or TLS callback (returning `MBEDTLS_ERR_xxx`) on top of PSA functions, but this is a very limited use case.
Conclusion: no need for public error code conversion functions.
### Hash gap analysis
Hashes do not involve keys, and involves no nontrivial data format. Therefore the only gap is with metadata, namely specifying a hash algorithm.
Hashes are often used as building blocks for other mechanisms (HMAC, signatures, key derivation, etc.). Therefore metadata about hashes is relevant not only when calculating hashes, but also when performing many other cryptographic operations.
Gap: functions to convert between `psa_algorithm_t` hash algorithms and `mbedtls_md_type_t`. Such functions exist in Mbed TLS 3.5 (`mbedtls_md_psa_alg_from_type`, `mbedtls_md_type_from_psa_alg`) but they are declared only in private headers.
### MAC gap analysis
[TODO]
### Cipher and AEAD gap analysis
[TODO]
### Key derivation gap analysis
[TODO]
### Random generation gap analysis
[TODO]
### Asymmetric cryptography gap analysis
#### Asymmetric cryptography metadata
The legacy API only has generic support for two key types: RSA and ECC, via the pk module. ECC keys can also be further classified according to their curve. The legacy API also supports DHM (Diffie-Hellman-Merkle = FFDH: finite-field Diffie-Hellman) keys, but those are not integrated in the pk module.
An RSA or ECC key can potentially be used for different algorithms in the scope of the pk module:
* RSA: PKCS#1v1.5 signature, PSS signature, PKCS#1v1.5 encryption, OAEP encryption.
* ECC: ECDSA signature (randomized or deterministic), ECDH key agreement (via `mbedtls_pk_ec`).
ECC keys are also involved in EC-JPAKE, but this happens internally: the EC-JPAKE interface only needs one piece of metadata, namely, to identify a curve.
Since there is no algorithm that can be used with multiple types, and PSA keys have a policy that (for the most part) limits them to one algorithm, there does not seem to be a need to convert between legacy and PSA asymmetric key types on their own. The useful metadata conversions are:
* Selecting an **elliptic curve**.
This means converting between an `mbedtls_ecp_group_id` and a pair of `{psa_ecc_family_t; size_t}`.
This is fulfilled by `mbedtls_ecc_group_to_psa` and `mbedtls_ecc_group_from_psa`, which were introduced into the public API between Mbed TLS 3.5 and 3.6 ([#8664](https://github.com/Mbed-TLS/mbedtls/pull/8664)).
* Selecting A **DHM group**.
PSA only supports predefined groups, whereas legacy only supports ad hoc groups. An existing application referring to `MBEDTLS_DHM_RFC7919_FFDHExxx` values would need to refer to `PSA_DH_FAMILY_RFC7919`; an existing application using arbitrary groups cannot migrate to PSA.
* Simultaneously supporting **a key type and an algorithm**.
On the legacy side, this is an `mbedtls_pk_type_t` value and more. For ECDSA, the choice between randomized and deterministic is made at compile time. For RSA, the choice of encryption or signature algorithm is made either by configuring the underlying `mbedtls_rsa_context` or when calling the operation function.
On the PSA side, this is a `psa_key_type_t` value and an algorithm which is normally encoded as policy information in a `psa_key_attributes_t`. The algorithm is also needed in its own right when calling operation functions.
#### Using a legacy key pair or public key with PSA
There are several scenarios where an application has a legacy key pair or public key (`mbedtls_pk_context`) and needs to create a PSA key object (`psa_key_id_t`).
Reasons for first creating a legacy key object, where it's impossible or impractical to directly create a PSA key:
* A very common case where the input is a legacy key object is parsing. PSA does not (yet) have an equivalent of the `mbedtls_pk_parse_xxx` functions.
* The PSA key creation interface is less flexible in some cases. In particular, PSA RSA key generation does not (yet) allow choosing the public exponent.
* The pk object may be created by a part of the application (or a third-party library) that hasn't been migrated to the PSA API yet.
Reasons for needing a PSA key object:
* Using the key with third-party interface that takes a PSA key identifier as input. (Mbed TLS itself has a few TLS functions that take PSA key identifiers, but as of Mbed TLS 3.5, it is always possible to use a legacy key instead.)
* Benefiting from a PSA accelerator, or from PSA's world separation, even without `MBEDTLS_USE_PSA_CRYPTO`. (Not a priority scenario: we generally expect people to activate `MBEDTLS_USE_PSA_CRYPTO` at an early stage of their migration to PSA.)
Gap: a way to create a PSA key object from an `mbedtls_pk_context`. This partially exists in the form of `mbedtls_pk_wrap_as_opaque`, but it is not fully satisfactory, for reasons that are detailed in “[API to create a PSA key from a PK context](#api-to-create-a-psa-key-from-a-pk-context)” below.
#### Using a PSA key as a PK context
There are several scenarios where an application has a PSA key and needs to use it through an interface that wants an `mbedtls_pk_context` object. Typically, there is an existing key in the PSA key store (possibly in a secure element and non-exportable), and the key needs to be used in an interface that requires a `mbedtls_pk_context *` input, such as Mbed TLS's X.509 and TLS APIs or a similar third-party interface, or the `mbedtls_pk_write_xxx` interfaces which do not (yet) have PSA equivalents.
There is a function `mbedtls_pk_setup_opaque` that mostly does this. However, it has several limitations:
* It creates a PK key of type `MBEDTLS_PK_OPAQUE` that wraps the PSA key. This is good enough in some scenarios, but not others. For example, it's ok for pkwrite, because we've upgraded the pkwrite code to handle `MBEDTLS_PK_OPAQUE`. That doesn't help users of third-party libraries that haven't yet been upgraded.
* It ties the lifetime of the PK object to the PSA key, which is error-prone: if the PSA key is destroyed but the PK object isn't, there is no way to reliably detect any subsequent misuse of the PK object.
* It is only available under `MBEDTLS_USE_PSA_CRYPTO`. This is not a priority concern, since we generally expect people to activate `MBEDTLS_USE_PSA_CRYPTO` at an early stage of their migration to PSA. However, this function is useful to use specific PSA keys in X.509/TLS regardless of whether X.509/TLS use the PSA API for all cryptographic operations, so this is a wart in the current API.
It therefore appears that we need two ways to “convert” a PSA key to PK:
* Wrapping, which is what `mbedtls_pk_setup_opaque` does. This works for any PSA key but is limited by the key's lifetime and creates a PK object with limited functionality.
* Copying, which requires a new function. This requires an exportable key but creates a fully independent, fully functional PK object.
Gap: a way to copy a PSA key into a PK context. This can only be expected to work if the PSA key is exportable.
After some discussion, have not identified anything we want to change in the behavior of `mbedtls_pk_setup_opaque`. We only want to generalize it to non-`MBEDTLS_USE_PSA_CRYPTO` and to document it better.
#### Signature formats
The pk module uses signature formats intended for X.509. The PSA module uses the simplest sensible signature format.
* For RSA, the formats are the same.
* For ECDSA, PSA uses a fixed-size concatenation of (r,s), whereas X.509 and pk use an ASN.1 DER encoding of the sequence (r,s).
Gap: We need APIs to convert between these two formats. The conversion code already exists under the hood, but it's in pieces that can't be called directly.
There is a design choice here: do we provide conversions functions for ECDSA specifically, or do we provide conversion functions that take an algorithm as argument and just happen to be a no-op with RSA? One factor is plausible extensions. These conversions functions will remain useful in Mbed TLS 4.x and perhaps beyond. We will at least add EdDSA support, and its signature encoding is the fixed-size concatenation (r,s) even in X.509. We may well also add support for some post-quantum signatures, and their concrete format is still uncertain.
Given the uncertainty, it would be nice to provide a sufficiently generic interface to convert between the PSA and the pk signature format, parametrized by the algorithm. However, it is difficult to predict exactly what parameters are needed. For example, converting from an ASN.1 ECDSA signature to (r,s) requires the knowledge of the curve, or at least the curve's size. Therefore we are not going to add a generic function at this stage.
For ECDSA, there are two plausible APIs: follow the ASN.1/X.509 write/parse APIs, or present an ordinary input/output API. The ASN.1 APIs are the way they are to accommodate nested TLV structures. But ECDSA signatures do not appear nested in TLV structures in either TLS (there's just a signature field) or X.509 (the signature is inside a BITSTRING, not directly in a SEQUENCE). So there does not seem to be a need for an ASN.1-like API for the ASN.1 format, just the format conversion itself in a buffer that just contains the signature.
#### Asymmetric cryptography TODO
[TODO] Other gaps?
## New APIs
This section presents new APIs to implement based on the [gap analysis](#gap-analysis).
### General notes
Each action to implement a function entails:
* Implement the library function.
* Document it precisely, including error conditions.
* Unit-test it.
* Mention it where relevant in the PSA transition guide.
### Hash APIs
Based on the [gap analysis](#hash-gap-analysis):
[ACTION] [#8340](https://github.com/Mbed-TLS/mbedtls/issues/8340) Move `mbedtls_md_psa_alg_from_type` and `mbedtls_md_type_from_psa_alg` from `library/md_psa.h` to `include/mbedtls/md.h`.
### MAC APIs
[TODO]
### Cipher and AEAD APIs
[TODO]
### Key derivation APIs
[TODO]
### Random generation APIs
[TODO]
### Asymmetric cryptography APIs
#### Asymmetric cryptography metadata APIs
Based on the [gap analysis](#asymmetric-cryptography-metadata):
* No further work is needed about RSA specifically. The amount of metadata other than hashes is sufficiently small to be handled in ad hoc ways in applications, and hashes have [their own conversions](#hash-apis).
* No further work is needed about ECC specifically. We have just added adequate functions.
* No further work is needed about DHM specifically. There is no good way to translate the relevant information.
* [OPEN] Is there a decent way to convert between `mbedtls_pk_type_t` plus extra information, and `psa_key_type_t` plus policy information? The two APIs are different in crucial ways, with different splits between key type, policy information and operation algorithm.
Thinking so far: there isn't really a nice way to present this conversion. For a specific key, `mbedtls_pk_get_psa_attributes` and `mbedtls_pk_copy_from_psa` do the job.
#### API to create a PSA key from a PK context
Based on the [gap analysis](#using-a-legacy-key-pair-or-public-key-with-psa):
Given an `mbedtls_pk_context`, we want a function that creates a PSA key with the same key material and algorithm. “Same key material” is straightforward, but “same algorithm” is not, because a PK context has incomplete algorithm information. For example, there is no way to distinguish between an RSA key that is intended for signature or for encryption. Between algorithms of the same nature, there is no way to distinguish a key intended for PKCS#1v1.5 and one intended for PKCS#1v2.1 (OAEP/PSS): this is indicated in the underlying RSA context, but the indication there is only a default that can be overridden by calling `mbedtls_pk_{sign,verify}_ext`. Also there is no way to distinguish between `PSA_ALG_RSA_PKCS1V15_SIGN(hash_alg)` and `PSA_ALG_RSA_PKCS1V15_SIGN_RAW`: in the legacy interface, this is only determined when actually doing a signature/verification operation. Therefore the function that creates the PSA key needs extra information to indicate which algorithm to put in the key's policy.
When creating a PSA key, apart from the key material, the key is determined by attributes, which fall under three categories:
* Type and size. These are directly related to the key material and can be deduced from it if the key material is in a structured format, which is the case with an `mbedtls_pk_context` input.
* Policy. This includes the chosen algorithm, which as discussed above cannot be fully deduced from the `mbedtls_pk_context` object. Just choosing one algorithm is problematic because it doesn't allow implementation-specific extensions, such as Mbed TLS's enrollment algorithm. The intended usage flags cannot be deduced from the PK context either, but the conversion function could sensibly just enable all the relevant usage flags. Users who want a more restrictive usage can call `psa_copy_key` and `psa_destroy_key` to obtain a PSA key object with a more restrictive usage.
* Persistence and location. This is completely orthogonal to the information from the `mbedtls_pk_context` object. It is convenient, but not necessary, for the conversion function to allow customizing these aspects. If it doesn't, users can call the conversion function and then call `psa_copy_key` and `psa_destroy_key` to move the key to its desired location.
To allow the full flexibility around policies, and make the creation of a persistent key more convenient, the conversion function shall take a `const psa_key_attributes_t *` input, like all other functions that create a PSA key. In addition, there shall be a helper function to populate a `psa_key_attributes_t` with a sensible default. This lets the caller choose a more flexible, or just different usage policy, unlike the default-then-copy approach which only allows restricting the policy.
This is close to the existing function `mbedtls_pk_wrap_as_opaque`, but does not bake in the implementation-specific consideration that a PSA key has exactly two algorithms, and also allows the caller to benefit from default for the policy in more cases.
[ACTION] [#8708](https://github.com/Mbed-TLS/mbedtls/issues/8708) Implement `mbedtls_pk_get_psa_attributes` and `mbedtls_pk_import_into_psa` as described below. These functions are available whenever `MBEDTLS_PK_C` and `MBEDTLS_PSA_CRYPTO_CLIENT` are both defined. Deprecate `mbedtls_pk_wrap_as_opaque`.
```
int mbedtls_pk_get_psa_attributes(const mbedtls_pk_context *pk,
psa_key_usage_flags_t usage,
psa_key_attributes_t *attributes);
int mbedtls_pk_import_into_psa(const mbedtls_pk_context *pk,
const psa_key_attributes_t *attributes,
mbedtls_svc_key_id_t *key_id);
```
* `mbedtls_pk_get_psa_attributes` does not change the id/lifetime fields of the attributes (which indicate a volatile key by default).
* [OPEN] Or should it reset them to 0? Resetting is more convenient for the case where the pk key is a `MBEDTLS_PK_OPAQUE`. But that's an uncommon use case. It's probably less surprising if this function leaves the lifetime-related alone, since its job is to set the type-related and policy-related attributes.
* `mbedtls_pk_get_psa_attributes` sets the type and size based on what's in the pk context.
* The key type is a key pair if the context contains a private key and the indicated usage is a private-key usage. The key type is a public key if the context only contains a public key, in which case a private-key usage is an error.
* `mbedtls_pk_get_psa_attributes` sets the usage flags based on the `usage` parameter. It extends the usage to other usage that is possible:
* `EXPORT` and `COPY` are always set.
* If `SIGN_{HASH,MESSAGE}` is set then so is `VERIFY_{HASH,MESSAGE}`.
* If `DECRYPT` is set then so is `ENCRYPT`.
* It is an error if `usage` has more than one flag set, or has a usage that is incompatible with the key type.
* `mbedtls_pk_get_psa_attributes` sets the algorithm usage policy based on information in the key object and on `usage`.
* For an RSA key with the `MBEDTLS_RSA_PKCS_V15` padding mode, the algorithm policy is `PSA_ALG_RSA_PKCS1V15_SIGN(PSA_ALG_ANY_HASH)` for a sign/verify usage, and `PSA_ALG_RSA_PKCS1V15_CRYPT` for an encrypt/decrypt usage.
* For an RSA key with the `MBEDTLS_RSA_PKCS_V21` padding mode, the algorithm policy is `PSA_ALG_RSA_PSS_ANY_SALT(PSA_ALG_ANY_HASH)` for a sign/verify usage, and `PSA_ALG_RSA_OAEP(hash)` for an encrypt/decrypt usage where `hash` is from the RSA key's parameters. (Note that `PSA_ALG_ANY_HASH` is only allowed in signature algorithms.)
* For an `MBEDTLS_PK_ECKEY` or `MBEDTLS_PK_ECDSA` with a sign/verify usage, the algorithm policy is `PSA_ALG_DETERMINISTIC_ECDSA` if `MBEDTLS_ECDSA_DETERMINISTIC` is enabled and `PSA_ALG_ECDSA` otherwise. In either case, the hash policy is `PSA_ALG_ANY_HASH`.
* For an `MBEDTLS_PK_ECKEY` or `MBEDTLS_PK_ECDKEY_DH` with the usage `PSA_KEY_USAGE_DERIVE`, the algorithm is `PSA_ALG_ECDH`.
* For a `MBEDTLS_PK_OPAQUE`, this function reads the attributes of the existing PK key and copies them (without overriding the lifetime and key identifier in `attributes`), then applies a public-key restriction if needed.
* Public-key restriction: if `usage` is a public-key usage, change the type to the corresponding public-key type, and remove private-key usage flags from the usage flags read from the existing key.
* `mbedtls_pk_import_into_psa` checks that the type field in the attributes is consistent with the content of the `mbedtls_pk_context` object (RSA/ECC, and availability of the private key).
* The key type can be a public key even if the private key is available.
* `mbedtls_pk_import_into_psa` does not need to check the bit-size in the attributes: `psa_import_key` will do enough checks.
* `mbedtls_pk_import_into_psa` does not check that the policy in the attributes is sensible. That's on the user.
#### API to copy a PSA key to a PK context
Based on the [gap analysis](#using-a-psa-key-as-a-pk-context):
[ACTION] [#8709](https://github.com/Mbed-TLS/mbedtls/issues/8709) Implement `mbedtls_pk_copy_from_psa` as described below.
```
int mbedtls_pk_copy_from_psa(mbedtls_svc_key_id_t key_id,
mbedtls_pk_context *pk);
```
* `pk` must be initialized, but not set up.
* It is an error if the key is neither a key pair nor a public key.
* It is an error if the key is not exportable.
* The resulting pk object has a transparent type, not `MBEDTLS_PK_OPAQUE`. That's `MBEDTLS_PK_RSA` for RSA keys (since pk objects don't use `MBEDTLS_PK_RSASSA_PSS` as a type), and `MBEDTLS_PK_ECKEY` for ECC keys (following the example of pkparse).
* Once this function returns, the pk object is completely independent of the PSA key.
* Calling `mbedtls_pk_sign`, `mbedtls_pk_verify`, `mbedtls_pk_encrypt`, `mbedtls_pk_decrypt` on the resulting pk context will perform an algorithm that is compatible with the PSA key's primary algorithm policy (`psa_get_key_algorithm`) if that is a matching operation type (sign/verify, encrypt/decrypt), but with no restriction on the hash (as if the policy had `PSA_ALG_ANY_HASH` instead of a specific hash, and with `PSA_ALG_RSA_PKCS1V15_SIGN_RAW` merged with `PSA_ALG_RSA_PKCS1V15_SIGN(hash_alg)`).
* For ECDSA, the choice of deterministic vs randomized will be based on the compile-time setting `MBEDTLS_ECDSA_DETERMINISTIC`, like `mbedtls_pk_sign` today.
* For an RSA key, the output key will allow both encrypt/decrypt and sign/verify regardless of the original key's policy. The original key's policy determines the output key's padding mode.
* The primary intent of this requirement is to allow an application to switch to PSA for creating the key material (for example to benefit from a PSA accelerator driver, or to start using a secure element), without modifying the code that consumes the key. For RSA keys, the PSA primary algorithm policy is how one conveys the same information as RSA key padding information in the legacy API. Convey this in the documentation.
#### API to create a PK object that wraps a PSA key
Based on the [gap analysis](#using-a-psa-key-as-a-pk-context):
[ACTION] [#8712](https://github.com/Mbed-TLS/mbedtls/issues/8712) Clarify the documentation of `mbedtls_pk_setup_opaque` regarding which algorithms the resulting key will perform with `mbedtls_pk_sign`, `mbedtls_pk_verify`, `mbedtls_pk_encrypt`, `mbedtls_pk_decrypt`.
[ACTION] [#8710](https://github.com/Mbed-TLS/mbedtls/issues/8710) Provide `mbedtls_pk_setup_opaque` whenever `MBEDTLS_PSA_CRYPTO_CLIENT` is enabled, not just when `MBEDTLS_USE_PSA_CRYPTO` is enabled. This is nice-to-have, not critical. Update `use-psa-crypto.md` accordingly.
[OPEN] What about `mbedtls_pk_sign_ext` and `mbedtls_pk_verify_ext`?
#### API to convert between signature formats
Based on the [gap analysis](#signature-formats):
[ACTION] [#7765](https://github.com/Mbed-TLS/mbedtls/issues/7765) Implement `mbedtls_ecdsa_raw_to_der` and `mbedtls_ecdsa_der_to_raw` as described below.
```
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);
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);
```
* These functions convert between the signature format used by `mbedtls_pk_{sign,verify}{,_ext}` and the signature format used by `psa_{sign,verify}_{hash,message}`.
* The input and output buffers can overlap.
* The `bits` parameter is necessary in the DER-to-raw direction because the DER format lacks leading zeros, so something else needs to convey the size of (r,s). The `bits` parameter is redundant in the raw-to-DER direction, but we have it anyway because [it helps catch errors](https://github.com/Mbed-TLS/mbedtls/pull/8681#discussion_r1445980971), and it isn't a burden on the caller because the information is readily available in practice.
* Should these functions rely on the ASN.1 module? We experimented [calling ASN.1 functions](https://github.com/Mbed-TLS/mbedtls/pull/8681), [reimplementing simpler ASN.1 functions](https://github.com/Mbed-TLS/mbedtls/pull/8696), and [providing the functions from the ASN.1 module](https://github.com/Mbed-TLS/mbedtls/pull/8703). Providing the functions from the ASN.1 module [won on a compromise of code size and simplicity](https://github.com/Mbed-TLS/mbedtls/issues/7765#issuecomment-1893670015).

View File

@ -0,0 +1,337 @@
This document lists current limitations of the PSA Crypto API (as of version
1.1) that may impact our ability to (1) use it for all crypto operations in
TLS and X.509 and (2) support isolation of all long-term secrets in TLS (that
is, goals G1 and G2 in [strategy.md](strategy.md) in the same directory).
This is supposed to be a complete list, based on a exhaustive review of crypto
operations done in TLS and X.509 code, but of course it's still possible that
subtle-but-important issues have been missed. The only way to be really sure
is, of course, to actually do the migration work.
Limitations relevant for G1 (performing crypto operations)
==========================================================
Restartable (aka interruptible) ECC operations
----------------------------------------------
Support for interruptible ECDSA sign/verify was added to PSA in Mbed TLS 3.4.
However, support for interruptible ECDH is not present yet. Also, PK, X.509 and
TLS have not yet been adapted to take advantage of the new PSA APIs. See:
- <https://github.com/Mbed-TLS/mbedtls/issues/7292>;
- <https://github.com/Mbed-TLS/mbedtls/issues/7293>;
- <https://github.com/Mbed-TLS/mbedtls/issues/7294>.
Currently, when `MBEDTLS_USE_PSA_CRYPTO` and `MBEDTLS_ECP_RESTARTABLE` are
both enabled, some operations that should be restartable are not (ECDH in TLS
1.2 clients using ECDHE-ECDSA), as they are using PSA instead, and some
operations that should use PSA do not (signature generation & verification) as
they use the legacy API instead, in order to get restartable behaviour.
Things that are in the API but not implemented yet
--------------------------------------------------
PSA Crypto has an API for FFDH, but it's not implemented in Mbed TLS yet.
(Regarding FFDH, see the next section as well.) See issue [3261][ffdh] on
github.
[ffdh]: https://github.com/Mbed-TLS/mbedtls/issues/3261
Arbitrary parameters for FFDH
-----------------------------
(See also the first paragraph in the previous section.)
Currently, the PSA Crypto API can only perform FFDH with a limited set of
well-known parameters (some of them defined in the spec, but implementations
are free to extend that set).
TLS 1.2 (and earlier) on the other hand have the server send explicit
parameters (P and G) in its ServerKeyExchange message. This has been found to
be suboptimal for security, as it is prohibitively hard for the client to
verify the strength of these parameters. This led to the development of RFC
7919 which allows use of named groups in TLS 1.2 - however as this is only an
extension, servers can still send custom parameters if they don't support the
extension.
In TLS 1.3 the situation will be simpler: named groups are the only
option, so the current PSA Crypto API is a good match for that. (Not
coincidentally, all the groups used by RFC 7919 and TLS 1.3 are included
in the PSA specification.)
There are several options here:
1. Implement support for custom FFDH parameters in PSA Crypto: this would pose
non-trivial API design problem, but most importantly seems backwards, as
the crypto community is moving away from custom FFDH parameters. (Could be
done any time.)
2. Drop the DHE-RSA and DHE-PSK key exchanges in TLS 1.2 when moving to PSA.
(For people who want some algorithmic variety in case ECC collapses, FFDH
would still be available in TLS 1.3, just not in 1.2.) (Can only be done in
4.0 or another major version.)
3. Variant of the precedent: only drop client-side support. Server-side is
easy to support in terms of API/protocol, as the server picks the
parameters: we just need remove the existing `mbedtls_ssl_conf_dh_param_xxx()`
APIs and tell people to use `mbedtls_ssl_conf_groups()` instead. (Can only be
done in 4.0 or another major version.)
4. Implement RFC 7919, support DHE-RSA and DHE-PSK only in conjunction with it
when moving to PSA. Server-side would work as above; unfortunately
client-side the only option is to offer named groups and break the handshake
if the server didn't take on our offer. This is not fully satisfying, but is
perhaps the least unsatisfying option in terms of result; it's also probably
the one that requires the most work, but it would deliver value beyond PSA
migration by implementing RFC 7919. (Implementing RFC 7919 could be done any
time; making it mandatory can only be done in 4.0 or another major version.)
As of early 2023, the plan is to go with option 2 in Mbed TLS 4.0, which has
been announced on the mailing-list and got no push-back, see
<https://github.com/Mbed-TLS/mbedtls/issues/5278>.
RSA-PSS parameters
------------------
RSA-PSS signatures are defined by PKCS#1 v2, re-published as RFC 8017
(previously RFC 3447).
As standardized, the signature scheme takes several parameters, in addition to
the hash algorithm potentially used to hash the message being signed:
- a hash algorithm used for the encoding function
- a mask generation function
- most commonly MGF1, which in turn is parametrized by a hash algorithm
- a salt length
- a trailer field - the value is fixed to 0xBC by PKCS#1 v2.1, but was left
configurable in the original scheme; 0xBC is used everywhere in practice.
Both the existing `mbedtls_` API and the PSA API support only MGF1 as the
generation function (and only 0xBC as the trailer field), but there are
discrepancies in handling the salt length and which of the various hash
algorithms can differ from each other.
### API comparison
- RSA:
- signature: `mbedtls_rsa_rsassa_pss_sign()`
- message hashed externally
- encoding hash = MGF1 hash (from context, or argument = message hash)
- salt length: always using the maximum legal value
- signature: `mbedtls_rsa_rsassa_pss_sign_ext()`
- message hashed externally
- encoding hash = MGF1 hash (from context, or argument = message hash)
- salt length: specified explicitly
- verification: `mbedtls_rsassa_pss_verify()`
- message hashed externally
- encoding hash = MGF1 hash (from context, or argument = message hash)
- salt length: any valid length accepted
- verification: `mbedtls_rsassa_pss_verify_ext()`
- message hashed externally
- encoding hash = MGF1 hash from dedicated argument
- expected salt length: specified explicitly, can specify "ANY"
- PK:
- signature: not supported
- verification: `mbedtls_pk_verify_ext()`
- message hashed externally
- encoding hash = MGF1 hash, specified explicitly
- expected salt length: specified explicitly, can specify "ANY"
- PSA:
- algorithm specification:
- hash alg used for message hashing, encoding and MGF1
- salt length can be either "standard" (<= hashlen, see note) or "any"
- signature generation:
- salt length: always <= hashlen (see note) and random salt
- verification:
- salt length: either <= hashlen (see note), or any depending on algorithm
Note: above, "<= hashlen" means that hashlen is used if possible, but if it
doesn't fit because the key is too short, then the maximum length that fits is
used.
The RSA/PK API is in principle more flexible than the PSA Crypto API. The
following sub-sections study whether and how this matters in practice.
### Use in X.509
RFC 4055 Section 3.1 defines the encoding of RSA-PSS that's used in X.509.
It allows independently specifying the message hash (also used for encoding
hash), the MGF (and its hash if MGF1 is used), and the salt length (plus an
extra parameter "trailer field" that doesn't vary in practice"). These can be
encoded as part of the key, and of the signature. If both encoding are
presents, all values must match except possibly for the salt length, where the
value from the signature parameters is used.
In Mbed TLS, RSA-PSS parameters can be parsed and displayed for various
objects (certificates, CRLs, CSRs). During parsing, the following properties
are enforced:
- the extra "trailer field" parameter must have its default value
- the mask generation function is MGF1
- encoding hash = message hashing algorithm (may differ from MGF1 hash)
When it comes to cryptographic operations, only two things are supported:
- verifying the signature on a certificate from its parent;
- verifying the signature on a CRL from the issuing CA.
The verification is done using `mbedtls_pk_verify_ext()`.
Note: since X.509 parsing ensures that message hash = encoding hash, and
`mbedtls_pk_verify_ext()` uses encoding hash = mgf1 hash, it looks like all
three hash algorithms must be equal, which would be good news as it would
match a limitation of the PSA API.
It is unclear what parameters people use in practice. It looks like by default
OpenSSL picks saltlen = keylen - hashlen - 2 (tested with openssl 1.1.1f).
The `certtool` command provided by GnuTLS seems to be picking saltlen = hashlen
by default (tested with GnuTLS 3.6.13). FIPS 186-4 requires 0 <= saltlen <=
hashlen.
### Use in TLS
In TLS 1.2 (or lower), RSA-PSS signatures are never used, except via X.509.
In TLS 1.3, RSA-PSS signatures can be used directly in the protocol (in
addition to indirect use via X.509). It has two sets of three signature
algorithm identifiers (for SHA-256, SHA-384 and SHA-512), depending of what
the OID of the public key is (rsaEncryption or RSASSA-PSS).
In both cases, it specifies that:
- the mask generation function is MGF1
- all three hashes are equal
- the length of the salt MUST be equal to the length of the digest algorithm
When signing, the salt length picked by PSA is the one required by TLS 1.3
(unless the key is unreasonably small).
When verifying signatures, PSA will by default enforce the salt len is the one
required by TLS 1.3.
### Current testing - X509
All test files use the default trailer field of 0xBC, as enforced by our
parser. (There's a negative test for that using the
`x509_parse_rsassa_pss_params` test function and hex data.)
Files with "bad" in the name are expected to be invalid and rejected in tests.
**Test certificates:**
server9-bad-mgfhash.crt (announcing mgf1(sha224), signed with another mgf)
Hash Algorithm: sha256
Mask Algorithm: mgf1 with sha224
Salt Length: 0xDE
server9-bad-saltlen.crt (announcing saltlen = 0xDE, signed with another len)
Hash Algorithm: sha256
Mask Algorithm: mgf1 with sha256
Salt Length: 0xDE
server9-badsign.crt (one bit flipped in the signature)
Hash Algorithm: sha1 (default)
Mask Algorithm: mgf1 with sha1 (default)
Salt Length: 0xEA
server9-defaults.crt
Hash Algorithm: sha1 (default)
Mask Algorithm: mgf1 with sha1 (default)
Salt Length: 0x14 (default)
server9-sha224.crt
Hash Algorithm: sha224
Mask Algorithm: mgf1 with sha224
Salt Length: 0xE2
server9-sha256.crt
Hash Algorithm: sha256
Mask Algorithm: mgf1 with sha256
Salt Length: 0xDE
server9-sha384.crt
Hash Algorithm: sha384
Mask Algorithm: mgf1 with sha384
Salt Length: 0xCE
server9-sha512.crt
Hash Algorithm: sha512
Mask Algorithm: mgf1 with sha512
Salt Length: 0xBE
server9-with-ca.crt
Hash Algorithm: sha1 (default)
Mask Algorithm: mgf1 with sha1 (default)
Salt Length: 0xEA
server9.crt
Hash Algorithm: sha1 (default)
Mask Algorithm: mgf1 with sha1 (default)
Salt Length: 0xEA
These certificates are signed with a 2048-bit key. It appears that they are
all using saltlen = keylen - hashlen - 2, except for server9-defaults which is
using saltlen = hashlen.
**Test CRLs:**
crl-rsa-pss-sha1-badsign.pem
Hash Algorithm: sha1 (default)
Mask Algorithm: mgf1 with sha1 (default)
Salt Length: 0xEA
crl-rsa-pss-sha1.pem
Hash Algorithm: sha1 (default)
Mask Algorithm: mgf1 with sha1 (default)
Salt Length: 0xEA
crl-rsa-pss-sha224.pem
Hash Algorithm: sha224
Mask Algorithm: mgf1 with sha224
Salt Length: 0xE2
crl-rsa-pss-sha256.pem
Hash Algorithm: sha256
Mask Algorithm: mgf1 with sha256
Salt Length: 0xDE
crl-rsa-pss-sha384.pem
Hash Algorithm: sha384
Mask Algorithm: mgf1 with sha384
Salt Length: 0xCE
crl-rsa-pss-sha512.pem
Hash Algorithm: sha512
Mask Algorithm: mgf1 with sha512
Salt Length: 0xBE
These CRLs are signed with a 2048-bit key. It appears that they are
all using saltlen = keylen - hashlen - 2.
**Test CSRs:**
server9.req.sha1
Hash Algorithm: sha1 (default)
Mask Algorithm: mgf1 with sha1 (default)
Salt Length: 0x6A
server9.req.sha224
Hash Algorithm: sha224
Mask Algorithm: mgf1 with sha224
Salt Length: 0x62
server9.req.sha256
Hash Algorithm: sha256
Mask Algorithm: mgf1 with sha256
Salt Length: 0x5E
server9.req.sha384
Hash Algorithm: sha384
Mask Algorithm: mgf1 with sha384
Salt Length: 0x4E
server9.req.sha512
Hash Algorithm: sha512
Mask Algorithm: mgf1 with sha512
Salt Length: 0x3E
These CSRs are signed with a 2048-bit key. It appears that they are
all using saltlen = keylen - hashlen - 2.
### Possible courses of action
There's no question about what to do with TLS (any version); the only question
is about X.509 signature verification. Options include:
1. Doing all verifications with `PSA_ALG_RSA_PSS_ANY_SALT` - while this
wouldn't cause a concrete security issue, this would be non-compliant.
2. Doing verifications with `PSA_ALG_RSA_PSS` when we're lucky and the encoded
saltlen happens to match hashlen, and falling back to `ANY_SALT` otherwise.
Same issue as with the previous point, except more contained.
3. Reject all certificates with saltlen != hashlen. This includes all
certificates generated with OpenSSL using the default parameters, so it's
probably not acceptable.
4. Request an extension to the PSA Crypto API and use one of the above options
in the meantime. Such an extension seems inconvenient and not motivated by
strong security arguments, so it's unclear whether it would be accepted.
Since Mbed TLS 3.4, option 1 is implemented.
Limitations relevant for G2 (isolation of long-term secrets)
============================================================
Currently none.

View File

@ -0,0 +1,486 @@
This document explains the strategy that was used so far in starting the
migration to PSA Crypto and mentions future perspectives and open questions.
Goals
=====
Several benefits are expected from migrating to PSA Crypto:
G1. Use PSA Crypto drivers when available.
G2. Allow isolation of long-term secrets (for example, private keys).
G3. Allow isolation of short-term secrets (for example, TLS session keys).
G4. Have a clean, unified API for Crypto (retire the legacy API).
G5. Code size: compile out our implementation when a driver is available.
As of Mbed TLS 3.2, most of (G1) and all of (G2) is implemented when
`MBEDTLS_USE_PSA_CRYPTO` is enabled. For (G2) to take effect, the application
needs to be changed to use new APIs. For a more detailed account of what's
implemented, see `docs/use-psa-crypto.md`, where new APIs are about (G2), and
internal changes implement (G1).
As of early 2023, work towards G5 is in progress: Mbed TLS 3.3 and 3.4 saw
some improvements in this area, and more will be coming in future releases.
Generally speaking, the numbering above doesn't mean that each goal requires
the preceding ones to be completed.
Compile-time options
====================
We currently have a few compile-time options that are relevant to the migration:
- `MBEDTLS_PSA_CRYPTO_C` - enabled by default, controls the presence of the PSA
Crypto APIs.
- `MBEDTLS_USE_PSA_CRYPTO` - disabled by default (enabled in "full" config),
controls usage of PSA Crypto APIs to perform operations in X.509 and TLS
(G1 above), as well as the availability of some new APIs (G2 above).
- `PSA_CRYPTO_CONFIG` - disabled by default, supports builds with drivers and
without the corresponding software implementation (G5 above).
The reasons why `MBEDTLS_USE_PSA_CRYPTO` is optional and disabled by default
are:
- it's not fully compatible with `MBEDTLS_ECP_RESTARTABLE`: you can enable
both, but then you won't get the full effect of RESTARTBLE (see the
documentation of this option in `mbedtls_config.h`);
- to avoid a hard/default dependency of TLS, X.509 and PK on
`MBEDTLS_PSA_CRYPTO_C`, for backward compatibility reasons:
- When `MBEDTLS_PSA_CRYPTO_C` is enabled and used, applications need to call
`psa_crypto_init()` before TLS/X.509 uses PSA functions. (This prevents us
from even enabling the option by default.)
- `MBEDTLS_PSA_CRYPTO_C` has a hard dependency on `MBEDTLS_ENTROPY_C ||
MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG` but it's
currently possible to compile TLS and X.509 without any of the options.
Also, we can't just auto-enable `MBEDTLS_ENTROPY_C` as it doesn't build
out of the box on all platforms, and even less
`MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG` as it requires a user-provided RNG
function.
The downside of this approach is that until we are able to make
`MBDEDTLS_USE_PSA_CRYPTO` non-optional (always enabled), we have to maintain
two versions of some parts of the code: one using PSA, the other using the
legacy APIs. However, see next section for strategies that can lower that
cost. The rest of this section explains the reasons for the
incompatibilities mentioned above.
At the time of writing (early 2022) it is unclear what could be done about the
backward compatibility issues, and in particular if the cost of implementing
solutions to these problems would be higher or lower than the cost of
maintaining dual code paths until the next major version. (Note: these
solutions would probably also solve other problems at the same time.)
### `MBEDTLS_ECP_RESTARTABLE`
Currently this option controls not only the presence of restartable APIs in
the crypto library, but also their use in the TLS and X.509 layers. Since PSA
Crypto does not support restartable operations, there's a clear conflict: the
TLS and X.509 layers can't both use only PSA APIs and get restartable
behaviour.
Support for restartable (aka interruptible) ECDSA sign/verify operation was
added to PSA in Mbed TLS 3.4, but support for ECDH is not present yet.
It will then require follow-up work to make use of the new PSA APIs in
PK/X.509/TLS in all places where we currently allow restartable operations.
### Backward compatibility issues with making `MBEDTLS_USE_PSA_CRYPTO` always on
1. Existing applications may not be calling `psa_crypto_init()` before using
TLS, X.509 or PK. We can try to work around that by calling (the relevant
part of) it ourselves under the hood as needed, but that would likely require
splitting init between the parts that can fail and the parts that can't (see
<https://github.com/ARM-software/psa-crypto-api/pull/536> for that).
2. It's currently not possible to enable `MBEDTLS_PSA_CRYPTO_C` in
configurations that don't have `MBEDTLS_ENTROPY_C`, and we can't just
auto-enable the latter, as it won't build or work out of the box on all
platforms. There are two kinds of things we'd need to do if we want to work
around that:
1. Make it possible to enable the parts of PSA Crypto that don't require an
RNG (typically, public key operations, symmetric crypto, some key
management functions (destroy etc)) in configurations that don't have
`ENTROPY_C`. This requires going through the PSA code base to adjust
dependencies. Risk: there may be annoying dependencies, some of which may be
surprising.
2. For operations that require an RNG, provide an alternative function
accepting an explicit `f_rng` parameter (see #5238), that would be
available in entropy-less builds. (Then code using those functions still needs
to have one version using it, for entropy-less builds, and one version using
the standard function, for driver support in build with entropy.)
See <https://github.com/Mbed-TLS/mbedtls/issues/5156>.
Taking advantage of the existing abstractions layers - or not
=============================================================
The Crypto library in Mbed TLS currently has 3 abstraction layers that offer
algorithm-agnostic APIs for a class of algorithms:
- MD for messages digests aka hashes (including HMAC)
- Cipher for symmetric ciphers (included AEAD)
- PK for asymmetric (aka public-key) cryptography (excluding key exchange)
Note: key exchange (FFDH, ECDH) is not covered by an abstraction layer.
These abstraction layers typically provide, in addition to the API for crypto
operations, types and numerical identifiers for algorithms (for
example `mbedtls_cipher_mode_t` and its values). The
current strategy is to keep using those identifiers in most of the code, in
particular in existing structures and public APIs, even when
`MBEDTLS_USE_PSA_CRYPTO` is enabled. (This is not an issue for G1, G2, G3
above, and is only potentially relevant for G4.)
The are multiple strategies that can be used regarding the place of those
layers in the migration to PSA.
Silently call to PSA from the abstraction layer
-----------------------------------------------
- Provide a new definition (conditionally on `USE_PSA_CRYPTO`) of wrapper
functions in the abstraction layer, that calls PSA instead of the legacy
crypto API.
- Upside: changes contained to a single place, no need to change TLS or X.509
code anywhere.
- Downside: tricky to implement if the PSA implementation is currently done on
top of that layer (dependency loop).
This strategy is currently (early 2023) used for all operations in the PK
layer; the MD layer uses a variant where it dispatches to PSA if a driver is
available and the driver subsystem has been initialized, regardless of whether
`USE_PSA_CRYPTO` is enabled; see `md-cipher-dispatch.md` in the same directory
for details.
This strategy is not very well suited to the Cipher layer, as the PSA
implementation is currently done on top of that layer.
This strategy will probably be used for some time for the PK layer, while we
figure out what the future of that layer is: parts of it (parse/write, ECDSA
signatures in the format that X.509 & TLS want) are not covered by PSA, so
they will need to keep existing in some way. (Also, the PK layer is a good
place for dispatching to either PSA or `mbedtls_xxx_restartable` while that
part is not covered by PSA yet, if we decide to do that.)
Replace calls for each operation
--------------------------------
- For every operation that's done through this layer in TLS or X.509, just
replace function call with calls to PSA (conditionally on `USE_PSA_CRYPTO`)
- Upside: conceptually simple, and if the PSA implementation is currently done
on top of that layer, avoids concerns about dependency loops.
- Upside: opens the door to building TLS/X.509 without that layer, saving some
code size.
- Downside: TLS/X.509 code has to be done for each operation.
This strategy is currently (early 2023) used for the MD layer and the Cipher
layer in X.509 and TLS. Crypto modules however always call to MD which may
then dispatch to PSA, see `md-cipher-dispatch.md`.
Opt-in use of PSA from the abstraction layer
--------------------------------------------
- Provide a new way to set up a context that causes operations on that context
to be done via PSA.
- Upside: changes mostly contained in one place, TLS/X.509 code only needs to
be changed when setting up the context, but not when using it. In
particular, no changes to/duplication of existing public APIs that expect a
key to be passed as a context of this layer (eg, `mbedtls_pk_context`).
- Upside: avoids dependency loop when PSA implemented on top of that layer.
- Downside: when the context is typically set up by the application, requires
changes in application code.
This strategy is not useful when no context is used, for example with the
one-shot function `mbedtls_md()`.
There are two variants of this strategy: one where using the new setup
function also allows for key isolation (the key is only held by PSA,
supporting both G1 and G2 in that area), and one without isolation (the key is
still stored outside of PSA most of the time, supporting only G1).
This strategy, with support for key isolation, is currently (early 2022) used for
private-key operations in the PK layer - see `mbedtls_pk_setup_opaque()`. This
allows use of PSA-held private ECDSA keys in TLS and X.509 with no change to
the TLS/X.509 code, but a contained change in the application.
This strategy, without key isolation, was also previously used (until 3.1
included) in the Cipher layer - see `mbedtls_cipher_setup_psa()`. This allowed
use of PSA for cipher operations in TLS with no change to the application
code, and a contained change in TLS code. (It only supported a subset of
ciphers.)
Note: for private key operations in the PK layer, both the "silent" and the
"opt-in" strategy can apply, and can complement each other, as one provides
support for key isolation, but at the (unavoidable) code of change in
application code, while the other requires no application change to get
support for drivers, but fails to provide isolation support.
Summary
-------
Strategies currently (early 2022) used with each abstraction layer:
- PK (for G1): silently call PSA
- PK (for G2): opt-in use of PSA (new key type)
- Cipher (G1): replace calls at each call site
- MD (G1, X.509 and TLS): replace calls at each call site (depending on
`USE_PSA_CRYPTO`)
- MD (G5): silently call PSA when a driver is available, see
`md-cipher-dispatch.md`.
Supporting builds with drivers without the software implementation
==================================================================
This section presents a plan towards G5: save code size by compiling out our
software implementation when a driver is available.
Let's expand a bit on the definition of the goal: in such a configuration
(driver used, software implementation and abstraction layer compiled out),
we want:
a. the library to build in a reasonably-complete configuration,
b. with all tests passing,
c. and no more tests skipped than the same configuration with software
implementation.
Criterion (c) ensures not only test coverage, but that driver-based builds are
at feature parity with software-based builds.
We can roughly divide the work needed to get there in the following steps:
0. Have a working driver interface for the algorithms we want to replace.
1. Have users of these algorithms call to PSA or an abstraction layer than can
dispatch to PSA, but not the low-level legacy API, for all operations.
(This is G1, and for PK, X.509 and TLS this is controlled by
`MBEDTLS_USE_PSA_CRYPTO`.) This needs to be done in the library and tests.
2. Have users of these algorithms not depend on the legacy API for information
management (getting a size for a given algorithm, etc.)
3. Adapt compile-time guards used to query availability of a given algorithm;
this needs to be done in the library (for crypto operations and data) and
tests.
Note: the first two steps enable use of drivers, but not by themselves removal
of the software implementation.
Note: the fact that step 1 is not achieved for all of libmbedcrypto (see
below) is the reason why criterion (a) has "a reasonably-complete
configuration", to allow working around internal crypto dependencies when
working on other parts such as X.509 and TLS - for example, a configuration
without RSA PKCS#1 v2.1 still allows reasonable use of X.509 and TLS.
Note: this is a conceptual division that will sometimes translate to how the
work is divided into PRs, sometimes not. For example, in situations where it's
not possible to achieve good test coverage at the end of step 1 or step 2, it
is preferable to group with the next step(s) in the same PR until good test
coverage can be reached.
**Status as of end of March 2023 (shortly after 3.4):**
- Step 0 is achieved for most algorithms, with only a few gaps remaining.
- Step 1 is achieved for most of PK, X.509, and TLS when
`MBEDTLS_USE_PSA_CRYPTO` is enabled with only a few gaps remaining (see
docs/use-psa-crypto.md).
- Step 1 is achieved for the crypto library regarding hashes: everything uses
MD (not low-level hash APIs), which then dispatches to PSA if applicable.
- Step 1 is not achieved for all of the crypto library when it come to
ciphers. For example,`ctr_drbg.c` calls the legacy API `mbedtls_aes`.
- Step 2 is achieved for most of X.509 and TLS (same gaps as step 1) when
`MBEDTLS_USE_PSA_CRYPTO` is enabled.
- Step 3 is done for hashes and top-level ECC modules (ECDSA, ECDH, ECJPAKE).
**Strategy for step 1:**
Regarding PK, X.509, and TLS, this is mostly achieved with only a few gaps.
(The strategy was outlined in the previous section.)
Regarding libmbedcrypto:
- for hashes and ciphers, see `md-cipher-dispatch.md` in the same directory;
- for ECC, we have no internal uses of the top-level algorithms (ECDSA, ECDH,
ECJPAKE), however they all depend on `ECP_C` which in turn depends on
`BIGNUM_C`. So, direct calls from TLS, X.509 and PK to ECP and Bignum will
need to be replaced; see <https://github.com/Mbed-TLS/mbedtls/issues/6839> and
linked issues for a summary of intermediate steps and open points.
**Strategy for step 2:**
The most satisfying situation here is when we can just use the PSA Crypto API
for information management as well. However sometimes it may not be
convenient, for example in parts of the code that accept old-style identifiers
(such as `mbedtls_md_type_t`) in their API and can't assume PSA to be
compiled in (such as `rsa.c`).
When using an existing abstraction layer such as MD, it can provide
information management functions. In other cases, information that was in a
low-level module but logically belongs in a higher-level module can be moved
to that module (for example, TLS identifiers of curves and there conversion
to/from PSA or legacy identifiers belongs in TLS, not `ecp.c`).
**Strategy for step 3:**
There are currently two (complementary) ways for crypto-using code to check if a
particular algorithm is supported: using `MBEDTLS_xxx` macros, and using
`PSA_WANT_xxx` macros. For example, PSA-based code that want to use SHA-256
will check for `PSA_WANT_ALG_SHA_256`, while legacy-based code that wants to
use SHA-256 will check for `MBEDTLS_SHA256_C` if using the `mbedtls_sha256`
API, or for `MBEDTLS_MD_C && MBEDTLS_SHA256_C` if using the `mbedtls_md` API.
Code that obeys `MBEDTLS_USE_PSA_CRYPTO` will want to use one of the two
dependencies above depending on whether `MBEDTLS_USE_PSA_CRYPTO` is defined:
if it is, the code want the algorithm available in PSA, otherwise, it wants it
available via the legacy API(s) is it using (MD and/or low-level).
As much as possible, we're trying to create for each algorithm a single new
macro that can be used to express dependencies everywhere (except pure PSA
code that should always use `PSA_WANT`). For example, for hashes this is the
`MBEDTLS_MD_CAN_xxx` family. For ECC algorithms, we have similar
`MBEDTLS_PK_CAN_xxx` macros.
Note that in order to achieve that goal, even for code that obeys
`USE_PSA_CRYPTO`, it is useful to impose that all algorithms that are
available via the legacy APIs are also available via PSA.
Executing step 3 will mostly consist of using the right dependency macros in
the right places (once the previous steps are done).
**Note on testing**
Since supporting driver-only builds is not about adding features, but about
supporting existing features in new types of builds, testing will not involve
adding cases to the test suites, but instead adding new components in `all.sh`
that build and run tests in newly-supported configurations. For example, if
we're making some part of the library work with hashes provided only by
drivers when `MBEDTLS_USE_PSA_CRYPTO` is defined, there should be a place in
`all.sh` that builds and run tests in such a configuration.
There is however a risk, especially in step 3 where we change how dependencies
are expressed (sometimes in bulk), to get things wrong in a way that would
result in more tests being skipped, which is easy to miss. Care must be
taken to ensure this does not happen. The following criteria can be used:
1. The sets of tests skipped in the default config and the full config must be
the same before and after the PR that implements step 3. This is tested
manually for each PR that changes dependency declarations by using the script
`outcome-analysis.sh` in the present directory.
2. The set of tests skipped in the driver-only build is the same as in an
equivalent software-based configuration. This is tested automatically by the
CI in the "Results analysis" stage, by running
`tests/scripts/analyze_outcomes.py`. See the
`analyze_driver_vs_reference_xxx` actions in the script and the comments above
their declaration for how to do that locally.
Migrating away from the legacy API
==================================
This section briefly introduces questions and possible plans towards G4,
mainly as they relate to choices in previous stages.
The role of the PK/Cipher/MD APIs in user migration
---------------------------------------------------
We're currently taking advantage of the existing PK layer in order
to reduce the number of places where library code needs to be changed. It's
only natural to consider using the same strategy (with the PK, MD and Cipher
layers) for facilitating migration of application code.
Note: a necessary first step for that would be to make sure PSA is no longer
implemented of top of the concerned layers
### Zero-cost compatibility layer?
The most favourable case is if we can have a zero-cost abstraction (no
runtime, RAM usage or code size penalty), for example just a bunch of
`#define`s, essentially mapping `mbedtls_` APIs to their `psa_` equivalent.
Unfortunately that's unlikely to fully work. For example, the MD layer uses the
same context type for hashes and HMACs, while the PSA API (rightfully) has
distinct operation types. Similarly, the Cipher layer uses the same context
type for unauthenticated and AEAD ciphers, which again the PSA API
distinguishes.
It is unclear how much value, if any, a zero-cost compatibility layer that's
incomplete (for example, for MD covering only hashes, or for Cipher covering
only AEAD) or differs significantly from the existing API (for example,
introducing new context types) would provide to users.
### Low-cost compatibility layers?
Another possibility is to keep most or all of the existing API for the PK, MD
and Cipher layers, implemented on top of PSA, aiming for the lowest possible
cost. For example, `mbedtls_md_context_t` would be defined as a (tagged) union
of `psa_hash_operation_t` and `psa_mac_operation_t`, then `mbedtls_md_setup()`
would initialize the correct part, and the rest of the functions be simple
wrappers around PSA functions. This would vastly reduce the complexity of the
layers compared to the existing (no need to dispatch through function
pointers, just call the corresponding PSA API).
Since this would still represent a non-zero cost, not only in terms of code
size, but also in terms of maintenance (testing, etc.) this would probably
be a temporary solution: for example keep the compatibility layers in 4.0 (and
make them optional), but remove them in 5.0.
Again, this provides the most value to users if we can manage to keep the
existing API unchanged. Their might be conflicts between this goal and that of
reducing the cost, and judgment calls may need to be made.
Note: when it comes to holding public keys in the PK layer, depending on how
the rest of the code is structured, it may be worth holding the key data in
memory controlled by the PK layer as opposed to a PSA key slot, moving it to a
slot only when needed (see current `ecdsa_verify_wrap` when
`MBEDTLS_USE_PSA_CRYPTO` is defined) For example, when parsing a large
number, N, of X.509 certificates (for example the list of trusted roots), it
might be undesirable to use N PSA key slots for their public keys as long as
the certs are loaded. OTOH, this could also be addressed by merging the "X.509
parsing on-demand" (#2478), and then the public key data would be held as
bytes in the X.509 CRT structure, and only moved to a PK context / PSA slot
when it's actually used.
Note: the PK layer actually consists of two relatively distinct parts: crypto
operations, which will be covered by PSA, and parsing/writing (exporting)
from/to various formats, which is currently not fully covered by the PSA
Crypto API.
### Algorithm identifiers and other identifiers
It should be easy to provide the user with a bunch of `#define`s for algorithm
identifiers, for example `#define MBEDTLS_MD_SHA256 PSA_ALG_SHA_256`; most of
those would be in the MD, Cipher and PK compatibility layers mentioned above,
but there might be some in other modules that may be worth considering, for
example identifiers for elliptic curves.
### Lower layers
Generally speaking, we would retire all of the low-level, non-generic modules,
such as AES, SHA-256, RSA, DHM, ECDH, ECP, bignum, etc, without providing
compatibility APIs for them. People would be encouraged to switch to the PSA
API. (The compatibility implementation of the existing PK, MD, Cipher APIs
would mostly benefit people who already used those generic APis rather than
the low-level, alg-specific ones.)
### APIs in TLS and X.509
Public APIs in TLS and X.509 may be affected by the migration in at least two
ways:
1. APIs that rely on a legacy `mbedtls_` crypto type: for example
`mbedtls_ssl_conf_own_cert()` to configure a (certificate and the
associated) private key. Currently the private key is passed as a
`mbedtls_pk_context` object, which would probably change to a `psa_key_id_t`.
Since some users would probably still be using the compatibility PK layer, it
would need a way to easily extract the PSA key ID from the PK context.
2. APIs the accept list of identifiers: for example
`mbedtls_ssl_conf_curves()` taking a list of `mbedtls_ecp_group_id`s. This
could be changed to accept a list of pairs (`psa_ecc_family_t`, size) but we
should probably take this opportunity to move to a identifier independent from
the underlying crypto implementation and use TLS-specific identifiers instead
(based on IANA values or custom enums), as is currently done in the new
`mbedtls_ssl_conf_groups()` API, see #4859).
Testing
-------
An question that needs careful consideration when we come around to removing
the low-level crypto APIs and making PK, MD and Cipher optional compatibility
layers is to be sure to preserve testing quality. A lot of the existing test
cases use the low level crypto APIs; we would need to either keep using that
API for tests, or manually migrate tests to the PSA Crypto API. Perhaps a
combination of both, perhaps evolving gradually over time.

View File

@ -0,0 +1,73 @@
#!/bin/sh
#
# Copyright The Mbed TLS Contributors
# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
#
# Purpose
#
# Show external links in built libraries (X509 or TLS) or modules. This is
# usually done to list Crypto dependencies or to check modules'
# interdependencies.
#
# Usage:
# - build the library with debug symbols and the config you're interested in
# (default, full minus MBEDTLS_USE_PSA_CRYPTO, full, etc.)
# - launch this script with 1 or more arguments depending on the analysis' goal:
# - if only 1 argument is used (which is the name of the used config,
# ex: full), then the analysis is done on libmbedx509 and libmbedtls
# libraries by default
# - if multiple arguments are provided, then modules' names (ex: pk,
# pkparse, pkwrite, etc) are expected after the 1st one and the analysis
# will be done on those modules instead of the libraries.
set -eu
# list mbedtls_ symbols of a given type in a static library
syms() {
TYPE="$1"
FILE="$2"
nm "$FILE" | sed -n "s/[0-9a-f ]*${TYPE} \(mbedtls_.*\)/\1/p" | sort -u
}
# Check if the provided name refers to a module or library and return the
# same path with proper extension
get_file_with_extension() {
BASE=$1
if [ -f $BASE.o ]; then
echo $BASE.o
elif [ -f $BASE.a ]; then
echo $BASE.a
fi
}
# create listings for the given library
list() {
NAME="$1"
FILE=$(get_file_with_extension "library/${NAME}")
PREF="${CONFIG}-$NAME"
syms '[TRrD]' $FILE > ${PREF}-defined
syms U $FILE > ${PREF}-unresolved
diff ${PREF}-defined ${PREF}-unresolved \
| sed -n 's/^> //p' > ${PREF}-external
sed 's/mbedtls_\([^_]*\).*/\1/' ${PREF}-external \
| uniq -c | sort -rn > ${PREF}-modules
rm ${PREF}-defined ${PREF}-unresolved
}
CONFIG="${1:-unknown}"
# List of modules to check is provided as parameters
if [ $# -gt 1 ]; then
shift 1
ITEMS_TO_CHECK="$@"
else
ITEMS_TO_CHECK="libmbedx509 libmbedtls"
fi
for ITEM in $ITEMS_TO_CHECK; do
list $ITEM
done

View File

@ -0,0 +1,99 @@
Testing strategy for `MBEDTLS_USE_PSA_CRYPTO`
=============================================
This document records the testing strategy used so far in implementing
`MBEDTLS_USE_PSA_CRYPTO`.
General considerations
----------------------
There needs to be at least one build in `all.sh` that enables
`MBEDTLS_USE_PSA_CRYPTO` and runs the full battery of tests; currently that's
ensured by the fact that `scripts/config.py full` enables
`MBEDTLS_USE_PSA_CRYPTO`. There needs to be at least one build with
`MBEDTLS_USE_PSA_CRYPTO` disabled (as long as it's optional); currently that's
ensured by the fact that it's disabled in the default config.
Generally, code review is enough to ensure that PSA APIs are indeed used where
they should be when `MBEDTLS_USE_PSA_CRYPTO` is enabled.
However, when it comes to TLS, we also have the option of using debug messages
to confirm which code path is taken. This is generally unnecessary, except when
a decision is made at run-time about whether to use the PSA or legacy code
path. (For example, for record protection, previously (until 3.1), some ciphers were supported
via PSA while some others weren't, with a run-time fallback. In this case, it's
good to have a debug message checked by the test case to confirm that the
right decision was made at run-time, i. e. that we didn't use the fallback for
ciphers that are supposed to be supported.)
New APIs meant for application use
----------------------------------
For example, `mbedtls_pk_setup_opaque()` is meant to be used by applications
in order to create PK contexts that can then be passed to existing TLS and
X.509 APIs (which remain unchanged).
In that case, we want:
- unit testing of the new API and directly-related APIs - for example:
- in `test_suite_pk` we have a new test function `pk_psa_utils` that exercises
`mbedtls_pk_setup_opaque()` and checks that various utility functions
(`mbedtls_pk_get_type()` etc.) work and the functions that are expected to
fail (`mbedtls_pk_verify()` etc) return the expected error.
- in `test_suite_pk` we modified the existing `pk_psa_sign` test function to
check that signature generation works as expected
- in `test_suite_pkwrite` we should have a new test function checking that
exporting (writing out) the public part of the key works as expected and
that exporting the private key fails as expected.
- integration testing of the new API with each existing API which should
accepts a context created this way - for example:
- in `programs/ssl/ssl_client2` a new option `key_opaque` that causes the
new API to be used, and one or more tests in `ssl-opt.sh` using that.
(We should have the same server-side.)
- in `test_suite_x509write` we have a new test function
`x509_csr_check_opaque()` checking integration of the new API with the
existing `mbedtls_x509write_csr_set_key()`. (And also
`mbedtls_x509write_crt_set_issuer_key()` since #5710.)
For some APIs, for example with `mbedtls_ssl_conf_psk_opaque()`, testing in
`test_suite_ssl` was historically not possible, so we only have testing in
`ssl-opt.sh`.
New APIs meant for internal use
-------------------------------
For example, `mbedtls_cipher_setup_psa()` (no longer used, soon to be
deprecated - #5261) was meant to be used by the TLS layer, but probably not
directly by applications.
In that case, we want:
- unit testing of the new API and directly-related APIs - for example:
- in `test_suite_cipher`, the existing test functions `auth_crypt_tv` and
`test_vec_crypt` gained a new parameter `use_psa` and corresponding test
cases
- integration testing:
- usually already covered by existing tests for higher-level modules:
- for example simple use of `mbedtls_cipher_setup_psa()` in TLS is already
covered by running the existing TLS tests in a build with
`MBEDTLS_USA_PSA_CRYPTO` enabled
- however if use of the new API in higher layers involves more logic that
use of the old API, specific integrations test may be required
- for example, the logic to fall back from `mbedtls_cipher_setup_psa()` to
`mbedtls_cipher_setup()` in TLS is tested by `run_test_psa` in
`ssl-opt.sh`.
Internal changes
----------------
For example, use of PSA to compute the TLS 1.2 PRF.
Changes in this category rarely require specific testing, as everything should
be already be covered by running the existing tests in a build with
`MBEDTLS_USE_PSA_CRYPTO` enabled; however we need to make sure the existing
test have sufficient coverage, and improve them if necessary.
However, if additional logic is involved, or there are run-time decisions about
whether to use the PSA or legacy code paths, specific tests might be in order.

View File

@ -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 `tests/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 `programs/test/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`.

View File

@ -0,0 +1,536 @@
# 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.
#### Dynamic secure element transaction file
Note that the code base already references a “transaction file” (`PSA_CRYPTO_ITS_TRANSACTION_UID` = 0xffffff54), used by dynamic secure elements (feature enabled with `MBEDTLS_PSA_CRYPTO_SE_C`). This is a deprecated feature that has not been fully implemented: when this feature is enabled, the transaction file gets written during transactions, but if it exists when PSA crypto starts, `psa_crypto_init()` fails because [recovery has never been implemented](https://github.com/ARMmbed/mbed-crypto/issues/218).
For the new kind of secure element driver, we pick a different file name to avoid any mixup.
## 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

View File

@ -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.

View File

@ -0,0 +1,133 @@
# Mbed TLS driver interface test strategy
This document describes the test strategy for the driver interfaces in Mbed TLS. Mbed TLS has interfaces for secure element drivers, accelerator drivers and entropy drivers. This document is about testing Mbed TLS itself; testing drivers is out of scope.
The driver interfaces are standardized through PSA Cryptography functional specifications.
## Secure element driver interface testing
### Secure element driver interfaces
#### Opaque driver interface
The [unified driver interface](../../proposed/psa-driver-interface.md) supports both transparent drivers (for accelerators) and opaque drivers (for secure elements).
Drivers exposing this interface need to be registered at compile time by declaring their JSON description file.
#### Dynamic secure element driver interface
The dynamic secure element driver interface (SE interface for short) is defined by [`psa/crypto_se_driver.h`](../../../include/psa/crypto_se_driver.h). This is an interface between Mbed TLS and one or more third-party drivers.
The SE interface consists of one function provided by Mbed TLS (`psa_register_se_driver`) and many functions that drivers must implement. To make a driver usable by Mbed TLS, the initialization code must call `psa_register_se_driver` with a structure that describes the driver. The structure mostly contains function pointers, pointing to the driver's methods. All calls to a driver function are triggered by a call to a PSA crypto API function.
### SE driver interface unit tests
This section describes unit tests that must be implemented to validate the secure element driver interface. Note that a test case may cover multiple requirements; for example a “good case” test can validate that the proper function is called, that it receives the expected inputs and that it produces the expected outputs.
Many SE driver interface unit tests could be covered by running the existing API tests with a key in a secure element.
#### SE driver registration
This applies to dynamic drivers only.
* Test `psa_register_se_driver` with valid and with invalid arguments.
* Make at least one failing call to `psa_register_se_driver` followed by a successful call.
* Make at least one test that successfully registers the maximum number of drivers and fails to register one more.
#### Dispatch to SE driver
For each API function that can lead to a driver call (more precisely, for each driver method call site, but this is practically equivalent):
* Make at least one test with a key in a secure element that checks that the driver method is called. A few API functions involve multiple driver methods; these should validate that all the expected driver methods are called.
* Make at least one test with a key that is not in a secure element that checks that the driver method is not called.
* Make at least one test with a key in a secure element with a driver that does not have the requisite method (i.e. the method pointer is `NULL`) but has the substructure containing that method, and check that the return value is `PSA_ERROR_NOT_SUPPORTED`.
* Make at least one test with a key in a secure element with a driver that does not have the substructure containing that method (i.e. the pointer to the substructure is `NULL`), and check that the return value is `PSA_ERROR_NOT_SUPPORTED`.
* At least one test should register multiple drivers with a key in each driver and check that the expected driver is called. This does not need to be done for all operations (use a white-box approach to determine if operations may use different code paths to choose the driver).
* At least one test should register the same driver structure with multiple lifetime values and check that the driver receives the expected lifetime value.
Some methods only make sense as a group (for example a driver that provides the MAC methods must provide all or none). In those cases, test with all of them null and none of them null.
#### SE driver inputs
For each API function that can lead to a driver call (more precisely, for each driver method call site, but this is practically equivalent):
* Wherever the specification guarantees parameters that satisfy certain preconditions, check these preconditions whenever practical.
* If the API function can take parameters that are invalid and must not reach the driver, call the API function with such parameters and verify that the driver method is not called.
* Check that the expected inputs reach the driver. This may be implicit in a test that checks the outputs if the only realistic way to obtain the correct outputs is to start from the expected inputs (as is often the case for cryptographic material, but not for metadata).
#### SE driver outputs
For each API function that leads to a driver call, call it with parameters that cause a driver to be invoked and check how Mbed TLS handles the outputs.
* Correct outputs.
* Incorrect outputs such as an invalid output length.
* Expected errors (e.g. `PSA_ERROR_INVALID_SIGNATURE` from a signature verification method).
* Unexpected errors. At least test that if the driver returns `PSA_ERROR_GENERIC_ERROR`, this is propagated correctly.
Key creation functions invoke multiple methods and need more complex error handling:
* Check the consequence of errors detected at each stage (slot number allocation or validation, key creation method, storage accesses).
* Check that the storage ends up in the expected state. At least make sure that no intermediate file remains after a failure.
#### Persistence of SE keys
The following tests must be performed at least one for each key creation method (import, generate, ...).
* Test that keys in a secure element survive `psa_close_key(); psa_open_key()`.
* Test that keys in a secure element survive `mbedtls_psa_crypto_free(); psa_crypto_init()`.
* Test that the driver's persistent data survives `mbedtls_psa_crypto_free(); psa_crypto_init()`.
* Test that `psa_destroy_key()` does not leave any trace of the key.
#### Resilience for SE drivers
Creating or removing a key in a secure element involves multiple storage modifications (M<sub>1</sub>, ..., M<sub>n</sub>). If the operation is interrupted by a reset at any point, it must be either rolled back or completed.
* For each potential interruption point (before M<sub>1</sub>, between M<sub>1</sub> and M<sub>2</sub>, ..., after M<sub>n</sub>), call `mbedtls_psa_crypto_free(); psa_crypto_init()` at that point and check that this either rolls back or completes the operation that was started.
* This must be done for each key creation method and for key destruction.
* This must be done for each possible flow, including error cases (e.g. a key creation that fails midway due to `OUT_OF_MEMORY`).
* The recovery during `psa_crypto_init` can itself be interrupted. Test those interruptions too.
* Two things need to be tested: the key that is being created or destroyed, and the driver's persistent storage.
* Check both that the storage has the expected content (this can be done by e.g. using a key that is supposed to be present) and does not have any unexpected content (for keys, this can be done by checking that `psa_open_key` fails with `PSA_ERROR_DOES_NOT_EXIST`).
This requires instrumenting the storage implementation, either to force it to fail at each point or to record successive storage states and replay each of them. Each `psa_its_xxx` function call is assumed to be atomic.
### SE driver system tests
#### Real-world use case
We must have at least one driver that is close to real-world conditions:
* With its own source tree.
* Running on actual hardware.
* Run the full driver validation test suite (which does not yet exist).
* Run at least one test application (e.g. the Mbed OS TLS example).
This requirement shall be fulfilled by the [Microchip ATECC508A driver](https://github.com/ARMmbed/mbed-os-atecc608a/).
#### Complete driver
We should have at least one driver that covers the whole interface:
* With its own source tree.
* Implementing all the methods.
* Run the full driver validation test suite (which does not yet exist).
A PKCS#11 driver would be a good candidate. It would be useful as part of our product offering.
## Transparent driver interface testing
The [unified driver interface](../../proposed/psa-driver-interface.md) defines interfaces for accelerators.
### Test requirements
#### Requirements for transparent driver testing
Every cryptographic mechanism for which a transparent driver interface exists (key creation, cryptographic operations, …) must be exercised in at least one build. The test must verify that the driver code is called.
#### Requirements for fallback
The driver interface includes a fallback mechanism so that a driver can reject a request at runtime and let another driver handle the request. For each entry point, there must be at least three test runs with two or more drivers available with driver A configured to fall back to driver B, with one run where A returns `PSA_SUCCESS`, one where A returns `PSA_ERROR_NOT_SUPPORTED` and B is invoked, and one where A returns a different error and B is not invoked.
## Entropy and randomness interface testing
TODO

View File

@ -0,0 +1,367 @@
# Mbed TLS invasive testing strategy
## Introduction
In Mbed TLS, we use black-box testing as much as possible: test the documented behavior of the product, in a realistic environment. However this is not always sufficient.
The goal of this document is to identify areas where black-box testing is insufficient and to propose solutions.
This is a test strategy document, not a test plan. A description of exactly what is tested is out of scope.
This document is structured as follows:
* [“Rules”](#rules) gives general rules and is written for brevity.
* [“Requirements”](#requirements) explores the reasons why invasive testing is needed and how it should be done.
* [“Possible approaches”](#possible-approaches) discusses some general methods for non-black-box testing.
* [“Solutions”](#solutions) explains how we currently solve, or intend to solve, specific problems.
### TLS
This document currently focuses on data structure manipulation and storage, which is what the crypto/keystore and X.509 parts of the library are about. More work is needed to fully take TLS into account.
## Rules
Always follow these rules unless you have a good reason not to. If you deviate, document the rationale somewhere.
See the section [“Possible approaches”](#possible-approaches) for a rationale.
### Interface design for testing
Do not add test-specific interfaces if there's a practical way of doing it another way. All public interfaces should be useful in at least some configurations. Features with a significant impact on the code size or attack surface should have a compile-time guard.
### Reliance on internal details
In unit tests and in test programs, it's ok to include internal header files from `library/`. Do not define non-public interfaces in public headers. In contrast, sample programs must not include header files from `library/`.
Sometimes it makes sense to have unit tests on functions that aren't part of the public API. Declare such functions in `library/*.h` and include the corresponding header in the test code. If the function should be `static` for optimization but can't be `static` for testing, declare it as `MBEDTLS_STATIC_TESTABLE`, and make the tests that use it depend on `MBEDTLS_TEST_HOOKS` (see [“rules for compile-time options”](#rules-for-compile-time-options)).
If test code or test data depends on internal details of the library and not just on its documented behavior, add a comment in the code that explains the dependency. For example:
> ```
> /* This test file is specific to the ITS implementation in PSA Crypto
> * on top of stdio. It expects to know what the stdio name of a file is
> * based on its keystore name.
> */
> ```
> ```
> # This test assumes that PSA_MAX_KEY_BITS (currently 65536-8 bits = 8191 bytes
> # and not expected to be raised any time soon) is less than the maximum
> # output from HKDF-SHA512 (255*64 = 16320 bytes).
> ```
### Rules for compile-time options
If the most practical way to test something is to add code to the product that is only useful for testing, do so, but obey the following rules. For more information, see the [rationale](#guidelines-for-compile-time-options).
* **Only use test-specific code when necessary.** Anything that can be tested through the documented API must be tested through the documented API.
* **Test-specific code must be guarded by `#if defined(MBEDTLS_TEST_HOOKS)`**. Do not create fine-grained guards for test-specific code.
* **Do not use `MBEDTLS_TEST_HOOKS` for security checks or assertions.** Security checks belong in the product.
* **Merely defining `MBEDTLS_TEST_HOOKS` must not change the behavior**. It may define extra functions. It may add fields to structures, but if so, make it very clear that these fields have no impact on non-test-specific fields.
* **Where tests must be able to change the behavior, do it by function substitution.** See [“rules for function substitution”](#rules-for-function-substitution) for more details.
#### Rules for function substitution
This section explains how to replace a library function `mbedtls_foo()` by alternative code for test purposes. That is, library code calls `mbedtls_foo()`, and there is a mechanism to arrange for these calls to invoke different code.
Often `mbedtls_foo` is a macro which is defined to be a system function (like `mbedtls_calloc` or `mbedtls_fopen`), which we replace to mock or wrap the system function. This is useful to simulate I/O failure, for example. Note that if the macro can be replaced at compile time to support alternative platforms, the test code should be compatible with this compile-time configuration so that it works on these alternative platforms as well.
Sometimes the substitutable function is a `static inline` function that does nothing (not a macro, to avoid accidentally skipping side effects in its parameters), to provide a hook for test code; such functions should have a name that starts with the prefix `mbedtls_test_hook_`. In such cases, the function should generally not modify its parameters, so any pointer argument should be const. The function should return void.
With `MBEDTLS_TEST_HOOKS` set, `mbedtls_foo` is a global variable of function pointer type. This global variable is initialized to the system function, or to a function that does nothing. The global variable is defined in a header in the `library` directory such as `psa_crypto_invasive.h`. This is similar to the platform function configuration mechanism with `MBEDTLS_PLATFORM_xxx_ALT`.
In unit test code that needs to modify the internal behavior:
* The test function (or the whole test file) must depend on `MBEDTLS_TEST_HOOKS`.
* At the beginning of the test function, set the global function pointers to the desired value.
* In the test function's cleanup code, restore the global function pointers to their default value.
## Requirements
### General goals
We need to balance the following goals, which are sometimes contradictory.
* Coverage: we need to test behaviors which are not easy to trigger by using the API or which cannot be triggered deterministically, for example I/O failures.
* Correctness: we want to test the actual product, not a modified version, since conclusions drawn from a test of a modified product may not apply to the real product.
* Effacement: the product should not include features that are solely present for test purposes, since these increase the attack surface and the code size.
* Portability: tests should work on every platform. Skipping tests on certain platforms may hide errors that are only apparent on such platforms.
* Maintainability: tests should only enforce the documented behavior of the product, to avoid extra work when the product's internal or implementation-specific behavior changes. We should also not give the impression that whatever the tests check is guaranteed behavior of the product which cannot change in future versions.
Where those goals conflict, we should at least mitigate the goals that cannot be fulfilled, and document the architectural choices and their rationale.
### Problem areas
#### Allocation
Resource allocation can fail, but rarely does so in a typical test environment. How does the product cope if some allocations fail?
Resources include:
* Memory.
* Files in storage (PSA API only — in the Mbed TLS API, black-box unit tests are sufficient).
* Key slots (PSA API only).
* Key slots in a secure element (PSA SE HAL).
* Communication handles (PSA crypto service only).
#### Storage
Storage can fail, either due to hardware errors or to active attacks on trusted storage. How does the code cope if some storage accesses fail?
We also need to test resilience: if the system is reset during an operation, does it restart in a correct state?
#### Cleanup
When code should clean up resources, how do we know that they have truly been cleaned up?
* Zeroization of confidential data after use.
* Freeing memory.
* Freeing key slots.
* Freeing key slots in a secure element.
* Deleting files in storage (PSA API only).
#### Internal data
Sometimes it is useful to peek or poke internal data.
* Check consistency of internal data (e.g. output of key generation).
* Check the format of files (which matters so that the product can still read old files after an upgrade).
* Inject faults and test corruption checks inside the product.
## Possible approaches
Key to requirement tables:
* ++ requirement is fully met
* \+ requirement is mostly met
* ~ requirement is partially met but there are limitations
* ! requirement is somewhat problematic
* !! requirement is very problematic
### Fine-grained public interfaces
We can include all the features we want to test in the public interface. Then the tests can be truly black-box. The limitation of this approach is that this requires adding a lot of interfaces that are not useful in production. These interfaces have costs: they increase the code size, the attack surface, and the testing burden (exponentially, because we need to test all these interfaces in combination).
As a rule, we do not add public interfaces solely for testing purposes. We only add public interfaces if they are also useful in production, at least sometimes. For example, the main purpose of `mbedtls_psa_crypto_free` is to clean up all resources in tests, but this is also useful in production in some applications that only want to use PSA Crypto during part of their lifetime.
Mbed TLS traditionally has very fine-grained public interfaces, with many platform functions that can be substituted (`MBEDTLS_PLATFORM_xxx` macros). PSA Crypto has more opacity and less platform substitution macros.
| Requirement | Analysis |
| ----------- | -------- |
| Coverage | ~ Many useful tests are not reasonably achievable |
| Correctness | ++ Ideal |
| Effacement | !! Requires adding many otherwise-useless interfaces |
| Portability | ++ Ideal; the additional interfaces may be useful for portability beyond testing |
| Maintainability | !! Combinatorial explosion on the testing burden |
| | ! Public interfaces must remain for backward compatibility even if the test architecture changes |
### Fine-grained undocumented interfaces
We can include all the features we want to test in undocumented interfaces. Undocumented interfaces are described in public headers for the sake of the C compiler, but are described as “do not use” in comments (or not described at all) and are not included in Doxygen-rendered documentation. This mitigates some of the downsides of [fine-grained public interfaces](#fine-grained-public-interfaces), but not all. In particular, the extra interfaces do increase the code size, the attack surface and the test surface.
Mbed TLS traditionally has a few internal interfaces, mostly intended for cross-module abstraction leakage rather than for testing. For the PSA API, we favor [internal interfaces](#internal-interfaces).
| Requirement | Analysis |
| ----------- | -------- |
| Coverage | ~ Many useful tests are not reasonably achievable |
| Correctness | ++ Ideal |
| Effacement | !! Requires adding many otherwise-useless interfaces |
| Portability | ++ Ideal; the additional interfaces may be useful for portability beyond testing |
| Maintainability | ! Combinatorial explosion on the testing burden |
### Internal interfaces
We can write tests that call internal functions that are not exposed in the public interfaces. This is nice when it works, because it lets us test the unchanged product without compromising the design of the public interface.
A limitation is that these interfaces must exist in the first place. If they don't, this has mostly the same downside as public interfaces: the extra interfaces increase the code size and the attack surface for no direct benefit to the product.
Another limitation is that internal interfaces need to be used correctly. We may accidentally rely on internal details in the tests that are not necessarily always true (for example that are platform-specific). We may accidentally use these internal interfaces in ways that don't correspond to the actual product.
This approach is mostly portable since it only relies on C interfaces. A limitation is that the test-only interfaces must not be hidden at link time (but link-time hiding is not something we currently do). Another limitation is that this approach does not work for users who patch the library by replacing some modules; this is a secondary concern since we do not officially offer this as a feature.
| Requirement | Analysis |
| ----------- | -------- |
| Coverage | ~ Many useful tests require additional internal interfaces |
| Correctness | + Does not require a product change |
| | ~ The tests may call internal functions in a way that does not reflect actual usage inside the product |
| Effacement | ++ Fine as long as the internal interfaces aren't added solely for test purposes |
| Portability | + Fine as long as we control how the tests are linked |
| | ~ Doesn't work if the users rewrite an internal module |
| Maintainability | + Tests interfaces that are documented; dependencies in the tests are easily noticed when changing these interfaces |
### Static analysis
If we guarantee certain properties through static analysis, we don't need to test them. This puts some constraints on the properties:
* We need to have confidence in the specification (but we can gain this confidence by evaluating the specification on test data).
* This does not work for platform-dependent properties unless we have a formal model of the platform.
| Requirement | Analysis |
| ----------- | -------- |
| Coverage | ~ Good for platform-independent properties, if we can guarantee them statically |
| Correctness | + Good as long as we have confidence in the specification |
| Effacement | ++ Zero impact on the code |
| Portability | ++ Zero runtime burden |
| Maintainability | ~ Static analysis is hard, but it's also helpful |
### Compile-time options
If there's code that we want to have in the product for testing, but not in production, we can add a compile-time option to enable it. This is very powerful and usually easy to use, but comes with a major downside: we aren't testing the same code anymore.
| Requirement | Analysis |
| ----------- | -------- |
| Coverage | ++ Most things can be tested that way |
| Correctness | ! Difficult to ensure that what we test is what we run |
| Effacement | ++ No impact on the product when built normally or on the documentation, if done right |
| | ! Risk of getting “no impact” wrong |
| Portability | ++ It's just C code so it works everywhere |
| | ~ Doesn't work if the users rewrite an internal module |
| Maintainability | + Test interfaces impact the product source code, but at least they're clearly marked as such in the code |
#### Guidelines for compile-time options
* **Minimize the number of compile-time options.**<br>
Either we're testing or we're not. Fine-grained options for testing would require more test builds, especially if combinatorics enters the play.
* **Merely enabling the compile-time option should not change the behavior.**<br>
When building in test mode, the code should have exactly the same behavior. Changing the behavior should require some action at runtime (calling a function or changing a variable).
* **Minimize the impact on code**.<br>
We should not have test-specific conditional compilation littered through the code, as that makes the code hard to read.
### Runtime instrumentation
Some properties can be tested through runtime instrumentation: have the compiler or a similar tool inject something into the binary.
* Sanitizers check for certain bad usage patterns (ASan, MSan, UBSan, Valgrind).
* We can inject external libraries at link time. This can be a way to make system functions fail.
| Requirement | Analysis |
| ----------- | -------- |
| Coverage | ! Limited scope |
| Correctness | + Instrumentation generally does not affect the program's functional behavior |
| Effacement | ++ Zero impact on the code |
| Portability | ~ Depends on the method |
| Maintainability | ~ Depending on the instrumentation, this may require additional builds and scripts |
| | + Many properties come for free, but some require effort (e.g. the test code itself must be leak-free to avoid false positives in a leak detector) |
### Debugger-based testing
If we want to do something in a test that the product isn't capable of doing, we can use a debugger to read or modify the memory, or hook into the code at arbitrary points.
This is a very powerful approach, but it comes with limitations:
* The debugger may introduce behavior changes (e.g. timing). If we modify data structures in memory, we may do so in a way that the code doesn't expect.
* Due to compiler optimizations, the memory may not have the layout that we expect.
* Writing reliable debugger scripts is hard. We need to have confidence that we're testing what we mean to test, even in the face of compiler optimizations. Languages such as gdb make it hard to automate even relatively simple things such as finding the place(s) in the binary corresponding to some place in the source code.
* Debugger scripts are very much non-portable.
| Requirement | Analysis |
| ----------- | -------- |
| Coverage | ++ The sky is the limit |
| Correctness | ++ The code is unmodified, and tested as compiled (so we even detect compiler-induced bugs) |
| | ! Compiler optimizations may hinder |
| | ~ Modifying the execution may introduce divergence |
| Effacement | ++ Zero impact on the code |
| Portability | !! Not all environments have a debugger, and even if they do, we'd need completely different scripts for every debugger |
| Maintainability | ! Writing reliable debugger scripts is hard |
| | !! Very tight coupling with the details of the source code and even with the compiler |
## Solutions
This section lists some strategies that are currently used for invasive testing, or planned to be used. This list is not intended to be exhaustive.
### Memory management
#### Zeroization testing
Goal: test that `mbedtls_platform_zeroize` does wipe the memory buffer.
Solution ([debugger](#debugger-based-testing)): implemented in `tests/scripts/test_zeroize.gdb`.
Rationale: this cannot be tested by adding C code, because the danger is that the compiler optimizes the zeroization away, and any C code that observes the zeroization would cause the compiler not to optimize it away.
#### Memory cleanup
Goal: test the absence of memory leaks.
Solution ([instrumentation](#runtime-instrumentation)): run tests with ASan. (We also use Valgrind, but it's slower than ASan, so we favor ASan.)
Since we run many test jobs with a memory leak detector, each test function or test program must clean up after itself. Use the cleanup code (after the `exit` label in test functions) to free any memory that the function may have allocated.
#### Robustness against memory allocation failure
Solution: TODO. We don't test this at all at this point.
#### PSA key store memory cleanup
Goal: test the absence of resource leaks in the PSA key store code, in particular that `psa_close_key` and `psa_destroy_key` work correctly.
Solution ([internal interface](#internal-interfaces)): in most tests involving PSA functions, the cleanup code explicitly calls `PSA_DONE()` instead of `mbedtls_psa_crypto_free()`. `PSA_DONE` fails the test if the key store in memory is not empty.
Note there must also be tests that call `mbedtls_psa_crypto_free` with keys still open, to verify that it does close all keys.
`PSA_DONE` is a macro defined in `psa_crypto_helpers.h` which uses `mbedtls_psa_get_stats()` to get information about the keystore content before calling `mbedtls_psa_crypto_free()`. This feature is mostly but not exclusively useful for testing, and may be moved under `MBEDTLS_TEST_HOOKS`.
### PSA storage
#### PSA storage cleanup on success
Goal: test that no stray files are left over in the key store after a test that succeeded.
Solution: TODO. Currently the various test suites do it differently.
#### PSA storage cleanup on failure
Goal: ensure that no stray files are left over in the key store even if a test has failed (as that could cause other tests to fail).
Solution: TODO. Currently the various test suites do it differently.
#### PSA storage resilience
Goal: test the resilience of PSA storage against power failures.
Solution: TODO.
See the [secure element driver interface test strategy](driver-interface-test-strategy.html) for more information.
#### Corrupted storage
Goal: test the robustness against corrupted storage.
Solution ([internal interface](#internal-interfaces)): call `psa_its` functions to modify the storage.
#### Storage read failure
Goal: test the robustness against read errors.
Solution: TODO
#### Storage write failure
Goal: test the robustness against write errors (`STORAGE_FAILURE` or `INSUFFICIENT_STORAGE`).
Solution: TODO
#### Storage format stability
Goal: test that the storage format does not change between versions (or if it does, an upgrade path must be provided).
Solution ([internal interface](#internal-interfaces)): call internal functions to inspect the content of the file.
Note that the storage format is defined not only by the general layout, but also by the numerical values of encodings for key types and other metadata. For numerical values, there is a risk that we would accidentally modify a single value or a few values, so the tests should be exhaustive. This probably requires some compile-time analysis (perhaps the automation for `psa_constant_names` can be used here). TODO
### Other fault injection
#### PSA crypto init failure
Goal: test the failure of `psa_crypto_init`.
Solution ([compile-time option](#compile-time-options)): replace entropy initialization functions by functions that can fail. This is the only failure point for `psa_crypto_init` that is present in all builds.
When we implement the PSA entropy driver interface, this should be reworked to use the entropy driver interface.
#### PSA crypto data corruption
The PSA crypto subsystem has a few checks to detect corrupted data in memory. We currently don't have a way to exercise those checks.
Solution: TODO. To corrupt a multipart operation structure, we can do it by looking inside the structure content, but only when running without isolation. To corrupt the key store, we would need to add a function to the library or to use a debugger.

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