feat(esp32p4): Support newer Key Manager key sources for ESP32-P4 V3

This commit is contained in:
harshal.patil
2026-04-06 18:11:43 +05:30
parent a21d116a57
commit 8dafc3b75f
25 changed files with 615 additions and 715 deletions
@@ -21,7 +21,7 @@ if(CONFIG_SOC_ECDSA_SUPPORTED)
list(APPEND srcs "ecdsa/test_ecdsa.c")
endif()
if(CONFIG_SOC_KEY_MANAGER_SUPPORTED)
if(CONFIG_CRYPTO_IS_KEY_MANAGER_SUPPORTED)
list(APPEND srcs "key_manager/test_key_manager.c"
"$ENV{IDF_PATH}/components/esp_security/src/esp_key_mgr.c")
list(APPEND priv_include_dirs "$ENV{IDF_PATH}/components/esp_security/include")
@@ -37,9 +37,17 @@ menu "Test App Configuration"
config CRYPTO_TESTAPP_USE_AES_INTERRUPT
bool "Use interrupt for long AES operations"
depends on SOC_AES_SUPPORTED
depends on SOC_AES_SUPPORTED
default n
help
Use an interrupt to coordinate long AES operations.
config CRYPTO_IS_KEY_MANAGER_SUPPORTED
bool
default n if IDF_TARGET_ESP32P4 && ESP32P4_SELECTS_REV_LESS_V3
default y
depends on SOC_KEY_MANAGER_SUPPORTED
help
A hidden config to determine if the Key Manager tests should be included.
endmenu
@@ -6,6 +6,7 @@
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "sdkconfig.h"
#include "unity.h"
#include "unity_fixture.h"
#include "unity_fixture_extras.h"
@@ -30,7 +31,7 @@ static void run_all_tests(void)
#endif /* !CONFIG_SOC_SHA_SUPPORT_PARALLEL_ENG*/
#endif
#if CONFIG_SOC_KEY_MANAGER_SUPPORTED
#if CONFIG_CRYPTO_IS_KEY_MANAGER_SUPPORTED
RUN_TEST_GROUP(key_manager);
#endif
@@ -93,6 +93,10 @@ static esp_err_t esp_ds_start_sign(const void *message, const esp_ds_data_t *dat
#if SOC_KEY_MANAGER_DS_KEY_DEPLOY
if (key_id == HMAC_KEY_KM) {
if (!key_mgr_ll_is_supported()) {
HAL_ASSERT(false && "Key manager is not supported");
}
ds_hal_set_key_source(DS_KEY_SOURCE_KEY_MGR);
} else {
ds_hal_set_key_source(DS_KEY_SOURCE_EFUSE);
@@ -1,4 +1,4 @@
# SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
# SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Unlicense OR CC0-1.0
import argparse
import hashlib
@@ -148,11 +148,11 @@ def generate_k1_G(key_file_path: str) -> tuple:
def generate_hmac_test_data(key: bytes) -> tuple:
hmac_message = (
'Deleniti voluptas explicabo et assumenda. Sed et aliquid minus quis. '
'Praesentium cupiditate quia nemo est. Laboriosam pariatur ut distinctio tenetur. '
'Sunt architecto iure aspernatur soluta ut recusandae. '
'Ut quibusdam occaecati ut qui sit dignissimos eaque..'
).encode('utf-8')
b'Deleniti voluptas explicabo et assumenda. Sed et aliquid minus quis. '
b'Praesentium cupiditate quia nemo est. Laboriosam pariatur ut distinctio tenetur. '
b'Sunt architecto iure aspernatur soluta ut recusandae. '
b'Ut quibusdam occaecati ut qui sit dignissimos eaque..'
)
hmac_result = hmac.HMAC(key, hmac_message, hashlib.sha256).digest()
return hmac_message, hmac_result
@@ -179,22 +179,18 @@ def number_as_bignum_words(number): # type: (int) -> str
return '{ ' + ', '.join(result) + ' }'
def generate_ds_encrypted_input_params(aes_key: bytes, target: str) -> tuple:
iv = os.urandom(16)
max_key_size = max(supported_ds_key_size[target])
key_size = max_key_size
private_key = rsa.generate_private_key(public_exponent=65537, key_size=key_size, backend=default_backend())
def generate_ds_encrypted_input_params(aes_key: bytes, max_key_size: int, iv: bytes) -> tuple:
private_key = rsa.generate_private_key(public_exponent=65537, key_size=max_key_size, backend=default_backend())
priv_numbers = private_key.private_numbers()
pub_numbers = private_key.public_key().public_numbers()
Y = priv_numbers.d
M = pub_numbers.n
rr = 1 << (key_size * 2)
rr = 1 << (max_key_size * 2)
rinv = rr % pub_numbers.n
mprime = -rsa._modinv(M, 1 << 32)
mprime &= 0xFFFFFFFF
length = key_size // 32 - 1
length = max_key_size // 32 - 1
# calculate MD from preceding values and IV
# Y_max_key_size || M_max_key_size || Rb_max_key_size || M_prime32 || LENGTH32 || IV128
@@ -230,12 +226,12 @@ def generate_ds_encrypted_input_params(aes_key: bytes, target: str) -> tuple:
encryptor = cipher.encryptor()
ds_encrypted_input_params = encryptor.update(p) + encryptor.finalize()
mask = (1 << key_size) - 1 # truncate messages if needed
mask = (1 << max_key_size) - 1 # truncate messages if needed
ds_message = random.randrange(0, 1 << max_key_size)
ds_result = number_as_bytes(pow(ds_message & mask, Y, M))
return number_as_bytes(ds_message), ds_encrypted_input_params, iv, key_size, ds_result
return number_as_bytes(ds_message), ds_encrypted_input_params, ds_result
def write_to_c_header(
@@ -254,77 +250,77 @@ def write_to_c_header(
k1_G_1: bytes,
hmac_message: bytes,
hmac_result: bytes,
ds_message: bytes,
ds_encrypted_input_params: bytes,
ds_encrypted_input_params_iv: bytes,
ds_key_size: int,
ds_result: bytes,
ds_message_4096: bytes,
ds_encrypted_input_params_4096: bytes,
ds_result_4096: bytes,
ds_message_3072: bytes,
ds_encrypted_input_params_3072: bytes,
ds_result_3072: bytes,
ds_iv: bytes,
) -> None:
with open('key_manager_test_cases.h', 'w', encoding='utf-8') as file:
header_content = """#include <stdint.h>
header_content = f"""#include <stdint.h>
#include "soc/soc_caps.h"
#define TEST_COUNT 5
typedef struct test_xts_data {
typedef struct test_xts_data {{
uint16_t data_size;
uint32_t data_offset;
uint8_t ciphertext[128];
} test_xts_data_t;
}} test_xts_data_t;
typedef struct test_ecdsa_data {
typedef struct test_ecdsa_data {{
uint8_t pubx[32];
uint8_t puby[32];
} test_ecdsa_data_t;
}} test_ecdsa_data_t;
typedef struct test_hmac_data {
uint8_t message[%d];
typedef struct test_hmac_data {{
uint8_t message[{len(hmac_message)}];
uint8_t hmac_result[32];
} test_hmac_data_t;
}} test_hmac_data_t;
typedef struct test_ds_data {
uint8_t ds_message[%d / 8];
uint8_t ds_encrypted_input_params[%d];
uint8_t ds_encrypted_input_params_iv[16];
typedef struct test_ds_data {{
#if SOC_RSA_MAX_BIT_LEN == 4096
uint8_t ds_message[4096 / 8];
uint8_t ds_encrypted_input_params[1584];
uint8_t ds_result[4096 / 8];
#elif SOC_RSA_MAX_BIT_LEN == 3072
uint8_t ds_message[3072 / 8];
uint8_t ds_encrypted_input_params[1200];
uint8_t ds_result[3072 / 8];
#endif
size_t ds_key_size;
uint8_t ds_result[%d];
} test_ds_data_t;
uint8_t ds_encrypted_input_params_iv[16];
}} test_ds_data_t;
typedef struct test_data {
typedef struct test_data {{
uint8_t init_key[32];
uint8_t k2_info[64];
uint8_t k1_encrypted[2][32]; // For both 256-bit and 512-bit keys
uint8_t plaintext_data[128];
union {
union {{
test_xts_data_t xts_test_data[TEST_COUNT];
test_ecdsa_data_t ecdsa_test_data;
test_hmac_data_t hmac_test_data;
test_ds_data_t ds_test_data;
};
} test_data_aes_mode_t;
}};
}} test_data_aes_mode_t;
typedef struct test_data_ecdh0 {
typedef struct test_data_ecdh0 {{
uint8_t plaintext_data[128];
uint8_t k1[2][32];
uint8_t k1_G[2][64];
} test_data_ecdh0_mode_t;
}} test_data_ecdh0_mode_t;
// For 32-byte k1 key
test_data_aes_mode_t test_data_xts_aes_128 = {
.init_key = { %s },
.k2_info = { %s },
.k1_encrypted = { { %s }, { } },
.plaintext_data = { %s },
.xts_test_data = {
""" % (
len(hmac_message),
ds_key_size,
len(ds_encrypted_input_params),
len(ds_result),
key_to_c_format(init_key),
key_to_c_format(k2_info),
key_to_c_format(k1_encrypted_32_reversed[0]),
key_to_c_format(bytes(range(1, 129))),
)
test_data_aes_mode_t test_data_xts_aes_128 = {{
.init_key = {{ {key_to_c_format(init_key)} }},
.k2_info = {{ {key_to_c_format(k2_info)} }},
.k1_encrypted = {{ {{ {key_to_c_format(k1_encrypted_32_reversed[0])} }}, {{ }} }},
.plaintext_data = {{ {key_to_c_format(bytes(range(1, 129)))} }},
.xts_test_data = {{
"""
for data_size, flash_address, ciphertext in test_data_xts_aes_128:
header_content += (
@@ -354,85 +350,65 @@ test_data_aes_mode_t test_data_xts_aes_128 = {
)
header_content += '\t}\n};\n'
header_content += """
test_data_aes_mode_t test_data_ecdsa = {
.init_key = { %s },
.k2_info = { %s },
.k1_encrypted = { { %s }, { } },
.ecdsa_test_data = {
.pubx = { %s },
.puby = { %s }
}
};\n
""" % (
key_to_c_format(init_key),
key_to_c_format(k2_info),
key_to_c_format(k1_encrypted_32_reversed[0]),
key_to_c_format(pubx),
key_to_c_format(puby),
)
header_content += f"""
test_data_aes_mode_t test_data_ecdsa = {{
.init_key = {{ {key_to_c_format(init_key)} }},
.k2_info = {{ {key_to_c_format(k2_info)} }},
.k1_encrypted = {{ {{ {key_to_c_format(k1_encrypted_32_reversed[0])} }}, {{ }} }},
.ecdsa_test_data = {{
.pubx = {{ {key_to_c_format(pubx)} }},
.puby = {{ {key_to_c_format(puby)} }}
}}
}};
"""
header_content += """
test_data_ecdh0_mode_t test_data_ecdh0 = {
.plaintext_data = { %s },
.k1 = {
{ %s },
{ %s },
},
.k1_G = {
{ %s },
{ %s },
}
};\n
""" % (
key_to_c_format(bytes(range(1, 129))),
key_to_c_format(k1),
key_to_c_format(k1),
key_to_c_format(k1_G_0),
key_to_c_format(k1_G_1),
)
header_content += f"""
test_data_ecdh0_mode_t test_data_ecdh0 = {{
.plaintext_data = {{ {key_to_c_format(bytes(range(1, 129)))} }},
.k1 = {{
{{ {key_to_c_format(k1)} }},
{{ {key_to_c_format(k1)} }},
}},
.k1_G = {{
{{ {key_to_c_format(k1_G_0)} }},
{{ {key_to_c_format(k1_G_1)} }},
}}
}};
"""
header_content += """
test_data_aes_mode_t test_data_hmac = {
.init_key = { %s },
.k2_info = { %s },
.k1_encrypted = { { %s }, { } },
.hmac_test_data = {
.message = { %s },
.hmac_result = { %s }
}
};\n
""" % (
key_to_c_format(init_key),
key_to_c_format(k2_info),
key_to_c_format(k1_encrypted_32[0]),
key_to_c_format(hmac_message),
key_to_c_format(hmac_result),
)
header_content += f"""
test_data_aes_mode_t test_data_hmac = {{
.init_key = {{ {key_to_c_format(init_key)} }},
.k2_info = {{ {key_to_c_format(k2_info)} }},
.k1_encrypted = {{ {{ {key_to_c_format(k1_encrypted_32[0])} }}, {{ }} }},
.hmac_test_data = {{
.message = {{ {key_to_c_format(hmac_message)} }},
.hmac_result = {{ {key_to_c_format(hmac_result)} }}
}}
}};
"""
header_content += """
test_data_aes_mode_t test_data_ds = {
.init_key = { %s },
.k2_info = { %s },
.k1_encrypted = { { %s }, { } },
.ds_test_data = {
.ds_message = { %s },
.ds_encrypted_input_params = { %s },
.ds_encrypted_input_params_iv = { %s },
.ds_key_size = %d,
.ds_result = { %s }
}
};\n
""" % (
key_to_c_format(init_key),
key_to_c_format(k2_info),
key_to_c_format(k1_encrypted_32_reversed[0]),
key_to_c_format(ds_message),
key_to_c_format(ds_encrypted_input_params),
key_to_c_format(ds_encrypted_input_params_iv),
ds_key_size,
key_to_c_format(ds_result),
)
header_content += f"""
test_data_aes_mode_t test_data_ds = {{
.init_key = {{ {key_to_c_format(init_key)} }},
.k2_info = {{ {key_to_c_format(k2_info)} }},
.k1_encrypted = {{ {{ {key_to_c_format(k1_encrypted_32_reversed[0])} }}, {{ }} }},
.ds_test_data = {{
#if SOC_DS_SIGNATURE_MAX_BIT_LEN == 4096
.ds_message = {{ {key_to_c_format(ds_message_4096)} }},
.ds_encrypted_input_params = {{ {key_to_c_format(ds_encrypted_input_params_4096)} }},
.ds_key_size = 4096,
.ds_result = {{ {key_to_c_format(ds_result_4096)} }},
#elif SOC_DS_SIGNATURE_MAX_BIT_LEN == 3072
.ds_message = {{ {key_to_c_format(ds_message_3072)} }},
.ds_encrypted_input_params = {{ {key_to_c_format(ds_encrypted_input_params_3072)} }},
.ds_key_size = 3072,
.ds_result = {{ {key_to_c_format(ds_result_3072)} }},
#endif
.ds_encrypted_input_params_iv = {{ {key_to_c_format(ds_iv)} }},
}},
}};
"""
file.write(header_content)
@@ -472,8 +448,14 @@ def generate_tests_cases(target: str) -> None:
hmac_message, hmac_result = generate_hmac_test_data(k1_32)
ds_message, ds_encrypted_input_params, ds_encrypted_input_params_iv, ds_key_size, ds_result = (
generate_ds_encrypted_input_params(k1_32, target)
ds_iv = os.urandom(16)
ds_message_4096, ds_encrypted_input_params_4096, ds_result_4096 = generate_ds_encrypted_input_params(
k1_32, 4096, ds_iv
)
ds_message_3072, ds_encrypted_input_params_3072, ds_result_3072 = generate_ds_encrypted_input_params(
k1_32, 3072, ds_iv
)
write_to_c_header(
@@ -492,11 +474,13 @@ def generate_tests_cases(target: str) -> None:
k1_G_1,
hmac_message,
hmac_result,
ds_message,
ds_encrypted_input_params,
ds_encrypted_input_params_iv,
ds_key_size,
ds_result,
ds_message_4096,
ds_encrypted_input_params_4096,
ds_result_4096,
ds_message_3072,
ds_encrypted_input_params_3072,
ds_result_3072,
ds_iv,
)
File diff suppressed because one or more lines are too long