
BootRom启动FSBL(TF-A BL2)是MP15启动的第一次跳转,对应到第一篇文章的这个图![]() 我是按从头到尾的流程来写的,和官方视频会有一些差异 ( [( T9 R7 L9 Z% C9 _& W* A2 n* V( ~( n+ h2 \ Y" c! h3 o [3 m 一、第一步:生成秘钥对 1 U S! T6 \$ y- P/ S8 c! c首先说一下官方是提供了PC端上位机工具的(名字叫KeyGen_tool,这个工具在STM32CubeProgrammer是自带的),其中加密方式使用ECDSA 256加密算法,椭圆曲线提供P-256 NIST、Brainpool 256 T1这两种,我们可以自行选择 S* @: K/ F1 K) p; @9 j2 H1 x 我们需要在PC上生成PB key和PV key,最后我们还要计算PB key的hash值(简称PKH)(使用SHA-256计算hash) ; ~: f+ b# t% o6 M( K' k4 f+ f; ^1 g% I' P- F# j 使用ST的工具生成的话,PKH是直接提供二进制的文件,这样我们就不需要自己再做转换了,下一步的烧录可以直接用 " l: d. O) v( \, q- p- J+ T![]() 具体如何使用KeyGen,我这边就不赘述了,大家看下面这个视频 [media=x,500,375]【【STM32MPU 安全启动线上课程】2.1.2 MP15x SecureBootROM 如何使能】 【精准空降到 03:14】 https://www.bilibili.com/video/B ... 43b6b7afd3cc3&t=194[/media] 4 c |+ l' M( ]- J% e+ ~6 H, H& c8 @ 二、第二步:编程OTP区数据 / B7 j4 X8 \1 D7 T/ I5 V2 j刚才第一步生成了一个PKH,他是要被写入到芯片的OTP中的,存放到OTP的第24-31字中 具体如何写入的操作这里就不展开了,可以看一下这个视频 [media=x,500,375]【【STM32MPU 安全启动线上课程】2.1.2 MP15x SecureBootROM 如何使能】 【精准空降到 07:02】 https://www.bilibili.com/video/B ... 43b6b7afd3cc3&t=422[/media] 6 g; s7 i5 h- Y: L o 这边我就简述一下有几种方法: 方法1:使用STM32CubeProgrammer写入,可以使用命令行 或 GUI界面(作为开发人员,在开发阶段我首选就是GUI) 方法2:使用U-Boot,可以使用stm32key command 或 fuse command 方法3:SSP(Secure Secret Provisioning),这是给代工厂生产时使用的,主要目的时实现在不安全的环境中安全的烧录这些敏感的数据到OTP中,他本质也是一些加密算法和加密硬件(ST有一个类似于身份认证的卡片,用于实现验证),对需要写入的数据做加解密,这样工厂就只能看到加密后的密文,解密后的明文都在ST的工具中执行,是一个黑盒,第三方是无法知道的,这样来实现安全烧录。对这个感兴趣的可以看一下这个视频 # F8 k4 t. }& I& V[media=x,500,375]【【STM32MPU 安全启动线上课程】2.4 OTP安全烧录介绍】 https://www.bilibili.com/video/B ... 8fc87a43b6b7afd3cc3[/media] + I% g q# C* }6 w) @( x 三、第三步:对TF-A固件签名 ( P$ z/ P! l1 g0 }ST也提供了签名用的工具,我们只需要把TF-A的固件、PV Key提供给工具就好,工具会使用PV Key对TF-A固件进行加密计算(加密方式就是我们之前说的ECDSA 256加密算法,2种椭圆曲线自己选择),这样得到的结果就是签名的结果了,可以放到header中。 4 t1 [' j* W4 t最终你会得到一个经过签名的TF-A固件(他就=header信息+原来的TF-A固件) ' @2 O, `, e% R( i, a5 F) X5 C/ E' a V6 K/ l 当然header里面还会有其他东西,下图是整各header的内容,可以做一些了解,但我这边不会详细展开 5 U. l+ G! _' i, Y3 z/ t' n6 r![]() 我们重点需要知道的是header里会储存PB Key(表中的ECDSA public key)、签名信息(表中的Image signature)、椭圆曲线(表中的ECDSA algorithm) ![]() 还有一个Version number,这个也很重要,是用于防回滚的,我会在下面章节说这个,这里就不说了 5 R! ^) d/ L- N0 t- h* I) Z- Z 四、第四步:close device(非必选) 9 y" l1 x- h- ]& v* D$ }% n. z什么是close device? 要解释这个东西,我们就要了解一下STM32MP15的Product Life Cycle,它覆盖了一个试用MP15的产品从开发、生产、市场问题排查三个阶段,下图为他的状态流程 % A+ P8 U& g* V T% d$ s![]() 我们就看C/F系列产品就好,其他系列都不支持安全启动,那也就没有close device这个操作了 % k' H7 A- n7 {9 a5 R2 Y) b3 F) p) C. @ UNDER_PROVISIONING状态时SSP时会经历的,我们开发阶段可以忽略 0 K7 M5 l0 z' }4 B1 R6 s, u/ h2 h6 s, i- X5 ^9 x 那么对于我们开发来说就只有3种状态了:LOCK、UNLOCK、RMA : ?( Y8 w+ O% X; T4 w6 n Z0 e( f1 M& u: N( U0 r- f' R 接下来我就描述一下这3种状态的具体含义 1.UNLOCK:出厂的默认状态,当产品为这个状态时,安全启动的业务都会执行,但是即使固件校验不通过,也会启动下一级的固件,可以用于早期调试阶段,这样旧不用每次都对固件签名,节省工作量 2:LOCK:UNLOCK的设备可以经过close device变成LOCK状态,在这个状态下会严格执行安全启动业务,校验不通过,就不会执行下一级的固件,并且各种调试接口都会被关闭。这个一般就是在生产阶段做的,生产好后的产品都是LOCK状态 3:RMA:用于处理市场问题时使用,刚才说了LOCK阶段所有调试都会关闭,那么有问题的产品回来后,研发人员如何排查问题呢?RMA状态就是在这个时候用的,我们可以使用密码,让固件进入RMA状态,此时我们就可以使用JTAG调试了 % |" f" D. s1 b+ H1 W. y![]() 还有一张图展示这三者的关系,虽然名字换成了open与close,但是是同一个意思 " T) r% F2 S" \![]() 4 A+ Q& H$ S4 S+ K+ ]& e8 ] 设备当前是否为open或close,是根据OTP中的一个flag来决定的,也就是说,我们close device的这个动作的本质就是往OTP中写入一个数据(图里也说了,如果OTP中没有数据的话,并且在没有干扰或错误的情况下完成了初始化OTP,设备就会处于open状态,这就是刚才说的出厂默认为UNLOCKJ) 五、第五步:运行时如何验证 9 m; ]. O1 O" ^" m. R& Y( L" o简单流程如下图所示 ![]() 1.上电后运行ROM Code,也就是BootRom,当要跳转到TF-A时,他会先加载FT-F的分区(这里面有2个东西,一个是TF-A固件代码,还有一个是TF-A的header,这个就是完成签名后的固件) 4 g% [) a* o: C+ n0 c9 }![]() 2.在芯片的OTP区中有PB key的hash值,还有一个version(这个用于防回滚,配合header中Version number实现的,他的具体机制后面会讲) . G7 Y4 \: s5 x' b& }( { r! z& @3 I' D![]() 3. ( P! Y- l- W# Q& I3.1 验证PB Key是否有效 6 U' z+ J4 ~0 H0 Q8 |* ~( {$ F 在header中有一个信息就是PB key,可以算出他的hash值,现在我们就可以用OTP中的hash值和header中的做个对比,看看是否一致,验证PB key是否有效。 3.2 验证image是否有效 如果PB Key有效,就可以开始验证TF-A固件,用PB key对TF-A固件代码进行ECDAS 256计算,和header中的Image signature作对比,验证固件是否被篡改(当然,如果设备为UNLOCK,即使验证失败,固件也会被启动) 9 s, e- p& h6 R* p2 q# D3.3 防回滚机制 下面有防回滚机制,这里不展开说 2 r. _# Y4 m: o: U; }6 a% f![]() 2 [7 l: c+ W) x 六、防回滚机制 % ?$ u1 \0 z; T刚才说了在OTP中会有一个version,TF-A的固件中也有一个version,他俩配合实现防回滚 其中OTP的是一个单向计数器,也就是说这玩意儿他只能++,看了一下header中的version,有32bit,也足够大,不管怎么++,也肯定够用了 当OTP中的version比header里的高,那么这个固件就不会被启动,这就是触发了防回滚的机制 如果我想退回到旧版本的固件应该怎么办?可以重新生成一个新的带签名的固件,但是header中的version写大一点,比OTP中的大,这样就可以达到目的啦 $ C- o1 V9 A5 e: ^# g6 n2 a* E a5 m 七、疑问与思考 & V$ g. R5 Z/ u; t这里我有几个疑问 1:既然保存在OTP中的UNLOCK与LOCK判定相关的数据这么重要,那么在LOCK后,我们应该是无法再次改写OTP了(这不是废话吗,这么明显的漏洞ST肯定堵住了),我想知道ST是否还做了其他的保护措施,例如给芯片一些干扰,让他读取到错误数据后,是否会阴差阳错的进入到UNLOCK状态?还有我直接磨芯片是否可以实现篡改OTP数据实现攻击?(有些产品使用单片机,会把关键数据储存到片内flash,有些攻击就是直接磨芯片,飞线直接读写flash) 2.LOCK与RMA之间relock最多就3次?为什么要这样设计?超过3次就永远锁死芯片?万一有一些玄学问题,需要反复LOCK与RMA之间切换该怎么办? 3.如果我header中的version不小心写成了0xFFFFFFFF,是不是这颗芯片就废了?因为OTP中的version无法再++了 4.OTP中的version是在什么时候增加的?是当TF=A固件成功运行后,直接把OTP中的version加到和header中的version一致? 5。我如果生成新的TF-A固件,但是header中的version还是和上一个可以正常运行的固件的版本一样,那设备会怎么样呢?会正常启动吗?还是说有一些什么其他机制来做判断 t1 n4 {+ t8 @! ` |
《STM32MPU安全启动》学**结
《STM32MPU安全启动》学习笔记5.2如何使能Uboot校验
《STM32MPU安全启动》学习笔记5.1 UBoot 的校验
《STM32MPU安全启动》学习笔记4.2使能M安全启动功能
《STM32MPU安全启动》学习笔记4.1 STM32MP1和STM32MP2 M核启动
《STM32MPU安全启动》学习笔记3.3使能TF-A带加密的功能 13/25系列
《STM32MPU安全启动》学习笔记使能TF-A身份验证STM32MP13/15
《STM32MPU安全启动》③TF-A BL2启动U-Boot与OP-TEE
《STM32MPU安全启动》④U-Boot启动Kernel
《STM32MPU安全启动》①信任根、信任链及MP15启动流程