Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions REUSE.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
version = 1

# Declare default license and copyright text for files that typically do not include them.
[[annotations]]
path = [
# zephyr-keep-sorted-start
"**/*.cfg",
"**/*.cmake",
"**/*.conf",
"**/*.ecl",
"**/*.html",
"**/*.md",
"**/*.rst",
"**/*.yaml",
"**/*.yml",
"**/*_defconfig",
"**/CMakeLists.txt",
"**/Kconfig*",
# zephyr-keep-sorted-stop
]
SPDX-License-Identifier = "Apache-2.0"
SPDX-FileCopyrightText = "Copyright (c) 2025 Silicon Laboratories Inc."
40 changes: 30 additions & 10 deletions tests/crypto/psa_crypto/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,22 +1,42 @@
# SPDX-License-Identifier: Apache-2.0
# Copyright (c) 2025 Silicon Laboratories Inc.

cmake_minimum_required(VERSION 3.20.0)

find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(psa_crypto)

target_sources(app PRIVATE
src/main.c
src/test_vectors.c
src/aead.c
src/cipher.c
src/hash.c
src/sign.c
src/key_agreement.c
src/main.c
src/test_vectors.c
src/aead.c
src/cipher.c
src/hash.c
src/sign.c
src/key_agreement.c
)

# Use CMake variable to configure testcase, since Kconfig can't be defined
# Use CMake variables to configure testcase, since Kconfig can't be defined
# in out-of-tree tests due to the compliance script failing.
if(DEFINED TEST_WRAPPED_KEYS)
target_compile_definitions(app PUBLIC TEST_WRAPPED_KEYS=${TEST_WRAPPED_KEYS})

# HSE fully supports opaque keys and multipart operations
if(CONFIG_PSA_CRYPTO_DRIVER_SILABS_HSE)
target_compile_definitions(app PUBLIC
TEST_OPAQUE_AEAD=1
TEST_OPAQUE_CIPHER=1
TEST_OPAQUE_KEY_AGREEMENT=1
TEST_OPAQUE_SIGN=1
)
endif()

# SiWx917 only supports one-shot operations on internally generated opaque keys
# for sign_message/verify_message and AEAD encrypt/decrypt
if(CONFIG_PSA_CRYPTO_DRIVER_SILABS_SIWX91X)
target_compile_definitions(app PUBLIC
TEST_OPAQUE_AEAD=1
TEST_OPAQUE_SIGN=1
TEST_OPAQUE_NO_IMPORT_KEY=1
TEST_OPAQUE_NO_MULTIPART=1
TEST_OPAQUE_NO_VERIFY=1
)
endif()
43 changes: 43 additions & 0 deletions tests/crypto/psa_crypto/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# PSA Crypto test

This test functions as a smoke test for PSA Crypto APIs, demonstrating that single and multipart
operations work as expected using both transparent drivers and opaque drivers on devices that
support them.

## Device Configuration

### Series 2

No special configuration is required.

### SiWx91x

In order for opaque APIs to work, the device needs to be provisioned to enable security features.
At a minimum, images must have a MIC, but can also be encrypted and signed.

#### Provisioning

See [UG574](https://www.silabs.com/documents/public/user-guides/ug574-siwx917-soc-manufacturing-utility-user-guide.pdf)
for details.

```
commander manufacturing init --mbr default -d SiWG917M111MGTBA
commander util genkeyconfig -o keys.json -d SiWG917M111MGTBA
commander manufacturing provision --keys keys.json -d SiWG917M111MGTBA
echo '{"efuse_data": {"ta_secure_boot_enable": 1, "m4_secure_boot_enable": 1}}' > mbr.json
commander manufacturing provision --mbr default --data mbr.json -d SiWG917M111MGTBA
```

#### Adding MIC to Images

The above configuration enables MIC authentication of images. A MIC is added to the image by a
post-build step in the Zephyr build system when `CONFIG_SIWX91X_MIC_KEY` is set. The Kconfig option
must be set to the key provisioned to the device in the previous section under `.KEYS.M4_OTA_KEY`.

Example using `jq` to extract the key from the json file:

```
west build -p -b siwx917_rb4338a tests/crypto/psa_crypto/ -T crypto.psa_crypto.default -DCONFIG_SIWX91X_MIC_KEY=`jq '.KEYS.M4_OTA_KEY' keys.json`
```

The key can also be given directly or set in `prj.conf`.
121 changes: 106 additions & 15 deletions tests/crypto/psa_crypto/src/aead.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ const uint8_t chachapoly_expect_cipher_tag_buf[] = {
0xe2, 0x6a, 0x7e, 0x90, 0x2e, 0xcb, 0xd0, 0x60, 0x06, 0x91,
};

ZTEST(psa_crypto_test, test_aead_aes_ccm)
void test_aead_aes_ccm(bool generate_key, psa_key_location_t location)
{
const uint8_t expect_cipher_tag_buf[] = {
0xe2, 0x2f, 0x37, 0x3b, 0xeb, 0xf6, 0x4a, 0x3e, 0x9b, 0x87, 0x75, 0x2b, 0xf9,
Expand All @@ -60,9 +60,18 @@ ZTEST(psa_crypto_test, test_aead_aes_ccm)
psa_set_key_type(&attributes, PSA_KEY_TYPE_AES);
psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT);
psa_set_key_algorithm(&attributes, alg);
psa_set_key_bits(&attributes, 128);
psa_set_key_lifetime(&attributes, PSA_KEY_LIFETIME_FROM_PERSISTENCE_AND_LOCATION(
PSA_KEY_PERSISTENCE_VOLATILE, location));

zassert_equal(psa_import_key(&attributes, aes_key_buf, sizeof(aes_key_buf), &key_id),
PSA_SUCCESS, "Failed to import key");
if (generate_key) {
zassert_equal(psa_generate_key(&attributes, &key_id), PSA_SUCCESS,
"Failed to generate key");
} else {
zassert_equal(
psa_import_key(&attributes, aes_key_buf, sizeof(aes_key_buf), &key_id),
PSA_SUCCESS, "Failed to import key");
}

zassert_equal(psa_aead_encrypt(key_id, alg, aes_nonce_buf, sizeof(aes_nonce_buf),
aes_ad_buf, sizeof(aes_ad_buf), aes_plaintext,
Expand All @@ -71,7 +80,10 @@ ZTEST(psa_crypto_test, test_aead_aes_ccm)
PSA_SUCCESS, "Failed to encrypt");

zassert_equal(out_len, sizeof(expect_cipher_tag_buf));
zassert_mem_equal(cipher_tag_buf, expect_cipher_tag_buf, sizeof(expect_cipher_tag_buf));
if (!generate_key) {
zassert_mem_equal(cipher_tag_buf, expect_cipher_tag_buf,
sizeof(expect_cipher_tag_buf));
}

zassert_equal(psa_aead_decrypt(key_id, alg, aes_nonce_buf, sizeof(aes_nonce_buf),
aes_ad_buf, sizeof(aes_ad_buf), cipher_tag_buf, out_len,
Expand All @@ -84,7 +96,7 @@ ZTEST(psa_crypto_test, test_aead_aes_ccm)
zassert_equal(psa_destroy_key(key_id), PSA_SUCCESS, "Failed to destroy key");
}

ZTEST(psa_crypto_test, test_aead_aes_gcm)
void test_aead_aes_gcm(bool generate_key, psa_key_location_t location)
{
const uint8_t expect_cipher_tag_buf[] = {
0x0f, 0x51, 0xf7, 0xa8, 0x3c, 0x5b, 0x5a, 0xa7, 0x96, 0xb9, 0x70, 0x25, 0x9c,
Expand All @@ -101,9 +113,18 @@ ZTEST(psa_crypto_test, test_aead_aes_gcm)
psa_set_key_type(&attributes, PSA_KEY_TYPE_AES);
psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT);
psa_set_key_algorithm(&attributes, alg);
psa_set_key_bits(&attributes, 128);
psa_set_key_lifetime(&attributes, PSA_KEY_LIFETIME_FROM_PERSISTENCE_AND_LOCATION(
PSA_KEY_PERSISTENCE_VOLATILE, location));

zassert_equal(psa_import_key(&attributes, aes_key_buf, sizeof(aes_key_buf), &key_id),
PSA_SUCCESS, "Failed to import key");
if (generate_key) {
zassert_equal(psa_generate_key(&attributes, &key_id), PSA_SUCCESS,
"Failed to generate key");
} else {
zassert_equal(
psa_import_key(&attributes, aes_key_buf, sizeof(aes_key_buf), &key_id),
PSA_SUCCESS, "Failed to import key");
}

zassert_equal(psa_aead_encrypt(key_id, alg, aes_nonce_buf, sizeof(aes_nonce_buf),
aes_ad_buf, sizeof(aes_ad_buf), aes_plaintext,
Expand All @@ -112,7 +133,10 @@ ZTEST(psa_crypto_test, test_aead_aes_gcm)
PSA_SUCCESS, "Failed to encrypt");

zassert_equal(out_len, sizeof(expect_cipher_tag_buf));
zassert_mem_equal(cipher_tag_buf, expect_cipher_tag_buf, sizeof(expect_cipher_tag_buf));
if (!generate_key) {
zassert_mem_equal(cipher_tag_buf, expect_cipher_tag_buf,
sizeof(expect_cipher_tag_buf));
}

zassert_equal(psa_aead_decrypt(key_id, alg, aes_nonce_buf, sizeof(aes_nonce_buf),
aes_ad_buf, sizeof(aes_ad_buf), cipher_tag_buf, out_len,
Expand All @@ -125,7 +149,7 @@ ZTEST(psa_crypto_test, test_aead_aes_gcm)
zassert_equal(psa_destroy_key(key_id), PSA_SUCCESS, "Failed to destroy key");
}

ZTEST(psa_crypto_test, test_aead_chacha20_poly1305)
void test_aead_chacha20_poly1305(bool generate_key, psa_key_location_t location)
{
uint8_t cipher_tag_buf[130]; /* Ciphertext + Tag */
uint8_t decrypted[sizeof(chachapoly_plaintext)] = {0};
Expand All @@ -135,13 +159,21 @@ ZTEST(psa_crypto_test, test_aead_chacha20_poly1305)
psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
psa_algorithm_t alg = PSA_ALG_CHACHA20_POLY1305;

psa_set_key_type(&attributes, PSA_KEY_TYPE_CHACHA20);
psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT);
psa_set_key_algorithm(&attributes, alg);
psa_set_key_type(&attributes, PSA_KEY_TYPE_CHACHA20);
psa_set_key_bits(&attributes, 256);
psa_set_key_lifetime(&attributes, PSA_KEY_LIFETIME_FROM_PERSISTENCE_AND_LOCATION(
PSA_KEY_PERSISTENCE_VOLATILE, location));

zassert_equal(psa_import_key(&attributes, chachapoly_key_buf, sizeof(chachapoly_key_buf),
&key_id),
PSA_SUCCESS, "Failed to import key");
if (generate_key) {
zassert_equal(psa_generate_key(&attributes, &key_id), PSA_SUCCESS,
"Failed to generate key");
} else {
zassert_equal(psa_import_key(&attributes, chachapoly_key_buf,
sizeof(chachapoly_key_buf), &key_id),
PSA_SUCCESS, "Failed to import key");
}

zassert_equal(psa_aead_encrypt(key_id, alg, chachapoly_nonce_buf,
sizeof(chachapoly_nonce_buf), chachapoly_ad_buf,
Expand All @@ -151,8 +183,10 @@ ZTEST(psa_crypto_test, test_aead_chacha20_poly1305)
PSA_SUCCESS, "Failed to encrypt");

zassert_equal(out_len, sizeof(chachapoly_expect_cipher_tag_buf));
zassert_mem_equal(cipher_tag_buf, chachapoly_expect_cipher_tag_buf,
sizeof(chachapoly_expect_cipher_tag_buf));
if (!generate_key) {
zassert_mem_equal(cipher_tag_buf, chachapoly_expect_cipher_tag_buf,
sizeof(chachapoly_expect_cipher_tag_buf));
}

zassert_equal(psa_aead_decrypt(key_id, alg, chachapoly_nonce_buf,
sizeof(chachapoly_nonce_buf), chachapoly_ad_buf,
Expand All @@ -165,3 +199,60 @@ ZTEST(psa_crypto_test, test_aead_chacha20_poly1305)

zassert_equal(psa_destroy_key(key_id), PSA_SUCCESS, "Failed to destroy key");
}

ZTEST(psa_crypto_test, test_aead_aes_ccm_transparent)
{
test_aead_aes_ccm(false, 0);
test_aead_aes_ccm(true, 0);
}

ZTEST(psa_crypto_test, test_aead_aes_ccm_opaque)
{
if (!IS_ENABLED(TEST_OPAQUE_AEAD)) {
ztest_test_skip();
}

if (!IS_ENABLED(TEST_OPAQUE_NO_IMPORT_KEY)) {
test_aead_aes_ccm(false, 1);
}

test_aead_aes_ccm(true, 1);
}

ZTEST(psa_crypto_test, test_aead_aes_gcm_transparent)
{
test_aead_aes_gcm(false, 0);
test_aead_aes_gcm(true, 0);
}

ZTEST(psa_crypto_test, test_aead_aes_gcm_opaque)
{
if (!IS_ENABLED(TEST_OPAQUE_AEAD)) {
ztest_test_skip();
}

if (!IS_ENABLED(TEST_OPAQUE_NO_IMPORT_KEY)) {
test_aead_aes_gcm(false, 1);
}

test_aead_aes_gcm(true, 1);
}

ZTEST(psa_crypto_test, test_aead_chacha20_poly1305_transparent)
{
test_aead_chacha20_poly1305(false, 0);
test_aead_chacha20_poly1305(true, 0);
}

ZTEST(psa_crypto_test, test_aead_chacha20_poly1305_opaque)
{
if (!IS_ENABLED(TEST_OPAQUE_AEAD)) {
ztest_test_skip();
}

if (!IS_ENABLED(TEST_OPAQUE_NO_IMPORT_KEY)) {
test_aead_chacha20_poly1305(false, 1);
}

test_aead_chacha20_poly1305(true, 1);
}
Loading