当前位置:首页 > 汽车电子 > 汽车电子
[导读]外部SPI Flash存固件最忌明文裸奔:编程器一夹就能dump完整固件,中间人改包也不会被察觉。车规做法不是“加个CRC”,而是Bootloader启动前完成信任链校验——哈希保完整、签名保来源、版本计数器防回滚。


外部SPI Flash存固件最忌明文裸奔:编程器一夹就能dump完整固件,中间人改包也不会被察觉。车规做法不是“加个CRC”,而是Bootloader启动前完成信任链校验——哈希保完整、签名保来源、版本计数器防回滚。

一、信任根别放普通Flash

SPI Flash本身不可信,公钥哈希/根公钥必须固化在芯片OTP、eFuse或HSM安全区,CPU主域读不到明文。

分层建议:

根公钥哈希 → OTP/eFuse(一次烧写不可逆)

App签名公钥 → HSM密钥槽,支持OTA轮换

私钥 → 厂内离线签名服务器,绝不下发到产线

BootROM或一级Bootloader先用固化公钥验二级BL,二级BL再验App,任一级失败即终止启动。

二、固件头结构设计

固件镜像头部带元数据,Bootloader按偏移解析:

typedef struct __attribute__((packed)) {

   uint32_t magic;        // 0x53454342 "SECB"

   uint32_t version;      // 单调版本号,防回滚

   uint32_t img_len;      // 不含header+signature

   uint8_t  hash[32];     // 固件体SHA-256

   uint8_t  sig[64];      // ECDSA/RSA签名

   uint32_t svn;          // 安全版本号

} fw_header_t;

固件体从header之后开始,签名对象通常是“header(不含sig)+固件体哈希”或整段固件摘要,具体按签名工具约定来。

三、Bootloader校验流程

SPI读按页搬进内部RAM缓冲,别逐字节调SPI函数算哈希:

int secure_verify(uint32_t slot_addr){

   fw_header_t h;

   spi_flash_read(slot_addr, &h, sizeof(h));

   if(h.magic != FW_MAGIC) return -1;


   /* 1. 防回滚:版本不低于当前 */

   if(h.svn < otp_read_svn()) return -2;


   /* 2. 算固件体哈希 */

   sha256_ctx ctx; sha256_init(&ctx);

   uint8_t buf[256]; uint32_t off = sizeof(h), left = h.img_len;

   while(left){

       uint32_t n = left>256?256:left;

       spi_flash_read(slot_addr+off, buf, n);

       sha256_update(&ctx, buf, n); off+=n; left-=n;

   }

   uint8_t digest[32]; sha256_final(&ctx, digest);

   if(memcmp(digest, h.hash, 32)) return -3;     // 完整性失败


   /* 3. 验签:交HSM,私钥不出安全域 */

   if(hsm_verify(h.sig, h.hash, pub_from_otp()) != HSM_OK)

       return -4;                                 // 来源伪造


   otp_commit_svn(h.svn);                        // 验过才升版本计数

   return 0;

}

CRC只防比特翻转,验签才防篡改;两者别互相替代。

四、跳转前清场

验签通过也别立刻跳,和OTA同理:

void jump_app(uint32_t app_addr){

   if((*(uint32_t*)app_addr & 0x2FFE0000) != 0x20000000) return;

   __disable_irq();

   SysTick->CTRL = 0;

   RCC->CIR = 0;

   SCB->VTOR = app_addr;

   __set_MSP(*(uint32_t*)app_addr);

   ((void(*)(void))(*(uint32_t*)(app_addr+4)))();

}

VTOR不重映射、SysTick没关,是新固件“跳过去HardFault”的高发原因。

五、防篡改补充手段

写保护:SPI Flash WP#脚接MCU GPIO或HSM,常态拉低锁状态寄存器;升级时才临时解

Boot区锁:Bootloader所在扇区写保护,App越权也擦不到

调试口熔断:量产锁JTAG/SWD,或走HSM挑战响应开放

运行时自检:关键函数段定期重算哈希,异常进安全态

外部Flash加密:代码大必须外挂时,存AES密文,Bootloader用HSM密钥解密进内部RAM/IFlash再跑

防回滚计数:优先放OTP/eFuse或HSM受保护区,普通Flash扇区只做辅助标记,别当唯一真相源

六、量产落坑

公钥哈希烧OTP前,先拿测试密钥跑通整链再换量产密钥

签名私钥泄露=所有在产ECU信任崩塌,轮换靠HSM存App公钥实现

SVN只增不减,回滚攻击就是刷旧漏洞版,必须卡死

Bootloader预留恢复槽,验签失败进Recovery而非变砖

SPI时钟、4线模式、地址映射(3字节/4字节)要和烧录工具一致,否则头都读歪

按“OTP存根公钥+SPI Flash头+哈希+签名+Bootloader验签后跳转+SVN防回滚+WP#锁Flash”落地,外部SPI Flash即使被物理读出也只是密文/脏数据,车规固件篡改、降级、克隆三条路都能堵住。



本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除( 邮箱:macysun@21ic.com )。
关闭