From b069b31a2c5d569b54e3292c9cf23de18fb907d1 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Thu, 19 Jul 2018 15:15:37 +1000 Subject: [PATCH 1/2] secure boot: Support secure boot signatures without hardware secure boot Allows OTA updates to be secured via signature checks, without requiring the overhead or complexity of a full secure boot implementation. Uses same signing mechanisms (build system and/or espsecure.py as Secure Boot). Requires: * [ ] More testing * [ ] Documentation --- components/app_update/esp_ota_ops.c | 2 +- components/bootloader/Kconfig.projbuild | 68 ++++++++++++++++--- components/bootloader_support/component.mk | 2 +- .../include/esp_secure_boot.h | 8 +++ .../bootloader_support/src/esp_image_format.c | 22 +++++- 5 files changed, 88 insertions(+), 14 deletions(-) diff --git a/components/app_update/esp_ota_ops.c b/components/app_update/esp_ota_ops.c index befdd33fc..cb1675b29 100644 --- a/components/app_update/esp_ota_ops.c +++ b/components/app_update/esp_ota_ops.c @@ -377,7 +377,7 @@ esp_err_t esp_ota_set_boot_partition(const esp_partition_t *partition) return ESP_ERR_OTA_VALIDATE_FAILED; } -#ifdef CONFIG_SECURE_BOOT_ENABLED +#ifdef CONFIG_SECURE_SIGNED_ON_UPDATE esp_err_t ret = esp_secure_boot_verify_signature(partition->address, data.image_len); if (ret != ESP_OK) { return ESP_ERR_OTA_VALIDATE_FAILED; diff --git a/components/bootloader/Kconfig.projbuild b/components/bootloader/Kconfig.projbuild index 75dae508a..63b9c2214 100644 --- a/components/bootloader/Kconfig.projbuild +++ b/components/bootloader/Kconfig.projbuild @@ -132,9 +132,59 @@ endmenu # Bootloader menu "Security features" +# These three are the actual options to check in code, +# selected by the displayed options +config SECURE_SIGNED_ON_BOOT + bool + default y + depends on SECURE_BOOT_ENABLED || SECURE_SIGNED_ON_BOOT_NO_SECURE_BOOT + +config SECURE_SIGNED_ON_UPDATE + bool + default y + depends on SECURE_BOOT_ENABLED || SECURE_SIGNED_ON_UPDATE_NO_SECURE_BOOT + +config SECURE_SIGNED_APPS + bool + default y + depends on SECURE_SIGNED_ON_BOOT || SECURE_SIGNED_ON_UPDATE + + +config SECURE_SIGNED_APPS_NO_SECURE_BOOT + bool "Require signed app images" + default n + depends on !SECURE_BOOT_ENABLED + help + Require apps to be signed to verify their integrity. + + This option uses the same app signature scheme as hardware secure boot, but unlike hardware secure boot it does not prevent the bootloader from being physically updated. This means that the device can be secured against remote network access, but not physical access. Compared to using hardware Secure Boot this option is much simpler to implement. + +config SECURE_SIGNED_ON_BOOT_NO_SECURE_BOOT + bool "Bootloader verifies app signatures" + default n + depends on SECURE_SIGNED_APPS_NO_SECURE_BOOT + help + If this option is set, the bootloader will be compiled with code to verify that an app is signed before booting it. + + If hardware secure boot is enabled, this option is always enabled and cannot be disabled. + If hardware secure boot is not enabled, this option doesn't add significant security by itself so most users will want to leave it disabled. + +config SECURE_SIGNED_ON_UPDATE_NO_SECURE_BOOT + bool "Verify app signature on update" + default y + depends on SECURE_SIGNED_APPS_NO_SECURE_BOOT + help + If this option is set, any OTA updated apps will have the signature verified before being considered valid. + + When enabled, the signature is automatically checked whenever the esp_ota_ops.h APIs are used for OTA updates, + or esp_image_format.h APIs are used to verify apps. + + If hardware secure boot is enabled, this option is always enabled and cannot be disabled. + If hardware secure boot is not enabled, this option still adds significant security against network-based attackers by preventing spoofing of OTA updates. + config SECURE_BOOT_ENABLED - bool "Enable secure boot in bootloader (READ DOCS FIRST)" - default N + bool "Enable hardware secure boot in bootloader (READ DOCS FIRST)" + default n help Build a bootloader which enables secure boot on first boot. @@ -169,12 +219,12 @@ endchoice config SECURE_BOOT_BUILD_SIGNED_BINARIES bool "Sign binaries during build" - depends on SECURE_BOOT_ENABLED + depends on SECURE_SIGNED_APPS default y help - Once secure boot is enabled, bootloader will only boot if partition table and app image are signed. + Once secure boot or signed app requirement is enabled, app images are required to be signed. - If enabled, these binary files are signed as part of the build process. The file named in "Secure boot private signing key" will be used to sign the image. + If enabled (default), these binary files are signed as part of the build process. The file named in "Secure boot private signing key" will be used to sign the image. If disabled, unsigned app/partition data will be built. They must be signed manually using espsecure.py (for example, on a remote signing server.) @@ -183,7 +233,7 @@ config SECURE_BOOT_SIGNING_KEY depends on SECURE_BOOT_BUILD_SIGNED_BINARIES default secure_boot_signing_key.pem help - Path to the key file used to sign partition tables and app images for secure boot. Once secure boot is enabled, bootloader will only boot if partition table and app image are signed. + Path to the key file used to sign app images. Key file is an ECDSA private key (NIST256p curve) in PEM format. @@ -196,11 +246,11 @@ config SECURE_BOOT_SIGNING_KEY config SECURE_BOOT_VERIFICATION_KEY string "Secure boot public signature verification key" - depends on SECURE_BOOT_ENABLED && !SECURE_BOOT_BUILD_SIGNED_BINARIES + depends on SECURE_SIGNED_APPS && !SECURE_BOOT_BUILD_SIGNED_BINARIES default signature_verification_key.bin help - Path to a public key file used to verify signed images. This key is compiled into the bootloader, - and may also be used to verify signatures on OTA images after download. + Path to a public key file used to verify signed images. This key is compiled into the bootloader and/or app, + to verify app images. Key file is in raw binary format, and can be extracted from a PEM formatted private key using the espsecure.py diff --git a/components/bootloader_support/component.mk b/components/bootloader_support/component.mk index 6db815aff..dc449a601 100644 --- a/components/bootloader_support/component.mk +++ b/components/bootloader_support/component.mk @@ -12,7 +12,7 @@ COMPONENT_SRCDIRS := src # # Secure boot signing key support # -ifdef CONFIG_SECURE_BOOT_ENABLED +ifdef CONFIG_SECURE_SIGNED_APPS # this path is created relative to the component build directory SECURE_BOOT_VERIFICATION_KEY := $(abspath signature_verification_key.bin) diff --git a/components/bootloader_support/include/esp_secure_boot.h b/components/bootloader_support/include/esp_secure_boot.h index 6aa4b6285..370bdd363 100644 --- a/components/bootloader_support/include/esp_secure_boot.h +++ b/components/bootloader_support/include/esp_secure_boot.h @@ -17,6 +17,14 @@ #include #include "soc/efuse_reg.h" +#include "sdkconfig.h" + +#ifdef CONFIG_SECURE_BOOT_ENABLED +#if !defined(CONFIG_SECURE_SIGNED_ON_BOOT) || !defined(CONFIG_SECURE_SIGNED_ON_UPDATE) || !defined(CONFIG_SECURE_SIGNED_APPS) +#error "internal sdkconfig error, secure boot should always enable all signature options" +#endif +#endif + #ifdef __cplusplus extern "C" { #endif diff --git a/components/bootloader_support/src/esp_image_format.c b/components/bootloader_support/src/esp_image_format.c index 92acf3b02..965e63987 100644 --- a/components/bootloader_support/src/esp_image_format.c +++ b/components/bootloader_support/src/esp_image_format.c @@ -24,6 +24,20 @@ #include #include +/* Checking signatures as part of verifying images is necessary: + - Always if secure boot is enabled + - Differently in bootloader and/or app, depending on kconfig +*/ +#ifdef BOOTLOADER_BUILD +#ifdef CONFIG_SECURE_SIGNED_ON_BOOT +#define SECURE_BOOT_CHECK_SIGNATURE +#endif +#else /* !BOOTLOADER_BUILD */ +#ifdef CONFIG_SECURE_SIGNED_ON_UPDATE +#define SECURE_BOOT_CHECK_SIGNATURE +#endif +#endif + static const char *TAG = "esp_image"; #define HASH_LEN 32 /* SHA-256 digest length */ @@ -107,7 +121,7 @@ esp_err_t esp_image_load(esp_image_load_mode_t mode, const esp_partition_pos_t * } // Calculate SHA-256 of image if secure boot is on, or if image has a hash appended -#ifdef CONFIG_SECURE_BOOT_ENABLED +#ifdef SECURE_BOOT_CHECK_SIGNATURE if (1) { #else if (data->image.hash_appended) { @@ -174,7 +188,7 @@ goto err; rewritten the header - rely on esptool.py having verified the bootloader at flashing time, instead. */ if (!is_bootloader) { -#ifdef CONFIG_SECURE_BOOT_ENABLED +#ifdef SECURE_BOOT_CHECK_SIGNATURE // secure boot images have a signature appended err = verify_secure_boot_signature(sha_handle, data); #else @@ -182,7 +196,7 @@ goto err; if (sha_handle != NULL && !esp_cpu_in_ocd_debug_mode()) { err = verify_simple_hash(sha_handle, data); } -#endif // CONFIG_SECURE_BOOT_ENABLED +#endif // SECURE_BOOT_CHECK_SIGNATURE } else { // is_bootloader // bootloader may still have a sha256 digest handle open if (sha_handle != NULL) { @@ -492,6 +506,8 @@ static esp_err_t verify_secure_boot_signature(bootloader_sha256_handle_t sha_han { uint8_t image_hash[HASH_LEN] = { 0 }; + ESP_LOGI(TAG, "Verifying image signature..."); + // For secure boot, we calculate the signature hash over the whole file, which includes any "simple" hash // appended to the image for corruption detection if (data->image.hash_appended) { From 7d847e60ecf7965a8f8382900a8fc37bc104fc64 Mon Sep 17 00:00:00 2001 From: Jitin George Date: Tue, 14 Aug 2018 18:55:11 +0530 Subject: [PATCH 2/2] docs/en/security: Add documentation for signed apps without hardware secure boot feature --- .../en/api-reference/system/esp_https_ota.rst | 5 +++ docs/en/api-reference/system/ota.rst | 7 ++++ docs/en/security/secure-boot.rst | 38 +++++++++++++++++++ 3 files changed, 50 insertions(+) diff --git a/docs/en/api-reference/system/esp_https_ota.rst b/docs/en/api-reference/system/esp_https_ota.rst index 762de6cf7..72e3c3285 100644 --- a/docs/en/api-reference/system/esp_https_ota.rst +++ b/docs/en/api-reference/system/esp_https_ota.rst @@ -29,6 +29,11 @@ Application Example return ESP_OK; } +Signature Verification +---------------------- + +For additional security, signature of OTA firmware images can be verified. For that, refer :ref:`secure-ota-updates` + API Reference ------------- diff --git a/docs/en/api-reference/system/ota.rst b/docs/en/api-reference/system/ota.rst index 825335473..db0280728 100644 --- a/docs/en/api-reference/system/ota.rst +++ b/docs/en/api-reference/system/ota.rst @@ -32,6 +32,13 @@ The OTA data partition is two flash sectors (0x2000 bytes) in size, to prevent p while it is being written. Sectors are independently erased and written with matching data, and if they disagree a counter field is used to determine which sector was written more recently. +.. _secure-ota-updates: + +Secure OTA Updates Without Secure boot +-------------------------------------- + +The verification of signed OTA updates can be performed even without enabling hardware secure boot. For doing so, refer :ref:`signed-app-verify` + See also -------- diff --git a/docs/en/security/secure-boot.rst b/docs/en/security/secure-boot.rst index da9a203d3..e14e6f833 100644 --- a/docs/en/security/secure-boot.rst +++ b/docs/en/security/secure-boot.rst @@ -128,6 +128,8 @@ openssl ecparam -name prime256v1 -genkey -noout -out my_secure_boot_signing_key. Remember that the strength of the secure boot system depends on keeping the signing key private. +.. _remote-sign-image: + Remote Signing of Images ------------------------ @@ -235,3 +237,39 @@ Keyfile is the 32 byte raw secure boot key for the device. To flash this digest esptool.py write_flash 0x0 bootloader-digest.bin +.. _secure-boot-and-flash-encr: + +Secure Boot & Flash Encryption +------------------------------ + +If secure boot is used without :doc:`Flash Encryption `, it is possible to launch "time-of-check to time-of-use" attack, where flash contents are swapped after the image is verified and running. Therefore, it is recommended to use both the features together. + +.. _signed-app-verify: + +Signed App Verification Without Hardware Secure Boot +---------------------------------------------------- + +The integrity of apps can be checked even without enabling the hardware secure boot option. This option uses the same app signature scheme as hardware secure +boot, but unlike hardware secure boot it does not prevent the bootloader from being physically updated. This means that the device can be secured +against remote network access, but not physical access. Compared to using hardware Secure Boot this option is much simpler to implement. See :ref:`signed-app-verify-howto` for step by step instructions. + +An app can be verified on update and, optionally, be verified on boot. + +- Verification on update: When enabled, the signature is automatically checked whenever the esp_ota_ops.h APIs are used for OTA updates. If hardware secure boot is enabled, this option is always enabled and cannot be disabled. If hardware secure boot is not enabled, this option still adds significant security against network-based attackers by preventing spoofing of OTA updates. + +- Verification on boot: When enabled, the bootloader will be compiled with code to verify that an app is signed before booting it. If hardware secure boot is enabled, this option is always enabled and cannot be disabled. If hardware secure boot is not enabled, this option doesn't add significant security by itself so most users will want to leave it disabled. + +.. _signed-app-verify-howto: + +How To Enable Signed App Verification +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +1. Run ``make menuconfig`` -> Security features -> Enable "Require signed app images" + +2. "Bootloader verifies app signatures" can be enabled, which verifies app on boot. + +3. By default, "Sign binaries during build" will be enabled on selecting "Require signed app images" option, which will sign binary files as a part of build process. The file named in "Secure boot private signing key" will be used to sign the image. + +4. If you disable "Sign binaries during build" option then you'll have to enter path of a public key file used to verify signed images in "Secure boot public signature verification key". + In this case, private signing key should be generated by following instructions in :ref:`secure-boot-generate-key`; public verification key and signed image should be generated by following instructions in :ref:`remote-sign-image`. +