安全需要一个起点。现在我们理解,没有安全启动,设备平台的安全难以得到保证。安全启动要求启动的位置一定是固定在某个地方。那么固定启动位置靠什么保证?必须靠硬件。软件本身的特点,决定了它很容易被修改,即使做了加密和加扰,破解的难度依然比硬件低很多。所以,安全启动一定是靠 STM32 硬件来保证。脱离硬件谈安全启动基本上是不可能的。
实现 Root of Trust(信任根)通用的做法是什么呢?一般是,芯片有一个 Bootrom 启动只读存储区。硬件的设计保证,芯片加电启动一定是从这个只读的甚至不可见的 Bootrom 里执行。
事实上,保持安全启动的原则不变,但是实现的方式可以不一样。 对于这个 Bootrom,直接固化在芯片里,会减少灵活性,无法适应 MCU 的广泛应用场景。所以,STM32 采用的是使用 STM32 硬件技术,允许客户在开发过程中形成 Bootrom。形成的 bootrom 具有我们前面所提到的安全启动几个特征:
◎ 启动位置是固定的
◎ 启动顺序是不可修改的
◎ 启动代码或者核心部分对后续代码是不可见的
安全启动的 STM32 软件架构
STM32 SBSFU 是一个层次结构,分为三层,可参考附件中的下图图示。
◇ 第一层是驱动层,包括 BSP 以及 STM32 HAL
◇ 第二层是中间件层,包括 STM32 Cryptolib,以及安全引擎。安全引擎提供了 Secure key storage 安全存储密钥的服务,以及安全进行加解密操作的服务。
◇ 第三层是应用层,包括 SBSFU,以及用户固件。其中,安全启动与安全固件更新部分,保括了安全配置,用户固件加载,以及为用户固件更新所准备的固件烧录功能。
在 STM32 中固定启动位置
我们看一下 SBSFU 的安全部分是如何实现的。复盘一下系统的初始执行过程:系统上电,STM32 MCU 根据 boot0 和 boot1 管脚的配置,再加上软件 boot 寄存器,可以确定系统应该什么地方启动,存在三种可能:
◎ 从系统内存启动 System memory bootloader。
◎ 从用户 Flash 启动
◎ 从SRAM 启动
理论上系统内存可以充当信任根。然而,考虑到系统内存所达到的安全级别和灵活性,我们不希望它从系统内存启动。从 SRAM 启动的话,如果没有信任根的话,那么这个 SRAM 的安全无法得到保证。因此,只有唯一的选择,也就是 STM32 目前的安全设计方案,将系统固定在用户 Flash 启动 。
我们如何将系统固定在用户 Flash 启动?
根据 STM32 手册,需要使用一个叫读保护的功能 RDP。不使用 RDP, 首先 boot pin 是可以重新拉高或者拉低,从而构成不同的配置;其次 JTAG 可以连上去,让 STM32 从 SRAM 启动。
读保护 RDP 要设置成2,才能够确保启动位置不会被修改。 将 RDP 设置成1,是保护 Flash 内容不被读出,并不能将启动顺序固定到用户 Flash。例如, JTAG 依然可以连上 STM32, boot 管脚依然可以重新修改。
所有的 STM32 系列都具备 RDP 功能。唯一需要注意的是 STM32F1 系列,不具备 RDP 级别2这一设置。
有些客户反映,使用 RDP 级别2,会不会造成一些问题,代码错了,系统会不会变化?还有使用 PCROP 保护的算法或者密钥会不会再也无法更新?为解决这些问题,可以采用特别的 STM32 型号,例如:STM32G0。
对于 STM32G0,这种情况下,是要使用一个选项字节功能。该功能被称为唯一启动入口 (Unique Boot entry)。若将该选项字节设置成1,STM32G0 只能从主 Flash 启动。不过,对于安全启动,需要将启动的位置固定这一需求,是可以进一步放松。例如:假如换到其他位置,对于安全相关的链条的影响为0,那么我们也可以认为这个信任的根的保密、完整、可靠目标在一定程度达到了。
例如,我们在不需要 RDP 为2,也可以实现可信的安全固件安装。在安全固件安装中,系统内存提供 RSS 根安全服务,在这个过程中,系统内存充当了信任根。这就是一个RDP 级别1 的信任根。
再例如:如果使用 STM32L4,将堆栈放在 SRAM2 中,那么在 RDP1 的情况下,想通过 JTAG 攻击STM32,例如读 Flash 内容,或者对 Flash 修改基本不可功能。
总结一下,构造安全启动,必然需要设置读保护 RDP, 一般设置成2,在有些情况下也可
以设置成1,这个时候要确保 SRAM1 不包含任何安全敏感信息。
相关文章