]> granicus.if.org Git - esp-idf/commitdiff
bootloader: Refactor secure boot digest generation
authorAngus Gratton <angus@espressif.com>
Tue, 25 Oct 2016 03:55:35 +0000 (14:55 +1100)
committerAngus Gratton <angus@espressif.com>
Tue, 1 Nov 2016 23:41:59 +0000 (10:41 +1100)
components/bootloader/src/main/bootloader_config.h
components/bootloader/src/main/bootloader_start.c
components/bootloader/src/main/secure_boot.c

index 8a837693c27406f77159852d00228b3dc93d355d..1655280dc7c14d22c31bb8afd21b741f81ce0462 100644 (file)
@@ -36,7 +36,6 @@ extern "C"
 #define RTC_DATA_LOW  0x50000000
 #define RTC_DATA_HIGH 0x50002000
 
-
 #define PART_TYPE_APP 0x00
 #define PART_SUBTYPE_FACTORY  0x00
 #define PART_SUBTYPE_OTA_FLAG 0x10
@@ -66,8 +65,7 @@ void boot_cache_redirect( uint32_t pos, size_t size );
 uint32_t get_bin_len(uint32_t pos);
 
 bool flash_encrypt(bootloader_state_t *bs);
-bool secure_boot(void);
-
+bool secure_boot_generate_bootloader_digest(void);
 
 #ifdef __cplusplus
 }
index 5b1e152070069465b79c35a9dade563d8ba51a67..a4b27702c4672965a62c49d8949bd7e6aca62b58 100644 (file)
@@ -256,6 +256,7 @@ void bootloader_main()
     bootloader_state_t bs;
     SpiFlashOpResult spiRet1,spiRet2;    
     esp_ota_select_entry_t sa,sb;
+
     memset(&bs, 0, sizeof(bs));
 
     ESP_LOGI(TAG, "compile time " __TIME__ );
@@ -329,16 +330,20 @@ void bootloader_main()
     }
 
     ESP_LOGI(TAG, "Loading app partition at offset %08x", load_part_pos);
+
     if(fhdr.secure_boot_flag == 0x01) {
-        /* protect the 2nd_boot  */    
-        if(false == secure_boot()){
-            ESP_LOGE(TAG, "secure boot failed");
-            return;
+        /* Generate secure digest from this bootloader to protect future
+         modifications */
+        if (secure_boot_generate_bootloader_digest() == false){
+            ESP_LOGE(TAG, "Bootloader digest generation failed. SECURE BOOT IS NOT ENABLED.");
+            /* Allow booting to continue, as the failure is probably
+               due to user-configured EFUSEs for testing...
+            */
         }
     }
 
     if(fhdr.encrypt_flag == 0x01) {
-        /* encrypt flash */            
+        /* encrypt flash */
         if (false == flash_encrypt(&bs)) {
            ESP_LOGE(TAG, "flash encrypt failed");
            return;
index 3dfdbd1412ea75eb318fd6e2d48300ff623bb3d6..9247f2cbd96f2c84bde3994a5780a85ab333495f 100644 (file)
@@ -40,7 +40,7 @@ static const char* TAG = "secure_boot";
  *
  *  @inputs:        bool
  */
-bool secure_boot_generate(uint32_t bin_len){
+static bool secure_boot_generate(uint32_t bin_len){
        SpiFlashOpResult spiRet;
        uint16_t i;
        uint32_t buf[32];
@@ -87,41 +87,112 @@ bool secure_boot_generate(uint32_t bin_len){
        return true;
 }
 
+/* Burn values written to the efuse write registers */
+static inline void burn_efuses()
+{
+    REG_WRITE(EFUSE_CONF_REG, 0x5A5A);  /* efuse_pgm_op_ena, force no rd/wr disable */
+    REG_WRITE(EFUSE_CMD_REG,  0x02);    /* efuse_pgm_cmd */
+    while (REG_READ(EFUSE_CMD_REG));    /* wait for efuse_pagm_cmd=0 */
+    REG_WRITE(EFUSE_CONF_REG, 0x5AA5);  /* efuse_read_op_ena, release force */
+    REG_WRITE(EFUSE_CMD_REG,  0x01);    /* efuse_read_cmd */
+    while (REG_READ(EFUSE_CMD_REG));    /* wait for efuse_read_cmd=0 */
+}
 
 /**
- *  @function :     secure_boot
- *  @description:   protect boot code in flash
+ *  @function :     secure_boot_generate_bootloader_digest
  *
- *  @inputs:        bool
+ *  @description: Called if the secure boot flag is set on the
+ *  bootloader image in flash. If secure boot is not yet enabled for
+ *  bootloader, this will generate the secure boot digest and enable
+ *  secure boot by blowing the EFUSE_RD_ABS_DONE_0 efuse.
+ *
+ *  This function does not verify secure boot of the bootloader (the
+ *  ROM bootloader does this.)
+ *
+ *  @return true if secure boot is enabled (either was already enabled,
+ *  or is freshly enabled as a result of calling this function.)
  */
-bool secure_boot(void){ 
-       uint32_t bin_len = 0;
-       if (REG_READ(EFUSE_BLK0_RDATA6_REG) & EFUSE_RD_ABS_DONE_0)
-       {     
-               ESP_LOGD(TAG, "already secure boot !");
-               return true;
-       } else {  
-               boot_cache_redirect( 0, 64*1024);
-               bin_len = get_bin_len((uint32_t)MEM_CACHE(0x1000));
-               if (bin_len == 0) {
-                       ESP_LOGE(TAG, "boot len is error");
-                       return false;
-               }
-               if (false == secure_boot_generate(bin_len)){
-                       ESP_LOGE(TAG, "secure boot generate failed");
-                       return false;
-               }  
-       }  
-
-       REG_SET_BIT(EFUSE_BLK0_WDATA6_REG, EFUSE_RD_ABS_DONE_0); 
-       REG_WRITE(EFUSE_CONF_REG, 0x5A5A);  /* efuse_pgm_op_ena, force no rd/wr disable */     
-       REG_WRITE(EFUSE_CMD_REG,  0x02);    /* efuse_pgm_cmd */    
-       while (REG_READ(EFUSE_CMD_REG));    /* wait for efuse_pagm_cmd=0 */   
-       ESP_LOGW(TAG, "burn abstract_done_0");   
-       REG_WRITE(EFUSE_CONF_REG, 0x5AA5);  /* efuse_read_op_ena, release force */   
-       REG_WRITE(EFUSE_CMD_REG,  0x01);    /* efuse_read_cmd */     
-       while (REG_READ(EFUSE_CMD_REG));    /* wait for efuse_read_cmd=0 */       
-       ESP_LOGI(TAG, "read EFUSE_BLK0_RDATA6 %x", REG_READ(EFUSE_BLK0_RDATA6_REG)); 
-       return true;
+bool secure_boot_generate_bootloader_digest(void) {
+    uint32_t bin_len = 0;
+    if (REG_READ(EFUSE_BLK0_RDATA6_REG) & EFUSE_RD_ABS_DONE_0)
+    {
+        ESP_LOGI(TAG, "bootloader secure boot is already enabled, continuing..");
+        return true;
+    }
+
+    boot_cache_redirect( 0, 64*1024);
+    bin_len = get_bin_len((uint32_t)MEM_CACHE(0x1000));
+    if (bin_len == 0) {
+        ESP_LOGE(TAG, "Invalid bootloader image length zero.");
+        return false;
+    }
+    if (bin_len > 0x100000) {
+        ESP_LOGE(TAG, "Invalid bootloader image length %x", bin_len);
+        return false;
+    }
+
+    uint32_t dis_reg = REG_READ(EFUSE_BLK0_RDATA0_REG);
+    bool efuse_key_read_protected = dis_reg & EFUSE_RD_DIS_BLK2;
+    bool efuse_key_write_protected = dis_reg & EFUSE_WR_DIS_BLK2;
+    if (efuse_key_read_protected == false
+        && efuse_key_write_protected == false
+        && REG_READ(EFUSE_BLK2_RDATA0_REG) == 0
+        && REG_READ(EFUSE_BLK2_RDATA1_REG) == 0
+        && REG_READ(EFUSE_BLK2_RDATA2_REG) == 0
+        && REG_READ(EFUSE_BLK2_RDATA3_REG) == 0
+        && REG_READ(EFUSE_BLK2_RDATA4_REG) == 0
+        && REG_READ(EFUSE_BLK2_RDATA5_REG) == 0
+        && REG_READ(EFUSE_BLK2_RDATA6_REG) == 0
+        && REG_READ(EFUSE_BLK2_RDATA7_REG) == 0) {
+        ESP_LOGI(TAG, "Generating new secure boot key...");
+        /* reuse the secure boot IV generation function to generate
+           the key, as this generator uses the hardware RNG. */
+        uint32_t buf[32];
+        ets_secure_boot_rd_iv(buf);
+        for (int i = 0; i < 8; i++) {
+            ESP_LOGV(TAG, "EFUSE_BLK2_WDATA%d_REG = 0x%08x", i, buf[i]);
+            REG_WRITE(EFUSE_BLK2_WDATA0_REG + 4*i, buf[i]);
+        }
+        bzero(buf, sizeof(buf));
+        burn_efuses();
+        ESP_LOGI(TAG, "Read & write protecting new key...");
+        REG_WRITE(EFUSE_BLK0_WDATA0_REG, EFUSE_WR_DIS_BLK2 | EFUSE_RD_DIS_BLK2);
+        burn_efuses();
+        efuse_key_read_protected = true;
+        efuse_key_write_protected = true;
+
+    } else {
+        ESP_LOGW(TAG, "Using pre-loaded secure boot key in EFUSE block 2");
+    }
+
+    ESP_LOGI(TAG, "Generating secure boot digest...");
+    if (false == secure_boot_generate(bin_len)){
+        ESP_LOGE(TAG, "secure boot generation failed");
+        return false;
+    }
+    ESP_LOGI(TAG, "Digest generation complete.");
+
+    if (!efuse_key_read_protected) {
+        ESP_LOGE(TAG, "Pre-loaded key is not read protected. Refusing to blow secure boot efuse.");
+        return false;
+    }
+    if (!efuse_key_write_protected) {
+        ESP_LOGE(TAG, "Pre-loaded key is not write protected. Refusing to blow secure boot efuse.");
+        return false;
+    }
 
+    ESP_LOGI(TAG, "blowing secure boot efuse & disabling JTAG...");
+    ESP_LOGD(TAG, "before updating, EFUSE_BLK0_RDATA6 %x", REG_READ(EFUSE_BLK0_RDATA6_REG));
+    REG_WRITE(EFUSE_BLK0_WDATA6_REG,
+                EFUSE_RD_ABS_DONE_0 | EFUSE_RD_DISABLE_JTAG);
+    burn_efuses();
+    uint32_t after = REG_READ(EFUSE_BLK0_RDATA6_REG);
+    ESP_LOGD(TAG, "after updating, EFUSE_BLK0_RDATA6 %x", after);
+    if (after & EFUSE_RD_ABS_DONE_0) {
+        ESP_LOGI(TAG, "secure boot is now enabled for bootloader image");
+        return true;
+    } else {
+        ESP_LOGE(TAG, "secure boot not enabled for bootloader image, EFUSE_RD_ABS_DONE_0 is probably write protected!");
+        return false;
+    }
 }