最近看了一些关于可信启动的文章,所以我想把可信启动的知识做一下梳理。
本文主要从抽象层面介绍可信启动原理,分别从启动过程,可信启动原理,模拟可信启动三个方面展开介绍。
计算机启动过程简介
我将按两类平台的启动过程分开描述,分别是x86/x86_64平台设备的启动和嵌入式平台设备的启动
x86/x86_64 平台设备的启动
x86 平台启动过程如下图所示
简略流程: cpu –> BIOS –> GRUB –> Kernel –> OS
嵌入式设备的启动
嵌入式平台启动过程如下图所示
简略流程: cpu –> u-boot –> Kernel –> OS
可信启动思路
可信启动的两个关键概念分别是可信根和可信链,可信根。
大家对 PKI 体系应该都有了解,可信启动的两个概念可类比与证书体系,当我们访问一个 https 站点时,站点会把证书传送给客户端。客户端要去校验证书的合法性和有效性,就需要验证两点,第一点,该站点的根证书(CA)在客户端所在机器是否是可信的,第二点,从 CA 到站点证书的证书链是否是完整的。
要实现可信启动,首先需要 cpu 的支持,其次还需要 TPM(Trusted Platform Module)芯片的支持,TPM 有两个作用,作用一:提供加解密算法的支持,作用 二:存储对称密钥及私钥。可能部分嵌入式产品还需要 OTP(One Time Programmable)芯片。下面以嵌入式环境为例,说明可信启动的实现方式。
环境
支持可信启动的主芯片,OTP 芯片,Flash 芯片
假设 flash 芯片的分区结构如下
| u-boot | kernel | romfs | config |
u-boot 分区结构如下
| 4 字节:公钥长度 | 1024 字节:RSA 公钥 | 4 字节:u-boot 的 hash 签名长度 | 1024 字节:u-boot 的 hash 签名 | 4 字节:u-boot 版本号 | 4 字节:u-boot 长度 | u-boot 内容 |
OTP 存储结构如下
| RSA 公钥的 sha256 值 | u-boot 版本号 |
可信启动流程
启动设备,cpu 判断是否使能可信启动,如果是,则按照可信启动流程执行
step1 读取Flash中u-boot分区里的RSA公钥,并计算hash值
step2 读取OTP中的RSA公钥hash值
step3 比较step1和step2的hash值,如果不一致则退出启动流程
step4 读取Flash中u-boot从版本号开始的内容,对 u-boot 内容做 hash 运算,记hash值为A
step5 读取 Flash中u-boot 的 hash 签名,使用step1的公钥验签,记验签结果为 B
step6 判断结果 A 和 结果 B 是否一致,如果不一致则退出启动流程
step7 读取 Flash中u-boot 的版本,记版本C
step8 读取 OTP 中的 u-boot 版本,记版本D
step9 判断版本D 是否大于 版本C,如果是则退出启动流程
stepx u-boot 验证 kernel 的完整性
stepy kernel 验证 romfs 的完整性
可信启动最关键的是从 cpu 到 bootloader 的过程,从 bootloader 开始到 kernel,到 romfs 等阶段都和前面的校验过程类似,就不再赘述了。
可信启动模拟实现
我用 python 写了一个可信启动从 cpu 到 u-boot 的模拟器,把我所理解的可信启动的过程呈现出来
模拟器文件结构如下
Kafrocs:Trusted Boot Emulate kafroc$ ls -R CPU Flash OTP power.py vendor ./CPU: cpu.config cpu.py ./Flash: config kernel romfs uboot ./Flash/config: config ./Flash/kernel: kernel ./Flash/romfs: romfs ./Flash/uboot: RSA_Pub uboot.py uboot_Version uboot_signature ./OTP: RSA_Pub_Hash u-boot_Version ./vendor: RSA_Pri RSA_Pub rsa-sig.py uboot-partition ./vendor/uboot-partition: RSA_Pub uboot.py uboot_Version uboot_signature
其中 CPU Flash OTP power.py 模拟嵌入式设备,vendor 模拟设备制造厂商
下面是关于模拟器的使用介绍
假设用户A是厂商人员,负责uboot开发以及固件打包
假设用户B是设备用户,负责升级固件包
1 用户A进入 vendor/uboot-partition 目录,对uboot(即uboot.py)进行开发,并更新uboot_Version
2 用户A进入vendor目录,执行 python3 rsa-sig.py 生成新固件(固件即为uboot-partition所有文件)
3 用户B升级新版本固件(把 vendor/uboot_signature 下的文件复制到 Flash/uboot/下面)
4 用户B配置 CPU/cpu.config 使能可信启动
5 用户B通过 python3 power.py On 来启动设备
在启动设备时,cpu 会按照可信启动流程执行,如果校验失败,则停止启动
如果成功,则加载 uboot 执行
python3 power.py On演示结果如下
Kafrocs:Trusted Boot Emulation kafroc$ python3 power.py On system starting ... Read RSA Public Key from Flash and Calculate the hash value Read the hash of RSA Public Key in OTP Verify RSA Public Key OK. Calculate the sha256 of uboot verify u-boot signature uboot verify OK. Check u-boot version ... u-boot running ...
模拟器代码:https://github.com/kafroc/Trusted-Boot-Emulation
总结
可信启动的关键,一要有cpu的支持,二要保证设备上有一处地方是只读不可写的(无论是cpu内部的存储器,还是安全芯片,或者是OTP芯片)把公钥的hash放到只读空间,保证公钥的完整性,公钥和私钥唯一匹配,只要保证私钥不泄露,这样的设计理论上是能保证安全的。
可信启动是设备安全的根基,理论上其他的安全功能都应该在可信启动的基础上建立。后续我想写一篇文章把可信执行也介绍一下。
如果你喜欢我的文章,请帮忙点个赞。
由于笔者水平有限,文章难免会有错误的,欢迎读者批评指正。笔者个人邮箱:[email protected]
来源:freebuf.com 2020-05-18 14:20:57 by: nobodyshome
请登录后发表评论
注册