Khorina · 1月8日

汽车信息安全 -- S32K1 如何更新 BOOT_MAC

1.安全启动模式回顾

之前提到过,S32K1 系列提供了 Crypto Service Engine 硬件加密模块(简称 CSEc),大家可以通过该芯片系统寄存器 SDID.FEATURES(System Device Identification Register)来判断自己的片子是否带 Security。

image.png

根据 RM 描述,CSEc 符合 HIS-SHE 和 GM SHE+标准,因此在固件更新、数据保护、安全启动上的设计是可以通过规范窥探一二的。

我们可以在 SHE 规范文档 4.10 章节看到关于 Secure Booting 的需求:

Image

根据这个需求,CSEc 提供了三种安全启动模式供用户选择:

  • Paraller Secure Boot:CSEc 模块执行“安全启动”程序,同时用户应用程序也运行;值得一提的是,如果验证失败,应用程序不会停止,只是用户无法使用设置了 BOOT_PROT 属性的密钥;
  • Sequential Secure Boot:CSEc 先执行“安全启动”程序,验证成功后才会释放 Host Core 执行用户程序;当然如果验证失败,Sanction 与并行启动一致;
  • Strict Boot:所谓严苛的启动,就是在顺序启动基础上,新增了验证失败后 CPU 一直复位的 Sanction。并且一旦配置了该启动模式,就不可逆了。

这里并没有我们现在经常配置的混合启动,这和芯片是否具备 Secure Core、Secure NVM 槽位设计有关。

我们知道,一旦出现不可逆这几个字眼,就很难为我们写代码的了,比如典型的 TC3xx 刷 UCB 稍不留神就锁板,能救回来的很少。

所以,搞清楚每块片子的启动逻辑是有道理的。

2.为什么要讨论 BOOT_MAC

首先我们要明白,安全启动其实只是用于验证应用程序\数据有没有被篡改、破坏,这就是要保证数据的完整性和真实性,常见的方式就有 HMAC、CMAC;在 SHE 的规范中提到需要使用 AES128-CMAC 来生成或者校验 MAC 值,那么在 CSEc 中安全启动所用算法就确定了;

Image

其次,既然是验证 MAC,那就必须有一个本次计算的 MAC 和预置 MAC 比较的动作,很明显预置 MAC 和对应算法所使用的密钥的安全就显得尤为重要了,因此在 SHE 的逻辑架构里,就专门划分了对应 Secure NVM 槽位,如下图红框所示:

Image

一般来说,Secure NVM 就只能有 SHE 中的控制逻辑访问,CPU、Debug、DMA 等等外设都不能访问这块空间,从隔离这个角度保证了这块 NVM 的数据安全可靠;

但是如果用户程序在量产后进行 BugFix 升级,那针对用户程序的 MAC 值就必须同步进行修改,因此讨论 BOOT_MAC 的更新也是非常有必要的。

3.S32K1 如何更新?

BOOT_MAC 位于 Secure NVM,因此肯定会出现首次为空需要添加、用户程序升级后需要更新这两种情况,我们分别来讨论。

针对首次添加 BOOT_MAC 到指定槽位,CSEc 提供了两种方式:

  • 手动添加 BOOT_MAC
  • CSEc 自动添加 BOOT_MAC

找到了关于 CSEc 使用的 SDK,链接放到文后了:

Image

具体来看看手动添加 BOOT_MAC 的流程:

  1. 导入 BOOT_MAC_KEY 到 CSEc 模块中的 Secure NVM(其他 Key 也可同步导入);
  2. 送 CMD_BOOT_DEFINE 或者调用 SDK API -- BOOT_DEFINE 来定义需要计算 MAC 的 Flash 空间、定义启动模式;
  3. 使用 BOOT_MAC_KEY 计算上述 Flash 空间的 MAC,可以通过加载 RAM_KEY 的方式进行计算;
  4. 将计算好的 MAC 加载到 BOOT_MAC 槽位中;
  5. 复位设备,CSEc 会进行 MAC 匹配,通过 FCSESTAT.BOK = 1 可判断安全启动是否成功。

具体代码如下:

/* Step-2 Define the secure boot flavor and the BOOT_SIZE*/
    csec_error = BOOT_DEFINE(128*1024*8, 1);

    /* ----- For Automatic BOOT_MAC generation stop execution here and reset the part twice for automatic BOOT_MAC generation and verification ----- */
    /* ----- For Manually set-up BOOT_MAC continue with the following steps ----- */

    /* Step-3 Calculate the CMAC using RAM_KEY feature of the CSEc */
    /*Load BOOT_MAC_KEY into RAM_KEY slot */
  csec_error = LOAD_RAM_KEY(BOOT_MAC_KEY_VALUE);
    /*Generate MAC for first 128kB data starting at memory address 0x0. */
    uint32_t *flash_pointer = (uint32_t *)(0x00000000);
  csec_error = MAC_SECURE_BOOT(boot_mac, flash_pointer, RAM_KEY, 128*1024*8);

  /* Step-4 Store BOOT_MAC at secure location */
    calculate_M1_to_M5(M1, M2, M3, M4, M5, MASTER_ECU_KEY_VALUE, boot_mac, MASTER_ECU_KEY, BOOT_MAC, 1, 0); /* Calculate M1 to M5 in Software, Authorizing Key = Master ECU Key */
    csec_error = LOAD_KEY(M4_out, M5_out, M1, M2, M3, BOOT_MAC); /* Load the key using M1 to M3, returns M4 and M5 */

自动更新 MAC,前置步骤相同,仅仅在 Step3、4 合并,全权交由 CSEc 进行计算和存储,不是很明白这块代码是具体怎么做的。

自动更新和手动计算 MAC 看起来一样,唯一区别在于,手动计算调用 API 时需要在数据前增加 128bit 的 Header,格式:00...00(96bits) || BootSize(32bits),代码如下:

CSE_PRAM->RAMn[4].DATA_32 = 0;
CSE_PRAM->RAMn[5].DATA_32 = 0;
CSE_PRAM->RAMn[6].DATA_32 = 0;
CSE_PRAM->RAMn[7].DATA_32 = message_length;

那么如果要用户程序升级后需要更新 BOOT_MAC 呢?这里就要分成两种情况:

  • CSEc 密钥槽中的所有密钥没有设置写保护属性,可以重新擦除该区域恢复到出厂设置,然后按照首次添加 BOOT_MAC 进行更新,广泛用于开发阶段;
  • CSEc 密钥槽任一或者多个密钥设置写保护属性,根据协议要求,该属性不可逆,密钥也不能再修改,因此只能将 BOOT_MAC_KEY 加载到 RAM_KEY 区域,然后进行计算;或者通过离线计算再根据协议进行 BOOT_MAC 的更新即可,一般用于 ECU 量产阶段。

CSEc 使用的 SDK 链接如下:

https://github.com/nxp-auto-support/AN5401_sw/tree/master

END

作者:快乐的肌肉
文章来源:汽车MCU软件设计

推荐阅读

更多物联网安全,PSA 等技术干货请关注平台安全架构(PSA)专栏。欢迎添加极术小姐姐微信(id:aijishu20)加入PSA 技术交流群,请备注研究方向。
推荐阅读
关注数
4575
内容数
212
Arm发布的PSA旨在为物联网安全提供一套全面的安全指导方针,使从芯片制造商到设备开发商等价值链中的每位成员都能成功实现安全运行。
目录
极术微信服务号
关注极术微信号
实时接收点赞提醒和评论通知
安谋科技学堂公众号
关注安谋科技学堂
实时获取安谋科技及 Arm 教学资源
安谋科技招聘公众号
关注安谋科技招聘
实时获取安谋科技中国职位信息