mirror of
https://github.com/espressif/esp-idf.git
synced 2026-10-02 11:10:54 +03:00
feat(esp_security): add ECDH1 deployment mode to Key Manager driver
This commit is contained in:
+107
-1
@@ -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
|
# SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||||
import hashlib
|
import hashlib
|
||||||
import hmac
|
import hmac
|
||||||
@@ -146,6 +146,39 @@ def generate_k1_G(k1_bytes: bytes) -> tuple:
|
|||||||
return k1_G, k1_G
|
return k1_G, k1_G
|
||||||
|
|
||||||
|
|
||||||
|
def compute_ecdh1_x(k1_be: bytes, k2_le: bytes) -> int:
|
||||||
|
"""Compute x(k1*k2*G) on NIST P-256 as an integer.
|
||||||
|
|
||||||
|
k1 is interpreted big-endian (matches the user's k1*G computation in
|
||||||
|
generate_k1_G); k2 is interpreted little-endian (the KM's convention
|
||||||
|
for k2 recovered from k2_info). The deployed-key byte string is the
|
||||||
|
big-endian encoding of the returned integer.
|
||||||
|
"""
|
||||||
|
k1_int = int.from_bytes(k1_be, byteorder='big')
|
||||||
|
k2_int = int.from_bytes(k2_le, byteorder='little')
|
||||||
|
generator = NIST256p.generator.to_affine()
|
||||||
|
point = (k1_int * k2_int) * generator
|
||||||
|
return int(point.x())
|
||||||
|
|
||||||
|
|
||||||
|
def generate_ecdsa_pub_from_scalar(scalar_int: int, curve_size_bits: int) -> tuple:
|
||||||
|
"""Compute (scalar * G).x, .y for the given P-N curve and return them
|
||||||
|
as little-endian bytes (the ECDSA peripheral's exported-pubkey order)."""
|
||||||
|
if curve_size_bits == 192:
|
||||||
|
curve = ec.SECP192R1()
|
||||||
|
elif curve_size_bits == 256:
|
||||||
|
curve = ec.SECP256R1()
|
||||||
|
elif curve_size_bits == 384:
|
||||||
|
curve = ec.SECP384R1()
|
||||||
|
else:
|
||||||
|
raise ValueError(f'Unsupported curve size: {curve_size_bits}')
|
||||||
|
private_key = ec.derive_private_key(scalar_int, curve)
|
||||||
|
pub_numbers = private_key.public_key().public_numbers()
|
||||||
|
pubx = pub_numbers.x.to_bytes(curve_size_bits // 8, byteorder='little')
|
||||||
|
puby = pub_numbers.y.to_bytes(curve_size_bits // 8, byteorder='little')
|
||||||
|
return pubx, puby
|
||||||
|
|
||||||
|
|
||||||
def generate_hmac_test_data(key: bytes) -> tuple:
|
def generate_hmac_test_data(key: bytes) -> tuple:
|
||||||
hmac_message = (
|
hmac_message = (
|
||||||
b'Deleniti voluptas explicabo et assumenda. Sed et aliquid minus quis. '
|
b'Deleniti voluptas explicabo et assumenda. Sed et aliquid minus quis. '
|
||||||
@@ -265,6 +298,10 @@ def write_to_c_header(
|
|||||||
ds_encrypted_input_params_3072: bytes,
|
ds_encrypted_input_params_3072: bytes,
|
||||||
ds_result_3072: bytes,
|
ds_result_3072: bytes,
|
||||||
ds_iv: bytes,
|
ds_iv: bytes,
|
||||||
|
ecdh1_xts_test_data: list,
|
||||||
|
ecdh1_hmac_result: bytes,
|
||||||
|
ecdh1_p256_pubx: bytes,
|
||||||
|
ecdh1_p256_puby: bytes,
|
||||||
) -> None:
|
) -> None:
|
||||||
with open('key_manager_test_cases.h', 'w', encoding='utf-8') as file:
|
with open('key_manager_test_cases.h', 'w', encoding='utf-8') as file:
|
||||||
header_content = f"""#include <stdint.h>
|
header_content = f"""#include <stdint.h>
|
||||||
@@ -327,6 +364,21 @@ typedef struct test_data_ecdh0 {{
|
|||||||
uint8_t k1_G[2][64];
|
uint8_t k1_G[2][64];
|
||||||
}} test_data_ecdh0_mode_t;
|
}} test_data_ecdh0_mode_t;
|
||||||
|
|
||||||
|
// ECDH1 takes the AES-mode-style (init_key, k2_info) inputs plus the ECDH
|
||||||
|
// k1*G public point (sourced from test_data_ecdh0.k1_G to share the same
|
||||||
|
// k1 across ECDH0 and ECDH1 tests). k1_encrypted is unused, so it isn't in
|
||||||
|
// this struct.
|
||||||
|
typedef struct test_data_ecdh1 {{
|
||||||
|
uint8_t init_key[32];
|
||||||
|
uint8_t k2_info[64];
|
||||||
|
uint8_t plaintext_data[128];
|
||||||
|
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_data_ecdh1_mode_t;
|
||||||
|
|
||||||
// For 32-byte k1 key
|
// For 32-byte k1 key
|
||||||
test_data_aes_mode_t test_data_xts_aes_128 = {{
|
test_data_aes_mode_t test_data_xts_aes_128 = {{
|
||||||
.init_key = {{ {key_to_c_format(init_key)} }},
|
.init_key = {{ {key_to_c_format(init_key)} }},
|
||||||
@@ -431,6 +483,44 @@ test_data_aes_mode_t test_data_ds = {{
|
|||||||
.ds_encrypted_input_params_iv = {{ {key_to_c_format(ds_iv)} }},
|
.ds_encrypted_input_params_iv = {{ {key_to_c_format(ds_iv)} }},
|
||||||
}},
|
}},
|
||||||
}};
|
}};
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Per-key-type ECDH1 instances. Expected per-peripheral outputs
|
||||||
|
# (XTS ciphertext, HMAC result, ECDSA pubkey) are computed off-device
|
||||||
|
# using the deployed key x(k1*k2*G).
|
||||||
|
header_content += f"""
|
||||||
|
test_data_ecdh1_mode_t test_data_ecdh1_xts_aes_128 = {{
|
||||||
|
.init_key = {{ {key_to_c_format(init_key)} }},
|
||||||
|
.k2_info = {{ {key_to_c_format(k2_info)} }},
|
||||||
|
.plaintext_data = {{ {key_to_c_format(bytes(range(1, 129)))} }},
|
||||||
|
.xts_test_data = {{
|
||||||
|
"""
|
||||||
|
for data_size, flash_address, ciphertext in ecdh1_xts_test_data:
|
||||||
|
header_content += (
|
||||||
|
f'\t\t{{.data_size = {data_size}, '
|
||||||
|
f'.data_offset = 0x{flash_address:x}, '
|
||||||
|
f'.ciphertext = {{{key_to_c_format(ciphertext)}}}}},\n'
|
||||||
|
)
|
||||||
|
header_content += '\t}\n};\n'
|
||||||
|
|
||||||
|
header_content += f"""
|
||||||
|
test_data_ecdh1_mode_t test_data_ecdh1_hmac = {{
|
||||||
|
.init_key = {{ {key_to_c_format(init_key)} }},
|
||||||
|
.k2_info = {{ {key_to_c_format(k2_info)} }},
|
||||||
|
.hmac_test_data = {{
|
||||||
|
.message = {{ {key_to_c_format(hmac_message)} }},
|
||||||
|
.hmac_result = {{ {key_to_c_format(ecdh1_hmac_result)} }}
|
||||||
|
}}
|
||||||
|
}};
|
||||||
|
|
||||||
|
test_data_ecdh1_mode_t test_data_ecdh1_ecdsa = {{
|
||||||
|
.init_key = {{ {key_to_c_format(init_key)} }},
|
||||||
|
.k2_info = {{ {key_to_c_format(k2_info)} }},
|
||||||
|
.ecdsa_test_data = {{
|
||||||
|
.ecdsa_p256_pubx = {{ {key_to_c_format(ecdh1_p256_pubx)} }},
|
||||||
|
.ecdsa_p256_puby = {{ {key_to_c_format(ecdh1_p256_puby)} }},
|
||||||
|
}}
|
||||||
|
}};
|
||||||
"""
|
"""
|
||||||
|
|
||||||
file.write(header_content)
|
file.write(header_content)
|
||||||
@@ -490,6 +580,18 @@ def generate_tests_cases() -> None:
|
|||||||
|
|
||||||
hmac_message, hmac_result = generate_hmac_test_data(k1_32)
|
hmac_message, hmac_result = generate_hmac_test_data(k1_32)
|
||||||
|
|
||||||
|
# ECDH1: deployed key bytes = big-endian x(k1*k2*G). Per-peripheral
|
||||||
|
# effective key:
|
||||||
|
# - XTS-AES-128: key = x_be (32 BE bytes)
|
||||||
|
# - HMAC: key = x_le (= x_be[::-1], the slot is read LE)
|
||||||
|
# - ECDSA-P256: scalar = x_int mod n_p256
|
||||||
|
ecdh1_x_int = compute_ecdh1_x(k1_32, k2)
|
||||||
|
ecdh1_x_be = ecdh1_x_int.to_bytes(32, byteorder='big')
|
||||||
|
ecdh1_x_le = ecdh1_x_be[::-1]
|
||||||
|
ecdh1_xts_test_data = generate_xts_test_data(ecdh1_x_be)
|
||||||
|
ecdh1_hmac_result = hmac.HMAC(ecdh1_x_le, hmac_message, hashlib.sha256).digest()
|
||||||
|
ecdh1_p256_pubx, ecdh1_p256_puby = generate_ecdsa_pub_from_scalar(ecdh1_x_int % NIST256p.order, 256)
|
||||||
|
|
||||||
ds_iv = os.urandom(16)
|
ds_iv = os.urandom(16)
|
||||||
|
|
||||||
ds_message_4096, ds_encrypted_input_params_4096, ds_result_4096 = generate_ds_encrypted_input_params(
|
ds_message_4096, ds_encrypted_input_params_4096, ds_result_4096 = generate_ds_encrypted_input_params(
|
||||||
@@ -531,6 +633,10 @@ def generate_tests_cases() -> None:
|
|||||||
ds_encrypted_input_params_3072,
|
ds_encrypted_input_params_3072,
|
||||||
ds_result_3072,
|
ds_result_3072,
|
||||||
ds_iv,
|
ds_iv,
|
||||||
|
ecdh1_xts_test_data,
|
||||||
|
ecdh1_hmac_result,
|
||||||
|
ecdh1_p256_pubx,
|
||||||
|
ecdh1_p256_puby,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+54
-8
File diff suppressed because one or more lines are too long
@@ -600,6 +600,118 @@ static void key_mgr_test_ds_aes_mode(void)
|
|||||||
}
|
}
|
||||||
#endif /* SOC_KEY_MANAGER_DS_KEY_DEPLOY */
|
#endif /* SOC_KEY_MANAGER_DS_KEY_DEPLOY */
|
||||||
|
|
||||||
|
/* ---- ECDH1 deployment helpers ----
|
||||||
|
*
|
||||||
|
* Per-key-type test vectors (k2_info, init_key, expected XTS ciphertext /
|
||||||
|
* HMAC result / ECDSA-P256 pubkey) are precomputed off-device by
|
||||||
|
* gen_key_manager_test_cases.py against the same committed k1_64.bin /
|
||||||
|
* k2.bin / init_key.bin / rand_num.bin used by the AES-mode and ECDH0
|
||||||
|
* tests, and emitted as test_data_ecdh1_xts_aes_128 / test_data_ecdh1_hmac
|
||||||
|
* / test_data_ecdh1_ecdsa instances of test_data_aes_mode_t. That lets the
|
||||||
|
* AES-mode per-peripheral verifiers (test_xts_aes_key_aes_mode,
|
||||||
|
* key_mgr_test_hmac_key_aes_mode, test_ecdsa_key_aes_mode) compare HW
|
||||||
|
* output bitwise against the precomputed expected values without any
|
||||||
|
* on-device key-derivation. k1*G (the ECDH input the user supplies) is
|
||||||
|
* shared with the ECDH0 tests via test_data_ecdh0.k1_G[0]. */
|
||||||
|
|
||||||
|
#if SOC_KEY_MANAGER_HMAC_KEY_DEPLOY
|
||||||
|
static void key_mgr_test_hmac_ecdh1_mode(void)
|
||||||
|
{
|
||||||
|
static esp_key_mgr_ecdh1_key_config_t key_config;
|
||||||
|
memcpy(key_config.k2_info, (uint8_t*) test_data_ecdh1_hmac.k2_info, KEY_MGR_K2_INFO_SIZE);
|
||||||
|
memcpy(key_config.k1_G[0], (uint8_t*) test_data_ecdh0.k1_G[0], KEY_MGR_ECDH0_INFO_SIZE);
|
||||||
|
memcpy(key_config.sw_init_key, (uint8_t*) test_data_ecdh1_hmac.init_key, KEY_MGR_SW_INIT_KEY_SIZE);
|
||||||
|
key_config.use_pre_generated_sw_init_key = 1;
|
||||||
|
key_config.key_type = ESP_KEY_MGR_HMAC_KEY;
|
||||||
|
|
||||||
|
static esp_key_mgr_key_recovery_info_t key_recovery_info;
|
||||||
|
TEST_ASSERT_EQUAL(ESP_OK, esp_key_mgr_deploy_key_in_ecdh1_mode(&key_config, &key_recovery_info));
|
||||||
|
TEST_ASSERT_EQUAL(ESP_OK, esp_key_mgr_activate_key(&key_recovery_info));
|
||||||
|
|
||||||
|
uint8_t hw_mac[32] = { 0 };
|
||||||
|
TEST_ASSERT_EQUAL(ESP_OK, hmac_calculate(HMAC_KEY_KM,
|
||||||
|
test_data_ecdh1_hmac.hmac_test_data.message,
|
||||||
|
sizeof(test_data_ecdh1_hmac.hmac_test_data.message),
|
||||||
|
hw_mac));
|
||||||
|
TEST_ASSERT_EQUAL_HEX8_ARRAY(test_data_ecdh1_hmac.hmac_test_data.hmac_result,
|
||||||
|
hw_mac, sizeof(hw_mac));
|
||||||
|
|
||||||
|
TEST_ASSERT_EQUAL(ESP_OK, esp_key_mgr_deactivate_key(key_recovery_info.key_type));
|
||||||
|
}
|
||||||
|
#endif /* SOC_KEY_MANAGER_HMAC_KEY_DEPLOY */
|
||||||
|
|
||||||
|
#if SOC_KEY_MANAGER_FE_KEY_DEPLOY && SOC_KEY_MANAGER_FE_KEY_DEPLOY_XTS_AES_128
|
||||||
|
/* Common XTS-AES verify body. Used by both the AES-mode and ECDH1-mode XTS
|
||||||
|
* tests, which carry their own struct types but share the same plaintext +
|
||||||
|
* expected-ciphertext layout. */
|
||||||
|
static void verify_xts_aes_test_data(const uint8_t *plaintext_data,
|
||||||
|
const test_xts_data_t *xts_test_data)
|
||||||
|
{
|
||||||
|
const esp_partition_t *partition = get_test_storage_partition();
|
||||||
|
ESP_ERROR_CHECK(esp_partition_erase_range(partition, 0, partition->size));
|
||||||
|
|
||||||
|
uint8_t read_data[128];
|
||||||
|
for (int i = 0; i < TEST_COUNT; i++) {
|
||||||
|
memset(read_data, 0, sizeof(read_data));
|
||||||
|
uint32_t address = xts_test_data[i].data_offset;
|
||||||
|
uint32_t data_size = xts_test_data[i].data_size;
|
||||||
|
|
||||||
|
ESP_ERROR_CHECK(esp_flash_write_encrypted(NULL, address, plaintext_data, data_size));
|
||||||
|
ESP_ERROR_CHECK(esp_flash_read(NULL, read_data, address, data_size));
|
||||||
|
|
||||||
|
TEST_ASSERT_EQUAL_HEX8_ARRAY(xts_test_data[i].ciphertext, read_data, data_size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void key_mgr_test_xts_aes_128_ecdh1_mode(void)
|
||||||
|
{
|
||||||
|
static esp_key_mgr_ecdh1_key_config_t key_config;
|
||||||
|
memcpy(key_config.k2_info, (uint8_t*) test_data_ecdh1_xts_aes_128.k2_info, KEY_MGR_K2_INFO_SIZE);
|
||||||
|
memcpy(key_config.k1_G[0], (uint8_t*) test_data_ecdh0.k1_G[0], KEY_MGR_ECDH0_INFO_SIZE);
|
||||||
|
memcpy(key_config.sw_init_key, (uint8_t*) test_data_ecdh1_xts_aes_128.init_key, KEY_MGR_SW_INIT_KEY_SIZE);
|
||||||
|
key_config.use_pre_generated_sw_init_key = 1;
|
||||||
|
key_config.key_type = ESP_KEY_MGR_FLASH_XTS_AES_KEY;
|
||||||
|
key_config.key_len = ESP_KEY_MGR_XTS_AES_LEN_128;
|
||||||
|
|
||||||
|
static esp_key_mgr_key_recovery_info_t key_recovery_info;
|
||||||
|
TEST_ASSERT_EQUAL(ESP_OK, esp_key_mgr_deploy_key_in_ecdh1_mode(&key_config, &key_recovery_info));
|
||||||
|
TEST_ASSERT_EQUAL(ESP_OK, esp_key_mgr_activate_key(&key_recovery_info));
|
||||||
|
verify_xts_aes_test_data(test_data_ecdh1_xts_aes_128.plaintext_data,
|
||||||
|
test_data_ecdh1_xts_aes_128.xts_test_data);
|
||||||
|
TEST_ASSERT_EQUAL(ESP_OK, esp_key_mgr_deactivate_key(key_recovery_info.key_type));
|
||||||
|
}
|
||||||
|
#endif /* SOC_KEY_MANAGER_FE_KEY_DEPLOY && SOC_KEY_MANAGER_FE_KEY_DEPLOY_XTS_AES_128 */
|
||||||
|
|
||||||
|
#if SOC_KEY_MANAGER_ECDSA_KEY_DEPLOY
|
||||||
|
static void key_mgr_test_ecdsa_p256_ecdh1_mode(void)
|
||||||
|
{
|
||||||
|
static esp_key_mgr_ecdh1_key_config_t key_config;
|
||||||
|
memcpy(key_config.k2_info, (uint8_t*) test_data_ecdh1_ecdsa.k2_info, KEY_MGR_K2_INFO_SIZE);
|
||||||
|
memcpy(key_config.k1_G[0], (uint8_t*) test_data_ecdh0.k1_G[0], KEY_MGR_ECDH0_INFO_SIZE);
|
||||||
|
memcpy(key_config.sw_init_key, (uint8_t*) test_data_ecdh1_ecdsa.init_key, KEY_MGR_SW_INIT_KEY_SIZE);
|
||||||
|
key_config.use_pre_generated_sw_init_key = 1;
|
||||||
|
key_config.key_type = ESP_KEY_MGR_ECDSA_KEY;
|
||||||
|
key_config.key_len = ESP_KEY_MGR_ECDSA_LEN_256;
|
||||||
|
|
||||||
|
static esp_key_mgr_key_recovery_info_t key_recovery_info;
|
||||||
|
TEST_ASSERT_EQUAL(ESP_OK, esp_key_mgr_deploy_key_in_ecdh1_mode(&key_config, &key_recovery_info));
|
||||||
|
TEST_ASSERT_EQUAL(ESP_OK, esp_key_mgr_activate_key(&key_recovery_info));
|
||||||
|
|
||||||
|
#if SOC_ECDSA_SUPPORT_DETERMINISTIC_MODE
|
||||||
|
test_ecdsa_key_aes_mode(ECDSA_CURVE_SECP256R1, sha_digest,
|
||||||
|
test_data_ecdh1_ecdsa.ecdsa_test_data.ecdsa_p256_pubx,
|
||||||
|
test_data_ecdh1_ecdsa.ecdsa_test_data.ecdsa_p256_puby,
|
||||||
|
ECDSA_K_TYPE_DETERMINISITIC);
|
||||||
|
#endif
|
||||||
|
test_ecdsa_key_aes_mode(ECDSA_CURVE_SECP256R1, sha_digest,
|
||||||
|
test_data_ecdh1_ecdsa.ecdsa_test_data.ecdsa_p256_pubx,
|
||||||
|
test_data_ecdh1_ecdsa.ecdsa_test_data.ecdsa_p256_puby,
|
||||||
|
ECDSA_K_TYPE_TRNG);
|
||||||
|
|
||||||
|
TEST_ASSERT_EQUAL(ESP_OK, esp_key_mgr_deactivate_key(key_recovery_info.key_type));
|
||||||
|
}
|
||||||
|
#endif /* SOC_KEY_MANAGER_ECDSA_KEY_DEPLOY */
|
||||||
|
|
||||||
TEST_GROUP(key_manager);
|
TEST_GROUP(key_manager);
|
||||||
|
|
||||||
TEST_SETUP(key_manager)
|
TEST_SETUP(key_manager)
|
||||||
@@ -629,6 +741,11 @@ TEST(key_manager, xts_key_128_ecdh0_deployment)
|
|||||||
key_mgr_test_xts_aes_128_ecdh0_mode();
|
key_mgr_test_xts_aes_128_ecdh0_mode();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(key_manager, xts_key_128_ecdh1_deployment)
|
||||||
|
{
|
||||||
|
key_mgr_test_xts_aes_128_ecdh1_mode();
|
||||||
|
}
|
||||||
|
|
||||||
#if CONFIG_CRYPTO_TEST_APP_ENABLE_FPGA_TESTS
|
#if CONFIG_CRYPTO_TEST_APP_ENABLE_FPGA_TESTS
|
||||||
TEST(key_manager, xts_key_128_random_deployment)
|
TEST(key_manager, xts_key_128_random_deployment)
|
||||||
{
|
{
|
||||||
@@ -691,6 +808,11 @@ TEST(key_manager, ecdsa_p256_key_ecdh0_deployment)
|
|||||||
key_mgr_test_ecdsa_key_ecdh0_mode(ESP_KEY_MGR_ECDSA_LEN_256);
|
key_mgr_test_ecdsa_key_ecdh0_mode(ESP_KEY_MGR_ECDSA_LEN_256);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(key_manager, ecdsa_p256_key_ecdh1_deployment)
|
||||||
|
{
|
||||||
|
key_mgr_test_ecdsa_p256_ecdh1_mode();
|
||||||
|
}
|
||||||
|
|
||||||
TEST(key_manager, ecdsa_p256_key_random_deployment)
|
TEST(key_manager, ecdsa_p256_key_random_deployment)
|
||||||
{
|
{
|
||||||
key_mgr_test_ecdsa_key_random_mode(ESP_KEY_MGR_ECDSA_LEN_256);
|
key_mgr_test_ecdsa_key_random_mode(ESP_KEY_MGR_ECDSA_LEN_256);
|
||||||
@@ -725,6 +847,11 @@ TEST(key_manager, hmac_key_ecdh0_deployment)
|
|||||||
key_mgr_test_hmac_ecdh0_mode();
|
key_mgr_test_hmac_ecdh0_mode();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(key_manager, hmac_key_ecdh1_deployment)
|
||||||
|
{
|
||||||
|
key_mgr_test_hmac_ecdh1_mode();
|
||||||
|
}
|
||||||
|
|
||||||
TEST(key_manager, hmac_key_random_deployment)
|
TEST(key_manager, hmac_key_random_deployment)
|
||||||
{
|
{
|
||||||
key_mgr_test_hmac_random_mode();
|
key_mgr_test_hmac_random_mode();
|
||||||
@@ -744,6 +871,7 @@ TEST_GROUP_RUNNER(key_manager)
|
|||||||
#if SOC_KEY_MANAGER_FE_KEY_DEPLOY_XTS_AES_128
|
#if SOC_KEY_MANAGER_FE_KEY_DEPLOY_XTS_AES_128
|
||||||
RUN_TEST_CASE(key_manager, xts_aes_128_key_aes_deployment);
|
RUN_TEST_CASE(key_manager, xts_aes_128_key_aes_deployment);
|
||||||
RUN_TEST_CASE(key_manager, xts_key_128_ecdh0_deployment);
|
RUN_TEST_CASE(key_manager, xts_key_128_ecdh0_deployment);
|
||||||
|
RUN_TEST_CASE(key_manager, xts_key_128_ecdh1_deployment);
|
||||||
#if CONFIG_CRYPTO_TEST_APP_ENABLE_FPGA_TESTS
|
#if CONFIG_CRYPTO_TEST_APP_ENABLE_FPGA_TESTS
|
||||||
// This tests expects Flash encryption to be enabled as the test compares the decrypted flash data with the plaintext data
|
// This tests expects Flash encryption to be enabled as the test compares the decrypted flash data with the plaintext data
|
||||||
RUN_TEST_CASE(key_manager, xts_key_128_random_deployment);
|
RUN_TEST_CASE(key_manager, xts_key_128_random_deployment);
|
||||||
@@ -766,6 +894,7 @@ TEST_GROUP_RUNNER(key_manager)
|
|||||||
|
|
||||||
RUN_TEST_CASE(key_manager, ecdsa_p256_key_aes_deployment);
|
RUN_TEST_CASE(key_manager, ecdsa_p256_key_aes_deployment);
|
||||||
RUN_TEST_CASE(key_manager, ecdsa_p256_key_ecdh0_deployment);
|
RUN_TEST_CASE(key_manager, ecdsa_p256_key_ecdh0_deployment);
|
||||||
|
RUN_TEST_CASE(key_manager, ecdsa_p256_key_ecdh1_deployment);
|
||||||
RUN_TEST_CASE(key_manager, ecdsa_p256_key_random_deployment);
|
RUN_TEST_CASE(key_manager, ecdsa_p256_key_random_deployment);
|
||||||
|
|
||||||
#if SOC_ECDSA_SUPPORT_CURVE_P384
|
#if SOC_ECDSA_SUPPORT_CURVE_P384
|
||||||
@@ -778,6 +907,7 @@ TEST_GROUP_RUNNER(key_manager)
|
|||||||
#if SOC_KEY_MANAGER_HMAC_KEY_DEPLOY
|
#if SOC_KEY_MANAGER_HMAC_KEY_DEPLOY
|
||||||
RUN_TEST_CASE(key_manager, hmac_key_aes_deployment);
|
RUN_TEST_CASE(key_manager, hmac_key_aes_deployment);
|
||||||
RUN_TEST_CASE(key_manager, hmac_key_ecdh0_deployment);
|
RUN_TEST_CASE(key_manager, hmac_key_ecdh0_deployment);
|
||||||
|
RUN_TEST_CASE(key_manager, hmac_key_ecdh1_deployment);
|
||||||
RUN_TEST_CASE(key_manager, hmac_key_random_deployment);
|
RUN_TEST_CASE(key_manager, hmac_key_random_deployment);
|
||||||
#endif /* SOC_KEY_MANAGER_HMAC_KEY_DEPLOY */
|
#endif /* SOC_KEY_MANAGER_HMAC_KEY_DEPLOY */
|
||||||
|
|
||||||
|
|||||||
@@ -58,6 +58,24 @@ typedef struct {
|
|||||||
WORD_ALIGNED_ATTR uint8_t k1_G[2][KEY_MGR_ECDH0_INFO_SIZE]; /*!< K1*G points for ECDH0 deployment */
|
WORD_ALIGNED_ATTR uint8_t k1_G[2][KEY_MGR_ECDH0_INFO_SIZE]; /*!< K1*G points for ECDH0 deployment */
|
||||||
} esp_key_mgr_ecdh0_key_config_t;
|
} esp_key_mgr_ecdh0_key_config_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Configuration for deploying a key in ECDH1 mode
|
||||||
|
*
|
||||||
|
* ECDH1 requires the same init_key/k2_info inputs as AES mode plus the
|
||||||
|
* ECDH k1*G public point(s). Unlike ECDH0, k2*G is computed by the user
|
||||||
|
* locally and is not read back from the Key Manager.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
esp_key_mgr_key_type_t key_type; /*!< Type of key to deploy */
|
||||||
|
esp_key_mgr_key_len_t key_len; /*!< Length of the key */
|
||||||
|
bool use_pre_generated_huk_info; /*!< Use pre-generated HUK info if true */
|
||||||
|
bool use_pre_generated_sw_init_key; /*!< Use pre-generated software init key if true */
|
||||||
|
WORD_ALIGNED_ATTR esp_key_mgr_huk_info_t huk_info; /*!< HUK recovery info */
|
||||||
|
WORD_ALIGNED_ATTR uint8_t sw_init_key[KEY_MGR_SW_INIT_KEY_SIZE]; /*!< Software init key */
|
||||||
|
WORD_ALIGNED_ATTR uint8_t k2_info[KEY_MGR_K2_INFO_SIZE]; /*!< K2 info for ECDH1 deployment */
|
||||||
|
WORD_ALIGNED_ATTR uint8_t k1_G[2][KEY_MGR_ECDH0_INFO_SIZE]; /*!< K1*G points for ECDH1 deployment */
|
||||||
|
} esp_key_mgr_ecdh1_key_config_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Configuration for deploying a key in Random mode
|
* @brief Configuration for deploying a key in Random mode
|
||||||
*/
|
*/
|
||||||
@@ -110,6 +128,18 @@ esp_err_t esp_key_mgr_deploy_key_in_aes_mode(const esp_key_mgr_aes_key_config_t
|
|||||||
*/
|
*/
|
||||||
esp_err_t esp_key_mgr_deploy_key_in_ecdh0_mode(const esp_key_mgr_ecdh0_key_config_t *key_config, esp_key_mgr_key_recovery_info_t *key_info, esp_key_mgr_ecdh0_info_t *ecdh0_key_info);
|
esp_err_t esp_key_mgr_deploy_key_in_ecdh0_mode(const esp_key_mgr_ecdh0_key_config_t *key_config, esp_key_mgr_key_recovery_info_t *key_info, esp_key_mgr_ecdh0_info_t *ecdh0_key_info);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Deploy key in ECDH1 deployment mode
|
||||||
|
*
|
||||||
|
* @param[in] key_config ECDH1 key configuration
|
||||||
|
* @param[out] key_info A writable struct of esp_key_mgr_key_recovery_info_t type.
|
||||||
|
* The recovery key info for the deployed key shall be stored here.
|
||||||
|
* @return
|
||||||
|
* - ESP_OK on success
|
||||||
|
* - ESP_FAIL or relevant error code on failure
|
||||||
|
*/
|
||||||
|
esp_err_t esp_key_mgr_deploy_key_in_ecdh1_mode(const esp_key_mgr_ecdh1_key_config_t *key_config, esp_key_mgr_key_recovery_info_t *key_info);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Deploy key in Random deployment mode
|
* @brief Deploy key in Random deployment mode
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -423,6 +423,10 @@ static esp_err_t key_mgr_deploy_key_aes_mode(aes_deploy_config_t *config)
|
|||||||
|
|
||||||
key_mgr_hal_read_public_info(key_recovery_info, KEY_MGR_KEY_RECOVERY_INFO_SIZE);
|
key_mgr_hal_read_public_info(key_recovery_info, KEY_MGR_KEY_RECOVERY_INFO_SIZE);
|
||||||
|
|
||||||
|
// Wait till Key Manager deployment is complete
|
||||||
|
key_mgr_hal_continue();
|
||||||
|
key_mgr_wait_for_state(ESP_KEY_MGR_STATE_IDLE);
|
||||||
|
|
||||||
// Check if key deployment validation should be skipped for this purpose
|
// Check if key deployment validation should be skipped for this purpose
|
||||||
// Primary purposes in multi-stage deployments skip validation after the first stage
|
// Primary purposes in multi-stage deployments skip validation after the first stage
|
||||||
// because the key is not yet completely deployed.
|
// because the key is not yet completely deployed.
|
||||||
@@ -434,10 +438,6 @@ static esp_err_t key_mgr_deploy_key_aes_mode(aes_deploy_config_t *config)
|
|||||||
}
|
}
|
||||||
ESP_LOGD(TAG, "Key deployment valid");
|
ESP_LOGD(TAG, "Key deployment valid");
|
||||||
|
|
||||||
// Wait till Key Manager deployment is complete
|
|
||||||
key_mgr_hal_continue();
|
|
||||||
key_mgr_wait_for_state(ESP_KEY_MGR_STATE_IDLE);
|
|
||||||
|
|
||||||
config->key_info->key_info[key_recovery_info_index].crc = esp_rom_crc32_le(0, key_recovery_info, KEY_MGR_KEY_RECOVERY_INFO_SIZE);
|
config->key_info->key_info[key_recovery_info_index].crc = esp_rom_crc32_le(0, key_recovery_info, KEY_MGR_KEY_RECOVERY_INFO_SIZE);
|
||||||
config->key_info->key_type = key_type;
|
config->key_info->key_type = key_type;
|
||||||
config->key_info->key_len = key_len;
|
config->key_info->key_len = key_len;
|
||||||
@@ -709,6 +709,10 @@ static esp_err_t key_mgr_deploy_key_ecdh0_mode(ecdh0_deploy_config_t *config)
|
|||||||
key_mgr_hal_read_public_info(key_recovery_info, KEY_MGR_KEY_RECOVERY_INFO_SIZE);
|
key_mgr_hal_read_public_info(key_recovery_info, KEY_MGR_KEY_RECOVERY_INFO_SIZE);
|
||||||
key_mgr_hal_read_assist_info(config->ecdh0_key_info);
|
key_mgr_hal_read_assist_info(config->ecdh0_key_info);
|
||||||
|
|
||||||
|
// Wait till Key Manager deployment is complete
|
||||||
|
key_mgr_hal_continue();
|
||||||
|
key_mgr_wait_for_state(ESP_KEY_MGR_STATE_IDLE);
|
||||||
|
|
||||||
// Check if key deployment validation should be skipped for this purpose
|
// Check if key deployment validation should be skipped for this purpose
|
||||||
// Primary purposes in multi-stage deployments skip validation after the first stage
|
// Primary purposes in multi-stage deployments skip validation after the first stage
|
||||||
// because the key is not yet completely deployed.
|
// because the key is not yet completely deployed.
|
||||||
@@ -720,10 +724,6 @@ static esp_err_t key_mgr_deploy_key_ecdh0_mode(ecdh0_deploy_config_t *config)
|
|||||||
}
|
}
|
||||||
ESP_LOGD(TAG, "Key deployment valid");
|
ESP_LOGD(TAG, "Key deployment valid");
|
||||||
|
|
||||||
// Wait till Key Manager deployment is complete
|
|
||||||
key_mgr_hal_continue();
|
|
||||||
key_mgr_wait_for_state(ESP_KEY_MGR_STATE_IDLE);
|
|
||||||
|
|
||||||
config->key_info->key_info[key_recovery_info_index].crc = esp_rom_crc32_le(0, key_recovery_info, KEY_MGR_KEY_RECOVERY_INFO_SIZE);
|
config->key_info->key_info[key_recovery_info_index].crc = esp_rom_crc32_le(0, key_recovery_info, KEY_MGR_KEY_RECOVERY_INFO_SIZE);
|
||||||
config->key_info->key_type = key_type;
|
config->key_info->key_type = key_type;
|
||||||
config->key_info->key_len = key_len;
|
config->key_info->key_len = key_len;
|
||||||
@@ -789,6 +789,155 @@ cleanup:
|
|||||||
return esp_ret;
|
return esp_ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef struct ecdh1_deploy {
|
||||||
|
esp_key_mgr_key_purpose_t key_purpose;
|
||||||
|
const uint8_t *k1_G;
|
||||||
|
const esp_key_mgr_ecdh1_key_config_t *key_config;
|
||||||
|
esp_key_mgr_key_recovery_info_t *key_info;
|
||||||
|
bool huk_deployed;
|
||||||
|
} ecdh1_deploy_config_t;
|
||||||
|
|
||||||
|
static esp_err_t key_mgr_deploy_key_ecdh1_mode(ecdh1_deploy_config_t *config)
|
||||||
|
{
|
||||||
|
esp_err_t esp_ret = ESP_FAIL;
|
||||||
|
key_mgr_wait_for_state(ESP_KEY_MGR_STATE_IDLE);
|
||||||
|
|
||||||
|
if ((!key_mgr_hal_is_huk_valid()) || (!config->huk_deployed)) {
|
||||||
|
huk_deploy_config_t huk_deploy_config = {
|
||||||
|
.use_pre_generated_huk_info = config->key_config->use_pre_generated_huk_info,
|
||||||
|
.pre_generated_huk_info = &config->key_config->huk_info,
|
||||||
|
.huk_recovery_info = &config->key_info->huk_info,
|
||||||
|
};
|
||||||
|
|
||||||
|
esp_ret = deploy_huk(&huk_deploy_config);
|
||||||
|
if (esp_ret != ESP_OK) {
|
||||||
|
return esp_ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ESP_LOGD(TAG, "HUK deployed successfully");
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t key_recovery_info_index = is_multi_stage_key_purpose(config->key_purpose) ? 0 : 1;
|
||||||
|
|
||||||
|
uint8_t *key_recovery_info = config->key_info->key_info[key_recovery_info_index].info;
|
||||||
|
|
||||||
|
// Step 1: Initialization
|
||||||
|
key_mgr_hal_set_key_generator_mode(ESP_KEY_MGR_KEYGEN_MODE_ECDH1);
|
||||||
|
|
||||||
|
key_mgr_hal_set_key_purpose(config->key_purpose);
|
||||||
|
|
||||||
|
esp_key_mgr_key_type_t key_type = config->key_config->key_type;
|
||||||
|
esp_key_mgr_key_len_t key_len = config->key_config->key_len;
|
||||||
|
|
||||||
|
if (key_type == ESP_KEY_MGR_FLASH_XTS_AES_KEY || key_type == ESP_KEY_MGR_PSRAM_XTS_AES_KEY) {
|
||||||
|
key_mgr_hal_set_xts_aes_key_len(key_type, key_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config->key_config->use_pre_generated_sw_init_key) {
|
||||||
|
key_mgr_hal_use_sw_init_key();
|
||||||
|
} else if (!esp_efuse_find_purpose(ESP_EFUSE_KEY_PURPOSE_KM_INIT_KEY, NULL)) {
|
||||||
|
ESP_LOGE(TAG, "Could not find key with purpose KM_INIT_KEY");
|
||||||
|
return ESP_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
key_mgr_hal_start();
|
||||||
|
|
||||||
|
// Step 2: Load phase
|
||||||
|
key_mgr_wait_for_state(ESP_KEY_MGR_STATE_LOAD);
|
||||||
|
|
||||||
|
if (config->key_config->use_pre_generated_sw_init_key) {
|
||||||
|
key_mgr_hal_write_sw_init_key(config->key_config->sw_init_key, KEY_MGR_SW_INIT_KEY_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
ESP_LOGD(TAG, "Writing Information into Key Manager Registers");
|
||||||
|
key_mgr_hal_write_assist_info(config->key_config->k2_info, KEY_MGR_K2_INFO_SIZE);
|
||||||
|
|
||||||
|
key_mgr_hal_write_public_info(config->k1_G, KEY_MGR_ECDH0_INFO_SIZE);
|
||||||
|
|
||||||
|
key_mgr_hal_continue();
|
||||||
|
|
||||||
|
// Step 3: Gain phase
|
||||||
|
key_mgr_wait_for_state(ESP_KEY_MGR_STATE_GAIN);
|
||||||
|
|
||||||
|
key_mgr_hal_read_public_info(key_recovery_info, KEY_MGR_KEY_RECOVERY_INFO_SIZE);
|
||||||
|
|
||||||
|
// Wait till Key Manager deployment is complete
|
||||||
|
key_mgr_hal_continue();
|
||||||
|
key_mgr_wait_for_state(ESP_KEY_MGR_STATE_IDLE);
|
||||||
|
|
||||||
|
// Check if key deployment validation should be skipped for this purpose
|
||||||
|
// Primary purposes in multi-stage deployments skip validation after the first stage
|
||||||
|
// because the key is not yet completely deployed.
|
||||||
|
if (!is_multi_stage_key_purpose(config->key_purpose)) {
|
||||||
|
if (!key_mgr_hal_is_key_deployment_valid(key_type, key_len)) {
|
||||||
|
ESP_LOGE(TAG, "Key deployment is not valid");
|
||||||
|
return ESP_FAIL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ESP_LOGD(TAG, "Key deployment valid");
|
||||||
|
|
||||||
|
config->key_info->key_info[key_recovery_info_index].crc = esp_rom_crc32_le(0, key_recovery_info, KEY_MGR_KEY_RECOVERY_INFO_SIZE);
|
||||||
|
config->key_info->key_type = key_type;
|
||||||
|
config->key_info->key_len = key_len;
|
||||||
|
config->key_info->key_deployment_mode = ESP_KEY_MGR_KEYGEN_MODE_ECDH1;
|
||||||
|
config->key_info->magic = KEY_HUK_SECTOR_MAGIC;
|
||||||
|
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t esp_key_mgr_deploy_key_in_ecdh1_mode(const esp_key_mgr_ecdh1_key_config_t *key_config,
|
||||||
|
esp_key_mgr_key_recovery_info_t *key_info)
|
||||||
|
{
|
||||||
|
if (!key_mgr_ll_is_supported()) {
|
||||||
|
return ESP_ERR_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key_config == NULL || key_info == NULL) {
|
||||||
|
return ESP_ERR_INVALID_ARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
ESP_LOGD(TAG, "Key Deployment in ECDH1 mode");
|
||||||
|
|
||||||
|
ecdh1_deploy_config_t ecdh1_deploy_config = {
|
||||||
|
.key_config = key_config,
|
||||||
|
.key_info = key_info,
|
||||||
|
.k1_G = key_config->k1_G[0],
|
||||||
|
};
|
||||||
|
|
||||||
|
ecdh1_deploy_config.key_purpose = get_key_purpose(key_config->key_type, key_config->key_len);
|
||||||
|
if (ecdh1_deploy_config.key_purpose == ESP_KEY_MGR_KEY_PURPOSE_INVALID) {
|
||||||
|
ESP_LOGE(TAG, "Invalid key type");
|
||||||
|
return ESP_ERR_INVALID_ARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_key_mgr_acquire_hardware(true);
|
||||||
|
|
||||||
|
esp_err_t esp_ret = key_mgr_deploy_key_ecdh1_mode(&ecdh1_deploy_config);
|
||||||
|
if (esp_ret != ESP_OK) {
|
||||||
|
ESP_LOGE(TAG, "Key deployment in ECDH1 mode failed");
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
ecdh1_deploy_config.huk_deployed = true;
|
||||||
|
|
||||||
|
if (is_multi_stage_key_purpose(ecdh1_deploy_config.key_purpose)) {
|
||||||
|
ecdh1_deploy_config.key_purpose = get_secondary_key_purpose(ecdh1_deploy_config.key_purpose);
|
||||||
|
ecdh1_deploy_config.k1_G = key_config->k1_G[1];
|
||||||
|
esp_ret = key_mgr_deploy_key_ecdh1_mode(&ecdh1_deploy_config);
|
||||||
|
if (esp_ret != ESP_OK) {
|
||||||
|
ESP_LOGE(TAG, "Key deployment in ECDH1 mode failed");
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the Key Manager Static Register to use own key for the respective key type
|
||||||
|
key_mgr_hal_set_key_usage(key_config->key_type, ESP_KEY_MGR_USE_OWN_KEY);
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
esp_key_mgr_release_hardware(true);
|
||||||
|
return esp_ret;
|
||||||
|
}
|
||||||
|
|
||||||
typedef struct random_deploy {
|
typedef struct random_deploy {
|
||||||
esp_key_mgr_key_purpose_t key_purpose;
|
esp_key_mgr_key_purpose_t key_purpose;
|
||||||
const esp_key_mgr_random_key_config_t *key_config;
|
const esp_key_mgr_random_key_config_t *key_config;
|
||||||
@@ -845,6 +994,10 @@ static esp_err_t key_mgr_deploy_key_random_mode(random_deploy_config_t *config)
|
|||||||
key_mgr_wait_for_state(ESP_KEY_MGR_STATE_GAIN);
|
key_mgr_wait_for_state(ESP_KEY_MGR_STATE_GAIN);
|
||||||
key_mgr_hal_read_public_info(key_recovery_info, KEY_MGR_KEY_RECOVERY_INFO_SIZE);
|
key_mgr_hal_read_public_info(key_recovery_info, KEY_MGR_KEY_RECOVERY_INFO_SIZE);
|
||||||
|
|
||||||
|
// Wait till Key Manager deployment is complete
|
||||||
|
key_mgr_hal_continue();
|
||||||
|
key_mgr_wait_for_state(ESP_KEY_MGR_STATE_IDLE);
|
||||||
|
|
||||||
// Check if key deployment validation should be skipped for this purpose
|
// Check if key deployment validation should be skipped for this purpose
|
||||||
// Primary purposes in multi-stage deployments skip validation after the first stage
|
// Primary purposes in multi-stage deployments skip validation after the first stage
|
||||||
// because the key is not yet completely deployed.
|
// because the key is not yet completely deployed.
|
||||||
@@ -856,10 +1009,6 @@ static esp_err_t key_mgr_deploy_key_random_mode(random_deploy_config_t *config)
|
|||||||
}
|
}
|
||||||
ESP_LOGD(TAG, "Key deployment valid");
|
ESP_LOGD(TAG, "Key deployment valid");
|
||||||
|
|
||||||
// Wait till Key Manager deployment is complete
|
|
||||||
key_mgr_hal_continue();
|
|
||||||
key_mgr_wait_for_state(ESP_KEY_MGR_STATE_IDLE);
|
|
||||||
|
|
||||||
config->key_info->key_info[key_recovery_info_index].crc = esp_rom_crc32_le(0, key_recovery_info, KEY_MGR_KEY_RECOVERY_INFO_SIZE);
|
config->key_info->key_info[key_recovery_info_index].crc = esp_rom_crc32_le(0, key_recovery_info, KEY_MGR_KEY_RECOVERY_INFO_SIZE);
|
||||||
config->key_info->key_type = key_type;
|
config->key_info->key_type = key_type;
|
||||||
config->key_info->key_len = key_len;
|
config->key_info->key_len = key_len;
|
||||||
|
|||||||
@@ -226,6 +226,36 @@ TEST_CASE("Key Manager Random mode: XTS-AES-128 key deployment", "[hw_crypto] [k
|
|||||||
free(key_config);
|
free(key_config);
|
||||||
free(key_recovery_info);
|
free(key_recovery_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Key Manager ECDH1 mode: XTS-AES-128 key deployment", "[hw_crypto] [key_mgr]")
|
||||||
|
{
|
||||||
|
SKIP_IF_KEY_MGR_NOT_SUPPORTED();
|
||||||
|
|
||||||
|
esp_key_mgr_ecdh1_key_config_t *key_config = calloc(1, sizeof(esp_key_mgr_ecdh1_key_config_t));
|
||||||
|
TEST_ASSERT_NOT_NULL(key_config);
|
||||||
|
|
||||||
|
memcpy(key_config->k2_info, (uint8_t*) k2_info, KEY_MGR_K2_INFO_SIZE);
|
||||||
|
memcpy(key_config->k1_G[0], (uint8_t*) k1_G, KEY_MGR_ECDH0_INFO_SIZE);
|
||||||
|
memcpy(key_config->sw_init_key, (uint8_t*) init_key, KEY_MGR_SW_INIT_KEY_SIZE);
|
||||||
|
key_config->use_pre_generated_sw_init_key = 1;
|
||||||
|
key_config->key_type = ESP_KEY_MGR_FLASH_XTS_AES_KEY;
|
||||||
|
key_config->key_len = ESP_KEY_MGR_XTS_AES_LEN_128;
|
||||||
|
|
||||||
|
esp_key_mgr_key_recovery_info_t *key_recovery_info = calloc(1, sizeof(esp_key_mgr_key_recovery_info_t));
|
||||||
|
TEST_ASSERT_NOT_NULL(key_recovery_info);
|
||||||
|
|
||||||
|
TEST_ASSERT_EQUAL(ESP_OK, esp_key_mgr_deploy_key_in_ecdh1_mode(key_config, key_recovery_info));
|
||||||
|
TEST_ASSERT_EQUAL(ESP_OK, esp_key_mgr_activate_key(key_recovery_info));
|
||||||
|
/* verify=false: same convention as the ECDH0 case above. The expected
|
||||||
|
* ciphertext IS derivable (k2 = AES_DEC(k2_info, init_key); deployed key
|
||||||
|
* = x(k1*k2*G)) but this app doesn't carry the off-device ECC code.
|
||||||
|
* Bitwise verification lives in the HAL crypto test app. */
|
||||||
|
TEST_ASSERT_EQUAL(ESP_OK, test_xts_aes_key(false));
|
||||||
|
TEST_ASSERT_EQUAL(ESP_OK, esp_key_mgr_deactivate_key(key_recovery_info->key_type));
|
||||||
|
|
||||||
|
free(key_config);
|
||||||
|
free(key_recovery_info);
|
||||||
|
}
|
||||||
#endif /* SOC_KEY_MANAGER_FE_KEY_DEPLOY */
|
#endif /* SOC_KEY_MANAGER_FE_KEY_DEPLOY */
|
||||||
|
|
||||||
#if SOC_KEY_MANAGER_ECDSA_KEY_DEPLOY
|
#if SOC_KEY_MANAGER_ECDSA_KEY_DEPLOY
|
||||||
@@ -333,6 +363,31 @@ TEST_CASE("Key Manager random mode: HMAC key deployment", "[hw_crypto] [key_mgr]
|
|||||||
free(key_config);
|
free(key_config);
|
||||||
free(key_recovery_info);
|
free(key_recovery_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Key Manager ECDH1 mode: HMAC key deployment", "[hw_crypto] [key_mgr]")
|
||||||
|
{
|
||||||
|
SKIP_IF_KEY_MGR_NOT_SUPPORTED();
|
||||||
|
|
||||||
|
esp_key_mgr_ecdh1_key_config_t *key_config = calloc(1, sizeof(esp_key_mgr_ecdh1_key_config_t));
|
||||||
|
TEST_ASSERT_NOT_NULL(key_config);
|
||||||
|
|
||||||
|
memcpy(key_config->k2_info, (uint8_t*) k2_info, KEY_MGR_K2_INFO_SIZE);
|
||||||
|
memcpy(key_config->k1_G[0], (uint8_t*) k1_G, KEY_MGR_ECDH0_INFO_SIZE);
|
||||||
|
memcpy(key_config->sw_init_key, (uint8_t*) init_key, KEY_MGR_SW_INIT_KEY_SIZE);
|
||||||
|
key_config->use_pre_generated_sw_init_key = 1;
|
||||||
|
key_config->key_type = ESP_KEY_MGR_HMAC_KEY;
|
||||||
|
|
||||||
|
esp_key_mgr_key_recovery_info_t *key_recovery_info = calloc(1, sizeof(esp_key_mgr_key_recovery_info_t));
|
||||||
|
TEST_ASSERT_NOT_NULL(key_recovery_info);
|
||||||
|
|
||||||
|
TEST_ASSERT_EQUAL(ESP_OK, esp_key_mgr_deploy_key_in_ecdh1_mode(key_config, key_recovery_info));
|
||||||
|
TEST_ASSERT_EQUAL(ESP_OK, esp_key_mgr_activate_key(key_recovery_info));
|
||||||
|
TEST_ASSERT_EQUAL(ESP_OK, test_hmac_key(false));
|
||||||
|
TEST_ASSERT_EQUAL(ESP_OK, esp_key_mgr_deactivate_key(key_recovery_info->key_type));
|
||||||
|
|
||||||
|
free(key_config);
|
||||||
|
free(key_recovery_info);
|
||||||
|
}
|
||||||
#endif /* SOC_KEY_MANAGER_HMAC_KEY_DEPLOY */
|
#endif /* SOC_KEY_MANAGER_HMAC_KEY_DEPLOY */
|
||||||
|
|
||||||
#if SOC_KEY_MANAGER_DS_KEY_DEPLOY
|
#if SOC_KEY_MANAGER_DS_KEY_DEPLOY
|
||||||
@@ -434,5 +489,33 @@ TEST_CASE("Key Manager random mode: DS key deployment", "[hw_crypto] [key_mgr]")
|
|||||||
free(key_config);
|
free(key_config);
|
||||||
free(key_recovery_info);
|
free(key_recovery_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Key Manager ECDH1 mode: DS key deployment", "[hw_crypto] [key_mgr]")
|
||||||
|
{
|
||||||
|
SKIP_IF_KEY_MGR_NOT_SUPPORTED();
|
||||||
|
|
||||||
|
esp_key_mgr_ecdh1_key_config_t *key_config = calloc(1, sizeof(esp_key_mgr_ecdh1_key_config_t));
|
||||||
|
TEST_ASSERT_NOT_NULL(key_config);
|
||||||
|
|
||||||
|
memcpy(key_config->k2_info, (uint8_t*) k2_info, KEY_MGR_K2_INFO_SIZE);
|
||||||
|
memcpy(key_config->k1_G[0], (uint8_t*) k1_G, KEY_MGR_ECDH0_INFO_SIZE);
|
||||||
|
memcpy(key_config->sw_init_key, (uint8_t*) init_key, KEY_MGR_SW_INIT_KEY_SIZE);
|
||||||
|
key_config->use_pre_generated_sw_init_key = 1;
|
||||||
|
key_config->key_type = ESP_KEY_MGR_DS_KEY;
|
||||||
|
|
||||||
|
esp_key_mgr_key_recovery_info_t *key_recovery_info = calloc(1, sizeof(esp_key_mgr_key_recovery_info_t));
|
||||||
|
TEST_ASSERT_NOT_NULL(key_recovery_info);
|
||||||
|
|
||||||
|
TEST_ASSERT_EQUAL(ESP_OK, esp_key_mgr_deploy_key_in_ecdh1_mode(key_config, key_recovery_info));
|
||||||
|
TEST_ASSERT_EQUAL(ESP_OK, esp_key_mgr_activate_key(key_recovery_info));
|
||||||
|
// Deploy/activate path coverage only. The deployed AES-CBC key for DS
|
||||||
|
// is x(k1*k2*G); pre-generating the encrypted DS input params would
|
||||||
|
// require running that key derivation plus the DS-blob AES-CBC step
|
||||||
|
// off-device, neither of which this app carries.
|
||||||
|
TEST_ASSERT_EQUAL(ESP_OK, esp_key_mgr_deactivate_key(key_recovery_info->key_type));
|
||||||
|
|
||||||
|
free(key_config);
|
||||||
|
free(key_recovery_info);
|
||||||
|
}
|
||||||
#endif /* SOC_KEY_MANAGER_DS_KEY_DEPLOY */
|
#endif /* SOC_KEY_MANAGER_DS_KEY_DEPLOY */
|
||||||
#endif /* SOC_KEY_MANAGER_SUPPORTED */
|
#endif /* SOC_KEY_MANAGER_SUPPORTED */
|
||||||
|
|||||||
@@ -108,16 +108,16 @@ In this mode, a private key is negotiated using Elliptic Curve Diffie-Hellman (E
|
|||||||
- The deployment process can occur over an untrusted channel.
|
- The deployment process can occur over an untrusted channel.
|
||||||
- Intended for high-security provisioning environments.
|
- Intended for high-security provisioning environments.
|
||||||
|
|
||||||
For detailed information various deployment modes, see **{IDF_TARGET_NAME} Technical Reference Manual** > **Chapter Key Manager** [`PDF <{IDF_TARGET_TRM_EN_URL}>`__] > **Section Key Manager**.
|
ECDH1 Deploy Mode
|
||||||
|
^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
.. ECDH1 Deploy Mode
|
This mode is similar to ECDH0 Deploy Mode, with additional flexibility for manufacturing workflows.
|
||||||
.. ~~~~~~~~~~~~~~~~~
|
|
||||||
..
|
- Supports negotiated key deployment using auxiliary recovery data
|
||||||
.. This mode is similar to ECDH0 Deploy Mode, with additional flexibility for manufacturing workflows.
|
- Allows updating deployed keys by replacing auxiliary information
|
||||||
..
|
- Intended for large-scale manufacturing with controlled trust assumptions
|
||||||
.. - Supports negotiated key deployment using auxiliary recovery data
|
|
||||||
.. - Allows updating deployed keys by replacing auxiliary information
|
For detailed information various deployment modes, see **{IDF_TARGET_NAME} Technical Reference Manual** > **Chapter Key Manager** [`PDF <{IDF_TARGET_TRM_EN_URL}>`__] > **Section Key Manager**.
|
||||||
.. - Intended for large-scale manufacturing with controlled trust assumptions
|
|
||||||
|
|
||||||
Typical Workflows
|
Typical Workflows
|
||||||
-----------------
|
-----------------
|
||||||
|
|||||||
@@ -108,16 +108,16 @@ ECDH0 部署模式
|
|||||||
- 部署过程可以通过不受信任的信道进行。
|
- 部署过程可以通过不受信任的信道进行。
|
||||||
- 适用于高安全性的配置环境。
|
- 适用于高安全性的配置环境。
|
||||||
|
|
||||||
有关各种部署模式的详细信息,请参阅 **《{IDF_TARGET_NAME} 技术参考手册》** > **密钥管理器章节** [`PDF <{IDF_TARGET_TRM_EN_URL}>`__] > **密钥管理器小节**。
|
ECDH1 部署模式
|
||||||
|
^^^^^^^^^^^^^^
|
||||||
|
|
||||||
.. ECDH1 Deploy Mode
|
此模式类似于 ECDH0 部署模式,但为生产配置流程提供了额外的灵活性。
|
||||||
.. ~~~~~~~~~~~~~~~~~
|
|
||||||
..
|
- 支持使用辅助恢复数据进行协商的密钥部署。
|
||||||
.. This mode is similar to ECDH0 Deploy Mode, with additional flexibility for manufacturing workflows.
|
- 允许通过替换辅助信息来更新已部署的密钥。
|
||||||
..
|
- 适用于具有受控信任假设的大规模生产场景。
|
||||||
.. - Supports negotiated key deployment using auxiliary recovery data
|
|
||||||
.. - Allows updating deployed keys by replacing auxiliary information
|
有关各种部署模式的详细信息,请参阅 **《{IDF_TARGET_NAME} 技术参考手册》** > **密钥管理器章节** [`PDF <{IDF_TARGET_TRM_EN_URL}>`__] > **密钥管理器小节**。
|
||||||
.. - Intended for large-scale manufacturing with controlled trust assumptions
|
|
||||||
|
|
||||||
典型工作流程
|
典型工作流程
|
||||||
------------
|
------------
|
||||||
|
|||||||
Reference in New Issue
Block a user