Added submodule contents into tree
This commit is contained in:
40
externals/mbedtls/3rdparty/p256-m/CMakeLists.txt
vendored
Normal file
40
externals/mbedtls/3rdparty/p256-m/CMakeLists.txt
vendored
Normal 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)
|
||||
5
externals/mbedtls/3rdparty/p256-m/Makefile.inc
vendored
Normal file
5
externals/mbedtls/3rdparty/p256-m/Makefile.inc
vendored
Normal 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
|
||||
4
externals/mbedtls/3rdparty/p256-m/README.md
vendored
Normal file
4
externals/mbedtls/3rdparty/p256-m/README.md
vendored
Normal 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()`.
|
||||
544
externals/mbedtls/3rdparty/p256-m/p256-m/README.md
vendored
Normal file
544
externals/mbedtls/3rdparty/p256-m/p256-m/README.md
vendored
Normal 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).
|
||||
1514
externals/mbedtls/3rdparty/p256-m/p256-m/p256-m.c
vendored
Normal file
1514
externals/mbedtls/3rdparty/p256-m/p256-m/p256-m.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
135
externals/mbedtls/3rdparty/p256-m/p256-m/p256-m.h
vendored
Normal file
135
externals/mbedtls/3rdparty/p256-m/p256-m/p256-m.h
vendored
Normal 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 */
|
||||
312
externals/mbedtls/3rdparty/p256-m/p256-m_driver_entrypoints.c
vendored
Normal file
312
externals/mbedtls/3rdparty/p256-m/p256-m_driver_entrypoints.c
vendored
Normal 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 */
|
||||
219
externals/mbedtls/3rdparty/p256-m/p256-m_driver_entrypoints.h
vendored
Normal file
219
externals/mbedtls/3rdparty/p256-m/p256-m_driver_entrypoints.h
vendored
Normal 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 */
|
||||
Reference in New Issue
Block a user