Merge branch 'change/secure_boot_signing_key_type_check' into 'master'

Validate secure boot signing key type at configure time

See merge request espressif/esp-idf!49529
This commit is contained in:
Harshal Patil
2026-06-30 12:31:42 +05:30
2 changed files with 124 additions and 0 deletions
@@ -76,6 +76,38 @@ if(CONFIG_SECURE_SIGNED_APPS)
endif()
else()
add_custom_target(gen_secure_boot_signing_key)
# Re-run CMake if the signing key file changes, so the key type check below is re-evaluated
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${secure_boot_signing_key}")
# Check that the signing key type matches the selected app signing scheme,
# as the signing step derives the signature type from the key itself.
if(CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME)
set(key_check_args --scheme rsa)
elseif(CONFIG_SECURE_SIGNED_APPS_ECDSA_SCHEME)
set(key_check_args --scheme ecdsa_v1)
elseif(CONFIG_SECURE_SIGNED_APPS_ECDSA_V2_SCHEME)
if(CONFIG_SECURE_BOOT_ECDSA_KEY_LEN_256_BITS)
set(key_check_args --scheme ecdsa_v2 --ecdsa-key-size 256)
elseif(CONFIG_SECURE_BOOT_ECDSA_KEY_LEN_384_BITS)
set(key_check_args --scheme ecdsa_v2 --ecdsa-key-size 384)
else()
set(key_check_args --scheme ecdsa_v2)
endif()
endif()
if(key_check_args)
idf_build_get_property(python PYTHON)
execute_process(
COMMAND ${python} "${CMAKE_CURRENT_LIST_DIR}/scripts/check_secure_boot_signing_key.py"
${key_check_args} "${secure_boot_signing_key}"
RESULT_VARIABLE key_check_result
ERROR_VARIABLE key_check_error
OUTPUT_QUIET)
if(NOT key_check_result EQUAL 0)
message(FATAL_ERROR "CONFIG_SECURE_BOOT_SIGNING_KEY check failed: ${key_check_error}")
endif()
endif()
endif()
set(SECURE_BOOT_SIGNING_KEY ${secure_boot_signing_key}) # needed by some other components
@@ -0,0 +1,92 @@
# SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
#
# SPDX-License-Identifier: Apache-2.0
#
# Check that the Secure Boot signing key matches the selected app signing
# scheme. The signing step (espsecure sign-data) derives the signature type
# from the key file itself, so a mismatching key would produce an image that
# only fails signature verification at boot.
#
# Invoked at configure time from components/bootloader/project_include.cmake.
# Exits non-zero with an explanatory message on a mismatch.
import argparse
from cryptography.hazmat.primitives.asymmetric import ec
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.primitives.serialization import load_pem_private_key
ECDSA_KEY_SIZE_TO_CURVE = {
'256': 'secp256r1',
'384': 'secp384r1',
}
def key_description(key: object) -> str:
if isinstance(key, rsa.RSAPrivateKey):
return f'an RSA {key.key_size}-bit key'
if isinstance(key, ec.EllipticCurvePrivateKey):
return f'an ECDSA key (curve {key.curve.name})'
return f'a {type(key).__name__} key'
def main() -> None:
parser = argparse.ArgumentParser(
description='Check that the secure boot signing key matches the selected app signing scheme'
)
parser.add_argument(
'--scheme',
choices=['rsa', 'ecdsa_v1', 'ecdsa_v2'],
required=True,
help='App signing scheme selected in sdkconfig',
)
parser.add_argument(
'--ecdsa-key-size',
choices=sorted(ECDSA_KEY_SIZE_TO_CURVE),
default=None,
help='ECDSA key size selected in sdkconfig (ECDSA V2 scheme only)',
)
parser.add_argument('key_file', help='Path to the secure boot signing key')
args = parser.parse_args()
try:
with open(args.key_file, 'rb') as f:
key = load_pem_private_key(f.read(), password=None)
except Exception:
raise SystemExit(
f'{args.key_file} could not be parsed as a PEM private key. '
'Secure boot signing keys must be unencrypted PEM private keys.'
)
if args.scheme == 'rsa':
if not isinstance(key, rsa.RSAPrivateKey):
raise SystemExit(
f'{args.key_file} is {key_description(key)}, but the selected app signing scheme '
'requires an RSA key. Update the App Signing Scheme choice or point '
'CONFIG_SECURE_BOOT_SIGNING_KEY to a matching key.'
)
return
if args.scheme in ('ecdsa_v1', 'ecdsa_v2'):
if not isinstance(key, ec.EllipticCurvePrivateKey):
raise SystemExit(
f'{args.key_file} is {key_description(key)}, but the selected app signing scheme '
'requires an ECDSA key. Update the App Signing Scheme choice or point '
'CONFIG_SECURE_BOOT_SIGNING_KEY to a matching key.'
)
if args.scheme == 'ecdsa_v1':
expected_curve = ECDSA_KEY_SIZE_TO_CURVE['256']
else:
expected_curve = ECDSA_KEY_SIZE_TO_CURVE.get(args.ecdsa_key_size or '', '')
if expected_curve and key.curve.name != expected_curve:
raise SystemExit(
f'{args.key_file} is {key_description(key)}, but the selected app signing scheme '
f'requires curve {expected_curve}. Signature verification would fail at boot. '
'Update the ECDSA key size choice or point CONFIG_SECURE_BOOT_SIGNING_KEY to '
'a matching key.'
)
if __name__ == '__main__':
main()