1.编译 bootloader image 时发现 menuconfig 中使能了 secure boot,于是根据 menuconfig 中指定的公钥/秘钥文件路径将公钥编译到 bootloader image 中,bootloader 被编译成支持 secure boot
2.编译 partition table 和 app images 时使用秘钥计算出签名,将签名编译到相应的二进制文件中
3.芯片第一次 boot 时,软件 bootloader 根据以下步骤使能 secure boot:
4.芯片在后面的 boot 中,ROM bootloader 发现 efuse 中的 ABS_DONE_0 被烧写,于是从 flash 的地址 0x0 读取第一次 boot 时保存的 secure digest 和随机数 IV,硬件使用 efuse 中的 secure boot key 、随机数 IV 与当前的 bootloader image 计算当前的 secure digest,若与 flash 中的 secure digest 不同,则 boot 不会继续,否则就执行软件 bootloader。
5.软件 bootloader 使用 bootloader image 中保存的公钥对 flash 中的 partition table 和 app images 签字进行验证,验证成功之后才会 boot 到 app 代码中
使用步骤:
1.make menuconfig 中选择 “secure bootloader mode”->”Reflashable”
2.按“使用步骤”一节步骤2和3生成公钥与秘钥
3.运行指令 “make bootloader” ,一个 256-bit secure boot key 会根据用于签名的私钥计算出,命令行会打印两个后续步骤,按循序执行:
4.从“使用步骤”一节的步骤6继续执行
串口重烧 flash 过程
1.make menuconfig 中选择 “Security features”->”Enable flash encryption on boot”
2.编译工程,将所有之前加密的 images (包括 bootloader)烧写到 flash 中
3.在 esp-idf 的 components/esptool_py/esptool 路径下使用命令 espefuse.py burn_efuse FLASH_CRYPT_CNT 烧写 efuse 中的 FLASH_CRYPT_CNT
4.重启设备,bootloader 根据 FLASH_CRYPT_CNT 的值重新加密 flash 数据
若用户确定不再需要通过串口重烧 flash,可以在 esp-idf 的 components/esptool_py/esptool 路径下使用命令 espefuse.py –port PORT write_protect_efuse FLASH_CRYPT_CNT 将 FLASH_CRYPT_CNT 设置为读写保护(注意此步骤必须在 bootloader 已经完成对 flash 加密后进行)
FLASH_CRYPT_CNT 的变化过程:
1.没有使能 flash 加密时,永远是0
2.使能了 flash 加密,在第一次 boot 时 bootloader 发现它的值是 0x00,于是知道 flash 中的数据还未加密,利用硬件随机数生成器产生 key,然后加密 flash,最后将它的最低位置1(取值为0x01)
3.后续 boot 时,bootloader 发现它的值是 0x01,知道 flash 中的数据已加密,可以解密后直接使用
4.用户需要串口重烧 flash ,于是使用命令行手动烧写 FLASH_CRYPT_CNT,此时2个 bit 被置为 1(取值为0x03)
5.重启设备,bootloader 发现 FLASH_CRYPT_CNT 的值是 0x03(2 bit 1),于是重新加密 flash 数据,加密完成后 bootloader 将 FLASH_CRYPT_CNT 烧写为0x07(3 bit 1),flash 加密正常使用
6.用户需要串口重烧 flash ,于是使用命令行手动烧写 FLASH_CRYPT_CNT,此时4个 bit 被置为 1(取值为0x0f)
7.重启设备,bootloader 发现 FLASH_CRYPT_CNT 的值是 0x0f(4 bit 1),于是重新加密 flash 数据,加密完成后 bootloader 将 FLASH_CRYPT_CNT 烧写为0x1f(5 bit 1),flash 加密正常使用
8.用户需要串口重烧 flash ,于是使用命令行手动烧写 FLASH_CRYPT_CNT,此时6个 bit 被置为 1(取值为0x3f)
9.重启设备,bootloader 发现 FLASH_CRYPT_CNT 的值是 0x4f(6 bit 1),于是重新加密 flash 数据,加密完成后 bootloader 将 FLASH_CRYPT_CNT 烧写为0x7f(7 bit 1),flash 加密正常使用
10.注意!此时不能再使用命令行烧写 FLASH_CRYPT_CNT,bootloader 读到 FLASH_CRYPT_CNT 为 0xff(8 bit 1)时,会停止后续的 boot。
第一次 boot 时 secure boot 与 flash encrypt 的生效过程如下图所示,图中蓝色框是 secure boot 的步骤,绿色框是 flash encrypt 的步骤
后续 boot 时流程图如下,图中绿色框中的步骤会执行解密,解密是由硬件自动完成的
ITEM |
Function | default |
---|---|---|
debug_enable | 是否开启debug模式,在debug模式下,工具会根据pem文件产生相同密钥,否则随机生成密钥 | True |
debug_pem_path | 设置证书地址,用于生成可重复烧写的密钥,尽在debug模式下有效 | |
SECURE BOOT |
||
secure_boot_en | 开启secure boot功能 | False |
burn_secure_boot_key | 使能secure boot key烧写 | False |
secure_boot_force_write | 是否不检查secure boot key block,强制烧写key | False |
secure_boot_rw_protect | 开启secure boot key区域的读写保护 | False |
FLASH ENCRYPTION |
||
flash_encryption_en | 开启flash加密功能 | False |
burn_flash_encryption_key | 使能flash encrypt key烧写 | False |
flash_encrypt_force_write | 是否不检查flash encrypt key block,强制烧写key | False |
flash_encrypt_rw_protect | 开启flash encrypt key区域的读写保护 | False |
AES KEY |
Not used yet | |
DISABLE FUNC |
||
jtag_disable | 是否关闭JTAG调试功能 | False |
dl_encrypt_disable | 是否关闭下载模式下flash加密功能 | False |
dl_decrypt_disable | 是否关闭下载模式下flash解密功能 | False |
dl_cache_disable | 是否关闭下载模式下的flash cache功能 | False |
安装eptool
也可以通过python安装:
pip install esptool
或者
pip3 install esptool
优势
: 可以批量进行flash烧录,初始化的固件相同,密钥在第一次上电有在设备内随机生成。缺陷
: 设备在首次初始化过程所用时间较长,如果在首次初始化过程发生掉电等意外情况,设备可能无法正常启动。1.随机生成RSA密钥文件:
$ espsecure.py generate_signing_key secure_boot_signing_key.pem
or
$ openssl ecparam -name prime256v1 -genkey -noout -out secure_boot_signing_key.pem
2.在menuconfig中,选择Sign binaries during build, 并指定刚才生成的密钥路径, 如下图。
3.分别编译bootloader与应用代码
$ make bootloader
$ make
4.使用 esptool 将编译生成的bin文件写入flash对应地址, 以example中hellow-world工程为例:
bootloader.bin --> 0x1000
partition.bin --> 0x8000
app.bin --> 0x10000
python $IDF_PATH/components/esptool_py/esptool/esptool.py --chip esp32 --port /dev/cu.SLAB_USBtoUART --baud 1152000 --before default_reset --after no_reset write_flash -z --flash_mode dio --flash_freq 40m --flash_size detect 0x1000 $IDS_PATH/esp-idf/examples/get-started/hello_world/build/bootloader/bootloader.bin 0xf000 $IDF_PATH/esp-idf/examples/get-started/hello_world/build/phy_init_data.bin 0x10000 $IDF_PATH/examples/get-started/hello_world/build/hello-world.bin 0x8000 $IDF_PATH/examples/get-started/hello_world/build/partitions_singleapp.bin
以上命令仅是示例代码,请在使用时,替换其中的文件路径以及所选参数,包括串口、波特率、SPI模式和频率等。
5.我们也可以使用window平台的下载工具来完成工厂下载。需要在配置文件中,关闭工具的security功能,这样工具端就不会操作security相关特性,完全由硬件和bootloader来完成初始化:
[SECURE BOOT]
secure_boot_en = False
[FLASH ENCRYPTION]
flash_encryption_en = False
注意:
修改并保存参数前,请先关闭下载工具,配置文件修改完成并保存后,再开启运行下载工具。
6.或者我们可以通过下载工具的combine功能,将多个bin文件打包为一个文件,再由工厂flash烧录器烧录进flash进行批量生产。
7.下载完成后,需要运行一次程序,使bootloader完成security相关特性的初始化,包括AES密钥的随机生成并写入EFUSE,以及对明文的flash进行首次加密。
请误在首次启动完成前,将芯片断电,以免造成芯片无法启动的情况。
注意事项
: 优势
: 工具进行密钥的随机生成,直接将 image 密文烧写进flash,然后配置efuse. 避免过程中掉电造成无法启动的情况。缺陷
: 每个设备必须通过下载工具进行烧写,因为密钥不同,无法预先烧写相同的固件到flash中。1.随机生成RSA密钥文件,用于签名固件:
$ espsecure.py generate_signing_key secure_boot_signing_key.pem
or
$ openssl ecparam -name prime256v1 -genkey -noout -out secure_boot_signing_key.pem
2.在menuconfig中,选择Sign binaries during build, 并指定刚才生成的密钥路径, 如下图。
3.分别编译bootloader与应用代码
$ make bootloader
$ make
4.设置下载工具的安全配置文件
[DEBUG MODE]
debug_enable = False #关闭debug模式,工具随机生成密钥。否则根据pem文件产生相同密钥
debug_pem_path = #debug模式下,设置证书地址,用于生成可重复烧写的密钥
[SECURE BOOT]
secure_boot_en = True #开启secure boot功能
burn_secure_boot_key = True #使能secure boot key烧写
secure_boot_force_write = False #是否不检查secure boot key block,强制烧写key
secure_boot_rw_protect = True #开启secure boot key区域的读写保护
[FLASH ENCRYPTION]
flash_encryption_en = True #开启flash加密功能
burn_flash_encryption_key = True #使能flash encrypt key烧写
flash_encrypt_force_write = False #是否不检查flash encrypt key block,强制烧写key
flash_encrypt_rw_protect = True #开启flash encrypt key区域的读写保护
[AES KEY]
aes_key_en = False #目前未实现,仅保留该选项
burn_aes_key = False #目前未实现,仅保留该选项
[DISABLE FUNC]
jtag_disable = True #是否关闭JTAG调试功能
dl_encrypt_disable = True #是否关闭下载模式下flash加密功能
dl_decrypt_disable = True #是否关闭下载模式下flash解密功能
dl_cache_disable = True #是否关闭下载模式下的flash cache功能
注意:
修改并保存参数前,请先关闭下载工具,配置文件修改完成并保存后,再开启运行下载工具。
5. 使用下载工具进行下载,若不希望工具修改任何配置参数(比如flash 频率和模式),请勾选‘DoNotChgBin’选项。下载工具会更具配置文件的设置,在下载过程中完成固件加密下载和密钥随机生成与烧写。
注意事项
: 1.make menuconfig 中使能 secure boot 和 flash encrypt,“Secure bootloader mode”选择“Reflashable”,并设置你的公钥/私钥.pem文件路径
2.编译 bootloader 并生成 secure boot key:
make bootloader
3.使用 key 和 bootloader 计算 带 digest 的 bootloader
python $IDF_PATH/components/esptool_py/esptool/espsecure.py digest_secure_bootloader --keyfile ./build/bootloader/secure_boot_key.bin -o ./build/bootloader/bootloader_with_digest.bin ./build/bootloader/bootloader.bin
4.编译 partition_table 与 app
make partition_table
make app
5.加密三个 bin 文件
python $IDF_PATH/components/esptool_py/esptool/espsecure.py encrypt_flash_data --keyfile flash_encrypt_key.bin --address 0x0 -o build/bootloader/bootloader_digest_encrypt.bin build/bootloader/bootloader_with_digest.bi
python $IDF_PATH/components/esptool_py/esptool/espsecure.py encrypt_flash_data --keyfile flash_encrypt_key.bin --address 0x8000 -o build/partitions_singleapp_encrypt.bin build/partitions_singleapp.bin
python $IDF_PATH/components/esptool_py/esptool/espsecure.py encrypt_flash_data --keyfile flash_encrypt_key.bin --address 0x10000 -o build/iot_encrypt.bin build/iot.bin
6.烧写三个加密后的 bin 文件
python $IDF_PATH/components/esptool_py/esptool/esptool.py --baud 1152000 write_flash 0x0 build/bootloader/bootloader_digest_encrypt.bin
python $IDF_PATH/components/esptool_py/esptool/esptool.py --baud 1152000 write_flash 0x8000 build/partitions_singleapp_encrypt.bin
python $IDF_PATH/components/esptool_py/esptool/esptool.py --baud 1152000 write_flash 0x10000 build/iot_encrypt.bin
7.将 flash_encryption_key 烧入 efuse (仅在第一次boot前烧写):
python $IDF_PATH/components/esptool_py/esptool/espefuse.py burn_key flash_encryption flash_encrypt_key.bin
8.将 secure boot key 烧入efuse(仅在第一次boot前烧写):
python $IDF_PATH/components/esptool_py/esptool/espefuse.py burn_key secure_boot ./build/bootloader/secure_boot_key.bin
9.烧写 efuse 中的控制标志(仅在第一次boot前烧写)
python $IDF_PATH/components/esptool_py/esptool/espefuse.py burn_efuse ABS_DONE_0
python $IDF_PATH/components/esptool_py/esptool/espefuse.py burn_efuse FLASH_CRYPT_CNT
python $IDF_PATH/components/esptool_py/esptool/espefuse.py burn_efuse FLASH_CRYPT_CONFIG 0xf
python $IDF_PATH/components/esptool_py/esptool/espefuse.py burn_efuse DISABLE_DL_ENCRYPT
python $IDF_PATH/components/esptool_py/esptool/espefuse.py burn_efuse DISABLE_DL_DECRYPT
python $IDF_PATH/components/esptool_py/esptool/espefuse.py burn_efuse DISABLE_DL_CACHE