feat(espefuse): Add custom key purposes for ESP32C6/C5/P4

This commit is contained in:
Konstantin Kondrashov
2025-07-25 19:53:55 +03:00
committed by Roland Dobai
parent 4a9a3d8a54
commit c6ce0bc14d
4 changed files with 56 additions and 3 deletions

View File

@@ -432,7 +432,9 @@ class EfuseMacField(EfuseField):
# fmt: off
class EfuseKeyPurposeField(EfuseField):
KEY_PURPOSES = [
key_purpose_len = 5 # bits for key purpose
KeyPurposeType = tuple[str, int, str | None, str | None, str]
KEY_PURPOSES: list[KeyPurposeType] = [
("USER", 0, None, None, "no_need_rd_protect"), # User purposes (software-only use)
("ECDSA_KEY_P256", 1, None, "Reverse", "need_rd_protect"), # ECDSA key P256
("ECDSA_KEY", 1, None, "Reverse", "need_rd_protect"), # ECDSA key P256
@@ -458,6 +460,14 @@ class EfuseKeyPurposeField(EfuseField):
("ECDSA_KEY_P384_H", 18, None, "Reverse", "need_rd_protect"), # ECDSA key P384 high
("ECDSA_KEY_P384", -3, "VIRTUAL", None, "need_rd_protect"), # Virtual purpose splits to ECDSA_KEY_P384_L and ECDSA_KEY_P384_H
]
CUSTOM_KEY_PURPOSES: list[KeyPurposeType] = []
for id in range(0, 1 << key_purpose_len):
if id not in [p[1] for p in KEY_PURPOSES]:
CUSTOM_KEY_PURPOSES.append((f"CUSTOM_{id}", id, None, None, "no_need_rd_protect"))
CUSTOM_KEY_PURPOSES.append((f"CUSTOM_DIGEST_{id}", id, "DIGEST", None, "no_need_rd_protect"))
CUSTOM_KEY_PURPOSES.append(("CUSTOM_MAX", (1 << key_purpose_len) - 1, None, None, "no_need_rd_protect"))
CUSTOM_KEY_PURPOSES.append(("CUSTOM_DIGEST_MAX", (1 << key_purpose_len) - 1, "DIGEST", None, "no_need_rd_protect"))
KEY_PURPOSES += CUSTOM_KEY_PURPOSES
# fmt: on
KEY_PURPOSES_NAME = [name[0] for name in KEY_PURPOSES]
DIGEST_KEY_PURPOSES = [name[0] for name in KEY_PURPOSES if name[2] == "DIGEST"]

View File

@@ -396,7 +396,9 @@ class EfuseMacField(EfuseField):
# fmt: off
class EfuseKeyPurposeField(EfuseField):
KEY_PURPOSES = [
key_purpose_len = 4 # bits for key purpose
KeyPurposeType = tuple[str, int, str | None, str | None, str]
KEY_PURPOSES: list[KeyPurposeType] = [
("USER", 0, None, None, "no_need_rd_protect"), # User purposes (software-only use)
("RESERVED", 1, None, None, "no_need_rd_protect"), # Reserved
("XTS_AES_128_KEY", 4, None, "Reverse", "need_rd_protect"), # XTS_AES_128_KEY (flash/PSRAM encryption)
@@ -408,6 +410,14 @@ class EfuseKeyPurposeField(EfuseField):
("SECURE_BOOT_DIGEST1", 10, "DIGEST", None, "no_need_rd_protect"), # SECURE_BOOT_DIGEST1 (Secure Boot key digest)
("SECURE_BOOT_DIGEST2", 11, "DIGEST", None, "no_need_rd_protect"), # SECURE_BOOT_DIGEST2 (Secure Boot key digest)
]
CUSTOM_KEY_PURPOSES: list[KeyPurposeType] = []
for id in range(0, 1 << key_purpose_len):
if id not in [p[1] for p in KEY_PURPOSES]:
CUSTOM_KEY_PURPOSES.append((f"CUSTOM_{id}", id, None, None, "no_need_rd_protect"))
CUSTOM_KEY_PURPOSES.append((f"CUSTOM_DIGEST_{id}", id, "DIGEST", None, "no_need_rd_protect"))
CUSTOM_KEY_PURPOSES.append(("CUSTOM_MAX", (1 << key_purpose_len) - 1, None, None, "no_need_rd_protect"))
CUSTOM_KEY_PURPOSES.append(("CUSTOM_DIGEST_MAX", (1 << key_purpose_len) - 1, "DIGEST", None, "no_need_rd_protect"))
KEY_PURPOSES += CUSTOM_KEY_PURPOSES
# fmt: on
KEY_PURPOSES_NAME = [name[0] for name in KEY_PURPOSES]
DIGEST_KEY_PURPOSES = [name[0] for name in KEY_PURPOSES if name[2] == "DIGEST"]

View File

@@ -387,7 +387,9 @@ class EfuseMacField(EfuseField):
# fmt: off
class EfuseKeyPurposeField(EfuseField):
KEY_PURPOSES = [
key_purpose_len = 4 # bits for key purpose
KeyPurposeType = tuple[str, int, str | None, str | None, str]
KEY_PURPOSES: list[KeyPurposeType] = [
("USER", 0, None, None, "no_need_rd_protect"), # User purposes (software-only use)
("ECDSA_KEY", 1, None, "Reverse", "need_rd_protect"), # ECDSA key
("XTS_AES_256_KEY_1", 2, None, "Reverse", "need_rd_protect"), # XTS_AES_256_KEY_1 (flash/PSRAM encryption)
@@ -403,6 +405,14 @@ class EfuseKeyPurposeField(EfuseField):
("KM_INIT_KEY", 12, None, None, "need_rd_protect"), # init key that is used for the generation of AES/ECDSA key
("XTS_AES_256_KEY", -1, "VIRTUAL", None, "no_need_rd_protect"), # Virtual purpose splits to XTS_AES_256_KEY_1 and XTS_AES_256_KEY_2
]
CUSTOM_KEY_PURPOSES: list[KeyPurposeType] = []
for id in range(0, 1 << key_purpose_len):
if id not in [p[1] for p in KEY_PURPOSES]:
CUSTOM_KEY_PURPOSES.append((f"CUSTOM_{id}", id, None, None, "no_need_rd_protect"))
CUSTOM_KEY_PURPOSES.append((f"CUSTOM_DIGEST_{id}", id, "DIGEST", None, "no_need_rd_protect"))
CUSTOM_KEY_PURPOSES.append(("CUSTOM_MAX", (1 << key_purpose_len) - 1, None, None, "no_need_rd_protect"))
CUSTOM_KEY_PURPOSES.append(("CUSTOM_DIGEST_MAX", (1 << key_purpose_len) - 1, "DIGEST", None, "no_need_rd_protect"))
KEY_PURPOSES += CUSTOM_KEY_PURPOSES
# fmt: on
KEY_PURPOSES_NAME = [name[0] for name in KEY_PURPOSES]
DIGEST_KEY_PURPOSES = [name[0] for name in KEY_PURPOSES if name[2] == "DIGEST"]

View File

@@ -2285,3 +2285,26 @@ class TestCSVEfuseTable(EfuseTestCase):
MY_ID_NUMK_1 1 \
MY_DATA_FIELD1 1"
)
@pytest.mark.skipif(
Command(arg_chip, "burn-key").does_not_support("CUSTOM_MAX"),
reason="Does not provides support for custom key purposes",
)
class TestCustomKeyPurposes(EfuseTestCase):
def test_custom_key_purposes(self):
self.espefuse_py(f"burn-key BLOCK_KEY0 {IMAGES_DIR}/256bit CUSTOM_MAX")
output = self.espefuse_py("-d summary")
self.check_data_block_in_log(output, f"{IMAGES_DIR}/256bit")
def test_custom_digest_key_purposes(self):
self.espefuse_py(
f"burn-key-digest BLOCK_KEY0 \
{S_IMAGES_DIR}/rsa_secure_boot_signing_key.pem \
CUSTOM_DIGEST_MAX"
)
output = self.espefuse_py("-d summary")
assert (
" = cb 27 91 a3 71 b0 c0 32 2b f7 37 04 78 ba 09 62 "
"22 4c ab 1c f2 28 78 79 e4 29 67 3e 7d a8 44 63 R/-"
) in output