From a91eee192ee0a2fb6624b6d3c8a912df57e1eb91 Mon Sep 17 00:00:00 2001 From: KonstantinKondrashov Date: Tue, 7 Nov 2023 16:04:35 +0800 Subject: [PATCH] feat(espefuse): Support XTS_AES_256_KEY key_purpose for ESP32P4 --- espefuse/efuse/esp32p4/fields.py | 1 + espefuse/efuse/esp32p4/operations.py | 67 ++++++++++++++++++++++++++++ test/test_espefuse.py | 12 ++--- 3 files changed, 74 insertions(+), 6 deletions(-) diff --git a/espefuse/efuse/esp32p4/fields.py b/espefuse/efuse/esp32p4/fields.py index b79816208b..4b912ec5cc 100644 --- a/espefuse/efuse/esp32p4/fields.py +++ b/espefuse/efuse/esp32p4/fields.py @@ -387,6 +387,7 @@ 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) ("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 ] # fmt: on KEY_PURPOSES_NAME = [name[0] for name in KEY_PURPOSES] diff --git a/espefuse/efuse/esp32p4/operations.py b/espefuse/efuse/esp32p4/operations.py index 093a04802d..b24a735121 100644 --- a/espefuse/efuse/esp32p4/operations.py +++ b/espefuse/efuse/esp32p4/operations.py @@ -5,6 +5,7 @@ # SPDX-License-Identifier: GPL-2.0-or-later import argparse +import io import os # noqa: F401. It is used in IDF scripts import traceback @@ -191,6 +192,67 @@ def adc_info(esp, efuses, args): print("not supported yet") +def key_block_is_unused(block, key_purpose_block): + if not block.is_readable() or not block.is_writeable(): + return False + + if key_purpose_block.get() != "USER" or not key_purpose_block.is_writeable(): + return False + + if not block.get_bitstring().all(False): + return False + + return True + + +def get_next_key_block(efuses, current_key_block, block_name_list): + key_blocks = [b for b in efuses.blocks if b.key_purpose_name] + start = key_blocks.index(current_key_block) + + # Sort key blocks so that we pick the next free block (and loop around if necessary) + key_blocks = key_blocks[start:] + key_blocks[0:start] + + # Exclude any other blocks that will be be burned + key_blocks = [b for b in key_blocks if b.name not in block_name_list] + + for block in key_blocks: + key_purpose_block = efuses[block.key_purpose_name] + if key_block_is_unused(block, key_purpose_block): + return block + + return None + + +def split_512_bit_key(efuses, block_name_list, datafile_list, keypurpose_list): + i = keypurpose_list.index("XTS_AES_256_KEY") + block_name = block_name_list[i] + + block_num = efuses.get_index_block_by_name(block_name) + block = efuses.blocks[block_num] + + data = datafile_list[i].read() + if len(data) != 64: + raise esptool.FatalError( + "Incorrect key file size %d, XTS_AES_256_KEY should be 64 bytes" % len(data) + ) + + key_block_2 = get_next_key_block(efuses, block, block_name_list) + if not key_block_2: + raise esptool.FatalError("XTS_AES_256_KEY requires two free keyblocks") + + keypurpose_list.append("XTS_AES_256_KEY_1") + datafile_list.append(io.BytesIO(data[:32])) + block_name_list.append(block_name) + + keypurpose_list.append("XTS_AES_256_KEY_2") + datafile_list.append(io.BytesIO(data[32:])) + block_name_list.append(key_block_2.name) + + keypurpose_list.pop(i) + datafile_list.pop(i) + block_name_list.pop(i) + + def burn_key(esp, efuses, args, digest=None): if digest is None: datafile_list = args.keyfile[ @@ -206,6 +268,11 @@ def burn_key(esp, efuses, args, digest=None): 0 : len([name for name in args.keypurpose if name is not None]) : ] + if "XTS_AES_256_KEY" in keypurpose_list: + # XTS_AES_256_KEY is not an actual HW key purpose, needs to be split into + # XTS_AES_256_KEY_1 and XTS_AES_256_KEY_2 + split_512_bit_key(efuses, block_name_list, datafile_list, keypurpose_list) + util.check_duplicate_name_in_list(block_name_list) if len(block_name_list) != len(datafile_list) or len(block_name_list) != len( keypurpose_list diff --git a/test/test_espefuse.py b/test/test_espefuse.py index cb8ada0d01..c38f96b98e 100755 --- a/test/test_espefuse.py +++ b/test/test_espefuse.py @@ -962,8 +962,8 @@ def test_burn_key_with_34_coding_scheme(self): self.check_data_block_in_log(output, f"{IMAGES_DIR}/192bit_2") @pytest.mark.skipif( - arg_chip not in ["esp32s2", "esp32s3"], - reason="512 bit keys are only supported on ESP32-S2 and S3", + arg_chip not in ["esp32s2", "esp32s3", "esp32p4"], + reason="512 bit keys are only supported on ESP32-S2, S3, and P4", ) def test_burn_key_512bit(self): self.espefuse_py( @@ -980,8 +980,8 @@ def test_burn_key_512bit(self): ) @pytest.mark.skipif( - arg_chip not in ["esp32s2", "esp32s3"], - reason="512 bit keys are only supported on ESP32-S2 and S3", + arg_chip not in ["esp32s2", "esp32s3", "esp32p4"], + reason="512 bit keys are only supported on ESP32-S2, S3, and P4", ) def test_burn_key_512bit_non_consecutive_blocks(self): # Burn efuses seperately to test different kinds @@ -1023,8 +1023,8 @@ def test_burn_key_512bit_non_consecutive_blocks(self): ) in output @pytest.mark.skipif( - arg_chip not in ["esp32s2", "esp32s3"], - reason="512 bit keys are only supported on ESP32-S2 and S3", + arg_chip not in ["esp32s2", "esp32s3", "esp32p4"], + reason="512 bit keys are only supported on ESP32-S2, S3, and P4", ) def test_burn_key_512bit_non_consecutive_blocks_loop_around(self): self.espefuse_py(