samples: tfm: Re-commit psa_crypto sample
Adds a refactored version of the psa_crypto sample back, which was removed as part of the update to TF-M 1.7.0 due to unresolvable (at the time) issues with use of MbedTLS instances on the S and NS sides. This sample takes advantage of changes to MbedTLS and TF-M that were introduced after the TF-M 1.7.0 and MbedTLS 3.3 release, and cherry-picked in Zephyr, allowing for improved linking of MbedTLS in secure and non-secure images. PSA API calls on the non-secure side can now be correctly routed to the secure partition, while X.509 and TLS calls remain on the non-secure/Zephyr side. Signed-off-by: Rajkumar Kanagaraj <rajkumar.kanagaraj@linaro.org>
This commit is contained in:
parent
80a06b2533
commit
682dbae203
21 changed files with 2248 additions and 0 deletions
29
samples/tfm_integration/psa_crypto/CMakeLists.txt
Normal file
29
samples/tfm_integration/psa_crypto/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
cmake_minimum_required(VERSION 3.20.0)
|
||||
|
||||
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
|
||||
|
||||
project(tfm_psa_crypto)
|
||||
|
||||
# Source files in this sample
|
||||
target_sources(app PRIVATE src/main.c)
|
||||
target_sources(app PRIVATE src/psa_attestation.c)
|
||||
target_sources(app PRIVATE src/psa_crypto.c)
|
||||
target_sources(app PRIVATE src/shell.c)
|
||||
target_sources(app PRIVATE src/util_app_cfg.c)
|
||||
target_sources(app PRIVATE src/util_app_log.c)
|
||||
target_sources(app PRIVATE src/util_sformat.c)
|
||||
|
||||
target_include_directories(app PRIVATE
|
||||
$<TARGET_PROPERTY:tfm,TFM_BINARY_DIR>/install/interface/include
|
||||
)
|
||||
|
||||
# In TF-M, default value of CRYPTO_ENGINE_BUF_SIZE is 0x2080. It causes
|
||||
# insufficient memory failure while verifying signature. Increase it to 0x2400.
|
||||
set_property(TARGET zephyr_property_target
|
||||
APPEND PROPERTY TFM_CMAKE_OPTIONS
|
||||
-DCRYPTO_ENGINE_BUF_SIZE=0x2400
|
||||
)
|
||||
|
||||
zephyr_include_directories(${APPLICATION_SOURCE_DIR}/src/tls_config)
|
||||
49
samples/tfm_integration/psa_crypto/Kconfig
Normal file
49
samples/tfm_integration/psa_crypto/Kconfig
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
# Private config options for PSA Crypto application
|
||||
|
||||
# Copyright (c) 2023 Linaro
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
mainmenu "PSA Crypto sample application"
|
||||
|
||||
menu "Application configuration"
|
||||
|
||||
module = PSA
|
||||
module-str = psa
|
||||
source "subsys/logging/Kconfig.template.log_config"
|
||||
|
||||
endmenu
|
||||
|
||||
config PSA_SHELL
|
||||
bool "The 'psa' shell command"
|
||||
depends on SHELL
|
||||
help
|
||||
Enabling this option will make the 'psa' shell command available.
|
||||
|
||||
config PSA_IMPORT_KEY
|
||||
bool "Support for importing private key data"
|
||||
help
|
||||
Enable support for importing a pre-generated or randomly generated
|
||||
private key using PSA APIs and PRIVATE_KEY_STATIC or
|
||||
PRIVATE_KEY_RANDOM.
|
||||
|
||||
choice
|
||||
prompt "Private Key"
|
||||
default PRIVATE_KEY_RANDOM
|
||||
|
||||
config PRIVATE_KEY_STATIC
|
||||
bool "Static"
|
||||
depends on PSA_IMPORT_KEY
|
||||
help
|
||||
A static key value will be used for the elliptic curve 'secp256r1'
|
||||
private key.
|
||||
|
||||
config PRIVATE_KEY_RANDOM
|
||||
bool "Random"
|
||||
depends on PSA_IMPORT_KEY
|
||||
help
|
||||
A randomly generated value will be used for the elliptic curve
|
||||
'secp256r1' private key.
|
||||
|
||||
endchoice
|
||||
|
||||
source "Kconfig.zephyr"
|
||||
388
samples/tfm_integration/psa_crypto/README.rst
Normal file
388
samples/tfm_integration/psa_crypto/README.rst
Normal file
|
|
@ -0,0 +1,388 @@
|
|||
.. _tfm_psa_crypto:
|
||||
|
||||
TF-M PSA crypto
|
||||
################
|
||||
|
||||
Overview
|
||||
********
|
||||
This TF-M integration example demonstrates how to use the PSA crypto API in
|
||||
Zephyr for cryptography and device certificate signing request. In addition,
|
||||
this example also demonstrates certain TF-M features that are covered as part
|
||||
of the RTOS vendor requirements for a `PSA Certified Level 1`_ product, such
|
||||
as secure storage for config data, initial attestation for device
|
||||
verification.
|
||||
|
||||
Trusted Firmware (TF-M) Platform Security Architecture (PSA) APIs
|
||||
are used for the secure processing environment, with Zephyr running in the
|
||||
non-secure processing environment.
|
||||
|
||||
It uses **IPC Mode** for communication, where an IPC mechanism is inserted to
|
||||
handle secure TF-M API calls and responses.
|
||||
|
||||
The sample prints test info to the console either as a single-thread or
|
||||
multi-thread application.
|
||||
|
||||
.. _PSA Certified Level 1:
|
||||
https://www.psacertified.org/security-certification/psa-certified-level-1/
|
||||
|
||||
Key Files
|
||||
*********
|
||||
|
||||
``psa_crypto.c``
|
||||
================
|
||||
|
||||
Demonstrates hash, sign/verify workflow:
|
||||
|
||||
- Generate/import a persistent key: secp256r1 (usage: ecdsa-with-SHA256)
|
||||
- Display the public key based on the private key data above
|
||||
- Calculate the SHA256 hash of a payload
|
||||
- Sign the hash with the persistent key
|
||||
- Verify the signature using the public key
|
||||
- Destroy the key
|
||||
|
||||
Also demonstrates device certificate signing request (CSR) workflow:
|
||||
|
||||
- Generate/import a persistent key: secp256r1 (usage: ecdsa-with-SHA256)
|
||||
- Set subject name in device CSR
|
||||
- Generate device CSR in PEM format
|
||||
- Encode device CSR as JSON
|
||||
|
||||
Importing/generating the persistent key is based on config option
|
||||
``PSA_IMPORT_KEY``. When ``PSA_IMPORT_KEY`` is enabled,
|
||||
the key data can be static if ``PRIVATE_KEY_STATIC`` is set or key data
|
||||
is generated using ``psa_generate_random`` if ``PRIVATE_KEY_RANDOM``
|
||||
is set.
|
||||
|
||||
``psa_attestation.c``
|
||||
=====================
|
||||
|
||||
Demonstrates how to request an initial attestation token (IAT) from the TF-M
|
||||
secure processing environment (SPE).
|
||||
|
||||
Building and Running
|
||||
********************
|
||||
|
||||
This project outputs startup status and info to the console. It can be built and
|
||||
executed on an ARM Cortex M33 target board or QEMU.
|
||||
|
||||
This sample will only build on a Linux or macOS development system
|
||||
(not Windows), and has been tested on the following setups:
|
||||
|
||||
- macOS Mojave using QEMU 4.2.0 with gcc-arm-none-eabi-7-2018-q2-update
|
||||
- macOS Mojave with gcc-arm-none-eabi-7-2018-q2-update
|
||||
- Ubuntu 18.04 using Zephyr SDK 0.11.2
|
||||
|
||||
TF-M BL2 logs
|
||||
=============
|
||||
Add the following to ``prj.conf`` to see the logs from TF-M BL2:
|
||||
.. code-block:: bash
|
||||
|
||||
CONFIG_TFM_BL2=y
|
||||
CONFIG_TFM_CMAKE_BUILD_TYPE_DEBUG=y
|
||||
|
||||
On MPS2+ AN521:
|
||||
===============
|
||||
|
||||
1. Build Zephyr with a non-secure configuration
|
||||
(``-DBOARD=mps2_an521_ns``).
|
||||
|
||||
Using ``west``
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
cd <ZEPHYR_ROOT>
|
||||
west build -p -b mps2_an521_ns samples/tfm_integration/psa_crypto
|
||||
|
||||
Using ``cmake`` and ``ninja``
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
cd <ZEPHYR_ROOT>/samples/tfm_integration/psa_crypto/
|
||||
rm -rf build
|
||||
mkdir build && cd build
|
||||
cmake -GNinja -DBOARD=mps2_an521_ns ..
|
||||
ninja
|
||||
|
||||
Using ``cmake`` and ``make``
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
cd <ZEPHYR_ROOT>/samples/tfm_integration/psa_crypto/
|
||||
rm -rf build
|
||||
mkdir build && cd build
|
||||
cmake -DBOARD=mps2_an521_ns ..
|
||||
make
|
||||
|
||||
2. Copy application binary files (mcuboot.bin and tfm_sign.bin) to
|
||||
``<MPS2 device name>/SOFTWARE/``.
|
||||
|
||||
3. Edit (e.g., with vim) the ``<MPS2 device name>/MB/HBI0263C/AN521/images.txt``
|
||||
file, and update it as shown below:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
TITLE: Versatile Express Images Configuration File
|
||||
|
||||
[IMAGES]
|
||||
TOTALIMAGES: 2 ;Number of Images (Max: 32)
|
||||
|
||||
IMAGE0ADDRESS: 0x10000000
|
||||
IMAGE0FILE: \SOFTWARE\mcuboot.bin ; BL2 bootloader
|
||||
|
||||
IMAGE1ADDRESS: 0x10080000
|
||||
IMAGE1FILE: \SOFTWARE\tfm_sign.bin ; TF-M with application binary blob
|
||||
|
||||
4. Save the file, exit the editor, and reset the MPS2+ board.
|
||||
|
||||
On QEMU:
|
||||
========
|
||||
|
||||
Build Zephyr with a non-secure configuration (``-DBOARD=mps2_an521_ns``)
|
||||
and run it in qemu via the ``run`` command.
|
||||
|
||||
Using ``west``
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
cd <ZEPHYR_ROOT>
|
||||
west build -p -b mps2_an521_ns samples/tfm_integration/psa_crypto -t run
|
||||
|
||||
Using ``cmake`` and ``ninja``
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
cd <ZEPHYR_ROOT>/samples/tfm_integration/psa_crypto/
|
||||
rm -rf build
|
||||
mkdir build && cd build
|
||||
cmake -GNinja -DBOARD=mps2_an521_ns ..
|
||||
ninja run
|
||||
|
||||
Using ``cmake`` and ``make``
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
cd <ZEPHYR_ROOT>/samples/tfm_integration/psa_crypto/
|
||||
rm -rf build
|
||||
mkdir build && cd build
|
||||
cmake -DBOARD=mps2_an521_ns ..
|
||||
make run
|
||||
|
||||
On LPCxpresso55S69:
|
||||
======================
|
||||
|
||||
Build Zephyr with a non-secure configuration:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ west build -p -b lpcxpresso55s69_ns samples/tfm_integration/psa_crypto/ --
|
||||
|
||||
Make sure your board is set up with :ref:`lpclink2-jlink-onboard-debug-probe`,
|
||||
since this isn't the debug interface boards ship with from the factory;
|
||||
|
||||
Next we need to manually flash the resulting image (``tfm_merged.bin``) with a
|
||||
J-Link as follows:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
JLinkExe -device lpc55s69 -if swd -speed 2000 -autoconnect 1
|
||||
J-Link>r
|
||||
J-Link>erase
|
||||
J-Link>loadfile build/tfm_merged.bin
|
||||
|
||||
Resetting the board and erasing it will unlock the board, this is useful in case
|
||||
it's in an unknown state and can't be flashed.
|
||||
|
||||
We need to reset the board manually after flashing the image to run this code.
|
||||
|
||||
On nRF5340 and nRF9160:
|
||||
=======================
|
||||
|
||||
Build Zephyr with a non-secure configuration
|
||||
(``-DBOARD=nrf5340dk_nrf5340_cpuapp_ns`` or ``-DBOARD=nrf9160dk_nrf9160_ns``).
|
||||
|
||||
Example, for nRF9160, using ``cmake`` and ``ninja``
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
cd <ZEPHYR_ROOT>/samples/tfm_integration/psa_crypto/
|
||||
rm -rf build
|
||||
mkdir build && cd build
|
||||
cmake -GNinja -DBOARD=nrf9160dk_nrf9160_ns ..
|
||||
|
||||
If building with BL2 (MCUboot bootloader) enabled, manually flash
|
||||
the MCUboot bootloader image binary (``bl2.hex``).
|
||||
|
||||
Example, using ``nrfjprog`` on nRF9160:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
nrfjprog -f NRF91 --program tfm/bin/bl2.hex --sectorerase
|
||||
|
||||
Finally, flash the concatenated TF-M + Zephyr binary.
|
||||
|
||||
Example, for nRF9160, using ``cmake`` and ``ninja``
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
ninja flash
|
||||
|
||||
On BL5340:
|
||||
==========
|
||||
|
||||
Build Zephyr with a non-secure configuration
|
||||
(``-DBOARD=bl5340_dvk_cpuapp_ns``).
|
||||
|
||||
Example using ``cmake`` and ``ninja``
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
cd <ZEPHYR_ROOT>/samples/tfm_integration/psa_crypto/
|
||||
rm -rf build
|
||||
mkdir build && cd build
|
||||
cmake -GNinja -DBOARD=bl5340_dvk_cpuapp_ns ..
|
||||
|
||||
Flash the concatenated TF-M + Zephyr binary.
|
||||
|
||||
Example using ``west``
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
west flash --hex-file tfm_merged.hex
|
||||
|
||||
Sample Output
|
||||
=============
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
[Sec Thread] Secure image initializing!
|
||||
Booting TFM v1.4.1
|
||||
[Crypto] Dummy Entropy NV Seed is not suitable for production!
|
||||
*** Booting Zephyr OS build v2.7.99-1102-gf503ba9f1ab3 ***
|
||||
[00:00:00.014,000] <inf> app: app_cfg: Creating new config file with UID 0x1055CFDA7A
|
||||
[00:00:01.215,000] <inf> app: att: System IAT size is: 545 bytes.
|
||||
[00:00:01.215,000] <inf> app: att: Requesting IAT with 64 byte challenge.
|
||||
[00:00:01.836,000] <inf> app: att: IAT data received: 545 bytes.
|
||||
|
||||
0 1 2 3 4 5 6 7 8 9 A B C D E F
|
||||
00000000 D2 84 43 A1 01 26 A0 59 01 D5 AA 3A 00 01 24 FF ..C..&.Y...:..$.
|
||||
00000010 58 40 00 11 22 33 44 55 66 77 88 99 AA BB CC DD X@.."3DUfw......
|
||||
00000020 EE FF 00 11 22 33 44 55 66 77 88 99 AA BB CC DD ...."3DUfw......
|
||||
00000030 EE FF 00 11 22 33 44 55 66 77 88 99 AA BB CC DD ...."3DUfw......
|
||||
00000040 EE FF 00 11 22 33 44 55 66 77 88 99 AA BB CC DD ...."3DUfw......
|
||||
00000050 EE FF 3A 00 01 24 FB 58 20 A0 A1 A2 A3 A4 A5 A6 ..:..$.X .......
|
||||
00000060 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 ................
|
||||
00000070 B7 B8 B9 BA BB BC BD BE BF 3A 00 01 25 00 58 21 .........:..%.X!
|
||||
00000080 01 FA 58 75 5F 65 86 27 CE 54 60 F2 9B 75 29 67 ..Xu_e.'.T`..u)g
|
||||
00000090 13 24 8C AE 7A D9 E2 98 4B 90 28 0E FC BC B5 02 .$..z...K.(.....
|
||||
000000A0 48 3A 00 01 24 FA 58 20 AA AA AA AA AA AA AA AA H:..$.X ........
|
||||
000000B0 BB BB BB BB BB BB BB BB CC CC CC CC CC CC CC CC ................
|
||||
000000C0 DD DD DD DD DD DD DD DD 3A 00 01 24 F8 20 3A 00 ........:..$. :.
|
||||
000000D0 01 24 F9 19 30 00 3A 00 01 24 FD 82 A5 01 63 53 .$..0.:..$....cS
|
||||
000000E0 50 45 04 65 30 2E 30 2E 30 05 58 20 BF E6 D8 6F PE.e0.0.0.X ...o
|
||||
000000F0 88 26 F4 FF 97 FB 96 C4 E6 FB C4 99 3E 46 19 FC .&..........>F..
|
||||
00000100 56 5D A2 6A DF 34 C3 29 48 9A DC 38 06 66 53 48 V].j.4.)H..8.fSH
|
||||
00000110 41 32 35 36 02 58 20 6D E1 0F 82 E0 CF FC 84 5A A256.X m.......Z
|
||||
00000120 24 25 2B EB 70 D7 2C 6B FC 92 CD BE 5B 65 9E C7 $%+.p.,k....[e..
|
||||
00000130 34 1E 1C D2 80 5D A3 A5 01 64 4E 53 50 45 04 65 4....]...dNSPE.e
|
||||
00000140 30 2E 30 2E 30 05 58 20 B3 60 CA F5 C9 8C 6B 94 0.0.0.X .`....k.
|
||||
00000150 2A 48 82 FA 9D 48 23 EF B1 66 A9 EF 6A 6E 4A A3 *H...H#..f..jnJ.
|
||||
00000160 7C 19 19 ED 1F CC C0 49 06 66 53 48 41 32 35 36 |......I.fSHA256
|
||||
00000170 02 58 20 01 4C F2 64 0D 49 F8 23 69 57 FE F3 73 .X .L.d.I.#iW..s
|
||||
00000180 97 7E 73 C2 2C 4F D2 95 25 D8 BE 29 32 14 23 5D .~s.,O..%..)2.#]
|
||||
00000190 A9 22 AD 3A 00 01 25 01 77 77 77 77 2E 74 72 75 .".:..%.wwww.tru
|
||||
000001A0 73 74 65 64 66 69 72 6D 77 61 72 65 2E 6F 72 67 stedfirmware.org
|
||||
000001B0 3A 00 01 24 F7 71 50 53 41 5F 49 4F 54 5F 50 52 :..$.qPSA_IOT_PR
|
||||
000001C0 4F 46 49 4C 45 5F 31 3A 00 01 24 FC 72 30 36 30 OFILE_1:..$.r060
|
||||
000001D0 34 35 36 35 32 37 32 38 32 39 31 30 30 31 30 58 456527282910010X
|
||||
000001E0 40 59 23 3E 80 5E E0 9F FA E3 F4 14 62 D3 15 A5 @Y#>.^......b...
|
||||
000001F0 B0 95 B5 E5 CB 79 92 F8 F1 A0 FE 14 0C 6C 84 2A .....y.......l.*
|
||||
00000200 41 97 BC 6F C6 7D 9C A5 21 BB 4C 2C D1 2C F3 66 A..o.}..!.L,.,.f
|
||||
00000210 4E D4 85 D2 57 15 72 11 E8 9E 06 4F C4 46 D0 58 N...W.r....O.F.X
|
||||
00000220 26 &
|
||||
|
||||
[00:00:01.905,000] <inf> app: Persisting SECP256R1 key as #1
|
||||
[00:00:02.458,000] <inf> app: Retrieving public key for key #1
|
||||
|
||||
0 1 2 3 4 5 6 7 8 9 A B C D E F
|
||||
00000000 04 07 93 39 CD 42 53 7B 18 8C 8A F1 05 7F 49 D1 ...9.BS{......I.
|
||||
00000010 6B 30 D5 39 0D 1A 6E 95 BA 0C CD FE DB 59 A3 03 k0.9..n......Y..
|
||||
00000020 02 61 B4 CF 13 CC 70 15 67 30 83 FE A0 D4 2A 19 .a....p.g0....*.
|
||||
00000030 72 82 3E 3F 90 00 91 C6 5E 43 DC E9 B4 C4 0E F3 r.>?....^C......
|
||||
00000040 79 y
|
||||
|
||||
[00:00:03.020,000] <inf> app: Calculating SHA-256 hash of value
|
||||
|
||||
0 1 2 3 4 5 6 7 8 9 A B C D E F
|
||||
00000000 50 6C 65 61 73 65 20 68 61 73 68 20 61 6E 64 20 Please hash and
|
||||
00000010 73 69 67 6E 20 74 68 69 73 20 6D 65 73 73 61 67 sign this messag
|
||||
00000020 65 2E e.
|
||||
|
||||
|
||||
0 1 2 3 4 5 6 7 8 9 A B C D E F
|
||||
00000000 9D 08 E3 E6 DB 1C 12 39 C0 9B 9A 83 84 83 72 7A .......9......rz
|
||||
00000010 EA 96 9E 1D 13 72 1E 4D 35 75 CC D4 C8 01 41 9C .....r.M5u....A.
|
||||
|
||||
[00:00:03.032,000] <inf> app: Signing SHA-256 hash
|
||||
|
||||
0 1 2 3 4 5 6 7 8 9 A B C D E F
|
||||
00000000 EE F1 FE A6 A8 41 5F CC A6 3A 73 A7 C1 33 B4 78 .....A_..:s..3.x
|
||||
00000010 BF B7 38 78 2A 91 C8 82 32 F8 73 85 56 08 D2 A0 ..8x*...2.s.V...
|
||||
00000020 A6 22 2C 64 7A C7 E4 0A FB 99 D1 8B 67 37 F7 13 .",dz.......g7..
|
||||
00000030 E6 6C 54 7B 29 1D 3B A2 D8 E3 C4 79 17 BA 34 A8 .lT{).;....y..4.
|
||||
|
||||
[00:00:03.658,000] <inf> app: Verifying signature for SHA-256 hash
|
||||
[00:00:06.339,000] <inf> app: Signature verified.
|
||||
[00:00:06.349,000] <inf> app: Destroyed persistent key #1
|
||||
[00:00:06.354,000] <inf> app: Generating 256 bytes of random data.
|
||||
|
||||
0 1 2 3 4 5 6 7 8 9 A B C D E F
|
||||
00000000 24 5C B3 EB 88 D2 80 76 23 B3 07 CA 16 92 8F 3D $\.....v#......=
|
||||
00000010 27 AC C2 42 59 15 5E 3C EB 11 20 3C 14 A6 EB 60 '..BY.^<.. <...`
|
||||
00000020 C0 92 12 97 4D D7 62 BC A0 0A 34 A7 CE A8 78 18 ....M.b...4...x.
|
||||
00000030 1B 30 6E 3C DA 80 F2 55 F7 FA 10 8B F5 78 CE 92 .0n<...U.....x..
|
||||
00000040 92 FF F2 A3 22 4D 2D F6 62 39 6D A5 DD E1 E1 C4 ...."M-.b9m.....
|
||||
00000050 67 67 30 19 98 D7 E4 AD A2 6A 27 1C A4 C2 A2 C6 gg0......j'.....
|
||||
00000060 8A B5 98 26 D3 1A 84 75 55 52 4F E1 6D 4B 84 99 ...&...uURO.mK..
|
||||
00000070 0F C2 5E 88 D5 8B E6 AA 2F 61 DC 63 79 5B 69 3F ..^...../a.cy[i?
|
||||
00000080 19 79 5A 78 49 29 22 92 9D F5 F3 FD 16 60 E2 72 .yZxI)"......`.r
|
||||
00000090 EA F8 8E 32 7D 81 A0 21 0C 82 4A A8 4C EE 9C 0E ...2}..!..J.L...
|
||||
000000A0 D7 BF 50 60 6C 65 8A 7C A6 CD C5 98 8B 15 EA F0 ..P`le.|........
|
||||
000000B0 26 D0 15 F4 EB DE A0 FD 88 2F 72 8B ED 07 44 5C &......../r...D\
|
||||
000000C0 91 46 17 8C 26 46 F2 7C BF 6B 45 63 B6 71 E7 51 .F..&F.|.kEc.q.Q
|
||||
000000D0 E4 34 A2 5A 01 F4 6E FF A2 67 82 7B F3 36 34 54 .4.Z..n..g.{.64T
|
||||
000000E0 80 ED 7E 9D 0A 21 09 9C 9C 55 A9 14 AF A2 66 65 ..~..!...U....fe
|
||||
000000F0 DE 8D BE C2 8B 31 B8 ED 06 AE A9 0B 7E 62 75 87 .....1......~bu.
|
||||
|
||||
[00:00:06.385,000] <inf> app: Initialising PSA crypto
|
||||
[00:00:06.386,000] <inf> app: PSA crypto init completed
|
||||
[00:00:06.387,000] <inf> app: Persisting SECP256R1 key as #1
|
||||
[00:00:06.938,000] <inf> app: Retrieving public key for key #1
|
||||
|
||||
0 1 2 3 4 5 6 7 8 9 A B C D E F
|
||||
00000000 04 34 B7 2F D5 EC 41 71 B1 04 D9 BE 1C E7 DD F7 .4./..Aq........
|
||||
00000010 C4 C0 B1 E9 64 CB 45 1F E3 4A 95 52 A8 75 B2 8C ....d.E..J.R.u..
|
||||
00000020 4D F1 CB 4F C2 26 2C 90 C9 05 B2 E4 4C 2A E9 9D M..O.&,.....L*..
|
||||
00000030 11 DF 35 1B 0E 86 D5 9C A1 1F FC FA ED 21 9A B5 ..5..........!..
|
||||
00000040 28 (
|
||||
|
||||
[00:00:07.495,000] <inf> app: Adding subject name to CSR
|
||||
[00:00:07.496,000] <inf> app: Adding subject name to CSR completed
|
||||
[00:00:07.497,000] <inf> app: Adding EC key to PK container
|
||||
[00:00:07.499,000] <inf> app: Adding EC key to PK container completed
|
||||
[00:00:07.500,000] <inf> app: Create device Certificate Signing Request
|
||||
[00:00:08.692,000] <inf> app: Create device Certificate Signing Request completed
|
||||
[00:00:08.693,000] <inf> app: Certificate Signing Request:
|
||||
|
||||
-----BEGIN CERTIFICATE REQUEST-----
|
||||
MIHrMIGQAgEAMC4xDzANBgNVBAoMBkxpbmFybzEbMBkGA1UEAwwSRGV2aWNlIENl
|
||||
cnRpZmljYXRlMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAENLcv1exBcbEE2b4c
|
||||
5933xMCx6WTLRR/jSpVSqHWyjE3xy0/CJiyQyQWy5Ewq6Z0R3zUbDobVnKEf/Prt
|
||||
IZq1KKAAMAwGCCqGSM49BAMCBQADSAAwRQIgaAlTPmrIaRO7myM2Qr+LNk9sagdO
|
||||
jPGUqbz4oUWhUsICIQCuHADW6F2l4czv78BO5Nf+FHZEpjbI1+fA2aLzglOaiA==
|
||||
-----END CERTIFICATE REQUEST-----
|
||||
|
||||
[00:00:08.696,000] <inf> app: Encoding CSR as json
|
||||
[00:00:08.699,000] <inf> app: Encoding CSR as json completed
|
||||
[00:00:08.700,000] <inf> app: Certificate Signing Request in JSON:
|
||||
|
||||
{"CSR":"-----BEGIN CERTIFICATE REQUEST-----\nMIHrMIGQAgEAMC4xDzANBgNVBAoMBkxpbmFybzEbMBkGA1UEAwwSRGV2aWNlIENl\ncnRpZmljYXRlMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAENLcv1exBcbEE2b4c\n5933xMCx6WTLRR/jSpVSqHWyjE3xy0/CJiyQyQWy5Ewq6Z0R3zUbDobVnKEf/Prt\nIZq1KKAAMAwGCCqGSM49BAMCBQADSAAwRQIgaAlTPmrIaRO7myM2Qr+LNk9sagdO\njPGUqbz4oUWhUsICIQCuHADW6F2l4czv78BO5Nf+FHZEpjbI1+fA2aLzglOaiA==\n-----END CERTIFICATE REQUEST-----\n"}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Copyright (c) 2020 Nordic Semiconductor ASA.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/* Modify the SRAM partitioning to accommodate the requirements
|
||||
* for the Secure (TF-M) firmware for the configuration that is
|
||||
* used in this sample.
|
||||
*/
|
||||
|
||||
/* Increase the size of the Secure Firmware (TF-M).
|
||||
* This modification is not required at the moment,
|
||||
* since TF-M region definitions are configured
|
||||
* statically in the TF-M project.
|
||||
*/
|
||||
&sram0_s {
|
||||
reg = <0x20000000 DT_SIZE_K(88)>;
|
||||
};
|
||||
|
||||
/* Decrease the size of the Non-Secure Firmware (Zephyr),
|
||||
* and move its starting address to the offset expected by
|
||||
* TF-M.
|
||||
*/
|
||||
/delete-node/ &sram0_ns;
|
||||
/ {
|
||||
reserved-memory {
|
||||
sram0_ns: image_ns@20016000 {
|
||||
reg = <0x20016000 DT_SIZE_K(168)>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
/* Disable UART1, because it is used by default in TF-M */
|
||||
&uart1 {
|
||||
status = "disabled";
|
||||
};
|
||||
38
samples/tfm_integration/psa_crypto/prj.conf
Normal file
38
samples/tfm_integration/psa_crypto/prj.conf
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
CONFIG_LOG=y
|
||||
CONFIG_LOG_RUNTIME_FILTERING=y
|
||||
CONFIG_LOG_BUFFER_SIZE=2048
|
||||
CONFIG_LOG_PROCESS_TRIGGER_THRESHOLD=0
|
||||
CONFIG_LOG_DEFAULT_LEVEL=3
|
||||
|
||||
#CONFIG_SHELL=n
|
||||
#CONFIG_SHELL_HISTORY=y
|
||||
#CONFIG_SHELL_VT100_COLORS=y
|
||||
#CONFIG_SHELL_CMDS=n
|
||||
#CONFIG_PSA_SHELL=y
|
||||
|
||||
CONFIG_BUILD_WITH_TFM=y
|
||||
CONFIG_TFM_PROFILE_TYPE_NOT_SET=y
|
||||
CONFIG_TFM_IPC=y
|
||||
|
||||
# The Zephyr CMSIS emulation assumes that ticks are ms, currently
|
||||
CONFIG_SYS_CLOCK_TICKS_PER_SEC=1000
|
||||
|
||||
CONFIG_MAIN_STACK_SIZE=8192
|
||||
CONFIG_HEAP_MEM_POOL_SIZE=4096
|
||||
|
||||
# Mbed TLS
|
||||
CONFIG_MBEDTLS=y
|
||||
CONFIG_MBEDTLS_BUILTIN=y
|
||||
CONFIG_MBEDTLS_ENABLE_HEAP=y
|
||||
CONFIG_MBEDTLS_HEAP_SIZE=32768
|
||||
CONFIG_MBEDTLS_USER_CONFIG_ENABLE=y
|
||||
CONFIG_MBEDTLS_USER_CONFIG_FILE="user-tls-conf.h"
|
||||
|
||||
# JSON
|
||||
CONFIG_JSON_LIBRARY=y
|
||||
|
||||
# Enable the initial attestation
|
||||
CONFIG_TFM_PARTITION_INITIAL_ATTESTATION=y
|
||||
CONFIG_TFM_QCBOR_PATH="DOWNLOAD"
|
||||
|
||||
CONFIG_NEWLIB_LIBC=y
|
||||
25
samples/tfm_integration/psa_crypto/sample.yaml
Normal file
25
samples/tfm_integration/psa_crypto/sample.yaml
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
sample:
|
||||
description: This app provides an example of using PSA crypto APIs
|
||||
to generate device certificate signing request in Zephyr
|
||||
using IPC mode.
|
||||
name: PSA crypto example
|
||||
tests:
|
||||
sample.psa_crypto:
|
||||
tags: introduction tfm crypto csr
|
||||
platform_allow: mps2_an521_ns v2m_musca_s1_ns
|
||||
nrf5340dk_nrf5340_cpuapp_ns nrf9160dk_nrf9160_ns
|
||||
stm32l562e_dk_ns bl5340_dvk_cpuapp_ns
|
||||
harness: console
|
||||
harness_config:
|
||||
type: multi_line
|
||||
regex:
|
||||
- "System IAT size is: (.*)"
|
||||
- "Requesting IAT with (.*) byte challenge."
|
||||
- "IAT data received: (.*)"
|
||||
- "Retrieving public key for key #1"
|
||||
- "Signature verified"
|
||||
- "Destroyed persistent key #1"
|
||||
- "Generating 256 bytes of random data."
|
||||
- "Create device Certificate Signing Request completed"
|
||||
- "BEGIN CERTIFICATE REQUEST"
|
||||
- "END CERTIFICATE REQUEST"
|
||||
48
samples/tfm_integration/psa_crypto/src/main.c
Normal file
48
samples/tfm_integration/psa_crypto/src/main.c
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Copyright (c) 2019,2020 Linaro Limited
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/logging/log_ctrl.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
|
||||
#include "tfm_ns_interface.h"
|
||||
#include "psa_attestation.h"
|
||||
#include "psa_crypto.h"
|
||||
#include "util_app_cfg.h"
|
||||
#include "util_app_log.h"
|
||||
#include "util_sformat.h"
|
||||
|
||||
/** Declare a reference to the application logging interface. */
|
||||
LOG_MODULE_DECLARE(app, CONFIG_LOG_DEFAULT_LEVEL);
|
||||
|
||||
/* Create an instance of the system config struct for the application. */
|
||||
static struct cfg_data cfg;
|
||||
|
||||
int main(void)
|
||||
{
|
||||
/* Initialise the logger subsys and dump the current buffer. */
|
||||
log_init();
|
||||
|
||||
/* Load app config struct from secure storage (create if missing). */
|
||||
if (cfg_load_data(&cfg)) {
|
||||
LOG_ERR("Error loading/generating app config data in SS.");
|
||||
}
|
||||
|
||||
/* Get the entity attestation token (requires ~1kB stack memory!). */
|
||||
att_test();
|
||||
|
||||
/* Crypto tests */
|
||||
crp_test();
|
||||
crp_test_rng();
|
||||
|
||||
/* Generate Certificate Signing Request using Mbed TLS */
|
||||
crp_generate_csr();
|
||||
|
||||
/* Dump any queued log messages, and wait for system events. */
|
||||
al_dump_log();
|
||||
|
||||
return 0;
|
||||
}
|
||||
144
samples/tfm_integration/psa_crypto/src/psa_attestation.c
Normal file
144
samples/tfm_integration/psa_crypto/src/psa_attestation.c
Normal file
|
|
@ -0,0 +1,144 @@
|
|||
/*
|
||||
* Copyright (c) 2019,2020 Linaro Limited
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <zephyr/kernel.h>
|
||||
#include <stdio.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
|
||||
#include "psa/initial_attestation.h"
|
||||
#include "psa_attestation.h"
|
||||
#include "util_app_log.h"
|
||||
#include "util_sformat.h"
|
||||
|
||||
LOG_MODULE_DECLARE(app, CONFIG_LOG_DEFAULT_LEVEL);
|
||||
|
||||
psa_status_t att_get_pub_key(void)
|
||||
{
|
||||
psa_status_t err = PSA_SUCCESS;
|
||||
|
||||
/* TODO: How to retrieve this?!? */
|
||||
|
||||
/* Log any eventual errors via app_log */
|
||||
return err ? al_psa_status(err, __func__) : err;
|
||||
}
|
||||
|
||||
psa_status_t att_get_iat(uint8_t *ch_buffer, uint32_t ch_sz,
|
||||
uint8_t *token_buffer, uint32_t *token_sz)
|
||||
{
|
||||
psa_status_t err = PSA_SUCCESS;
|
||||
uint32_t sys_token_sz;
|
||||
size_t token_buf_size = ATT_MAX_TOKEN_SIZE;
|
||||
|
||||
|
||||
/* Call with with bigger challenge object than allowed */
|
||||
|
||||
/*
|
||||
* First determine how large the token is on this system.
|
||||
* We don't need to compare with the size of ATT_MAX_TOKEN_SIZE here
|
||||
* since a check will be made in 'psa_initial_attest_get_token' and the
|
||||
* error return code will indicate a mismatch.
|
||||
*/
|
||||
switch (ch_sz) {
|
||||
case 32:
|
||||
err = psa_initial_attest_get_token(
|
||||
ch_buffer,
|
||||
PSA_INITIAL_ATTEST_CHALLENGE_SIZE_32,
|
||||
token_buffer,
|
||||
token_buf_size,
|
||||
&sys_token_sz);
|
||||
break;
|
||||
case 48:
|
||||
err = psa_initial_attest_get_token(
|
||||
ch_buffer,
|
||||
PSA_INITIAL_ATTEST_CHALLENGE_SIZE_48,
|
||||
token_buffer,
|
||||
token_buf_size,
|
||||
&sys_token_sz);
|
||||
break;
|
||||
case 64:
|
||||
err = psa_initial_attest_get_token(
|
||||
ch_buffer,
|
||||
PSA_INITIAL_ATTEST_CHALLENGE_SIZE_64,
|
||||
token_buffer,
|
||||
token_buf_size,
|
||||
&sys_token_sz);
|
||||
break;
|
||||
default:
|
||||
err = -EINVAL;
|
||||
break;
|
||||
}
|
||||
if (err) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
LOG_INF("att: System IAT size is: %u bytes.", sys_token_sz);
|
||||
|
||||
/* Request the initial attestation token w/the challenge data. */
|
||||
LOG_INF("att: Requesting IAT with %u byte challenge.", ch_sz);
|
||||
err = psa_initial_attest_get_token(
|
||||
ch_buffer, /* Challenge/nonce input buffer. */
|
||||
ch_sz, /* Challenge size (32, 48 or 64). */
|
||||
token_buffer, /* Token output buffer. */
|
||||
token_buf_size,
|
||||
token_sz /* Post exec output token size. */
|
||||
);
|
||||
LOG_INF("att: IAT data received: %u bytes.", *token_sz);
|
||||
|
||||
err:
|
||||
/* Log any eventual errors via app_log */
|
||||
return err ? al_psa_status(err, __func__) : err;
|
||||
}
|
||||
|
||||
psa_status_t att_test(void)
|
||||
{
|
||||
psa_status_t err = PSA_SUCCESS;
|
||||
|
||||
/* 64-byte nonce/challenge, encrypted using the default public key;
|
||||
*
|
||||
* 00 11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF
|
||||
* 00 11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF
|
||||
* 00 11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF
|
||||
* 00 11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF
|
||||
*/
|
||||
uint32_t nonce_sz = 64;
|
||||
uint8_t nonce_buf[ATT_MAX_TOKEN_SIZE] = {
|
||||
0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
|
||||
0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF,
|
||||
0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
|
||||
0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF,
|
||||
0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
|
||||
0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF,
|
||||
0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
|
||||
0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF,
|
||||
0
|
||||
};
|
||||
|
||||
/* IAT response buffer. */
|
||||
uint32_t iat_sz = ATT_MAX_TOKEN_SIZE;
|
||||
uint8_t iat_buf[ATT_MAX_TOKEN_SIZE] = { 0 };
|
||||
|
||||
/* String format output config. */
|
||||
struct sf_hex_tbl_fmt fmt = {
|
||||
.ascii = true,
|
||||
.addr_label = true,
|
||||
.addr = 0
|
||||
};
|
||||
|
||||
/* Request the IAT from the initial attestation service. */
|
||||
err = att_get_iat(nonce_buf, nonce_sz, iat_buf, &iat_sz);
|
||||
if (err) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Display queued log messages before dumping the IAT. */
|
||||
al_dump_log();
|
||||
|
||||
/* Dump the IAT for debug purposes. */
|
||||
sf_hex_tabulate_16(&fmt, iat_buf, (size_t)iat_sz);
|
||||
|
||||
err:
|
||||
return err;
|
||||
}
|
||||
65
samples/tfm_integration/psa_crypto/src/psa_attestation.h
Normal file
65
samples/tfm_integration/psa_crypto/src/psa_attestation.h
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* Copyright (c) 2019,2020 Linaro Limited
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "psa/error.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** Maximum buffer size for an initial attestation token instance. */
|
||||
#define ATT_MAX_TOKEN_SIZE (0x240)
|
||||
|
||||
/**
|
||||
* @brief Gets the public key portion of the attestation service's securely
|
||||
* stored key pair. This public key can be provided to external
|
||||
* verification services for device verification purposes.
|
||||
*
|
||||
* @return Returns error code as specified in \ref psa_status_t
|
||||
*/
|
||||
psa_status_t att_get_pub_key(void);
|
||||
|
||||
/**
|
||||
* @brief Gets an initial attestation token (IAT) from the TF-M secure
|
||||
* processing environment (SPE). This data will be provided in CBOR
|
||||
* format and is encrypted using the private key held on the SPE.
|
||||
*
|
||||
* The initial attestation token (IAT) is composed of a series of 'claims' or
|
||||
* data points used to uniquely identify this device to an external
|
||||
* verification entity (the IAT consumer).
|
||||
*
|
||||
* The generated IAT should be cryptographically verifiable by the IAT consumer.
|
||||
*
|
||||
* For details on IAT see https://tools.ietf.org/html/draft-mandyam-eat-01
|
||||
*
|
||||
* @param ch_buffer Pointer to the buffer containing the nonce or
|
||||
* challenge data to be validated with the private key.
|
||||
* @param ch_sz The number of bytes in the challenge. 32, 48 or 64.
|
||||
* @param token_buffer Pointer to the buffer where the IAT will be written.
|
||||
* Must be equal in size to the system IAT output, which
|
||||
* can be determined via a call to
|
||||
* 'psa_initial_attest_get_token_size'.
|
||||
* @param token_sz Pointer to the size of token_buffer, this value will be
|
||||
* updated in this function to contain the number of bytes
|
||||
* actually retrieved during the IAT request.
|
||||
*
|
||||
* @return Returns error code as specified in \ref psa_status_t
|
||||
*/
|
||||
psa_status_t att_get_iat(uint8_t *ch_buffer, uint32_t ch_sz,
|
||||
uint8_t *token_buffer, uint32_t *token_sz);
|
||||
|
||||
/**
|
||||
* @brief TODO!
|
||||
*
|
||||
* @return Returns error code as specified in \ref psa_status_t
|
||||
*/
|
||||
psa_status_t att_test(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
871
samples/tfm_integration/psa_crypto/src/psa_crypto.c
Normal file
871
samples/tfm_integration/psa_crypto/src/psa_crypto.c
Normal file
|
|
@ -0,0 +1,871 @@
|
|||
/*
|
||||
* Copyright (c) 2019,2020 Linaro Limited
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/logging/log_ctrl.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
#include <zephyr/data/json.h>
|
||||
|
||||
#include "mbedtls/pk.h"
|
||||
#include "mbedtls/x509.h"
|
||||
#include "mbedtls/x509_csr.h"
|
||||
|
||||
#include "psa_crypto.h"
|
||||
#include "util_app_log.h"
|
||||
#include "util_sformat.h"
|
||||
|
||||
/** Declare a reference to the application logging interface. */
|
||||
LOG_MODULE_DECLARE(app, CONFIG_LOG_DEFAULT_LEVEL);
|
||||
|
||||
/* Formatting details for displaying hex dumps. */
|
||||
struct sf_hex_tbl_fmt crp_fmt = {
|
||||
.ascii = true,
|
||||
.addr_label = true,
|
||||
.addr = 0
|
||||
};
|
||||
|
||||
struct csr_json_struct {
|
||||
const char *CSR;
|
||||
};
|
||||
|
||||
static const struct json_obj_descr csr_json_descr[] = {
|
||||
JSON_OBJ_DESCR_PRIM(struct csr_json_struct, CSR, JSON_TOK_STRING)
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Extracts the public key from the specified persistent key id.
|
||||
*
|
||||
* @param key_id The permanent identifier for the generated key.
|
||||
* @param key Pointer to the buffer where the public key data
|
||||
* will be written.
|
||||
* @param key_buf_size Size of key buffer in bytes.
|
||||
* @param key_len Number of bytes written into key by this function.
|
||||
*/
|
||||
static psa_status_t crp_get_pub_key(psa_key_id_t key_id,
|
||||
uint8_t *key, size_t key_buf_size,
|
||||
size_t *key_len)
|
||||
{
|
||||
psa_status_t status;
|
||||
psa_key_handle_t key_handle;
|
||||
|
||||
LOG_INF("Retrieving public key for key #%d", key_id);
|
||||
al_dump_log();
|
||||
|
||||
/* Now try to re-open the persisted key based on the key ID. */
|
||||
status = al_psa_status(
|
||||
psa_open_key(key_id, &key_handle),
|
||||
__func__);
|
||||
if (status != PSA_SUCCESS) {
|
||||
LOG_ERR("Failed to open persistent key #%d", key_id);
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Export the persistent key's public key part. */
|
||||
status = al_psa_status(
|
||||
psa_export_public_key(key_handle, key, key_buf_size, key_len),
|
||||
__func__);
|
||||
if (status != PSA_SUCCESS) {
|
||||
LOG_ERR("Failed to export public key.");
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Display the binary key data for debug purposes. */
|
||||
sf_hex_tabulate_16(&crp_fmt, key, *key_len);
|
||||
|
||||
/* Close the key to free up the volatile slot. */
|
||||
status = al_psa_status(
|
||||
psa_close_key(key_handle),
|
||||
__func__);
|
||||
if (status != PSA_SUCCESS) {
|
||||
LOG_ERR("Failed to close persistent key.");
|
||||
goto err;
|
||||
}
|
||||
|
||||
return status;
|
||||
err:
|
||||
al_dump_log();
|
||||
return status;
|
||||
}
|
||||
|
||||
#if CONFIG_PSA_IMPORT_KEY
|
||||
/**
|
||||
* @brief Stores a new persistent secp256r1 key (usage: ecdsa-with-SHA256)
|
||||
* in ITS, associating it with the specified unique key identifier.
|
||||
*
|
||||
* This function will store a new persistent secp256r1 key in internal trusted
|
||||
* storage. Cryptographic operations can then be performed using the key
|
||||
* identifier (key_id) associated with this persistent key. Only the 32-byte
|
||||
* private key needs to be supplied, the public key can be derived using
|
||||
* the supplied private key value.
|
||||
*
|
||||
* @param key_id The permament identifier for the generated key.
|
||||
* @param key_usage The usage policy for the key.
|
||||
* @param key_data Pointer to the 32-byte private key data.
|
||||
*/
|
||||
static psa_status_t crp_imp_key_secp256r1(psa_key_id_t key_id,
|
||||
psa_key_usage_t key_usage,
|
||||
uint8_t *key_data)
|
||||
{
|
||||
psa_status_t status = PSA_SUCCESS;
|
||||
psa_key_attributes_t key_attributes = PSA_KEY_ATTRIBUTES_INIT;
|
||||
psa_key_type_t key_type =
|
||||
PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1);
|
||||
psa_algorithm_t alg = PSA_ALG_ECDSA(PSA_ALG_SHA_256);
|
||||
psa_key_handle_t key_handle;
|
||||
size_t key_len = 32;
|
||||
size_t data_len;
|
||||
uint8_t data_out[65] = { 0 }; /* ECDSA public key = 65 bytes. */
|
||||
int comp_result;
|
||||
|
||||
LOG_INF("Persisting SECP256R1 key as #%d", (uint32_t)key_id);
|
||||
al_dump_log();
|
||||
|
||||
/* Setup the key's attributes before the creation request. */
|
||||
psa_set_key_id(&key_attributes, key_id);
|
||||
psa_set_key_usage_flags(&key_attributes, key_usage);
|
||||
psa_set_key_lifetime(&key_attributes, PSA_KEY_LIFETIME_PERSISTENT);
|
||||
psa_set_key_algorithm(&key_attributes, alg);
|
||||
psa_set_key_type(&key_attributes, key_type);
|
||||
|
||||
/* Import the private key, creating the persistent key on success */
|
||||
status = al_psa_status(
|
||||
psa_import_key(&key_attributes, key_data, key_len, &key_handle),
|
||||
__func__);
|
||||
if (status != PSA_SUCCESS) {
|
||||
LOG_ERR("Failed to import key.");
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Close the key to free up the volatile slot. */
|
||||
status = al_psa_status(
|
||||
psa_close_key(key_handle),
|
||||
__func__);
|
||||
if (status != PSA_SUCCESS) {
|
||||
LOG_ERR("Failed to close persistent key.");
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Try to retrieve the public key. */
|
||||
status = crp_get_pub_key(key_id, data_out, sizeof(data_out), &data_len);
|
||||
|
||||
/* Export the private key if usage includes PSA_KEY_USAGE_EXPORT. */
|
||||
if (key_usage & PSA_KEY_USAGE_EXPORT) {
|
||||
/* Re-open the persisted key based on the key ID. */
|
||||
status = al_psa_status(
|
||||
psa_open_key(key_id, &key_handle),
|
||||
__func__);
|
||||
if (status != PSA_SUCCESS) {
|
||||
LOG_ERR("Failed to open persistent key #%d", key_id);
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Read the original (private) key data back. */
|
||||
status = al_psa_status(
|
||||
psa_export_key(key_handle, data_out,
|
||||
sizeof(data_out), &data_len),
|
||||
__func__);
|
||||
if (status != PSA_SUCCESS) {
|
||||
LOG_ERR("Failed to export key.");
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Check key len. */
|
||||
if (data_len != key_len) {
|
||||
LOG_ERR("Unexpected number of bytes in exported key.");
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Verify that the exported private key matches input data. */
|
||||
comp_result = memcmp(data_out, key_data, key_len);
|
||||
if (comp_result != 0) {
|
||||
LOG_ERR("Imported/exported private key mismatch.");
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Display the private key. */
|
||||
LOG_INF("Private key data:");
|
||||
al_dump_log();
|
||||
sf_hex_tabulate_16(&crp_fmt, data_out, data_len);
|
||||
|
||||
/* Close the key to free up the volatile slot. */
|
||||
status = al_psa_status(
|
||||
psa_close_key(key_handle),
|
||||
__func__);
|
||||
if (status != PSA_SUCCESS) {
|
||||
LOG_ERR("Failed to close persistent key.");
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
err:
|
||||
al_dump_log();
|
||||
return status;
|
||||
}
|
||||
|
||||
#else /* !CONFIG_PSA_IMPORT_KEY */
|
||||
/**
|
||||
* @brief Generates a new permanent, persistent prime256v1 (ecdsa-with-SHA256)
|
||||
* key in ITS, associating it with the specified unique key identifier.
|
||||
*
|
||||
* This function will generate a new permanent prime256v1 key in internal trusted
|
||||
* storage. Cryptographic operations can then be performed using the key
|
||||
* identifier (key_id) associated with this persistent key.
|
||||
*
|
||||
* @param key_id The permanent identifier for the generated key.
|
||||
* @param key_usage The usage policy for the key.
|
||||
*/
|
||||
static psa_status_t crp_gen_key_secp256r1(psa_key_id_t key_id,
|
||||
psa_key_usage_t key_usage)
|
||||
{
|
||||
psa_status_t status = PSA_SUCCESS;
|
||||
psa_key_attributes_t key_attributes = PSA_KEY_ATTRIBUTES_INIT;
|
||||
psa_key_type_t key_type =
|
||||
PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1);
|
||||
psa_algorithm_t alg = PSA_ALG_ECDSA(PSA_ALG_SHA_256);
|
||||
psa_key_handle_t key_handle;
|
||||
size_t key_len = 32;
|
||||
size_t data_len;
|
||||
uint8_t data_out[65] = { 0 }; /* ECDSA public key = 65 bytes. */
|
||||
|
||||
LOG_INF("Persisting SECP256R1 key as #%d", (uint32_t)key_id);
|
||||
al_dump_log();
|
||||
|
||||
/* Setup the key's attributes before the creation request. */
|
||||
psa_set_key_id(&key_attributes, key_id);
|
||||
psa_set_key_usage_flags(&key_attributes, key_usage);
|
||||
psa_set_key_lifetime(&key_attributes, PSA_KEY_LIFETIME_PERSISTENT);
|
||||
psa_set_key_algorithm(&key_attributes, alg);
|
||||
psa_set_key_type(&key_attributes, key_type);
|
||||
psa_set_key_bits(&key_attributes, 256);
|
||||
|
||||
/* Generate the private key, creating the persistent key on success */
|
||||
status = al_psa_status(
|
||||
psa_generate_key(&key_attributes, &key_handle),
|
||||
__func__);
|
||||
if (status != PSA_SUCCESS) {
|
||||
LOG_ERR("Failed to generate key.");
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Close the key to free up the volatile slot. */
|
||||
status = al_psa_status(
|
||||
psa_close_key(key_handle),
|
||||
__func__);
|
||||
if (status != PSA_SUCCESS) {
|
||||
LOG_ERR("Failed to close persistent key.");
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Try to retrieve the public key. */
|
||||
status = crp_get_pub_key(key_id, data_out, sizeof(data_out), &data_len);
|
||||
|
||||
/* Export the private key if usage includes PSA_KEY_USAGE_EXPORT. */
|
||||
if (key_usage & PSA_KEY_USAGE_EXPORT) {
|
||||
/* Re-open the persisted key based on the key ID. */
|
||||
status = al_psa_status(
|
||||
psa_open_key(key_id, &key_handle),
|
||||
__func__);
|
||||
if (status != PSA_SUCCESS) {
|
||||
LOG_ERR("Failed to open persistent key #%d", key_id);
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Read the original (private) key data back. */
|
||||
status = al_psa_status(
|
||||
psa_export_key(key_handle, data_out,
|
||||
sizeof(data_out), &data_len),
|
||||
__func__);
|
||||
if (status != PSA_SUCCESS) {
|
||||
LOG_ERR("Failed to export key.");
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Check key len. */
|
||||
if (data_len != key_len) {
|
||||
LOG_ERR("Unexpected number of bytes in exported key.");
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Display the private key. */
|
||||
LOG_INF("Private key data:");
|
||||
al_dump_log();
|
||||
|
||||
sf_hex_tabulate_16(&crp_fmt, data_out, data_len);
|
||||
|
||||
/* Close the key to free up the volatile slot. */
|
||||
status = al_psa_status(
|
||||
psa_close_key(key_handle),
|
||||
__func__);
|
||||
if (status != PSA_SUCCESS) {
|
||||
LOG_ERR("Failed to close persistent key.");
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
err:
|
||||
al_dump_log();
|
||||
return status;
|
||||
}
|
||||
#endif /* CONFIG_PSA_IMPORT_KEY */
|
||||
|
||||
/**
|
||||
* @brief PSA Random number generator wrapper for Mbed TLS
|
||||
*/
|
||||
static int psa_rng_for_mbedtls(void *p_rng,
|
||||
unsigned char *output, size_t output_len)
|
||||
{
|
||||
(void)p_rng;
|
||||
|
||||
return psa_generate_random(output, output_len);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Generates device certificate signing request (CSR) using Mbed TLS
|
||||
* X.509 and TF-M crypto service.
|
||||
*/
|
||||
void crp_generate_csr(void)
|
||||
{
|
||||
psa_status_t status;
|
||||
psa_key_id_t key_slot = 1;
|
||||
psa_key_handle_t key_handle;
|
||||
|
||||
unsigned char output_buf[1024];
|
||||
unsigned char json_encoded_buf[1024];
|
||||
|
||||
mbedtls_pk_context pk_key_container;
|
||||
mbedtls_x509write_csr req;
|
||||
|
||||
struct csr_json_struct csr_json = {
|
||||
.CSR = output_buf
|
||||
};
|
||||
|
||||
/* Initialize Mbed TLS structures. */
|
||||
mbedtls_x509write_csr_init(&req);
|
||||
mbedtls_pk_init(&pk_key_container);
|
||||
memset(output_buf, 0, sizeof(output_buf));
|
||||
|
||||
/* Initialize crypto API. */
|
||||
LOG_INF("Initialising PSA crypto");
|
||||
al_dump_log();
|
||||
|
||||
status = al_psa_status(psa_crypto_init(), __func__);
|
||||
if (status != PSA_SUCCESS) {
|
||||
LOG_ERR("Crypto init failed.");
|
||||
goto err;
|
||||
}
|
||||
|
||||
LOG_INF("PSA crypto init completed");
|
||||
al_dump_log();
|
||||
|
||||
/* prime256v1 (ecdsa-with-SHA256) private key. */
|
||||
#if CONFIG_PSA_IMPORT_KEY
|
||||
#if CONFIG_PRIVATE_KEY_STATIC
|
||||
/* This value is based on the private key in user.pem,
|
||||
* which can be viewed viw the following command:
|
||||
*
|
||||
* $ openssl ec -in user.pem -text -noout
|
||||
*/
|
||||
uint8_t priv_key_data[32] = {
|
||||
0x14, 0xbc, 0xb9, 0x53, 0xa4, 0xee, 0xed, 0x50,
|
||||
0x09, 0x36, 0x92, 0x07, 0x1d, 0xdb, 0x24, 0x2c,
|
||||
0xef, 0xf9, 0x57, 0x92, 0x40, 0x4f, 0x49, 0xaa,
|
||||
0xd0, 0x7c, 0x5b, 0x3f, 0x26, 0xa7, 0x80, 0x48
|
||||
};
|
||||
#else /* !CONFIG_PRIVATE_KEY_STATIC */
|
||||
/* Randomly generate the private key. */
|
||||
uint8_t priv_key_data[32] = { 0 };
|
||||
|
||||
LOG_INF("Generate rnadom data for private key");
|
||||
al_dump_log();
|
||||
|
||||
psa_generate_random(priv_key_data, sizeof(priv_key_data));
|
||||
LOG_INF("Random data generation for private key completed");
|
||||
al_dump_log();
|
||||
|
||||
#endif /* CONFIG_PRIVATE_KEY_STATIC */
|
||||
|
||||
/* Generate persistent prime256v1 (ecdsa-with-SHA256) key w/ID #1. */
|
||||
/* PSA_KEY_USAGE_EXPORT can be added for debug purposes. */
|
||||
status = al_psa_status(
|
||||
crp_imp_key_secp256r1(key_slot,
|
||||
PSA_KEY_USAGE_SIGN_HASH |
|
||||
PSA_KEY_USAGE_VERIFY_HASH,
|
||||
priv_key_data),
|
||||
__func__);
|
||||
if (status != PSA_SUCCESS) {
|
||||
LOG_ERR("Failed to create persistent key #%d", key_slot);
|
||||
goto err;
|
||||
}
|
||||
#else /* !CONFIG_PSA_IMPORT_KEY */
|
||||
|
||||
/* NOTE: The certificate signing request (CSR) can be generated using
|
||||
* openssl by using following commands:
|
||||
*
|
||||
* Generate a new key:
|
||||
*
|
||||
* $ openssl ecparam -name secp256k1 -genkey -out USER.key
|
||||
*
|
||||
* Generate a certificate signing request, containing the user public key
|
||||
* and required details to be inserted into the user certificate.
|
||||
* openssl req -new -key USER.key -out USER.csr \
|
||||
* -subj "/O=Linaro/CN=$(uuidgen | tr '[:upper:]' '[:lower:]')"
|
||||
*
|
||||
*/
|
||||
|
||||
/* Generate persistent prime256v1 (ecdsa-with-SHA256) key w/ID #1. */
|
||||
/* PSA_KEY_USAGE_EXPORT can be added for debug purposes. */
|
||||
status = al_psa_status(
|
||||
crp_gen_key_secp256r1(key_slot,
|
||||
PSA_KEY_USAGE_SIGN_HASH |
|
||||
PSA_KEY_USAGE_VERIFY_HASH),
|
||||
__func__);
|
||||
if (status != PSA_SUCCESS) {
|
||||
LOG_ERR("Failed to create persistent key #%d", key_slot);
|
||||
goto err;
|
||||
}
|
||||
#endif /* CONFIG_PSA_IMPORT_KEY */
|
||||
|
||||
status = al_psa_status(
|
||||
psa_open_key(key_slot, &key_handle),
|
||||
__func__);
|
||||
if (status != PSA_SUCCESS) {
|
||||
LOG_ERR("Failed to open persistent key #%d", key_slot);
|
||||
goto err;
|
||||
}
|
||||
|
||||
psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
|
||||
|
||||
psa_get_key_attributes(key_handle, &attributes);
|
||||
mbedtls_x509write_csr_set_md_alg(&req, MBEDTLS_MD_SHA256);
|
||||
|
||||
LOG_INF("Adding subject name to CSR");
|
||||
al_dump_log();
|
||||
|
||||
status = mbedtls_x509write_csr_set_subject_name(&req, "O=Linaro,CN=Device Certificate");
|
||||
if (status != 0) {
|
||||
LOG_ERR("failed! mbedtls_x509write_csr_set_subject_name returned %d", status);
|
||||
goto err;
|
||||
}
|
||||
|
||||
LOG_INF("Adding subject name to CSR completed");
|
||||
al_dump_log();
|
||||
|
||||
LOG_INF("Adding EC key to PK container");
|
||||
al_dump_log();
|
||||
|
||||
status = mbedtls_pk_setup_opaque(&pk_key_container, key_handle);
|
||||
if (status != 0) {
|
||||
LOG_ERR("failed! mbedtls_pk_setup_opaque returned -0x%04x", (unsigned int) -status);
|
||||
goto err;
|
||||
}
|
||||
|
||||
LOG_INF("Adding EC key to PK container completed");
|
||||
al_dump_log();
|
||||
|
||||
mbedtls_x509write_csr_set_key(&req, &pk_key_container);
|
||||
|
||||
LOG_INF("Create device Certificate Signing Request");
|
||||
al_dump_log();
|
||||
|
||||
status = mbedtls_x509write_csr_pem(&req, output_buf, sizeof(output_buf),
|
||||
psa_rng_for_mbedtls, NULL);
|
||||
if (status < 0) {
|
||||
LOG_ERR("failed! mbedtls_x509write_csr_pem returned -0x%04x",
|
||||
(unsigned int) -status);
|
||||
goto err;
|
||||
}
|
||||
|
||||
LOG_INF("Create device Certificate Signing Request completed");
|
||||
al_dump_log();
|
||||
|
||||
LOG_INF("Certificate Signing Request:\n");
|
||||
al_dump_log();
|
||||
|
||||
printf("%s\n", output_buf);
|
||||
|
||||
/*
|
||||
* 1.3. Encoding CSR as JSON
|
||||
*/
|
||||
LOG_INF("Encoding CSR as json");
|
||||
al_dump_log();
|
||||
|
||||
status = json_obj_encode_buf(csr_json_descr, ARRAY_SIZE(csr_json_descr),
|
||||
&csr_json, json_encoded_buf, sizeof(json_encoded_buf));
|
||||
|
||||
if (status != 0) {
|
||||
LOG_ERR("failed! json_obj_encode_buf returned 0x%04x", status);
|
||||
goto err;
|
||||
}
|
||||
|
||||
LOG_INF("Encoding CSR as json completed");
|
||||
al_dump_log();
|
||||
|
||||
LOG_INF("Certificate Signing Request in JSON:\n");
|
||||
al_dump_log();
|
||||
|
||||
printf("%s\n", json_encoded_buf);
|
||||
|
||||
/* Close the key to free up the volatile slot. */
|
||||
status = al_psa_status(
|
||||
psa_close_key(key_handle),
|
||||
__func__);
|
||||
if (status != PSA_SUCCESS) {
|
||||
LOG_ERR("Failed to close persistent key.");
|
||||
goto err;
|
||||
}
|
||||
|
||||
err:
|
||||
al_dump_log();
|
||||
mbedtls_x509write_csr_free(&req);
|
||||
mbedtls_pk_free(&pk_key_container);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Calculates the SHA256 hash for the supplied message.
|
||||
*
|
||||
* @param msg Pointer to the buffer to read when generating the hash.
|
||||
* @param msg_len Number of bytes in msg.
|
||||
* @param hash Pointer to the buffer where the hash should be written.
|
||||
* @param hash_buf_size Size of hash in bytes.
|
||||
* @param hash_len Placeholder for the number of hash bytes written.
|
||||
*/
|
||||
static psa_status_t crp_hash_payload(uint8_t *msg, size_t msg_len,
|
||||
uint8_t *hash, size_t hash_buf_size,
|
||||
size_t *hash_len)
|
||||
{
|
||||
psa_status_t status;
|
||||
psa_hash_operation_t hash_handle = psa_hash_operation_init();
|
||||
psa_algorithm_t alg = PSA_ALG_SHA_256;
|
||||
|
||||
LOG_INF("Calculating SHA-256 hash of value");
|
||||
al_dump_log();
|
||||
|
||||
/* Display the input message */
|
||||
sf_hex_tabulate_16(&crp_fmt, msg, msg_len);
|
||||
|
||||
/* Setup the hash object. */
|
||||
status = al_psa_status(psa_hash_setup(&hash_handle, alg),
|
||||
__func__);
|
||||
if (status != PSA_SUCCESS) {
|
||||
LOG_ERR("Failed to setup hash op.");
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Update object with all the message chunks. */
|
||||
/* For the moment, the message is passed in a single operation, */
|
||||
/* but this can be broken up in chunks for larger messages. */
|
||||
status = al_psa_status(psa_hash_update(&hash_handle, msg, msg_len),
|
||||
__func__);
|
||||
if (status != PSA_SUCCESS) {
|
||||
LOG_ERR("Failed to update hash.");
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Finalize the hash calculation. */
|
||||
status = al_psa_status(psa_hash_finish(&hash_handle,
|
||||
hash, hash_buf_size, hash_len),
|
||||
__func__);
|
||||
if (status != PSA_SUCCESS) {
|
||||
LOG_ERR("Failed to finalize hash op.");
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Display the SHA-256 hash for debug purposes */
|
||||
sf_hex_tabulate_16(&crp_fmt, hash, (size_t)(PSA_HASH_MAX_SIZE));
|
||||
|
||||
return status;
|
||||
err:
|
||||
psa_hash_abort(&hash_handle);
|
||||
al_dump_log();
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Signs the supplied hash using the specified persistent key.
|
||||
*
|
||||
* @param key_id The identifier of the key to use when signing.
|
||||
* @param hash Pointer to the buffer where the hash should be written.
|
||||
* @param hash_buf_size Size of hash in bytes.
|
||||
* @param sig Pointer to the buffer to read when generating the sig.
|
||||
* @param sig_buf_size Size of sig buffer in bytes.
|
||||
* @param sig_len Number of bytes written to sig.
|
||||
*/
|
||||
static psa_status_t crp_sign_hash(psa_key_id_t key_id,
|
||||
uint8_t *hash, size_t hash_buf_size,
|
||||
uint8_t *sig, size_t sig_buf_size,
|
||||
size_t *sig_len)
|
||||
{
|
||||
psa_status_t status;
|
||||
psa_key_handle_t key_handle;
|
||||
|
||||
LOG_INF("Signing SHA-256 hash");
|
||||
al_dump_log();
|
||||
|
||||
/* Try to open the persisted key based on the key ID. */
|
||||
status = al_psa_status(
|
||||
psa_open_key(key_id, &key_handle),
|
||||
__func__);
|
||||
if (status != PSA_SUCCESS) {
|
||||
LOG_ERR("Failed to open persistent key #%d", key_id);
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Sign using psa_sign_hash. */
|
||||
status = al_psa_status(
|
||||
psa_sign_hash(key_handle,
|
||||
PSA_ALG_ECDSA(PSA_ALG_SHA_256),
|
||||
hash, hash_buf_size,
|
||||
sig, sig_buf_size, sig_len),
|
||||
__func__);
|
||||
if (status != PSA_SUCCESS) {
|
||||
LOG_ERR("Failed to sign hash w/persistent key #%d", key_id);
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Display the ECDSA signature for debug purposes */
|
||||
sf_hex_tabulate_16(&crp_fmt, sig, *sig_len);
|
||||
|
||||
/* You can test this same operation with openssl as follows:
|
||||
*
|
||||
* $ openssl dgst -sha256 -sign
|
||||
*/
|
||||
|
||||
/* Close the key to free up the volatile slot. */
|
||||
status = al_psa_status(
|
||||
psa_close_key(key_handle),
|
||||
__func__);
|
||||
if (status != PSA_SUCCESS) {
|
||||
LOG_ERR("Failed to close persistent key.");
|
||||
goto err;
|
||||
}
|
||||
|
||||
return status;
|
||||
err:
|
||||
al_dump_log();
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Verifies the hash signature using the public key associated
|
||||
* with key_id.
|
||||
*
|
||||
* @param key_id The identifier for the persistent key.
|
||||
* @param hash Pointer to the hash data to verify.
|
||||
* @param hash_len Size of the hash buffer in bytes.
|
||||
* @param sig Pointer to the signature buffer.
|
||||
* @param sig_len Size of the signature buffer in bytes.
|
||||
*/
|
||||
static psa_status_t crp_verify_sign(psa_key_id_t key_id,
|
||||
uint8_t *hash, size_t hash_len,
|
||||
uint8_t *sig, size_t sig_len)
|
||||
{
|
||||
psa_status_t status;
|
||||
psa_key_handle_t key_handle;
|
||||
|
||||
LOG_INF("Verifying signature for SHA-256 hash");
|
||||
al_dump_log();
|
||||
|
||||
/* Try to open the persisted key based on the key ID. */
|
||||
status = al_psa_status(
|
||||
psa_open_key(key_id, &key_handle),
|
||||
__func__);
|
||||
if (status != PSA_SUCCESS) {
|
||||
LOG_ERR("Failed to open persistent key #%d", key_id);
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Verify the hash signature. */
|
||||
status = al_psa_status(
|
||||
psa_verify_hash(key_handle,
|
||||
PSA_ALG_ECDSA(PSA_ALG_SHA_256),
|
||||
hash, hash_len,
|
||||
sig, sig_len),
|
||||
__func__);
|
||||
if (status != PSA_SUCCESS) {
|
||||
LOG_ERR("Signature verification failed!");
|
||||
goto err;
|
||||
}
|
||||
|
||||
LOG_INF("Signature verified.");
|
||||
al_dump_log();
|
||||
|
||||
/* Close the key to free up the volatile slot. */
|
||||
status = al_psa_status(
|
||||
psa_close_key(key_handle),
|
||||
__func__);
|
||||
if (status != PSA_SUCCESS) {
|
||||
LOG_ERR("Failed to close persistent key.");
|
||||
goto err;
|
||||
}
|
||||
|
||||
return status;
|
||||
err:
|
||||
al_dump_log();
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Destroys the specified persistent key.
|
||||
*
|
||||
* @param key_id The identifier for the persistent key.
|
||||
*/
|
||||
static psa_status_t crp_dest_key(psa_key_id_t key_id)
|
||||
{
|
||||
psa_status_t status;
|
||||
psa_key_handle_t key_handle;
|
||||
|
||||
/* Try to open the persisted key based on the key ID. */
|
||||
status = al_psa_status(
|
||||
psa_open_key(key_id, &key_handle),
|
||||
__func__);
|
||||
if (status != PSA_SUCCESS) {
|
||||
LOG_ERR("Failed to open persistent key #%d", key_id);
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Destroy the persistent key */
|
||||
status = al_psa_status(
|
||||
psa_destroy_key(key_handle),
|
||||
__func__);
|
||||
if (status != PSA_SUCCESS) {
|
||||
LOG_ERR("Failed to destroy a persistent key");
|
||||
goto err;
|
||||
}
|
||||
|
||||
LOG_INF("Destroyed persistent key #%d", (uint32_t)key_id);
|
||||
al_dump_log();
|
||||
|
||||
return status;
|
||||
err:
|
||||
al_dump_log();
|
||||
return status;
|
||||
}
|
||||
|
||||
void crp_test(void)
|
||||
{
|
||||
psa_status_t status;
|
||||
uint8_t msg[] = "Please hash and sign this message.";
|
||||
uint8_t hash[PSA_HASH_MAX_SIZE] = { 0 };
|
||||
size_t hash_len;
|
||||
uint8_t sig[PSA_VENDOR_ECDSA_SIGNATURE_MAX_SIZE] = { 0 };
|
||||
size_t sig_len;
|
||||
|
||||
/* secp256r1 private key. */
|
||||
#if CONFIG_PSA_IMPORT_KEY
|
||||
#if CONFIG_PRIVATE_KEY_STATIC
|
||||
/* This value is based on the private key in user.pem,
|
||||
* which can be viewed viw the following command:
|
||||
*
|
||||
* $ openssl ec -in user.pem -text -noout
|
||||
*/
|
||||
uint8_t priv_key_data[32] = {
|
||||
0x14, 0xbc, 0xb9, 0x53, 0xa4, 0xee, 0xed, 0x50,
|
||||
0x09, 0x36, 0x92, 0x07, 0x1d, 0xdb, 0x24, 0x2c,
|
||||
0xef, 0xf9, 0x57, 0x92, 0x40, 0x4f, 0x49, 0xaa,
|
||||
0xd0, 0x7c, 0x5b, 0x3f, 0x26, 0xa7, 0x80, 0x48
|
||||
};
|
||||
#else /* !CONFIG_PRIVATE_KEY_STATIC */
|
||||
/* Randomly generate the private key. */
|
||||
uint8_t priv_key_data[32] = { 0 };
|
||||
|
||||
psa_generate_random(priv_key_data, sizeof(priv_key_data));
|
||||
#endif /* CONFIG_PRIVATE_KEY_STATIC */
|
||||
#endif /* CONFIG_PSA_IMPORT_KEY */
|
||||
|
||||
/* Initialize crypto API. */
|
||||
status = al_psa_status(psa_crypto_init(), __func__);
|
||||
if (status != PSA_SUCCESS) {
|
||||
LOG_ERR("Crypto init failed.");
|
||||
return;
|
||||
}
|
||||
|
||||
/* NOTE: The same key generation, SHA256 hash, sign, and verify
|
||||
* operations performed in this file can be also performed with
|
||||
* openssl using the commands described below.
|
||||
*
|
||||
* Generate a new key:
|
||||
*
|
||||
* The curve `prime256v1` is same as `secp256r1` in OpenSSL
|
||||
* (https://github.com/openssl/openssl/blob/master/apps/ecparam.c#L216)
|
||||
* $ openssl ecparam -name prime256v1 -genkey -out user.pem
|
||||
*
|
||||
* Display the public and private keys in hexadecimal format:
|
||||
*
|
||||
* $ openssl ec -in user.pem -text -noout
|
||||
*
|
||||
* Update the private key value in priv_key_data with the hexadecimal
|
||||
* values from "priv:" to be able to compare the PSA API and openssl
|
||||
* output.
|
||||
*
|
||||
* Generate a PEM file with the public key (which will be used to
|
||||
* verify any data signed with the private key):
|
||||
*
|
||||
* $ openssl ec -in user.pem -pubout -out user_pub.pem
|
||||
*
|
||||
* Hash the message with SHA256, and sign it with the private key:
|
||||
*
|
||||
* $ echo "Please hash and sign this message." > message.txt
|
||||
* $ openssl dgst -sha256 -sign user.pem message.txt > signature.der
|
||||
*
|
||||
* Verify the signature using the public key and message file:
|
||||
*
|
||||
* $ openssl dgst -sha256 -verify user_pub.pem \
|
||||
* -signature signature.der message.txt
|
||||
*
|
||||
* If everything ws OK you should see "Verified OK".
|
||||
*/
|
||||
|
||||
/* Generate persistent secp256r1 key w/ID #1. */
|
||||
/* PSA_KEY_USAGE_EXPORT can be added for debug purposes. */
|
||||
#if CONFIG_PSA_IMPORT_KEY
|
||||
status = crp_imp_key_secp256r1(1,
|
||||
PSA_KEY_USAGE_SIGN_HASH |
|
||||
PSA_KEY_USAGE_VERIFY_HASH,
|
||||
priv_key_data);
|
||||
#else /* !CONFIG_PSA_IMPORT_KEY */
|
||||
status = crp_gen_key_secp256r1(1,
|
||||
PSA_KEY_USAGE_SIGN_HASH |
|
||||
PSA_KEY_USAGE_VERIFY_HASH);
|
||||
#endif
|
||||
|
||||
/* Hash some data with the key using SHA256. */
|
||||
status = crp_hash_payload(msg, strlen(msg),
|
||||
hash, sizeof(hash), &hash_len);
|
||||
|
||||
/* Sign the hash using key #1. */
|
||||
status = crp_sign_hash(1,
|
||||
hash, hash_len,
|
||||
sig, sizeof(sig), &sig_len);
|
||||
|
||||
/* Verify the hash signature using the public key. */
|
||||
status = crp_verify_sign(1, hash, hash_len, sig, sig_len);
|
||||
|
||||
/* Destroy the key. */
|
||||
status = crp_dest_key(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Generates random values using the TF-M crypto service.
|
||||
*/
|
||||
void crp_test_rng(void)
|
||||
{
|
||||
psa_status_t status;
|
||||
uint8_t outbuf[256] = { 0 };
|
||||
struct sf_hex_tbl_fmt fmt = {
|
||||
.ascii = true,
|
||||
.addr_label = true,
|
||||
.addr = 0
|
||||
};
|
||||
|
||||
status = al_psa_status(psa_generate_random(outbuf, 256), __func__);
|
||||
LOG_INF("Generating 256 bytes of random data.");
|
||||
al_dump_log();
|
||||
sf_hex_tabulate_16(&fmt, outbuf, 256);
|
||||
}
|
||||
34
samples/tfm_integration/psa_crypto/src/psa_crypto.h
Normal file
34
samples/tfm_integration/psa_crypto/src/psa_crypto.h
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Copyright (c) 2019,2020 Linaro Limited
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <zephyr/kernel.h>
|
||||
|
||||
#include "psa/crypto.h"
|
||||
#include "psa/error.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Generates random values using the TF-M crypto service.
|
||||
*/
|
||||
void crp_test_rng(void);
|
||||
|
||||
/**
|
||||
* @brief Runs a series of PSA Cryptography API test functions.
|
||||
*/
|
||||
void crp_test(void);
|
||||
|
||||
/**
|
||||
* @brief Generates device certificate signing request (CSR) using Mbed TLS
|
||||
* X.509 and TF-M crypto service.
|
||||
*/
|
||||
void crp_generate_csr(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
40
samples/tfm_integration/psa_crypto/src/shell.c
Normal file
40
samples/tfm_integration/psa_crypto/src/shell.c
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Copyright (c) 2019,2020 Linaro Limited
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <zephyr/shell/shell.h>
|
||||
|
||||
#if CONFIG_PSA_SHELL
|
||||
|
||||
static int
|
||||
psa_shell_invalid_arg(const struct shell *sh, char *arg_name)
|
||||
{
|
||||
shell_print(sh, "Error: invalid argument \"%s\"\n", arg_name);
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int
|
||||
psa_shell_cmd_version(const struct shell *sh, size_t argc, char **argv)
|
||||
{
|
||||
shell_print(sh, "%s", "0.0.0");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Subcommand array for "psa" (level 1). */
|
||||
SHELL_STATIC_SUBCMD_SET_CREATE(sub_psa,
|
||||
/* 'version' command handler. */
|
||||
SHELL_CMD(version, NULL, "app version", psa_shell_cmd_version),
|
||||
/* Array terminator. */
|
||||
SHELL_SUBCMD_SET_END
|
||||
);
|
||||
|
||||
/* Root command "psa" (level 0). */
|
||||
SHELL_CMD_REGISTER(psa, &sub_psa, "PSA commands", NULL);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* Copyright (c) 2023 Linaro Limited
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#define MBEDTLS_USE_PSA_CRYPTO
|
||||
#define MBEDTLS_PSA_CRYPTO_C
|
||||
|
||||
#define MBEDTLS_ENTROPY_C
|
||||
#define MBEDTLS_TEST_NULL_ENTROPY
|
||||
|
||||
#define MBEDTLS_ECP_C
|
||||
#define MBEDTLS_ECP_DP_SECP256R1_ENABLED
|
||||
#define MBEDTLS_ECDSA_C
|
||||
|
||||
#define MBEDTLS_X509_CSR_WRITE_C
|
||||
#define MBEDTLS_X509_CREATE_C
|
||||
#define MBEDTLS_PEM_WRITE_C
|
||||
#define MBEDTLS_BASE64_C
|
||||
#define MBEDTLS_OID_C
|
||||
#define MBEDTLS_ASN1_WRITE_C
|
||||
#define MBEDTLS_PK_WRITE_C
|
||||
#define MBEDTLS_PK_C
|
||||
76
samples/tfm_integration/psa_crypto/src/util_app_cfg.c
Normal file
76
samples/tfm_integration/psa_crypto/src/util_app_cfg.c
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* Copyright (c) 2019,2020 Linaro Limited
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
|
||||
#include "psa/error.h"
|
||||
#include "psa/protected_storage.h"
|
||||
#include "util_app_cfg.h"
|
||||
#include "util_app_log.h"
|
||||
|
||||
/** The 64-bit UID associated with the config record in secure storage. */
|
||||
static psa_storage_uid_t cfg_data_uid = 0x0000000055CFDA7A;
|
||||
|
||||
LOG_MODULE_DECLARE(app, CONFIG_LOG_DEFAULT_LEVEL);
|
||||
|
||||
/**
|
||||
* @brief Default config settings. These settings will be used when a new
|
||||
* config record is created, or when the config record is reset.
|
||||
*/
|
||||
static struct cfg_data cfg_data_dflt = {
|
||||
.magic = 0x55CFDA7A,
|
||||
.version = 1,
|
||||
.scratch = { 0 }
|
||||
};
|
||||
|
||||
psa_status_t cfg_create_data(void)
|
||||
{
|
||||
psa_status_t status;
|
||||
|
||||
LOG_INF("app_cfg: Creating new config file with UID 0x%llX",
|
||||
(uint64_t)cfg_data_uid);
|
||||
|
||||
/*
|
||||
* psa_ps_create can also be used here, which enables to the use of
|
||||
* the psa_ps_set_extended function, but this requires us to set a
|
||||
* maximum file size for resource allocation. Since the upper limit
|
||||
* isn't known at present, we opt here for the simpler psa_ps_set
|
||||
* call which also creates the secure storage record if necessary,
|
||||
* but precludes the use of psa_ps_set_extended.
|
||||
*/
|
||||
status = psa_ps_set(cfg_data_uid, sizeof(cfg_data_dflt),
|
||||
(void *)&cfg_data_dflt, 0);
|
||||
if (status) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
err:
|
||||
return (status ? al_psa_status(status, __func__) : status);
|
||||
}
|
||||
|
||||
psa_status_t cfg_load_data(struct cfg_data *p_cfg_data)
|
||||
{
|
||||
psa_status_t status;
|
||||
struct psa_storage_info_t p_info;
|
||||
|
||||
memset(&p_info, 0, sizeof(p_info));
|
||||
|
||||
/* Check if the config record exists, if not create it. */
|
||||
status = psa_ps_get_info(cfg_data_uid, &p_info);
|
||||
if (status == PSA_ERROR_DOES_NOT_EXIST) {
|
||||
/* Create a new config file. */
|
||||
status = cfg_create_data();
|
||||
/* Copy default values to the cfg_data placeholder. */
|
||||
memcpy(p_cfg_data, &cfg_data_dflt, sizeof(cfg_data_dflt));
|
||||
}
|
||||
if (status) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
err:
|
||||
return (status ? al_psa_status(status, __func__) : status);
|
||||
}
|
||||
63
samples/tfm_integration/psa_crypto/src/util_app_cfg.h
Normal file
63
samples/tfm_integration/psa_crypto/src/util_app_cfg.h
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* Copyright (c) 2019,2020 Linaro Limited
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <zephyr/kernel.h>
|
||||
|
||||
#include "psa/error.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief The struct used to persist config data to secure storage.
|
||||
*
|
||||
* The first 6 bytes of this struct should remain consistent in any future
|
||||
* firmware updates, since they can be used to identify to layout of the rest
|
||||
* of the struct in cases where config data version management becomes
|
||||
* a necessity.
|
||||
*/
|
||||
struct cfg_data {
|
||||
/**
|
||||
* @brief Magic number for config data payloads (0x55CFDA7A).
|
||||
*/
|
||||
uint32_t magic;
|
||||
|
||||
/**
|
||||
* @brief The version number for the stored config record.
|
||||
*
|
||||
* This number should be incremented any time the config_data struct
|
||||
* definition changes to allow version management of config data at
|
||||
* the application level.
|
||||
*/
|
||||
uint16_t version;
|
||||
|
||||
/** @brief 256-byte debug scratch area. */
|
||||
uint8_t scratch[256];
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Creates a new config record in secure storage.
|
||||
*
|
||||
* @return #PSA_SUCCESS on success, otherwise a appropriate psa_status_t code.
|
||||
*/
|
||||
psa_status_t cfg_create_data(void);
|
||||
|
||||
/**
|
||||
* @brief Attempts to load the config record from secure storage. If the
|
||||
* record is not found in secure storage, a new record will be created
|
||||
* using default config settings.
|
||||
*
|
||||
* @param p_cfg_data Pointer to the cfg_data struct where the config data
|
||||
* should be assigned once loaded.
|
||||
*
|
||||
* @return #PSA_SUCCESS on success, otherwise a appropriate psa_status_t code.
|
||||
*/
|
||||
psa_status_t cfg_load_data(struct cfg_data *p_cfg_data);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
110
samples/tfm_integration/psa_crypto/src/util_app_log.c
Normal file
110
samples/tfm_integration/psa_crypto/src/util_app_log.c
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
/*
|
||||
* Copyright (c) 2019,2020 Linaro Limited
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/logging/log_ctrl.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
|
||||
#include "psa/crypto.h"
|
||||
#include "util_app_log.h"
|
||||
|
||||
LOG_MODULE_REGISTER(app, CONFIG_LOG_DEFAULT_LEVEL);
|
||||
|
||||
psa_status_t al_psa_status(psa_status_t status, const char *func_name)
|
||||
{
|
||||
switch (status) {
|
||||
case PSA_SUCCESS:
|
||||
break;
|
||||
|
||||
/* Generic PSA errors (psa/error.h). */
|
||||
case PSA_ERROR_PROGRAMMER_ERROR:
|
||||
LOG_ERR("Programmer error");
|
||||
break;
|
||||
case PSA_ERROR_CONNECTION_REFUSED:
|
||||
LOG_ERR("Connection refused");
|
||||
break;
|
||||
case PSA_ERROR_CONNECTION_BUSY:
|
||||
LOG_ERR("Connection busy");
|
||||
break;
|
||||
case PSA_ERROR_GENERIC_ERROR:
|
||||
LOG_ERR("Generic error");
|
||||
break;
|
||||
case PSA_ERROR_NOT_PERMITTED:
|
||||
LOG_ERR("Not permitted");
|
||||
break;
|
||||
case PSA_ERROR_NOT_SUPPORTED:
|
||||
LOG_ERR("Unsupported operation");
|
||||
break;
|
||||
case PSA_ERROR_INVALID_ARGUMENT:
|
||||
LOG_ERR("Invalid argument");
|
||||
break;
|
||||
case PSA_ERROR_INVALID_HANDLE:
|
||||
LOG_ERR("Invalid handle");
|
||||
break;
|
||||
case PSA_ERROR_BAD_STATE:
|
||||
LOG_ERR("Bad state");
|
||||
break;
|
||||
case PSA_ERROR_BUFFER_TOO_SMALL:
|
||||
LOG_ERR("Buffer too small");
|
||||
break;
|
||||
case PSA_ERROR_ALREADY_EXISTS:
|
||||
LOG_ERR("Already exists");
|
||||
break;
|
||||
case PSA_ERROR_DOES_NOT_EXIST:
|
||||
LOG_ERR("Does not exist");
|
||||
break;
|
||||
case PSA_ERROR_INSUFFICIENT_MEMORY:
|
||||
LOG_ERR("Insufficient memory");
|
||||
break;
|
||||
case PSA_ERROR_INSUFFICIENT_STORAGE:
|
||||
LOG_ERR("Insufficient storage");
|
||||
break;
|
||||
case PSA_ERROR_INSUFFICIENT_DATA:
|
||||
LOG_ERR("Insufficient memory data");
|
||||
break;
|
||||
case PSA_ERROR_SERVICE_FAILURE:
|
||||
LOG_ERR("Service failure");
|
||||
break;
|
||||
case PSA_ERROR_COMMUNICATION_FAILURE:
|
||||
LOG_ERR("Communication failure");
|
||||
break;
|
||||
case PSA_ERROR_STORAGE_FAILURE:
|
||||
LOG_ERR("Storage failure");
|
||||
break;
|
||||
case PSA_ERROR_HARDWARE_FAILURE:
|
||||
LOG_ERR("Hardware failure");
|
||||
break;
|
||||
case PSA_ERROR_INVALID_SIGNATURE:
|
||||
LOG_ERR("Invalid signature");
|
||||
break;
|
||||
|
||||
/* PSA crypto errors (psa/crypto_values.h). */
|
||||
case PSA_ERROR_INSUFFICIENT_ENTROPY:
|
||||
LOG_ERR("CRYPTO: Insufficient entropy");
|
||||
break;
|
||||
case PSA_ERROR_CORRUPTION_DETECTED:
|
||||
LOG_ERR("CRYPTO: Tampering detected");
|
||||
break;
|
||||
|
||||
/* Catch-all error handler. */
|
||||
default:
|
||||
LOG_ERR("Unhandled status response: %d", status);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Display the calling function name for debug purposes. */
|
||||
if (status != PSA_SUCCESS) {
|
||||
LOG_ERR("Function: '%s'", func_name);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
void al_dump_log(void)
|
||||
{
|
||||
while (log_process()) {
|
||||
|
||||
}
|
||||
}
|
||||
35
samples/tfm_integration/psa_crypto/src/util_app_log.h
Normal file
35
samples/tfm_integration/psa_crypto/src/util_app_log.h
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* Copyright (c) 2019,2020 Linaro Limited
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "psa/error.h"
|
||||
#include "psa/initial_attestation.h"
|
||||
#include "psa/protected_storage.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Logs PSA response messages other than PSA_SUCCESS for debugging
|
||||
* purposes.
|
||||
*
|
||||
* @param status The psa_status_t value to log.
|
||||
* @param func_name The name of the function that made this function call.
|
||||
*
|
||||
* @return Returns the psa_status_t value passed into the function.
|
||||
*/
|
||||
psa_status_t al_psa_status(psa_status_t status, const char *func_name);
|
||||
|
||||
/**
|
||||
* @brief Calls 'log_process' in Zephyr to dump any queued log messages.
|
||||
*/
|
||||
void al_dump_log(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
115
samples/tfm_integration/psa_crypto/src/util_sformat.c
Normal file
115
samples/tfm_integration/psa_crypto/src/util_sformat.c
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
/*
|
||||
* Copyright (c) 2019,2020 Linaro Limited
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include "util_sformat.h"
|
||||
|
||||
static void sf_hex_ascii(unsigned char *data, size_t len, unsigned char nonvis)
|
||||
{
|
||||
uint32_t idx;
|
||||
|
||||
/* Render printable characters. */
|
||||
idx = 0;
|
||||
while (len) {
|
||||
printf("%c", isprint(data[idx]) ? data[idx] : nonvis);
|
||||
idx++;
|
||||
len--;
|
||||
}
|
||||
}
|
||||
|
||||
void sf_hex_tabulate_16(struct sf_hex_tbl_fmt *fmt, unsigned char *data,
|
||||
size_t len)
|
||||
{
|
||||
uint32_t idx;
|
||||
uint32_t cpos; /* Current position. */
|
||||
uint32_t ca; /* Current address. */
|
||||
uint32_t ea; /* End address. */
|
||||
|
||||
if (!len) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Set the end address (since we modify len in the write loop). */
|
||||
ea = fmt->addr + len;
|
||||
|
||||
/* Check if we need to render the top address bar. */
|
||||
if (fmt->addr_label) {
|
||||
/* Render the top address bar. */
|
||||
printf("\n");
|
||||
printf(" ");
|
||||
printf("0 1 2 3 4 5 6 7 8 9 ");
|
||||
printf("A B C D E F\n");
|
||||
printf("%08X ", fmt->addr - (fmt->addr % 16));
|
||||
}
|
||||
|
||||
/* Insert offset padding for first row if necessary. */
|
||||
cpos = fmt->addr % 16;
|
||||
if (cpos != 0) {
|
||||
for (idx = 0; idx < cpos; idx++) {
|
||||
printf(" ");
|
||||
}
|
||||
}
|
||||
|
||||
/* Print data row by row. */
|
||||
idx = 0;
|
||||
ca = fmt->addr;
|
||||
while (len) {
|
||||
/* Print the current value. */
|
||||
printf("%02X ", data[idx++]);
|
||||
cpos++;
|
||||
ca++;
|
||||
|
||||
/* Wrap around to the next line if necessary. */
|
||||
if (cpos == 16 || ca == ea) {
|
||||
/* Render ASCII equiv at end of row if requested. */
|
||||
if (fmt->ascii) {
|
||||
if (ca == ea) {
|
||||
/* Handle last/single row. */
|
||||
if (ca % 16) {
|
||||
/* PARTIAL row (< 16 vals). */
|
||||
printf("%.*s",
|
||||
(16 - ca % 16) * 3,
|
||||
" "
|
||||
" "
|
||||
" ");
|
||||
sf_hex_ascii(
|
||||
&data[idx - (ca % 16)],
|
||||
ca - fmt->addr < 16 ?
|
||||
idx % 16 : ca % 16,
|
||||
'.');
|
||||
} else {
|
||||
/* FULL row. */
|
||||
sf_hex_ascii(
|
||||
&data[idx - 16],
|
||||
16, '.');
|
||||
}
|
||||
} else if (ca < fmt->addr + 15) {
|
||||
/* Handle first row. */
|
||||
printf("%.*s", fmt->addr % 16,
|
||||
" ");
|
||||
sf_hex_ascii(data,
|
||||
16 - fmt->addr % 16, '.');
|
||||
} else {
|
||||
/* Full row. */
|
||||
sf_hex_ascii(&data[idx - 16], 16, '.');
|
||||
}
|
||||
}
|
||||
|
||||
/* Wrap around if this isn't the last row. */
|
||||
printf("\n");
|
||||
if (ca != ea) {
|
||||
/* Render the next base row addr. */
|
||||
if (fmt->addr_label) {
|
||||
printf("%08X ", ca);
|
||||
}
|
||||
}
|
||||
cpos = 0;
|
||||
}
|
||||
len--;
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
45
samples/tfm_integration/psa_crypto/src/util_sformat.h
Normal file
45
samples/tfm_integration/psa_crypto/src/util_sformat.h
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Copyright (c) 2019,2020 Linaro Limited
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef _SFORMAT_H_
|
||||
#define _SFORMAT_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <zephyr/kernel.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Indicates how hex data should be rendered in tabular format.
|
||||
*/
|
||||
struct sf_hex_tbl_fmt {
|
||||
/** Whether or not to render ASCII equivalents. */
|
||||
uint8_t ascii : 1;
|
||||
/** Whether or not to add address labels to the output. */
|
||||
uint8_t addr_label : 1;
|
||||
/** The starting value for the address labels. */
|
||||
uint32_t addr;
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* @brief Prints a 16-value wide tabular rendering of 8-bit hex data, with
|
||||
* optional ascii equivalents and address labels.
|
||||
*
|
||||
* @param fmt Pointer to thee sf_hex_tbl_fmt struct indicating how the
|
||||
* table should be rendered.
|
||||
* @param data Pointer to the data to render.
|
||||
* @param len The number of bytes to render from data.
|
||||
*/
|
||||
void sf_hex_tabulate_16(struct sf_hex_tbl_fmt *fmt, unsigned char *data,
|
||||
size_t len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _SFORMAT_H_ */
|
||||
8
samples/tfm_integration/psa_crypto/user.pem
Normal file
8
samples/tfm_integration/psa_crypto/user.pem
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
-----BEGIN EC PARAMETERS-----
|
||||
BggqhkjOPQMBBw==
|
||||
-----END EC PARAMETERS-----
|
||||
-----BEGIN EC PRIVATE KEY-----
|
||||
MHcCAQEEIBS8uVOk7u1QCTaSBx3bJCzv+VeSQE9JqtB8Wz8mp4BIoAoGCCqGSM49
|
||||
AwEHoUQDQgAER+qu2dZtLh1lBfUE/swhmb5eWlZrTx4MQ+Jbzht9BtezceIKPEft
|
||||
hJ9lDtv5PdIHu4Gmc+Y7FpUZrAECyxz1NQ==
|
||||
-----END EC PRIVATE KEY-----
|
||||
4
samples/tfm_integration/psa_crypto/user_pub.pem
Normal file
4
samples/tfm_integration/psa_crypto/user_pub.pem
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
-----BEGIN PUBLIC KEY-----
|
||||
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAER+qu2dZtLh1lBfUE/swhmb5eWlZr
|
||||
Tx4MQ+Jbzht9BtezceIKPEfthJ9lDtv5PdIHu4Gmc+Y7FpUZrAECyxz1NQ==
|
||||
-----END PUBLIC KEY-----
|
||||
Loading…
Reference in a new issue