X5 Customer root rsa key hash烧录及使用
只有no-secure芯片才支持烧Customer root rsa key hash,可以通过boardinfo接口查看当前芯片是否是secure芯片,以及是哪种secure芯片
在未烧key的芯片上字段”sec_chip”是”nosec_chip”
在烧了地瓜key的芯片上字段”sec_chip”是”sec_chip1”
在烧了Customer root rsa key hash的芯片上字段”sec_chip”是”sec_chip2”
介绍
本文档主要说明客户如何将Customer root rsa public key hash烧录到eFuse中,并且在之后的secure boot中,将会使用这个key验签BL2、BL2_CFG、DDR_FW、BL31、optee和Uboot。

启动流程如上图所示:
bootrom负责验证和加载BL2,bootrom使用RSA4096验证BL2。
BL2负责加载和验证BL3X的各个镜像,包括BL31,optee,DDR FW,BL2 CFG和Uboot,均使用RSA对其进行验证。
以上阶段中进行RSA4096所使用的key的hash均为eFuse中的Customer root rsa public key hash。
烧了Customer root rsa public key hash之后,会默认开启全局secure boot,对于boot和system等镜像也会校验,具体请参考Kernel & rootfs校验
Customer root rsa private key的替换
Customer root rsa private key位于
device/horizon/x5/board_cfg/soc/bl2_cfg/bl2_rot_prikey.pem
客户在使用时替换这个key即可;签名校验算法使用的是RSA 4096。可以使用下列命令生成私钥文件
# 替换Customer root private key之后请注意保护,不要泄露
openssl genrsa -out bl2_rot_prikey.pem 4096 #生成私钥
Customer root public key hash的烧录
关于eFuse的烧录请先看X5对外文档中的章节:eFuses烧录。然后再进行下面的步骤。 当前Customer root public key hash的烧录支持以下两种方式,一是通过在启动时BL2阶段通过BL2_CFG烧录,二是在Kernel 侧通过libefuse接口烧录。
BL2_CFG烧录
eFuse的配置信息位于BL2_CFG文件中,文件路径为
device/horizon/x5/board_cfg/soc/bl2_cfg/bl2_cfg.json
{
"bl2_cfg": {
...
},
"efuse_cfg": {
"bypass": 0,
"secure_boot": "false",
"secure_boot_all": "true",
"debug_disable": "false",
"burn_user_rot_key": "false",
"status_gpio" : {
"gpio_sub": "none",
"gpio_group": 0,
"gpio_num": 0
},
"nonsecure_bank": {
"bank11":["0x0"],
"bank12":["0x0"],
"bank13":["0x0"]
},
"delay_before_efuse": 0,
"delay_after_efuse": 0
},
...
}
bypass: BL2是否烧录eFuse,1表示bypass,0表示BL2将烧录eFuse
secure_boot_all:BL2是否烧录Customer root public key hash,true表示烧录,默认这个字段为空,是false
以下是烧eFuse时的启动log

以下是重启之后secure boot log,会校验以上提到的镜像
SNOTICE: Welcome to Horizon X5 ASIC BOOTROM - V4.1
...
NOTICE: Enter media_source_select process(1).
NOTICE: Get S5PK
NOTICE: [verify_signature] pass. # 校验BL2
NOTICE: [verify_hash] pass.
NOTICE: [verify_hash] pass.
NOTICE: BL1: BL2 memory layout address = 0x1fe9f000
NOTICE: BL1: Booting BL2
...
NOTICE: fip index:0
NOTICE: GET BL2 ROTPK FROM OTP
NOTICE: [verify_signature] pass. # 校验BL2_CFG
NOTICE: [verify_hash] pass.
NOTICE: [verify_signature] pass.
NOTICE: [verify_signature] pass.
NOTICE: start to load bl2 cfg image
NOTICE: [verify_hash] pass.
NOTICE: BL2 CFG ADDR:0x1ff00000, MAGIC:0x474643324c424248
...
NOTICE: disable wdt
NOTICE: GET BL2 ROTPK FROM OTP
NOTICE: [verify_signature] pass. # 校验ddr_fw
NOTICE: [verify_hash] pass.
NOTICE: [verify_signature] pass.
NOTICE: start to load ddr image
NOTICE: [verify_hash] pass.
NOTICE: run ddr Fw
...
NOTICE: ddr ready
NOTICE: GET BL2 ROTPK FROM OTP
NOTICE: [verify_signature] pass. # 校验bl31
NOTICE: [verify_hash] pass.
NOTICE: [verify_signature] pass.
NOTICE: start to load bl31 image
NOTICE: [verify_hash] pass.
NOTICE: GET BL2 ROTPK FROM OTP
NOTICE: [verify_signature] pass. # 校验optee
NOTICE: [verify_hash] pass.
NOTICE: [verify_signature] pass.
NOTICE: start to load optee image
NOTICE: [verify_hash] pass.
NOTICE: [verify_hash] pass.
NOTICE: start to load uboot image
NOTICE: [verify_hash] pass. # 校验uboot
NOTICE: BL1: Booting BL31
...
U-Boot 2022.10-ga0b1798835 (Jan 15 2025 - 21:16:27 +0800)
...
read_is_device_unlocked not supported yet
Can not find partition 'boot_a'
## Android Verified Boot 2.0 version 1.1.0
read_is_device_unlocked not supported yet
read_rollback_index not supported yet
Verification passed successfully # 校验boot
## Loading kernel from FIT Image at 90000000 ...
Using 'boardid-0xFF10' configuration
Trying 'kernel' kernel subimage
Verifying Hash Integrity ... OK
Decrypting Data ... OK
## Loading fdt from FIT Image at 90000000 ...
Using 'boardid-0xFF10' configuration
Trying 'fdt3' fdt subimage
Verifying Hash Integrity ... OK
Decrypting Data ... OK
Booting using the fdt blob at 0x909200e4
Uncompressing Kernel Image
Loading Device Tree to 0000000087fd3000, end 0000000087ffb77c ... OK
Set Mem[ion_reserved_2g] Size to 0x0000000020000000@0xa4100000
Set Mem[ion_carveout_2g] Size to 0x0000000020000000@0xc4100000
Set Mem[ion_cma_2g] Size to 0x000000000c000000@0xe4100000
enable CPU 1.8G!
Starting kernel ...
[ 0.000000] Linux version 6.1.83-DR-PL5.1_V1.0.16 (lzw@Dpx-5CD32807NR) (aarch64-none-linux-gnu-gcc (Arm GNU Toolchain 11.3.Rel1) 11.3.1 20220712, GNU ld (Arm GNU Toolchain 11.3.Rel1) 2.38.20220708) #9 SMP PREEMPT Sat Dec 28 14:36:40 CST 2024
[ 0.000000] Kernel command line: console=ttyS0,921600n8 root=/dev/dm-0 ro rootwait hobotboot.slot_suffix=_a hobotboot.reason=UBOOT_RESET hobotboot.medium=MMC hobotboot.mode=normal hobotboot.ab_switch_reason=misc-broken hobotboot.pmic_type=dual-pmic dm-mod.create="dm-verity,,,ro,0 331488 verity 1 /dev/mmcblk0p9 /dev/mmcblk0p9 4096 4096 41436 41438 sha256 c40af26e5dfece85c3daecc5a43dca9ca00cabacbcf2500f57f5d86c1e5a8260 c405f45a37da45645bb4d5fac354ef14030cfc18ee3e0eb7371349fd20d09988 2 restart_on_corruption ignore_zero_blocks" androidboot.verifiedbootstate=green
# kernel cmdline中有dm-verity,表示会校验system
...
Welcome to Buildroot
buildroot login: root
Password:
root@buildroot:~#
hbre libefuse烧录
接口头文件位于hbre/libefuse/include/drobot_efuse.h,与此功能相关的是以下4个接口
# 正式调用的接口
int drobot_efuse_update_key_hash_and_sec_boot(const char *hash_file); //烧写key hash和sec boot flag
# 调试接口
int drobot_efuse_update_key_hash(const char *hash_file); //烧写key hash
int drobot_efuse_update_sec_boot(void); //烧写sec boot flag
int drobot_efuse_dump_key_hash_and_sec_boot(uint32_t *hash_data, //dump 烧写的key hash和sec boot flag
uint32_t hash_size, uint32_t *is_sec_boot);
正式调用的接口示例
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <drobot_efuse.h>
int main(int argc, char *argv[])
{
int32_t ret = 0;
if ((argc < 2) || (strncmp(argv[1], "-h", strlen("-h") + 1) == 0) ||
(strncmp(argv[1], "--help", strlen("--help") + 1) == 0)) {
printf("usage: %s hash_file\n", argv[0]);
return -1;
}
ret = drobot_efuse_update_key_hash_and_sec_boot(argv[1]);
if (ret) {
printf("update customer root key hash failed\n");
return -1;
}
printf("update customer root key hash success\n");
return 0;
}
其中接口传入参数为root key hash文件,位于编译输出目录out/deploy/uboot/pubkey-hash.txt。按照第2章描述替换key之后,需要整编镜像,pubkey-hash.txt中的内容才会对应到新key的公钥的hash。pubkey-hash.txt中内容如下:
public key hash[0]: 0x14cbfc67
public key hash[1]: 0x66fd37ba
public key hash[2]: 0xf4a7d476
public key hash[3]: 0x65bf079e
public key hash[4]: 0x5a83a3ad
public key hash[5]: 0xa6104524
public key hash[6]: 0x00ed3137
public key hash[7]: 0x1eff5f0d
以下是成功运行时的log

重启之后可以调用drobot_efuse_dump_key_hash_and_sec_boot接口查看烧写情况
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <drobot_efuse.h>
int main(int argc, char *argv[])
{
int32_t ret = 0;
uint32_t hash_data[8] = {0};
uint32_t is_sec_boot = 0;
ret = drobot_efuse_dump_key_hash_and_sec_boot(hash_data, sizeof(hash_data), &is_sec_boot);
if (ret)
return -1;
for (uint32_t i = 0; i < 8; i++) {
printf("hash data[%d]: 0x%08x\n", i, hash_data[i]);
}
if (is_sec_boot == 1) {
printf("[secure boot all]: True\n");
} else {
printf("[secure boot all]: False\n");
}
return 0;
}
以下是成功运行时的log

调试接口示例
调试接口可以用来测试要烧写的pubkey-hash.txt文件是否与device/horizon/x5/board_cfg/soc/bl2_cfg/bl2_rot_prikey.pem对应,防止不对应而出现大量eFuse烧错的情况。
单独调用drobot_efuse_update_key_hash接口烧写hash,如果成功,重启
单独调用
drobot_efuse_dump_key_hash_and_sec_boot接口dump key_hash,与板端的pubkey-hash.txt比较,与代码目录的out/deploy/uboot/pubkey-hash.txt比较,如果一致则表示烧写正确,如果不一致,需要先检查原因。如果key hash烧错了,不要再继续以下的步骤,当前板子只能当做no-secure板子使用。此时secure boot all flag是False状态单独调用
drobot_efuse_update_sec_boot接口烧写secure boot all flag,如果成功,重启,芯片进去secure boot状态。此接口必须要在drobot_efuse_update_key_hash调用成功之后才能调用单独调用
drobot_efuse_dump_key_hash_and_sec_boot接口查询烧写情况
Dump eFuse烧录情况
除了通过libefuse中的drobot_efuse_dump_key_hash_and_sec_boot接口查看eFuse烧录情况之外,还支持在Uboot下通过命令查看。
进入Uboot命令行,使用命令efuse dump root_hash

镜像编译
完成BL2_CFG中烧eFuse的配置或开发完使用libefuse烧eFuse的应用程序之后,需要按照此章节描述编译镜像。
使用Customer root rsa private key,需要在配置文件中增加配置,编译系统才会使用这个key去签名miniboot中的相关镜像和Uboot。
以X5_EVB_debug为例,配置文件位于:
device/horizon/x5/board_x5_evb_debug_config.mk

在以上配置上需要添加
export HR_ENABLE_CUSTOMER_KEY="yes"
在 ./bd.sh lunch 中选择修改的配置,以选择 board_x5_evb_debug_config.mk 为例
$ ./bd.sh lunch
You're building on #1 SMP Fri Apr 2 22:23:49 UTC 2021
Lunch menu... pick a combo:
0. horizon/x5/board_x5_evb_debug_config.mk
1. horizon/x5/board_x5_evb_jammy_debug_config.mk
2. horizon/x5/board_x5_evb_jammy_release_config.mk
3. horizon/x5/board_x5_evb_nand_debug_config.mk
4. horizon/x5/board_x5_evb_nand_release_config.mk
5. horizon/x5/board_x5_evb_release_config.mk
6. horizon/x5/board_x5_soc_debug_config.mk
7. horizon/x5/board_x5_soc_release_config.mk
Which would you like? [0] : 0
You are selected board config: horizon/x5/board_x5_evb_debug_config.mk
之后运行命令整编即可
./bd.sh
注意
无论使用哪种方式烧eFuse,需要确保烧录之前,eFuse中的root key hash区域都是为0,secure boot all flag为False。否则,eFuse会烧录失败。

如果使用BL2_CFG烧录,根据BL2_CFG,整编镜像,然后将镜像烧到no-secure芯片板子上然后启动即可。
如果通过libefuse烧录,也是将整编出的镜像烧到no-secure芯片板子,启动之后把烧eFuse的应用程序和hash文件
out/deploy/uboot/pubkey-hash.txt推到板端,使用程序烧eFuse。