secureboot实现加密spl + 加密kernel+验签根文件系统
一 安全启动说明
- CPU 启动的时验证 SPL 的的签名,保证代码没有更改过。 利⽤ RSA 的⾮对称加解特性, 私钥加密, 只有公钥可以解密. 把 SPL 的 HASH 值加密, 在启动的时候验通过公钥解密,检校 HASH 是否正确. 这样只有有私钥的才能使⽤, 防⽌代码发⽣变化.
- CPU启动时候使⽤ USERKEY 解密(可选) 代码段可以通过 AES 加密. 启动过程中⽤ AES 解密, 保证⽤⼾的代码是加密的, 防⽌泄露. AES 的秘钥要与 CPU 内部烧录的秘钥相同.
- CPU 启动时候使⽤ CHIPKEY 解密(可选) 代码是通过 CPU 的⾃⾝的 CHIPKEY 解密的, 每个CPU的 CHIPKEY 是不同的, ⽽通过这个 KEY 加密的 Firmware 也是不同的, 保证了 FLASH ⾥⾯的代码是⽆法 COPY 的
CPU 内部保存了3个 KEY:
- RSA的公钥签名, 保证公钥是和⽤⼾的私钥对应.
- USERKEY, 保证⽤⼾使⽤ OTA 时代码是加密的.
- CHIPKEY, 保证每个 CPU 的KEY是不同的.
这三个 KEY 是保存 CPU 内部 EFUSE 中, 在⾮安全核不可读取, 对外不开放. 在使⽤安全 BOOT 前需要烧录, 并打开security功能的BIT位.
具体加密流程如下:
对于 rootfs,采用只签名,不加密的方式
二 软硬件环境说明
⽀持X1600、X2000、X2600系列CPU,已在Darwin(x2000),Halley6(x1600e),VAST(x2600e),RD_AD100_EVB_V1.0开发板验证.
2.1 硬件环境说明
需要有对 efuse 使能的电路.
此处注意x2000及x1600e电路外接io及默认使能电平需要与烧录工具efuse设置匹配. io不对会导致烧录不进去,电平不匹配会导致芯片可能烧坏.RD_AD100_EVB_V1.0开发板需要对efuse使能的电路进行飞线处理,默认是拉低
x2600不需要.
2.2 软件环境说明
以RD_AD100_EVB_V1.0 开发板为例
主配置文件:ad100_evb_v10_nor_quickstart_5.10_defconfig
uboot配置和kernel配置如下:
需修改 uboot 工程中的文件,使用配置为 ad100_evb_v10_nor_quickstart_5.10_defconfig
kenny@kenny-MS-7B89:~/source/linux_ad100_source/build$ grep -nr "uboot" configs/ad100_evb_v10_nor_quickstart_5.10_defconfig
3:APP_uboot_toolchain_dir=../tools/toolchains/mips-gcc720-glibc229
4:APP_uboot_dir=../bootloader/uboot-x2000
5:APP_uboot_config=ad100_uImage_quickstart_sfc_nor //uboot配置(使用rtos启动kernel的配置)
查找/Linux工程目录/bootloader/uboot-x2000/boards.cfg内的ad100_uImage_quickstart_sfc_nor
ad100_uImage_quickstart_sfc_nor mips xburst2 ad100_base ingenic ad100 ad100_base:AD100N_DDR,SPL_SFC_NOR,ENV_IS_IN_SFC,MTD_SFCNOR,SPL_PARAMS_FIXER,SPL_OS_BOOT,NOR_SPL_BOOT_OS,RMEM_MB=16,RTOS_SIZE_MB=4,QUICK_START,LPJ="11935744"
可以看到uboot使用的为ad100_base, 位于bootloader/uboot-x2000/include/configs下的ad100_base.h文件, 改动后内容如下:
#ifndef __AD100_BASE_H__
#define __AD100_BASE_H__
#define CONFIG_ROOTFS_SQUASHFS
#define CONFIG_ROOTFS2_SQUASHFS
#define CONFIG_ARG_QUIET
//#define CONFIG_SPL_SERIAL_SUPPORT //#define CONFIG_SPL_SERIAL_SUPPORT 需要删除,不然编译会编译不过
/* 添加以下 3 个宏 */
#define CONFIG_SPL_RTOS_LOAD_KERNEL
#define CONFIG_JZ_SCBOOT
#define CONFIG_JZ_SECURE_SUPPORT
#include "ad100_base_common.h"
#ifdef CONFIG_AD_SLT
#include "ad100_slt_common.h"
#endif
#endif /* __AD100_BASE_H__ */
kernel 编译配置文件
kenny@kenny-MS-7B89:~/source/linux_ad100_source/build$ grep -nr "kernel" configs/ad100_evb_v10_nor_quickstart_5.10_defconfig
6:APP_kernel_dir=../kernel/kernel
7:APP_kernel_config=ad100_module_base_linux_sfc_quickstart_nor_defconfig //kernel 配置
9:APP_kernel_uImage=y //kernel 镜像类型选择 uImage
10:# APP_kernel_uImage_split is not set
11:# APP_kernel_dtb is not set
kernel 镜像类型,选择uImage
编译linux固件命令:
kenny@kenny-MS-7B89:~/source/linux_source_ingenic/build$ make clean;make x2600e_nand_5.10_defconfig;make
RTOS系统配置文件
本文默认使用的nor,nand也可以支持, 但是对于 nor 介质来说,rtos 能挂载文件系统,但是 rtos 和 linux 的文件系统格式要不一样,如果在 rtos 挂载文件系统,会破坏 linux 文件系统的分区(需在 rtos 的 iconfig 中取消掉文件系统勾选)
主配置文件为: ad100_evb_v10_quick_start_nor_defconfig
这里的支持fat文件系统不能勾选
由于设置rtos的加载地址为内存的后半段,不与kernel的固件地址重合,所以这里的固件加载地址设置为 0x82000000
勾选 secure boot驱动
选择zlib compression
修改vendor.c内容如下:
kenny@kenny-MS-7B89:~/source/freertos_source/freertos$ cat vendor/vendor.c
#include <stdio.h>
#include "../example/driver/quick_boot_logo_and_load_uimage_example.c"
void vendor_init(void *arg)
{
printf("vendor init...\n");
quick_boot_logo_and_load_kernel(arg);
}
kenny@kenny-MS-7B89:~/source/freertos_source/freertos$ cat example/driver/quick_boot_logo_and_load_uimage_example.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <common.h>
#include <os.h>
#include <driver/cache.h>
#include <driver/scboot.h>
#include <uboot_lib.h>
#include <be_byteshift.h>
//添加该宏,表示会验签文件系统rootfs,如果不需要验签rootfs,就不需要定义这个宏
#define CONFIG_SECURE_ROOTFS
编译rtos系统
kenny@kenny-MS-7B89:~/source/freertos_source/freertos$ source build/envsetup.sh;make ad100_evb_v10_quick_start_nor_defconfig;make
三 签名和加密
注:本文档描述的功能只适用于 cloner-2.5.47-ubuntu_alpha/windows_alpha 以上的烧录工具
x1600、x2000、x2600使用的工具一样,都在securitytool/x2000目录下
3.1 生成秘钥
生成秘钥的工具在烧录工具目录的 securitytool/x2000/keytool/
下:
kenny@kenny-MS-7B89:~/source/linux_ad100_source/jp/cloner-2.5.47-ubuntu_alpha/securitytool/x2000/keytool$ ls
keygen-32 keygen-64 qm_cn.qm
其中 keygen-32 对于 32 位 pc,keygen-64 对应 64 位 pc
运行:sudo./keygen-64
点击 Generate Key 后就会在当前路径下生成秘钥,也可以点击 Path 选择生成的路径。
如下会生成 key.bin,pri_key.pem ,user_key.bin
kenny@kenny-MS-7B89:~/source/linux_ad100_source/jp/cloner-2.5.47-ubuntu_alpha/securitytool/x2000/keytool$ ls
keygen-32 keygen-64 key.bin pri_key.pem user_key.bin qm_cn.qm
将秘钥拷贝到烧录工具的对应位置
将 key.bin 拷贝到烧录工具
security/x2000/
下:kenny@kenny-MS-7B89:~/source/linux_ad100_source/jp/cloner-2.5.47-ubuntu_alpha/securitytool/x2000/keytool$ cp key.bin ../../../security/x2000/ -arf
将 pri_key.pem 和 user_key.bin 拷贝到烧录工具的
securitytool/x2000/sigtool/security_key
下:kenny@kenny-MS-7B89:~/source/linux_ad100_source/jp/cloner-2.5.47-ubuntu_alpha/securitytool/x2000/keytool$ sudo cp pri_key.pem ../sigtool/security_key/ -arf
kenny@kenny-MS-7B89:~/source/linux_ad100_source/jp/cloner-2.5.47-ubuntu_alpha/securitytool/x2000/keytool$ sudo cp user_key.bin ../sigtool/security_key/ -arf
3.2 签名和加密的工具
签名工具在烧录工具目录的 securitytool/x2000/sigtool/
下:
kenny@kenny-MS-7B89:~/source/linux_ad100_source/jp/cloner-2.5.47-ubuntu_alpha/securitytool/x2000/sigtool$ ls
rsa.txt security_key setting.ini settings.ini sigtool-32 sigtool-64 sigtool.exe
其中 sigtool-32、sigtool-64、sigtool.exe 为对应 pc 下使用的工具
创建文件settings.ini , 写入内容
[debug]
value=1
运行:sudo ./sigtool-64
其中 AES 选上为启用加密功能,不选为只签名。
3.3 签名和加密
在对镜像进⾏加密之前, 先烧录⼀次未加密过的镜像, 待spl能加载kernel, kernel挂载⽂件系统, ⽂件系统起来后,确定镜像可⽤即可进⾏签名镜像操作
3.3.1 burn bin (烧录工具固件加密)
3.3.2 spl bin
操作如图:
选择好后点击 sign,就会在对应的目录下生成加密后的文件,对于上面的文件就会生成 u-boot-spl-pad-dst.bin
,等会烧录 spl 时要选择这个文件
3.3.2 kernel bin
操作如图:
选择好后点击 sign,就会在对应的目录下生成加密后的文件,对于上面的文件就会生成 uImage-dst.bin
3.3.3 rootfs
对于 rootfs ,采用不加密,只签名. 具体操作如下:
选择好后点击 sign,就会在对应的目录下生成加密后的文件,对于上面的文件就会生成 rootfs-dst.squashfs
,然后使用 dd 命令分离出签名信息(等会需要将该签名信息烧录到 flash 中):
dd if=rootfs-dst.squashfs of=signature bs=2048 count=1
如图,signature 就是签名信息,等会需要烧录这个文件:
kenny@kenny-MS-7B89:~/source/linux_source_ingenic/build/output$ dd if=rootfs-dst.squashfs of=signature bs=2048 count=1
记录了1+0 的读入
记录了1+0 的写出
2048字节(2.0 kB,2.0 KiB)已复制,0.000144619 s,14.2 MB/s
kenny@kenny-MS-7B89:~/source/linux_source_ingenic/build/output$ ls
rootfs-dst.squashfs rootfs.squashfs signature u-boot-spl-pad.bin u-boot-spl-pad-dst.bin uImage uImage-dst.bin
对uImage-dst.bin 和 文件系统的签名信息进行合并,方便验签文件系统
cat uImage-dst.bin signature > uImage-dst-with-rootfs-sig.bin
到时烧录工具烧录的时候,选择uImage-dst-with-rootfs-sig.bin,到时烧录工具烧录kernel选择这个文件
3.3.4 rtos bin
操作如下:
选择好后点击 sign,就会在对应的目录下生成加密后的文件,对于上面的文件就会生成 zero-dst.bin
,等会烧录 rtos 时要选择这个文件
四 烧录
本文档使用 cloner-2.5.47-ubuntu_alpha 烧录工具:
4.1 选择配置文件
4.2 分区配置
4.3 启用安全烧录
RD_AD100_EVB_V1.0开发板,EFUSE使能引脚,默认是拉低的,需要硬件上手动拉高一下。
4.4 选择烧录文件
五 问题汇总
1. 烧录到boot 40%变红
可能是cpu烧坏了, 需要重新更换cpu.
efuse烧录有严格的供电要求, 写⼊efuse时, 给efuse的供电时间不能超过200ms, ⼀旦超过200ms就会烧坏efuse, 导致整个芯⽚不能正常使⽤, 此时就需要更换主控芯⽚了
2 烧录到boot 90% SEND KU ERR 变红
直接表现是烧录⼯具烧录之前解码固件失败, 根本原因应该是efuse因为某些原因没有写⼊成功.
此时应当检查efuse的供电及使能电平, 确保硬件设计和烧录⼯具设置的⼀致. 排除此处原因后, 重新烧录可以成功的.
3 换其他烧录⼯具烧录后系统⽆法启动
由于efuse中数据位跳变是不可逆的, 所以⼀定要保证⽤此加密烧录后的系统再次更新还是使⽤同样的烧录⼯具和密钥来完成的. 如果使⽤新的烧录⼯具烧录了其他的密钥, 那么再⽤原先的烧录⼯具也⽆法再次烧录正确的密钥了, 引起系统可能再也启动不了了. 到此步, 只能更换主控芯⽚才能再次使⽤了.
六 系统解密流程
对应log
# [0.000086] gpio: VDDIO_SD(PD00~PD05) = 3.3V
[0.000253] pwm clk rate 400000000
[0.002041] lcd_mem left 0x7b000 bytes
[0.002435] sfc_nor: find chip:GD25Q256DYIG id:0xc84019
[0.003584] vendor init...
[0.081379] Security boot... //验签kernel+解密kernel
[0.746105] Security boot... //验签文件系统
[ 0.000000] Linux version 5.10.186+ (kenny@kenny-MS-7B89) (mips-linux-gnu-gcc (Ingenic Linux-Release5.1.9.sr02-Default_xburst2_glibc2.29 Fix: uclibc0.9.33.2 e6b2efb7a460ae93975997edb4fb1658230c5bec 2023.12-21 04:08:14) 7.2.0, GNU ld (Ingenic Linux-Release5.1.9.sr02-Default_xburst2_glibc2.29 Fix: uclibc0.9.33.2 e6b2efb7a460ae93975997edb4fb1658230c5bec 2023.12-21 04:08:14) 2.27) #36 SMP PREEMPT Wed Aug 14 15:56:36 CST 2024
[ 0.000000] CPU0 RESET ERROR PC:80019EF8
[ 0.000000] [<80019ef8>] 0x80019ef8
[ 0.000000] printk: bootconsole [early0] enabled
[ 0.000000] CPU0 revision is: 00132000 (Ingenic XBurst II)
[ 0.000000] FPU revision is: 00f32000
[ 0.000000] MSA revision is: 00002000
[ 0.000000] OF: fdt: No chosen node found, continuing without
[ 0.000000] MIPS: machine is ingenic,ad100
[ 0.000000] [<80019ef8>] 0x80019ef8
[ 0.000000] ingenic-dma 13660000.dma: IRQ pdmam not found
[ 0.000000] ingenic-dma 13420000.dma: IRQ pdmam not found
[ 0.020727] s2d successfully!-----0
[ 0.029566] mtd: partition "userdata" is out of reach -- disabled
mount: mounting devpts on /dev/pts failed: No such device
Starting mdev... OK
[ 0.896950] md_ingenic,sdhci md_ingenic,sdhci.1: card insert manually
/
[ 0.939183] Too few erase blocks (0)
mount: mounting /dev/mtdblock4 on /usr/data/ failed: Invalid argument
mount jffs2 error, try mount again
Floating point exception
[ 0.949119] Too few erase blocks (0)
mount: mounting /dev/mtdblock4 on /usr/data/ failed: Invalid argument
mount jffs2 error again
Starting system message bus: done
Starting bluetoothd: OK
Starting network: OK
rmem_extra: mem 62914560, size 4194304
# [Warn] (0.000, +0) lv_demo_widgets: LV_FONT_MONTSERRAT_24 is not enabled for the widgets demo. Using LV_FONT_DEFAULT instead. (in lv_demo_widgets.c line #114)
[Warn] (0.000, +0) lv_demo_widgets: LV_FONT_MONTSERRAT_16 is not enabled for the widgets demo. Using LV_FONT_DEFAULT instead. (in lv_demo_widgets.c line #119)