]> granicus.if.org Git - esp-idf/commitdiff
flash encryption: Add config option to disable any plaintext reflashes
authorAngus Gratton <angus@espressif.com>
Wed, 12 Jun 2019 01:03:42 +0000 (11:03 +1000)
committerAngus Gratton <gus@projectgus.com>
Thu, 5 Sep 2019 08:54:29 +0000 (18:54 +1000)
Enabled by default when Secure Boot is on, so Flash Encryption protection
is always available in case of a Secure Boot bypass.

components/bootloader/Kconfig.projbuild
components/bootloader_support/src/flash_encrypt.c
components/esp32/cpu_start.c
docs/en/security/flash-encryption.rst

index 3ecbed93b987eede62d7f7fb9e9096fff79bc058..2bf32a73091048eb04561c6c2b7f4f28cdcb79ea 100644 (file)
@@ -426,4 +426,22 @@ config SECURE_BOOT_TEST_MODE
 
 
 endmenu  # Potentially Insecure
+
+    config FLASH_ENCRYPTION_DISABLE_PLAINTEXT
+        bool "Disable serial reflashing of plaintext firmware"
+        depends on FLASH_ENCRYPTION_ENABLED
+        default y if SECURE_BOOT_ENABLED
+        default n if !SECURE_BOOT_ENABLED
+        help
+            If this option is enabled, flash encryption is permanently enabled after first boot by write-protecting
+            the FLASH_CRYPT_CNT efuse. This is the recommended configuration for a secure production system.
+
+            If this option is disabled, FLASH_CRYPT_CNT is left writeable and up to 4 plaintext re-flashes are allowed.
+            An attacker with physical access will be able to read out encrypted flash contents until all plaintext
+            re-flashes have been used up.
+
+            If this option is disabled and hardware Secure Boot is enabled, Secure Boot must be configured in
+            Reflashable mode so that a new Secure Boot digest can be flashed at the same time as plaintext firmware.
+            This combination is not secure and should not be used for a production system.
+
 endmenu  # Security features
index 8d5955eff74a5f715cfdd0e0877fb6bbd8e5b589..b0a28819a61f41d105ed678f5680ccab726e8116 100644 (file)
@@ -205,6 +205,14 @@ static esp_err_t encrypt_flash_contents(uint32_t flash_crypt_cnt, bool flash_cry
     uint32_t new_flash_crypt_cnt = flash_crypt_cnt + (1 << (ffs_inv - 1));
     ESP_LOGD(TAG, "FLASH_CRYPT_CNT 0x%x -> 0x%x", flash_crypt_cnt, new_flash_crypt_cnt);
     REG_SET_FIELD(EFUSE_BLK0_WDATA0_REG, EFUSE_FLASH_CRYPT_CNT, new_flash_crypt_cnt);
+
+#ifdef CONFIG_FLASH_ENCRYPTION_DISABLE_PLAINTEXT
+    ESP_LOGI(TAG, "Write protecting FLASH_CRYPT_CNT efuse...");
+    REG_SET_BIT(EFUSE_BLK0_WDATA0_REG, EFUSE_WR_DIS_FLASH_CRYPT_CNT);
+#else
+    ESP_LOGW(TAG, "Not disabling FLASH_CRYPT_CNT - plaintext flashing is still possible");
+#endif
+
     esp_efuse_burn_new_values();
 
     ESP_LOGI(TAG, "Flash encryption completed");
index 5601a7fb0c108dcccf0af1f4e2ca643d0d35117f..ed579e8af433c6b379f6f3c8dcd3fac10df6bd83 100644 (file)
@@ -69,6 +69,7 @@
 #include "esp_clk_internal.h"
 #include "esp_timer.h"
 #include "esp_pm.h"
+#include "esp_flash_encrypt.h"
 #include "pm_impl.h"
 #include "trax.h"
 #include "bootloader_common.h"
@@ -329,6 +330,11 @@ void start_cpu0_default(void)
 #endif
 #if CONFIG_DISABLE_BASIC_ROM_CONSOLE
     esp_efuse_disable_basic_rom_console();
+#endif
+#ifdef CONFIG_FLASH_ENCRYPTION_DISABLE_PLAINTEXT
+    if (esp_flash_encryption_enabled()) {
+        esp_flash_write_protect_crypt_cnt();
+    }
 #endif
     rtc_gpio_force_hold_dis_all();
     esp_vfs_dev_uart_register();
index 136d18822264ba912fe8b815fe2eb8edcbba11ed..166046678203ce4c9ea245296a234d5d8eeb0c6f 100644 (file)
@@ -3,7 +3,9 @@ Flash Encryption
 
 Flash Encryption is a feature for encrypting the contents of the ESP32's attached SPI flash. When flash encryption is enabled, physical readout of the SPI flash is not sufficient to recover most flash contents.
 
-Flash Encryption is separate from the :doc:`Secure Boot <secure-boot>` feature, and you can use flash encryption without enabling secure boot. However, for a secure environment both should be used simultaneously. In absence of secure boot, additional configuration needs to be performed to ensure effectiveness of flash encryption. See :ref:`flash-encryption-without-secure-boot` for more details.
+Flash Encryption is separate from the :doc:`Secure Boot <secure-boot>` feature, and you can use flash encryption without enabling secure boot. However, **for a secure environment both should be used simultaneously**.
+
+When using any non-default configuration in production, additional steps may also be needed to ensure effectiveness of flash encryption. See :ref:`securing-flash-encryption` for more details.
 
 .. important::
   Enabling flash encryption limits your options for further updates of your ESP32. Make sure to read this document (including :ref:`flash-encryption-limitations`) and understand the implications of enabling flash encryption.
@@ -37,6 +39,23 @@ Background
 
 - If flash encryption may be enabled, the programmer must take certain precautions when writing code that :ref:`uses encrypted flash <using-encrypted-flash>`.
 
+.. _storing-encrypted-data:
+
+Storing Encrypted Data
+----------------------
+
+Aside from encrypting the firmware binary, the app may need to store some sensitive data in an encrypted form. For example, in a filesystem or NVS data partition.
+
+The recommended way to do this is to use :ref:`nvs_encryption` .
+
+Alternatively, it is possible to use the :doc:`Wear Levelling feature </api-reference/storage/wear-levelling>` with an encrypted partition, if the "encrypted" flag is set on the partition. This allows, for example, a FATFS partition to be stored encrypted in flash.
+
+The following are **not suitable** and will store data where an attacker with physical access can read it out:
+
+- Custom efuse fields (these can be write protected against modification but not read protected if the app needs to read them)
+- SPIFFS (SPIFFS is optimized for the read and write behavior of NOR flash, so it's not possible to encrypt this filesystem)
+
+
 .. _flash-encryption-initialisation:
 
 Flash Encryption Initialisation
@@ -172,15 +191,7 @@ Serial Re-Flashing Procedure
 
 - Reset the device and it will re-encrypt plaintext partitions, then burn the :ref:`FLASH_CRYPT_CNT` again to re-enable encryption.
 
-
-Disabling Serial Updates
-~~~~~~~~~~~~~~~~~~~~~~~~
-
-To prevent further plaintext updates via serial, use espefuse.py to write protect the :ref:`FLASH_CRYPT_CNT` after flash encryption has been enabled (ie after first boot is complete)::
-
-    espefuse.py --port PORT write_protect_efuse FLASH_CRYPT_CNT
-
-This prevents any further modifications to disable or re-enable flash encryption.
+To prevent any further serial updates, see :ref:`securing-flash-encryption`.
 
 .. _pregenerated-flash-encryption-key:
 
@@ -269,7 +280,7 @@ Limitations of Flash Encryption
 
 Flash Encryption prevents plaintext readout of the encrypted flash, to protect firmware against unauthorised readout and modification. It is important to understand the limitations of the flash encryption system:
 
-- Flash encryption is only as strong as the key. For this reason, we recommend keys are generated on the device during first boot (default behaviour). If generating keys off-device (see :ref:`pregenerated-flash-encryption-key`), ensure proper procedure is followed.
+- Flash encryption is only as strong as the key. For this reason, we recommend keys are generated on the device during first boot (default behavior). If generating keys off-device (see :ref:`pregenerated-flash-encryption-key`), ensure proper procedure is followed.
 
 - Not all data is stored encrypted. If storing data on flash, check if the method you are using (library, API, etc.) supports flash encryption.
 
@@ -291,15 +302,24 @@ It is recommended to use flash encryption and secure boot together. However, if
 - :ref:`pregenerated-flash-encryption-key` is still possible, provided the bootloader is not reflashed. Reflashing the bootloader requires the same :ref:`Reflashable <CONFIG_SECURE_BOOTLOADER_MODE>` option to be enabled in the Secure Boot config.
 
 .. _flash-encryption-without-secure-boot:
+.. _securing-flash-encryption:
+
+Securing Flash Encryption
+-------------------------
+
+In a production setting it's important to ensure that flash encryption cannot be temporarily disabled.
+
+This is because if the :doc:`secure-boot` feature is not enabled, or if Secure Boot is somehow bypassed by an attacker, then unauthorised code can be written to flash in plaintext. This code can then re-enable encryption and access encrypted data, making flash encryption ineffective.
+
+This problem must be avoided by write-protecting :ref:`FLASH_CRYPT_CNT` and thereby keeping flash encryption permanently enabled.
 
-Using Flash Encryption without Secure Boot
-------------------------------------------
+The simplest way to do this is to enable the configuration option :ref:`CONFIG_FLASH_ENCRYPTION_DISABLE_PLAINTEXT` (enabled by default if Secure Boot is enabled). This option causes :ref:`FLASH_CRYPT_CNT` to be write protected during initial app startup, or during first boot when the bootloader enables flash encryption. This includes if an app with this option is OTA updated.
 
-If flash encryption is used without secure boot, it is possible to load unauthorised code using serial re-flashing. See :ref:`updating-encrypted-flash-serial` for details. This unauthorised code can then read all encrypted partitions (in decrypted form) making flash-encryption ineffective. This can be avoided by write-protecting :ref:`FLASH_CRYPT_CNT` and thereby disallowing serial re-flashing. :ref:`FLASH_CRYPT_CNT` can be write-protected using command::
+Alternatively, :ref:`FLASH_CRYPT_CNT` can be write-protected using the serial bootloader::
 
   espefuse.py --port PORT write_protect_efuse FLASH_CRYPT_CNT
 
-Alternatively, the app can call :func:`esp_flash_write_protect_crypt_cnt` during its startup process.
+A third option with more flexibility: the app can call :func:`esp_flash_write_protect_crypt_cnt` at a convenient time during its startup or provisioning process.
 
 .. _flash-encryption-advanced-features: