从嵌入式角度出发,安全启动最早应用在linux系统上,全称叫secureboot;它是一种逐级验证镜像,从而实现固件可信运行。
以常见的uboot启动为例,通常要经过BootRom->SPL->uboot三个大阶段(其中BootRom出厂时掩膜在ROM介质中,不可更改,SPL(SecondatyProgramLoader)用于初始化C语言环境等);BootRom作为信任根,会首先验证SPL代码(这里不讨论具体算法),确认SPL无误后,加载SPL代码到DDR或者SRAM;然后由SPL对uboot进行校验;方式同上,最后验证无误完成启动。
上述简述中各位发现问题没?
基于上述目标,我们来依次拆解出策略:
保证代码可信且完整,常见方式有签名验证、HASH、CMAC等,因此需要HSM外设以提供上述服务;
加快安全启动速度和每次复位都要验证目标代码,因此需要高效的代码、加密引擎的硬件加速能力、可信的启动引导程序。
所以想要做好安全启动,首先有MCU中最好自带符合EVITA的HSM模块,其次在MCU内部最好有属于自己的信任根,最后在硬件上需要设计高效的host和hsm核之间交互策略,从而给软件提供了实现不同启动方式的平台。
(1)用户的bootloader程序不被篡改或者破坏;
(1)HSM固件、用户代码执行前均需要被验证;
基于上述需求和目标,我们来分析不同启动方式对系统启动效率的影响。
具体流程示例如下:
这里面就出现了一个很矛盾的点,HSMBootRom是如何知道HSM固件、用户程序存放的位置以及对应签名或者MAC值的呢?BootRom不能改,是不是提前就得定好程序、签名、MAC存放位置?那这样风险不就又增加了,虽说大家都要签NDA。
所以,我很少看到有在BootRom里就做安全启动的;那不在BootROM里做校验,这种情况信任根和信任锚点就出现了转移。这是后话,扯远了。
并行启动就很好描述了,Host启动HSM之后,继续运行其App代码,HSM自行启动,去验证HSM固件、HOSTApp代码,一旦验证不通过,HSM有权限将整个系统重启,并在一个可行环境中运行(这里其实也有绕开的办法)。
其流程如下:
这种方式启动速度很快,但是缺点也很明显,一旦运行被篡改的程序,不知道会发生什么样的危险事件,未知的才是恐惧的。
基于上述顺序和并行启动方式的优缺点,目前还有一个启动方式,即混合启动。
混合启动的出现兼顾效率和信息安全,比如说,要快速发报文,那我就先校验通信栈,先发再说,应用程序等HSM校验完成后再运行。当然这也是一种投机倒把的技巧。
那么我们可以怎么做呢?
从配置工具上提供校验程序的配置(我这里称之为group),例如group的起始位置和大小,group的分类、group是按照顺序启动校验还是并行启动检验;同时提供了link的配置,从根本上解决了配置困难这个问题,但是callout和callback还是需要自己定义,不过这已经是大大的进步了。
上面三个小章节介绍了启动的方式,下面解析下安全启动中使用的验证方式(我也很容易搞混淆):
具体做法为:发送方将发送消息和密钥进行MAC运算,得到MAC值,并把MAC值与消息一同发送给接收方。接收方接收到消息后,将消息部分与事先共享的密钥进行MAC运算,得到MAC值,将MAC值与发送方发送的MAC值进行比较,如果一致,证明消息是来自发送方。
这样,即使密钥泄露,由于有MAC(Hash单向性),对于同一条消息,攻击者基本无法伪造出相同的MAC,从而保证该消息是正确且没有被篡改。
常见的算法有:AES-CMAC\SHA-HMAC。而随着加密引擎的硬件化,上述算法效率大大提升。
既然上面提到的MAC属于Hash,我们来讲下Hash。
Hash就是将任意数据转换成一个固定长度的字符串,很明显,这个字符串无法反向推导出原文,因此不可逆。常见为SHA-2-256(目前MD5和SHA1已经被破解,一般推荐至少使用SHA2-256算法。)
上文,我们详解了安全启动方式(顺序、并行、混合),分析了不同启动的优劣势;梳理了安全验证的三种不同方式:签名、Hash、MAC。有了基础概念,我们接下来就可以分析安全启动加密算法的具体细节。