Open carloscn opened 1 year ago
您好,我按照https://docs.xilinx.com/v/u/en-US/xapp1319-zynq-usp-prog-nvm ,同时参考了这篇帖子,尝试用BBRAM Red Key来安全启动,奇怪的是,烧录key的时候显示status=0x00000000应该是成功了,但是我把加密的boot.bin放在SD卡上启动时完全没有输出。我在板卡上插入了纽扣电池,但是好像没起到作用。您有空帮我解答一下吗
您好,我按照https://docs.xilinx.com/v/u/en-US/xapp1319-zynq-usp-prog-nvm ,同时参考了这篇帖子,尝试用BBRAM Red Key来安全启动,奇怪的是,烧录key的时候显示status=0x00000000应该是成功了,但是我把加密的boot.bin放在SD卡上启动时完全没有输出。我在板卡上插入了纽扣电池,但是好像没起到作用。您有空帮我解答一下吗
你可以把你的bif文件分享出来吗?
//arch = zynqmp; split = false; format = BIN; key_part_name = XCZU15EG the_ROM_image: { [keysrc_encryption]bbram_red_key [bootloader, encryption = aes, destination_cpu = a53-0]D:/back/01_ps_hello/vitis/ps_hello_platform/export/ps_hello_platform/sw/ps_hello_platform/boot/fsbl.elf [encryption = aes, destination_cpu = a53-0]D:/back/01_ps_hello/vitis/ps_hello_test/Debug/ps_hello_test.elf }
我尝试的是最简单的例子,我刚开始以为是电池没有电,或者卡槽没有卡紧。后面我试了不断电,用jtag烧录BBRAM,再调整到SD模式,按reset读取SD里面的BOOT.BIN。这种方式其实已经没有用外接纽扣电池了,还是没有任何输出。会不会是fsbl代码需要改,或者再vivado里面设计的时候需要进行某些特殊设计,才能支持使用BBRAM key
应该是成功了,我用QSPI测试不掉电,加载加密比特流
//arch = zynqmp; split = false; format = BIN; key_part_name = XCZU15EG the_ROM_image: { [keysrc_encryption]bbram_red_key [bootloader, encryption = aes, destination_cpu = a53-0]D:/back/01_ps_hello/vitis/ps_hello_platform/export/ps_hello_platform/sw/ps_hello_platform/boot/fsbl.elf [encryption = aes, destination_cpu = a53-0]D:/back/01_ps_hello/vitis/ps_hello_test/Debug/ps_hello_test.elf }
在我看来,你的bif文件似乎是不正确的,指定了encryption = aes ,但是你的nky文件在哪里指定?
[Embedded] ZYNQ-Secure Boot Flow
ZYNQ的secure boot方案提供了三大特性的验证:
ZYNQ在secure boot的支持上提供了:
本节overview主要是用于如何实现和使用:
对于一个启动过程可以总结如下:
Final Boot Image with Secure Attributes:
注意, TF-A和uboot和linux不能加密!
1. Secure Boot 所涉及的安全机制
我们需要关注点在于[^2]:
支持安全启动的模式有 QSPI、SD、emmc、USB boot还有NAND。AES的加密后的key和未加密的key存储在eFUSEs上面;BBRAM未加密,NVM已加密。在Zynq UltraScale+MPSoC设备中,分区可以以分区进行加密和/或身份验证。zynq建议是所有的分区都是用rsa进行认证,分区如linux或者uboot如果没有一些非常保密的信息,则不需要被加密。在存在敏感数据和/或专有IP的多个来源/供应商的系统中,使用唯一密钥加密分区可能很重要。
Hardware Root of Trust¶
信任的根是存储(RTS)、完整性(RTI)、验证(RTV)、测量(RTM)和报告(RTR)的安全原语。RoT由硬件、固件和软件组成。HWRoT比软件RoT具有优势,因为HWRoT是不可变的,攻击面更小,行为更可靠。
HWRoT基于CSU、eFUSE、BBRAM(电池支持的RAM)和隔离元件。HWRoT负责验证操作环境和配置是否未被修改。RoT充当引导的锚,因此对手无法在检测机制启动之前插入恶意代码。
固件和软件在引导期间在HWRoT上运行。Zynq UltraScale+提供了不可变的引导ROM代码、第一阶段引导加载程序、设备驱动程序以及在HWRoT上运行的XILSKEY和XILSECURE库。这些提供了一个经过良好测试、经过验证的使用中API,这样开发人员就不会通过有限的测试从头开始创建安全组件。
Data Integrity¶
数据完整性是指硬件、固件和软件没有损坏。数据完整性功能验证对手未篡改配置和操作环境。
Zynq UltraScale+使用对称密钥(AES-GCM)和非对称密钥(RSA)身份验证验证分区的完整性。RSA使用私钥/公钥对。现场的嵌入式系统只有公钥。窃取公钥的价值有限,因为在当前技术下,无法从公钥中导出私钥。
加密分区也使用AES的伽罗瓦计数器模式(GCM)模式进行身份验证。在安全引导中,分区首先经过身份验证,然后根据需要进行解密。
Authentication¶
下图显示了分区的RSA签名和验证。Bootgen工具使用私钥从安全设施对分区进行签名。在设备中,ROM验证FSBL,FSBL或U-Boot使用公钥验证后续分区。
使用primary和secondary私钥/公钥对。主私钥/公钥对的功能是对次私钥/公共密钥对进行身份验证。辅助密钥的功能是对分区进行签名/验证。
要签署分区,Bootgen首先计算分区数据的SHA3。然后使用私钥对384位散列进行RSA签名。生成的RSA签名被放置在身份验证证书中。在图像中,每个签名分区都有分区数据,后面是一个包含RSA签名的身份验证证书。
FSBL的验证由CSU ROM代码处理。为了验证后续分区,FSBL或U-Boot使用XILSECURE库。
有一种用于身份验证的调试模式,称为引导头身份验证(boot header authentication)。在这种认证模式中,CSU ROM代码不检查存储在设备eFUSE中的主公钥摘要、会话密钥ID或密钥撤销位。因此,此模式不安全。然而,它对于测试和调试很有用,因为它不需要对eFUSE进行编程。
本教程使用此模式。然而,现场系统不应使用引导头身份验证。本节末尾包含了完全安全系统的示例BIF文件。
Boot Image Confidentiality and DPA¶
AES用于确保敏感数据和IP的机密性。Zynq UltraScale+使用AES伽罗瓦计数器模式(GCM)和256位AES密钥。Zynq UltraScale+提供的AES增强功能主要是增强了对差分功率分析(DPA)攻击的抵抗力,以及启动后AES加密/解密的可用性。
Bootgen和FSBL软件支持AES加密。私钥用于AES加密,AES加密由Bootgen使用密钥文件完成。密钥文件可以由Bootgen或OpenSSL生成。操作键的使用限制了device key的暴露。下一节将讨论操作键在key rolling中的使用。为了保持引导映像的机密性,可以使用Bootgen创建加密的引导映像。Vitis中还提供了对BBRAM和eFUSE键编程。
DPA Protections¶
key rolling用于DPA抵抗。key rolling和黑密钥存储可以在同一设计中使用。在密钥滚动中,软件和比特流被分成多个数据块,每个数据块都用唯一的AES密钥加密。初始密钥存储在BBRAM或eFUSE NVM中。连续数据块的密钥在前一数据块中被加密。在初始密钥之后,密钥更新寄存器用作密钥源。
96位初始化向量包含在NKY密钥文件中。IV使用96位初始化AES计数器。当使用密钥滚动时,在引导头中提供128位IV。32个最低有效位定义了使用当前密钥解密的数据块大小。IV中定义的初始块之后的块大小定义为Bootgen图像格式(BIF)文件中的属性。
一种有效的key rolling使用操作键。使用操作密钥,Bootgen使用用户指定的操作密钥和第一个块IV创建加密的安全头。eFUSE或BBRAM中的AES密钥仅用于使用256位操作密钥解密384位安全头。这限制了设备密钥暴露于DPA攻击。
Black Key Storage¶
PUF能够以加密(黑色)格式存储AES密钥。黑密钥可以存储在eFUSE或引导头中。当需要解密时,使用PUF生成的密钥加密密钥(KEK)解密eFUSE中的加密密钥或引导头。
使用PUF进行黑密钥存储有两个步骤:
本教程使用PUF引导头模式,因为它不需要对eFUSE进行编程,因此对于测试和调试非常有用。然而,最常见的模式是PUF eFUSE模式,因为PUB引导头模式需要为每个设备运行唯一的Bootgen。
2. Secure boot High-Level Design
ZYNQ所有的关于secure boot的顶层设计全部在bootgen tool的设计中表述^1。对于secure boot在high-level层面我们只需要关注两个问题,一个是image的签名和验签(认证),另一个是image的加解密。对于这两个问题,需要共同关注对于key的使用和管理,这部分就需要结合第1节的安全机制。综上所述,本节我们需要弄清楚:
2.1 image加解密
ZYNQ设备使用GCM(32-bit, word-based)256-bit key 作为数据加解密,消息认证,完整性检查,这种安全机制可以cover数据保密性、完整性和消息认证,但是没有办法防否认。关于GCM的介绍可以参考:3.3_Security_对称密钥算法之AEAD
mbedtls的接口定义可以参考:
https://siliconlabs.github.io/Gecko_SDK_Doc/mbedtls/html/gcm_8h.html
关于密钥产生,bootgen能够产生满足要求的GCM的Key,使用CMAC作为伪随机数为核心的生成器。比如在Key Rolling的时候则需要随机数作为支撑。而且可以指定种子(没有指定使用key0)作为种子。
2.1.1 image加解密原理
ZYNQ提供了bootgen工具的用以加密引导image的分区,用户可以制定BIF格式的文件用来描述image分区的加密命令和加密属性。ZYNQ只提供了AES对称加密算法,加密和解密的密钥是一致的,因此,key应该在两个地方:
加密过程如下:key需要写入到eFUSE或者BBRAM中,同时key需要给同给bootgen tool用来加密image分区。
Note,根据zynq的设计,每个分区都可以使用不同的对称加密的密钥。
解密过程如下:一个SoC设备是由BootROM和FSBL来进行解密的,换句话说,BootROM作为根启动是不能进行加密的。在BootROM引导程序中,BootROM从flash里面读取FSBL,然后对FSBL进行解密,然后把FSBL加载到OCM中,接着把hands off控制权到FSBL,FSBL会读取剩余的image分区,然后加载、解密、hands off。
在这个过程中BootROM和FSBL是从eFUSE或者BBRAM中读取到AES的key,并且使用加密硬件引擎操作,保障了密钥不被泄露。BootROM和FSBL可以从image分区的boot header中有一个
key source
区域,知道AES加密key的来源是哪里。2.1.2 AES key管理
CSU ROM会访问AES的Key进行管理。这些Key的源头可以是:
这些key的编写方式:
Operational Key
关于Operational key的密码学意义可以参考[^3],简言之就是一个份很私密的密钥因为业务原因不得不保存在host端,这就存在一个显著的安全风险,尤其是跨团队的操作,导致这个密钥被copy了很多份。Operational Key提供了保护私密的密钥途径,ZYNQ对于两个团队之间传输私密的OPT Key产生过程,以防止密钥泄露,可以参考^4。
bootgen tool可以创建一个加密的安全header,其中包含用户指定的opt_key,以及启动此功能时第一个块IV。结果就是,存储在eFUSE或BBRAM的密钥长度是384位(AES-GCM需要256,剩余128密钥位就是opt_key加成的结果),这种方式可以防止侧信道攻击。
对于一个image,使用opt_key的一个BIF示例:
我们使用bootgen来产生这个文件:
bootgen -arch zynqmp -image ./image.bif -w -o u-boot-enc.bin -p xc7z020clg484
注意,如果指定elf文件,bootgen会check elf文件头。 注意, key0是nsbl的key,如果有多个分区,多个分区的aes key文件里面的key0都是一样的,如果多个分区的aes key文件中的key0不一致,bootgen tool会拒绝加密。
此时就会生成:
生成的aes_p1.nky内容如下:
这里生成key是 64字节(512bit), IV是24字节(192bit)。能够注意到Key Opt包含在了这个文件里。
Rolling Key
GCM也支持Rolling Key,防止差分功率分析的侧信道攻击。Roling Key会把加密信息分为几个不同大小的块,每一个块使用一个不同的密钥进行加密。bootgen tool支持这个模式。
根据blocks的信息产生了这么多的key:
aes_p1.nky:
aes_p2.nky:
Note:
no. of blocks + 1
pairsGray/Obfuscated Key
Gray Key(模糊Key)这个Key的业务逻辑是,允许一批设备使用相同的Family Key加密red key。比如我们经常说的Model Key,这个密钥可以存储在eFUSE或在image的boot header中(没有BBRAM)。对于希望以模糊形式存储加密密钥的用户,可以使用Gray密钥作为加密密钥对红色密钥进行加密。ZynqMP将解密模糊密钥以获得实际的红色密钥。请注意,系列密钥在ZynqMP SoC系列中的所有设备上都是相同的。该解决方案允许用户将混淆的密钥分发给合同制造商,而不泄露实际的加密密钥。
注意,创建Gray密钥还需要创建bhiv.txt文件,在这个文件中放置IV,这个字段会出现在Boot Header的BH IV中。
bootgen -arch zynqmp -image ./gray_key.bif -w -o u-boot-enc.bin -p xc7z020clg484
产生Family Key是有安全要求的,我们需要使用bootgen来产生Family Key。产生Key的bif如下:
The command to generate the Obfuscated key is(需要自己创造IV):
我们拿不到familyKey.cfg文件,这部分需要找xilinx团队要。
Black/PUF Keys
black key解决方案是对安全性能的增强,属于KEK(Key encryption Key),而且这种Key并不是使用算法或者软件进行加密,而是使用PUF这种硬件期间。PUF会加扰写在eFUSE上的密钥。黑密钥可以写入eFUSE或者a part of the authenticated boot header。
关于PUF的一些参数如上图所示。
note: puf_file是一个输入文件,关于这个输入文件,需要参考External Secure Storage Using the PUF (XAPP1333)
关于PUF和eFUSE的安全功能,详细在Secure Storage中展开讨论,参考: [Embedded] ZYNQ-Secure Storage 。
多个加密密钥文件
早期版本的Bootgen支持通过使用单个加密密钥加密多个分区来创建引导映像。对于每个分区,重复使用相同的密钥。这是一个安全漏洞,不建议使用。每个key在流中只能使用一次。
Bootgen支持每个分区单独的加密密钥。如果有多个密钥文件,请确保每个加密密钥文件使用相同的Key0(设备密钥)、IV0和操作密钥。如果每个加密密钥文件中的启动映像不同,Bootgen不允许创建启动映像。您必须指定多个加密密钥文件,一个用于映像中的每个分区。指定分区使用指定的密钥加密。
比如:
test2.1.nky
.test2.2.nky
.1.2.3 use case(bbram-red key)[^2]
测试GCM-AES加密,并不是bh_auth(boot header)模式可以跳过eFUSE或者BBRAM的检查,我们唯一的方法就是烧录AES key到BBRAM进行测,eFUSE虽然有TEST模式可以编程,但很容易由于操作错误导致eFUSE熔断,因此我们在没有把握的情况下不对eFUSE做编程操作。
生成aes key
以2.2.7 为例,在上面增加aes加密,会生成fsbl.nky文件,密钥读取从bbram_red_key中:
输出的 fsbl.nky文件为:
记录key0:
081A9BCAD0A8FDE197CB7840171AF0666F0689D3D047ADDFAB8F3EF0492149D0
修改SoC的BBRAM中的key
https://docs.xilinx.com/v/u/en-US/xapp1319-zynq-usp-prog-nvm 该文档有描述,需要用到vitis这个软件。
把我们的key粘进去就好了,然后使用SD卡运行这个BOOT.BIN,这个程序就修改了BBRAM里面的red key:
换成我们刚才编译的带Linux和ATF的BOOT.BIN,就可以启动了。注意,如果Key验证失败,没有任何Log输出。
1.2.4 use case(opt key {DPA protections} )[^2]
在[fsbl_config]中配置
opt_key
即可使能Operational Key。如果基于上面生产的密钥,我们需要做一些操作:1.2.5 use case(Rolling Key)[^2]
使用Rolling Key,加入blocks,例如:
blocks=4096,1024(3),512(*)
,同样,我们需要把生成的key0 改为 BBRAM Red Key的内容。
2.2 image认证
image的认证使用的RSA算法,RSA则需要用Secret Key/Private Key做签名,需要用Public Key做验签。RSA的公钥是不需要做保护的,因此不需要特殊的保存。RSA也可以用用做加密和解密分区。
Zynq ® UltraScale+TM MPSoC 使用RSA-4096作为签名验签算法,这就是意味着主引导密钥和辅助引导密钥的key的长度是4096-bit。
也可以使用bootgen产生密钥
Zynq ® UltraScale+TM MPSoC 使用Keccak SHA-3作为hash运算主算法。
RSA的公钥的hash值需要存储在eFUSE/OTP上面。Xilinx的SoC设备一共有四个公钥私钥,一对公钥私钥用于认证主引导,另一对公钥私钥用于认证辅助引导。在Xilinx的SoC里面用下面的符号定义主引导和辅助引导的四种key:
PPK PSK SPK SSK可以通过bootgen tool产生:
简言之,要么提供两个私钥,缺私钥需要使用公钥+签名结果才可以。
注意,PPK的hash值会被存储到eFUSE上面,这个hash值会和存储在FSBL的boot image中的比较。hash值可以通过vitis提供的独立的工具烧写到eFUSE的内存中。
BootGen命令,结果会产生两个私钥:
2.2.1 签名过程
bootgen tool使用Secret Key进行签名。签名的过程如下:
主引导的密钥对一部分存入eFUSE,作为辅助引导凭证的验签。而辅助引导的密钥才是真的对分区进行验证。这样才完成加签链。
密钥解释如下:
2.2.2 验签过程
认证的过程可以分为:
一个分区接着一个分区进行验证:
A. 验证PPK(主引导公钥)
第一步需要先认证PPK主引导公钥是否可信,这一步通过和eFUSE中的hash值进行对比。因此步骤是:
B. 验证SPK(辅助引导公钥)
第二步需要认证SPK辅助引导是否可信,这一步需要读取AC header中的SPK原件,还需要读取AC header中的对应的SPK签名:
C. 验证分区数据
最后一步就是验证分区的数据,需要用到步骤B的辅助引导的公钥:
2.2.3 认证示例
Example 1:
启动分区认证用于一组:
Example 2:
启动分区认证用于分开的辅助引导证书对于每一个分区,使用
sskfile = secondary_p2.pem
在分区属性内指定:2.2.4 bitstream的特殊处理
bitstream是一个十分特殊的文件,因此认证和其他分区不同。FSBL是会被BootROM加载到OCM上的,因此认证和解密都是在设备的内部。但是对于比较庞大的bitstream文件,它需要借助外部内存才能够认证和使用。从安全角度来看,这就带来了安全挑战。为了应对这个问题,bootgen tool把bitstream按照8MB大小进行切分。当同时启用身份验证和加密时,首先在比特流上进行加密,然后Bootgen将加密数据划分为块,并为每个块放置身份验证证书。
Bitstream Authentication Using External Memory:
2.2.5 RSA Key Revocation
ZYNQ提供了撤销某个分区的密钥(辅助引导),而不连带撤销所有分区的能力。这个功能的启动,需要使用USER_FUSE0-USER_FUSE7在spk_select上面。下面的例子表示,
spk_select = spk-efuse
indicates thatspk_id
eFUSE will be used for that partition.spk_select = user-efuse
indicates that user eFUSE will be used for that partition.2.2.6 为eFUSE生成PPK hash
bootgen可以产生PPK hash用于存储到eFUSE上。这个步骤仅仅是用于真实使用eFUSE的模式和bootheader模式。efuseppksha.txt生成的值可以写入到eFUSA中。 如何编写eFUSE,可以查看 https://docs.xilinx.com/v/u/en-US/xapp1319-zynq-usp-prog-nvm
The following is a sample BIF file, generate_hash_ppk.bif.
运行:
生成:
3B33F1F24B92F42F87F2133993DF3284DB68797DFEBFEBC3FB46A7D358AFF41C9A532424EE0F233D5B4159B2411BA13B0
2.2.7 use case(boot-header模式)[^2]
在调试阶段,我们可以使用boot-header模式来跳过eFUSE的检测PPK hash(注意不能跳过image加密)。这种模式对于测试和调试很有用,因为它不需要对 eFUSE 进行编程。通过对 RSA_EN eFUSE 进行编程,可以为设备永久禁用此模式,这会强制使用 eFUSE 检查进行 RSA 身份验证。注意,项目release严禁使用该模式。
加入
bh_auth_enable
属性在[fsbl_config]
bif文件:使用bootgen:
bootgen -arch zynqmp -image ./image.bif -w -o BOOT.BIN -p xc7z020clg484
启动之后,看不出在哪里验签了,log没有任何输出。
2.4 使用HSM模式
3. Secure boot Low-Level Design
关于secure boot的low level design(具体设计细节),最重要的就是对于数据的打包,包含:
boot image整体的设计如图所示:
一个完整的BOOTBIN的分布如下:
Ref
[^2]:Embedded-Design-Tutorials - secure-boot [^3]:Operational keys