forked from espressif/esp-idf
feat(security): update idf.py extensions to support security feature application
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
# SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
import json
|
||||
import os
|
||||
@@ -290,7 +290,8 @@ def action_extensions(base_actions: Dict, project_path: str) -> Dict:
|
||||
format: str,
|
||||
md5_disable: str,
|
||||
flash_offset: str,
|
||||
fill_flash_size: str) -> None:
|
||||
fill_flash_size: str,
|
||||
merge_args: str) -> None:
|
||||
ensure_build_directory(args, ctx.info_name)
|
||||
project_desc = _get_project_desc(ctx, args)
|
||||
merge_bin_args = [PYTHON, '-m', 'esptool']
|
||||
@@ -320,7 +321,10 @@ def action_extensions(base_actions: Dict, project_path: str) -> Dict:
|
||||
yellow_print('idf.py merge-bin: --fill-flash-size is only valid for RAW format, option will be ignored.')
|
||||
else:
|
||||
merge_bin_args += ['--fill-flash-size', fill_flash_size]
|
||||
merge_bin_args += ['@flash_args']
|
||||
if not merge_args:
|
||||
merge_bin_args += ['@flash_args']
|
||||
else:
|
||||
merge_bin_args += ['@{}'.format(merge_args)]
|
||||
print(f'Merged binary {output} will be created in the build directory...')
|
||||
RunTool('merge_bin', merge_bin_args, args.build_dir, build_dir=args.build_dir, hints=not args.no_hints)()
|
||||
|
||||
@@ -424,6 +428,15 @@ def action_extensions(base_actions: Dict, project_path: str) -> Dict:
|
||||
generate_signing_key_args += [extra_args['keyfile']]
|
||||
RunTool('espsecure', generate_signing_key_args, args.project_dir)()
|
||||
|
||||
def secure_generate_key_digest(action: str, ctx: click.core.Context, args: PropertyDict, keyfile:str, output:str, **extra_args: str) -> None:
|
||||
ensure_build_directory(args, ctx.info_name)
|
||||
generate_key_digest_args = [PYTHON, '-m', 'espsecure', 'digest_sbv2_public_key']
|
||||
if keyfile:
|
||||
generate_key_digest_args += ['--keyfile', keyfile]
|
||||
if output:
|
||||
generate_key_digest_args += ['--output', output]
|
||||
RunTool('espsecure', generate_key_digest_args, args.project_dir)()
|
||||
|
||||
def secure_sign_data(action: str,
|
||||
ctx: click.core.Context,
|
||||
args: PropertyDict,
|
||||
@@ -468,6 +481,35 @@ def action_extensions(base_actions: Dict, project_path: str) -> Dict:
|
||||
verify_signature_args += [extra_args['datafile']]
|
||||
RunTool('espsecure', verify_signature_args, args.build_dir)()
|
||||
|
||||
def secure_generate_nvs_partition_key(action: str,
|
||||
ctx: click.core.Context,
|
||||
args: PropertyDict,
|
||||
encryption_scheme: str,
|
||||
keyfile: str,
|
||||
hmac_keyfile: str,
|
||||
**extra_args: str) -> None:
|
||||
ensure_build_directory(args, ctx.info_name)
|
||||
generate_nvs_partition_key_args = [PYTHON, '-m', 'esp_idf_nvs_partition_gen', 'generate-key']
|
||||
if encryption_scheme == 'HMAC':
|
||||
generate_nvs_partition_key_args += ['--key_protect_hmac']
|
||||
generate_nvs_partition_key_args += ['--kp_hmac_keygen']
|
||||
generate_nvs_partition_key_args += ['--kp_hmac_keyfile', hmac_keyfile]
|
||||
generate_nvs_partition_key_args += ['--keyfile', keyfile]
|
||||
|
||||
RunTool('espsecure', generate_nvs_partition_key_args, args.project_dir)()
|
||||
|
||||
def secure_encrypt_nvs_partition(action: str, ctx: click.core.Context, args: PropertyDict, keyfile: str, **extra_args: str) -> None:
|
||||
ensure_build_directory(args, ctx.info_name)
|
||||
encrypt_nvs_partition_args = [PYTHON, '-m', 'esp_idf_nvs_partition_gen', 'encrypt']
|
||||
encrypt_nvs_partition_args += ['--inputkey', keyfile]
|
||||
if extra_args['input_file']:
|
||||
encrypt_nvs_partition_args += [extra_args['input_file']]
|
||||
if extra_args['output_file']:
|
||||
encrypt_nvs_partition_args += [extra_args['output_file']]
|
||||
if extra_args['partition_size']:
|
||||
encrypt_nvs_partition_args += [extra_args['partition_size']]
|
||||
RunTool('espsecure', encrypt_nvs_partition_args, args.project_dir)()
|
||||
|
||||
def _parse_efuse_args(ctx: click.core.Context, args: PropertyDict, extra_args: Dict) -> List:
|
||||
efuse_args = []
|
||||
if args.port:
|
||||
@@ -639,6 +681,13 @@ def action_extensions(base_actions: Dict, project_path: str) -> Dict:
|
||||
'help': ('[ONLY RAW] If set, the final binary file will be padded with FF bytes up to this flash size.'),
|
||||
'type': click.Choice(['256KB', '512KB', '1MB', '2MB', '4MB', '8MB', '16MB', '32MB', '64MB', '128MB']),
|
||||
},
|
||||
{
|
||||
'names': ['--merge-args'],
|
||||
'help': (
|
||||
'Filepath to specify which binaries should be merged with their respective addresses. '
|
||||
'The file format should be the same as flash_args.'
|
||||
),
|
||||
}
|
||||
],
|
||||
'dependencies': ['all'], # all = build
|
||||
},
|
||||
@@ -781,6 +830,20 @@ def action_extensions(base_actions: Dict, project_path: str) -> Dict:
|
||||
},
|
||||
],
|
||||
},
|
||||
'secure-generate-key-digest': {
|
||||
'callback': secure_generate_key_digest,
|
||||
'help': ('Generate a digest of a puiblic key file for use with secure boot.'),
|
||||
'options': [
|
||||
{
|
||||
'names': ['--keyfile', '-k'],
|
||||
'help': ('Public key file for digest generation.'),
|
||||
},
|
||||
{
|
||||
'names': ['--output', '-o'],
|
||||
'help': ('Output file for key digest.'),
|
||||
},
|
||||
],
|
||||
},
|
||||
'secure-sign-data': {
|
||||
'callback': secure_sign_data,
|
||||
'help': ('Sign a data file for use with secure boot. Signing algorithm is deterministic ECDSA w/ SHA-512 (V1) or either RSA-'
|
||||
@@ -851,6 +914,51 @@ def action_extensions(base_actions: Dict, project_path: str) -> Dict:
|
||||
},
|
||||
],
|
||||
},
|
||||
'secure-generate-nvs-partition-key': {
|
||||
'callback': secure_generate_nvs_partition_key,
|
||||
'help': 'Generate a key for NVS partition encryption.',
|
||||
'options': [
|
||||
{
|
||||
'names': ['--keyfile', '-k'],
|
||||
'help': 'File to store the generated key.',
|
||||
},
|
||||
{
|
||||
'names': ['--encryption-scheme', '-s'],
|
||||
'help': 'Encryption scheme to use.',
|
||||
'type': click.Choice(['HMAC', 'Flash']),
|
||||
'default': 'HMAC',
|
||||
},
|
||||
{
|
||||
'names': ['--hmac-keyfile', '-l'],
|
||||
'help': 'File to store the generated HMAC key.',
|
||||
|
||||
}
|
||||
],
|
||||
},
|
||||
'secure-encrypt-nvs-partition': {
|
||||
'callback': secure_encrypt_nvs_partition,
|
||||
'help': 'Encrypt the NVS partition.',
|
||||
'options': [
|
||||
{
|
||||
'names': ['--keyfile', '-k'],
|
||||
'help': 'File with NVS partition key.',
|
||||
}
|
||||
],
|
||||
'arguments': [
|
||||
{
|
||||
'names': ['input_file'],
|
||||
'nargs': 1,
|
||||
},
|
||||
{
|
||||
'names': ['output_file'],
|
||||
'nargs': 1,
|
||||
},
|
||||
{
|
||||
'names': ['partition_size'],
|
||||
'nargs': 1,
|
||||
}
|
||||
]
|
||||
},
|
||||
'efuse-burn': {
|
||||
'callback': efuse_burn,
|
||||
'help': 'Burn the eFuse with the specified name.',
|
||||
@@ -878,8 +986,8 @@ def action_extensions(base_actions: Dict, project_path: str) -> Dict:
|
||||
'names': ['--force-write-always'],
|
||||
'is_flag': True,
|
||||
'help': (
|
||||
"Write the eFuse even if it looks like it's already been written, or is write protected."
|
||||
"Note that this option can't disable write protection, or clear any bit which has already been set."
|
||||
'Write the eFuse even if it looks like it\'s already been written, or is write protected.'
|
||||
'Note that this option can\'t disable write protection, or clear any bit which has already been set.'
|
||||
),
|
||||
},
|
||||
{
|
||||
@@ -977,7 +1085,7 @@ def action_extensions(base_actions: Dict, project_path: str) -> Dict:
|
||||
'Baud rate for monitor. '
|
||||
'If this option is not provided IDF_MONITOR_BAUD and MONITORBAUD '
|
||||
'environment variables, global baud rate and project_description.json in build directory '
|
||||
"(generated by CMake from project's sdkconfig) "
|
||||
'(generated by CMake from project\'s sdkconfig) '
|
||||
'will be checked for default value.'
|
||||
),
|
||||
},
|
||||
|
@@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# SPDX-FileCopyrightText: 2019-2024 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-FileCopyrightText: 2019-2025 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
import json
|
||||
import os
|
||||
@@ -409,6 +409,7 @@ class TestSecureCommands(TestWrapperCommands):
|
||||
subprocess.run([sys.executable, idf_py_path, 'build'], stdout=subprocess.DEVNULL)
|
||||
cls.flash_encryption_key = 'test_key.bin'
|
||||
cls.signing_key = 'test_signing_key.pem'
|
||||
cls.nvs_partition_key = 'nvs_partition_key.bin'
|
||||
|
||||
def secure_generate_flash_encryption_key(self):
|
||||
generate_key_command = [sys.executable, idf_py_path, 'secure-generate-flash-encryption-key', self.flash_encryption_key]
|
||||
@@ -449,19 +450,6 @@ class TestSecureCommands(TestWrapperCommands):
|
||||
self.assertIn('Using 256-bit key', output)
|
||||
self.assertIn('Done', output)
|
||||
|
||||
def secure_generate_signing_key(self):
|
||||
generate_key_command = [sys.executable,
|
||||
idf_py_path,
|
||||
'secure-generate-signing-key',
|
||||
'--version',
|
||||
'2',
|
||||
'--scheme',
|
||||
'rsa3072',
|
||||
self.signing_key]
|
||||
output = self.call_command(generate_key_command)
|
||||
self.assertIn(f'RSA 3072 private key in PEM format written to {self.signing_key}', output)
|
||||
self.assertIn('Done', output)
|
||||
|
||||
def secure_sign_data(self):
|
||||
self.secure_generate_signing_key()
|
||||
sign_command = [sys.executable,
|
||||
@@ -490,6 +478,43 @@ class TestSecureCommands(TestWrapperCommands):
|
||||
output = self.call_command(sign_command)
|
||||
self.assertIn('verification successful', output)
|
||||
|
||||
def secure_generate_signing_key(self):
|
||||
generate_key_command = [sys.executable,
|
||||
idf_py_path,
|
||||
'secure-generate-signing-key',
|
||||
'--version',
|
||||
'2',
|
||||
'--scheme',
|
||||
'rsa3072',
|
||||
self.signing_key]
|
||||
output = self.call_command(generate_key_command)
|
||||
self.assertIn(f'RSA 3072 private key in PEM format written to {self.signing_key}', output)
|
||||
|
||||
def test_secure_generate_key_digest(self):
|
||||
self.secure_generate_signing_key()
|
||||
digest_command = [sys.executable,
|
||||
idf_py_path,
|
||||
'secure-generate-key-digest',
|
||||
'--keyfile',
|
||||
f'{self.signing_key}',
|
||||
'--output',
|
||||
'key_digest.bin']
|
||||
output = self.call_command(digest_command)
|
||||
self.assertIn(f'Writing the public key digest of {self.signing_key} to key_digest.bin', output)
|
||||
|
||||
def test_secure_generate_nvs_partition_key(self):
|
||||
generate_key_command = [sys.executable,
|
||||
idf_py_path,
|
||||
'secure-generate-nvs-partition-key',
|
||||
'--keyfile',
|
||||
f'{self.nvs_partition_key}',
|
||||
'--encryption-scheme',
|
||||
'HMAC',
|
||||
'--hmac-keyfile',
|
||||
'nvs_partition_key.bin']
|
||||
output = self.call_command(generate_key_command)
|
||||
self.assertIn('Created encryption keys:', output)
|
||||
|
||||
|
||||
class TestMergeBinCommands(TestWrapperCommands):
|
||||
"""
|
||||
|
Reference in New Issue
Block a user