samples: tfm_integration: Extend PSA cryptography demo

This commit extends the psa_level_1 sample's use of the PSA
Cryptography 1.0 API to demonstrate the following functionality:

- Generate a persistent key (secp256r1)
- Display the public key based on the private key above
- Calculates the SHA256 hash of a payload
- Signs the hash with the persistent key
- Verifies the signature using the public key
- Destroys the key

Signed-off-by: Kevin Townsend <kevin.townsend@linaro.org>
This commit is contained in:
Kevin Townsend 2020-05-13 20:03:30 +02:00 committed by Ioannis Glaropoulos
parent 45eca4ce10
commit 0d1fe4a161
10 changed files with 647 additions and 118 deletions

View file

@ -18,3 +18,10 @@ target_sources(app PRIVATE src/util_sformat.c)
target_include_directories(app PRIVATE
${ZEPHYR_TRUSTED_FIRMWARE_M_MODULE_DIR}/trusted-firmware-m/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
)

View file

@ -19,4 +19,20 @@ config PSA_SHELL
help
Enabling this option will make the 'psa' shell command available.
choice
prompt "Private Key"
default PRIVATE_KEY_RANDOM
config PRIVATE_KEY_STATIC
bool "Static"
help
A static key value will be used for the private key.
config PRIVATE_KEY_RANDOM
bool "Random"
help
A randomly generated value will be used for the private key.
endchoice
source "Kconfig.zephyr"

View file

@ -25,6 +25,27 @@ multi-thread application.
.. _PSA Certified Level 1:
https://www.psacertified.org/security-certification/psa-certified-level-1/
Key Files
*********
``psa_crypto.c``
================
Demonstrates the following workflow:
- Generate a persistent key: secp256r1 (usage: ecdsa-with-SHA256)
- Display the public key based on the private key data above
- Calculates the SHA256 hash of a payload
- Signs the hash with the persistent key
- Verifies the signature using the public key
- Destroys the key
``psa_attestation.c``
=====================
Demonstrates how to request an initial attestation token (IAT) from the TF-M
secure processing environment (SPE).
Building and Running
********************
@ -38,6 +59,14 @@ This sample will only build on a Linux or macOS development system
- 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:
===============
@ -216,24 +245,24 @@ Sample Output
[INF] Swap type: none
[INF] Swap type: none
[INF] Bootloader chainload address offset: 0x80000
[INF] Jumping to the first image slot
[Sec Thread] Secure image initializing!
TF-M isolation level is: 1
Booting TFM v1.0
*** Booting Zephyr OS build v1.12.0-rc1-19787-g7bf29820769f ***
[00:00:00.003,000] <inf> app: app_cfg: Creating new config file with UID 0x155cfda7a
[00:00:03.517,000] <inf> app: att: System IAT size is: 545 bytes.
[00:00:03.517,000] <inf> app: att: Requesting IAT with 64 byte challenge.
[00:00:06.925,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
TF-M isolation level is: 0x00000001
Booting TFM v1.3.0
Jumping to non-secure code...
*** Booting Zephyr OS build v2.6.0-rc2-1-g77259223c716 ***
[00:00:00.037,000] <inf> app: app_cfg: Creating new config file with UID 0x1055CFDA7A
[00:00:03.968,000] <inf> app: att: System IAT size is: 545 bytes.
[00:00:03.968,000] <inf> app: att: Requesting IAT with 64 byte challenge.
[00:00:05.961,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
@ -245,43 +274,74 @@ Sample Output
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 EF FC 32 08 03 06 CA 5A 8C A256.X ..2....Z.
00000120 D2 93 C8 46 04 DD 45 3F CA 41 20 47 A8 F7 D4 09 ...F..E?.A G....
00000130 24 16 94 38 05 68 B6 A5 01 64 4E 53 50 45 04 65 $..8.h...dNSPE.e
00000110 41 32 35 36 02 58 20 AE AA BE 88 46 21 BA 4F ED A256.X ....F!.O.
00000120 E9 68 26 05 08 42 FC D0 1E AE 31 EB A9 47 5B D7 .h&..B....1..G[.
00000130 5E C0 7F 75 C8 0A 0A A5 01 64 4E 53 50 45 04 65 ^..u.....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 D5 3F 25 8F AA 5A 05 33 36 F4 D9 2C D6 .X .?%..Z.36..,.
00000180 11 DF 6E 1B 18 B9 03 09 37 01 9D A7 5E FC 57 32 ..n.....7...^.W2
00000190 B3 1A 94 3A 00 01 25 01 77 77 77 77 2E 74 72 75 ...:..%.wwww.tru
00000170 02 58 20 FC 36 15 76 EE 01 5C FC 2A 2E 23 C6 43 .X .6.v..\.*.#.C
00000180 DD 3C C4 5A 68 A7 1A CC 14 7A BF 3F B1 9B E2 D7 .<.Zh....z.?....
00000190 E3 74 88 3A 00 01 25 01 77 77 77 77 2E 74 72 75 .t.:..%.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 51 33 D9 87 96 A9 91 55 18 9E BF 14 7A E1 76 @Q3.....U....z.v
000001F0 F5 0F A6 3C 7B F2 3A 1B 59 24 5B 2E 67 A8 F8 AB ...<{.:.Y$[.g...
00000200 12 B4 2E 09 13 5B BF 35 1F ED 66 E3 36 CF DA CE .....[.5..f.6...
00000210 06 03 69 DF C0 DC 4D 2F 17 33 D7 5E BE 73 B9 0E ..i...M/.3.^.s..
00000220 08 .
[00:00:06.982,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 0C 90 D8 0C FA 0F 97 00 29 B2 AE 5C 90 48 3D 39 ........)..\.H=9
00000010 00 14 6C A3 84 E2 C0 C9 82 F5 8B A6 E9 38 66 16 ..l..........8f.
00000020 EA B7 E7 78 91 0D 6D 87 5B B8 04 0B 8B E0 74 23 ...x..m.[.....t#
00000030 7D 11 E2 17 32 34 1A 01 71 24 29 D5 7C 05 B1 11 }...24..q$).|...
00000040 A0 97 20 82 03 FF D6 76 9D 6F D5 52 45 C9 E1 17 .. ....v.o.RE...
00000050 69 DF 18 B6 8E 0C AA 3B 74 B4 EF 97 D9 0E 82 25 i......;t......%
00000060 E1 97 0E 6E 4F 0F DE B9 20 60 34 A4 EA 0D 9A B3 ...nO... `4.....
00000070 3F C4 9A CF F3 5E F2 2C 78 96 6F 0E DD E3 E6 CB ?....^.,x.o.....
00000080 DC 19 26 A3 E8 8E 07 0E 1E 5B DB 59 B0 05 41 E2 ..&......[.Y..A.
00000090 A4 ED 90 35 8B AB 1C B8 00 7E BB 2D 22 FE 7A EA ...5.....~.-".z.
000000A0 CF A0 BB DF 4F 2B 32 55 C9 07 0D 3D CE B8 43 78 ....O+2U...=..Cx
000000B0 63 33 6C 79 CA 43 3A 4F 0B 93 33 2B B1 D2 B0 A7 c3ly.C:O..3+....
000000C0 44 A0 E9 E8 BF FB FD 89 2A 44 7A 60 2D 9B 0F 9E D.......*Dz`-...
000000D0 0D B1 0E 9D 5C 60 5D E6 92 78 36 79 68 37 24 C5 ....\`]..x6yh7$.
000000E0 57 7F 2E DF 53 D2 7B 3F EE 56 9B 9E BB 39 2C B6 W...S.{?.V...9,.
000000F0 AA FF B5 3B 59 4E 40 1D E0 34 50 05 D0 E0 95 12 ...;YN@..4P.....
[00:00:07.004,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 E3 B0 C4 42 98 FC 1C 14 9A FB F4 C8 99 6F B9 24
00000010 27 AE 41 E4 64 9B 93 4C A4 95 99 1B 78 52 B8 55
000001E0 40 53 A1 B7 9B 18 45 D4 15 4D 84 8C A6 D6 0C 10 @S....E..M......
000001F0 A3 88 17 E7 E7 C9 39 72 DC 32 ED A0 DB FB EA 06 ......9r.2......
00000200 19 AF AF 6C 88 55 22 84 4E 1B 2F DF 9E 57 C3 12 ...l.U".N./..W..
00000210 7E 96 39 DB DC F8 A3 7F C1 BC 6D C2 9B 42 16 40 ~.9.......m..B.@
00000220 49 I
[00:00:06.025,000] <inf> app: Persisting SECP256R1 key as #1
[00:00:06.035,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 2E 36 AC C3 55 DC 17 A5 D8 0C 9B 70 F5 C6 C2 ..6..U......p...
00000010 F0 10 67 8E C5 21 D7 D7 43 79 2C CF 41 32 C1 15 ..g..!..Cy,.A2..
00000020 33 CC A8 F4 1E ED FB 45 CA 1C E7 C0 FD 07 B2 85 3......E........
00000030 B3 AD CC C3 7C 08 81 9B 44 64 E4 EA 9A 2A 38 46 ....|...Dd...*8F
00000040 D5 .
[00:00:07.935,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:07.945,000] <inf> app: Signing SHA-256 hash
0 1 2 3 4 5 6 7 8 9 A B C D E F
00000000 E8 59 8C C1 A1 D7 0C 00 34 60 D7 D7 1D 82 DA 26 .Y......4`.....&
00000010 5D EC 2A 40 26 8F 20 A3 4B B8 B4 8D 44 25 1D F1 ].*@&. .K...D%..
00000020 78 FF CA CB 96 0B B3 31 F0 68 AB BF F3 57 FF A8 x......1.h...W..
00000030 DB E6 02 01 59 22 5D 53 13 81 63 31 3C 75 61 92 ....Y"]S..c1<ua.
[00:00:09.919,000] <inf> app: Verifying signature for SHA-256 hash
[00:00:14.559,000] <inf> app: Signature verified.
[00:00:14.570,000] <inf> app: Destroyed persistent key #1
[00:00:14.574,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 30 13 B1 67 10 2E 2B 7A 45 A7 89 32 80 89 DB 05 0..g..+zE..2....
00000010 30 93 CF F0 03 9A BA 92 0C A4 54 46 96 A4 C2 A9 0.........TF....
00000020 11 A2 0B F6 3A C5 5A FB 55 51 4F CB C5 7D 02 71 ....:.Z.UQO..}.q
00000030 19 AA A0 62 36 AA 69 5F 8E 93 A8 9B DB 8C AF 7C ...b6.i_.......|
00000040 A0 68 C7 60 48 1C 30 51 20 2E AD B6 91 22 38 14 .h.`H.0Q ...."8.
00000050 87 00 F6 59 18 81 DB 6B E0 67 95 0C FF 67 B2 1D ...Y...k.g...g..
00000060 9E 15 B6 46 94 F0 08 15 5F C8 B7 61 72 34 28 18 ...F...._..ar4(.
00000070 BA D1 41 2B D3 5B C7 72 87 89 70 E4 34 6D 40 B7 ..A+.[.r..p.4m@.
00000080 B2 38 77 C9 A9 C3 81 18 3C 67 AD 30 CC B4 CE 77 .8w.....<g.0...w
00000090 54 11 D6 8B FC 18 D1 7B 26 D3 45 00 67 23 E7 F2 T......{&.E.g#..
000000A0 5C 59 CB 63 8F C5 8C 2F 01 CC 09 CE 06 85 4D DC \Y.c.../......M.
000000B0 33 41 48 F8 01 8D DA 39 F9 DB 71 0D 80 E6 53 42 3AH....9..q...SB
000000C0 58 B0 A8 50 6D 5E 11 B1 EC 53 5E FA 23 AC 7A 0D X..Pm^...S^.#.z.
000000D0 EF AC 98 76 68 82 4C 48 8E B4 51 D4 31 78 AE 52 ...vh.LH..Q.1x.R
000000E0 7F F2 19 0D 57 6B C7 5B 77 77 36 E7 87 E2 DA 74 ....Wk.[ww6....t
000000F0 BF BB 83 5F 8F 94 83 21 28 3A A6 B9 5A 73 18 E2 ..._...!(:..Zs..

View file

@ -12,6 +12,7 @@ tests:
harness_config:
type: multi_line
regex:
- "Creating new config file with UID"
- "System IAT size is"
- "Generating 256 bytes of random data"
- "Retrieving public key for key #1"
- "Signature verified"
- "Destroyed persistent key #1"
- "Generating 256 bytes of random data."

View file

@ -35,15 +35,9 @@ void main(void)
att_test();
/* Crypto tests */
crp_test();
crp_test_rng();
crp_test_sha256();
/* Dump any queued log messages, and wait for system events. */
while (1) {
al_dump_log();
}
while (1) {
}
al_dump_log();
}

View file

@ -8,7 +8,6 @@
#include <logging/log_ctrl.h>
#include <logging/log.h>
#include "psa/crypto.h"
#include "psa_crypto.h"
#include "util_app_log.h"
#include "util_sformat.h"
@ -16,6 +15,498 @@
/** 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
};
/**
* @brief Extracts the public key from the specified persistent key id.
*
* @param key_id The permament 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;
}
/**
* @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_gen_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_CURVE_SECP256R1);
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_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;
}
/**
* @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_SIZE(alg)));
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_SIZE(PSA_ALG_SHA_256)] = { 0 };
size_t hash_len;
uint8_t sig[PSA_VENDOR_ECDSA_SIGNATURE_MAX_SIZE] = { 0 };
size_t sig_len;
/* secp256r1 private 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
/* Randomly generate the private key. */
uint8_t priv_key_data[32] = { 0 };
psa_generate_random(priv_key_data, sizeof(priv_key_data));
#endif
/* 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. */
status = crp_gen_key_secp256r1(1,
PSA_KEY_USAGE_SIGN_HASH |
PSA_KEY_USAGE_VERIFY_HASH,
priv_key_data);
/* 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, sizeof(hash),
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.
*/
@ -34,65 +525,3 @@ void crp_test_rng(void)
al_dump_log();
sf_hex_tabulate_16(&fmt, outbuf, 256);
}
/**
* @brief Demonstrates how to calcute the SHA-256 hash of a value in chunks.
*/
void crp_test_sha256(void)
{
const psa_algorithm_t alg = PSA_ALG_SHA_256;
static const char *const msg[] = { "This is my test message, ",
"please generate a hash for this." };
const size_t msg_size[] = { 25, 32 };
uint8_t hash_val[PSA_HASH_SIZE(PSA_ALG_SHA_256)] = { 0 };
size_t hash_len;
const uint32_t msg_num = ARRAY_SIZE(msg) / sizeof(msg[0]);
uint32_t idx;
psa_status_t status;
psa_hash_operation_t handle = psa_hash_operation_init();
LOG_INF("Calculating SHA-256 hash of value.");
al_dump_log();
/* Setup the hash object. */
status = al_psa_status(psa_hash_setup(&handle, alg), __func__);
if (status != PSA_SUCCESS) {
goto err;
}
/* Update object with all the message chunks. */
for (idx = 0; idx < msg_num; idx++) {
status = al_psa_status(
psa_hash_update(
&handle,
(const uint8_t *)msg[idx], msg_size[idx]),
__func__);
if (status != PSA_SUCCESS) {
goto err;
}
}
/* Finalize the hash calculation. */
status = al_psa_status(
psa_hash_finish(&handle,
hash_val,
sizeof(hash_val),
&hash_len),
__func__);
if (status != PSA_SUCCESS) {
goto err;
}
/* Display the SHA-256 hash for debug purposes */
struct sf_hex_tbl_fmt fmt = {
.ascii = false,
.addr_label = true,
.addr = 0
};
sf_hex_tabulate_16(&fmt, hash_val, (size_t)(PSA_HASH_SIZE(alg)));
return;
err:
psa_hash_abort(&handle);
al_dump_log();
}

View file

@ -6,14 +6,22 @@
#include <zephyr.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);
void crp_test_sha256(void);
/**
* @brief Runs a series of PSA Cryptography API test functions.
*/
void crp_test(void);
#ifdef __cplusplus
}

View file

@ -39,6 +39,7 @@ void sf_hex_tabulate_16(struct sf_hex_tbl_fmt *fmt, unsigned char *data,
/* 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");
@ -110,4 +111,5 @@ void sf_hex_tabulate_16(struct sf_hex_tbl_fmt *fmt, unsigned char *data,
}
len--;
}
printf("\n");
}

View 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-----

View file

@ -0,0 +1,4 @@
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAER+qu2dZtLh1lBfUE/swhmb5eWlZr
Tx4MQ+Jbzht9BtezceIKPEfthJ9lDtv5PdIHu4Gmc+Y7FpUZrAECyxz1NQ==
-----END PUBLIC KEY-----