Open carloscn opened 3 months ago
本文来捋顺以下,Secure Boot如何使能。和其他MCU的Secure Boot不同,S32K344的固件需要SoC之上的HSE进行密钥管理和固件签名,而其他的MCU控制器通常是在编译固件的时候进行签名,接着使用烧录器烧录到芯片的NVM中。
对于一般的Secure Boot和S32K3系列的Secure Boot做以下对比:
对于S32K344理论上需要编译两个工程:
首先,是App工程。该工程就是我们正常的S32K344的业务工程。不过相比于普通的业务工程,还需要定义包含App头的描述之类的,所以link文件和工程需要做一些适配;
然后,是Secure Boot配置工程。该工程用于配置Secure Boot,在编译阶段,我们需要把App工程的二进制指定到该工程中。通过烧录和运行该工程,该工程会完成:
当Secure Boot配置工程执行完成之后,在板子下一次reset之后,就完成了secure boot的使能,并且能正确引导App工程的启动。
如果需要重新烧录固件,则需要重新使用Secure Boot配置工程。
Secure Boot保证的是非法固件的启动和运行,安全性的保证是通过HSE的签名操作。
攻击1 : 在一个已经启动Secure Boot的设备上,替换NVM存储器(例如Flash)
通过SBAF(BootROM)程序强制从HSE启动,并利用HSE内置密钥进行固件验证,确实能够有效防止未经授权的固件运行。这种设计确保了攻击者即使通过物理手段替换NVM,也无法绕过HSE的签名验证,从而防止恶意固件的加载。因此,这种机制能够有效抵御通过NVM替换进行的攻击,提供了很强的安全性。
攻击2:通过JTAG接口下载恶意代码并尝试清空HSE的密钥
SoC启动HSE之后,需要开启Secure Debug功能。通过在eFUSE中烧录DAPK或AES密钥,或通过挑战响应模式来验证调试者的身份,这种机制能够有效地防止未经授权的JTAG访问。如果攻击者没有正确的密钥或身份验证手段,那么他们将无法通过JTAG接口重新烧录程序或清空HSE的密钥。因此,这种机制在防止物理调试接口攻击方面是安全的。参考: https://www.pemicro.com/blog/index.cfm?post_id=216
攻击3:通过App的外部接口进行反向固件注入
SBAF程序会强制通过HSE验证固件,并且MPU配置了对HSE区域的保护。对于普通应用程序区域,HSE在启动时验证固件的签名,防止未授权固件通过外部接口(如网络、串口)注入。而对于HSE固件,MPU的保护使得HSE区域无法被写入,从而防止通过应用程序进行的攻击。
攻击4:回滚攻击
攻击者可能尝试通过将固件或软件降级到一个存在已知漏洞的版本,从而利用这些漏洞进行攻击。启动HSE的固件,不可以卸载HSE,只能升级。
在使能Secure Boot基于 https://github.com/carloscn/libs/blob/master/nxp/s32k344/sw745310_SecureBootAppNoteDemo.zip 这个版本,手册对应AN13465 Rev. 0.1.1.0, 12/2021。S32K344无论是HSE还是RTD,都对版本比较敏感。因此,我们谨慎对待版本的选择。主要涉及:
RTD Driver的安装是通过S32DS安装,类似可以串口的工程: https://github.com/carloscn/blog/issues/240
HSE Firmware安装,请参考: https://github.com/carloscn/blog/issues/236
Secure Boot的工程我放在这里:
打开之后:
通过S32DS.3.5 IDE,import功能,打开exist project,导入工程:
需要先编译App (S32K344_SecureBootAppABSwap_Example_100_341_FW0110),再编译Cfg (S32K344_SecureBootCfgABSwap_Example_100_341_FW0110),因为Cfg需要依赖App的bin文件。
工程 S32K344_SecureBootAppABSwap_Example_100_341_FW0110 未来是我们自己的业务工程。在NXP的工程中 S32K344_SecureBootAppABSwap_Example_100_341_FW0110和S32K344_SecureBootCfgABSwap_Example_100_341_FW0110共用一个main.c文件,通过工程定义的宏定义隔离开功能。
NXP的Secure Boot的Demo工程环境变量有问题,修改成为:
我的S32DS.3.5安装路径并非是默认的路径,而是C:\opt\NXP\S32DS.3.5,所以环境变量应该替换成为正确的环境变量。
C:\opt\NXP\S32DS.3.5
C:\opt\NXP\S32DS.3.5\eclipse\..\S32DS\build_tools\gcc_v10.2\gcc-10.2-arm32-eabi\bin;C:\opt\NXP\S32DS.3.5\S32DS\build_tools\msys32\usr\bin;C:/opt/NXP/S32DS.3.5/eclipse/jre/bin/server;C:/opt/NXP/S32DS.3.5/eclipse/jre/bin;C:/opt/NXP/S32DS.3.5/eclipse/jre/lib/amd64;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\WINDOWS\System32\WindowsPowerShell\v1.0\;C:\WINDOWS\System32\OpenSSH\;C:\Program Files (x86)\PuTTY\;"C:\Program Files\Java\jre1.8.0_221\bin;";C:\Program Files\TortoiseSVN\bin;C:\Program Files\Git\cmd;C:\Program Files\MATLAB\R2020a\runtime\win64;C:\Program Files\MATLAB\R2020a\bin;C:\Program Files\CMake\bin;C:\Program Files\TortoiseGit\bin;C:\Program Files\OpenSSL-Win64\bin;C:\Program Files (x86)\Pulse Secure\VC142.CRT\X64\;C:\Program Files (x86)\Pulse Secure\VC142.CRT\X86\;C:\Program Files (x86)\Common Files\Pulse Secure\VC142.CRT\X64\;C:\Program Files (x86)\Common Files\Pulse Secure\VC142.CRT\X86\;C:\Program Files (x86)\RedHat\java-1.8.0-openjdk-1.8.0.275-1\bin;C:\Program Files (x86)\RedHat\java-1.8.0-openjdk-1.8.0.275-1\jre\bin;C:\Program Files\RedHat\java-1.8.0-openjdk-1.8.0.275-1\bin;C:\Program Files\RedHat\java-1.8.0-openjdk-1.8.0.275-1\jre\bin;C:\Users\NXF55009\AppData\Local\Programs\Python\Python38\Scripts\;C:\Users\NXF55009\AppData\Local\Programs\Python\Python38\;C:\Users\NXF55009\AppData\Local\Microsoft\WindowsApps;c:\Programs\Microsoft VS Code\bin;C:\Program Files\CMake\bin;D:\dev\s32k148avb_master\tools\ninja;C:\opt\NXP\S32DS.3.3\S32DS\build_tools\gcc_v9.2\gcc-9.2-arm32-eabi\bin;C:\Program Files\CodeBlocks\MinGW\bin;;C:\opt\NXP\S32DS.3.5\S32DS\tools\S32Trace\bin;C:\opt\NXP\S32DS.3.5\eclipse
在原始的工程基础上,需要创建以下格式在NVM中:
#ifdef SECURE_BOOT_CFG const char program_info[] = "CFG"; unsigned int __attribute__((section("._int_ivt_0"))) ivt_flash[] = { /*00h*/ SBAF_BOOT_MARKER /* IVT marker */ , /* Boot configuration word */ /*04h*/ (CM7_0_ENABLE << CM7_0_ENABLE_SHIFT) | (CM7_1_ENABLE << CM7_1_ENABLE_SHIFT) , /*08h*/ IVT_RESERVED /* Reserved */ , /*C0h*/ CM7_0_VTOR_ADDR /* CM7_0 Start address */ , /*10h*/ IVT_RESERVED /* Reserved */, /*14h*/ CM7_1_VTOR_ADDR /* CM7_1 Start address , lockstep only run CM7_0 */ , /*18h*/ IVT_RESERVED /* Reserved */ , /*1ch*/ CM7_2_VTOR_ADDR /* CM7_2 Start address , lockstep only run CM7_0 */ , /*20h*/ XRDC_CONFIG_ADDR /* XRDC configuration pointer */ , /*24h*/ LF_CONFIG_ADDR /* Lifecycle configuration pointer */ , /*28h*/ IVT_RESERVED /* Reserved */, /*2ch*/ HSE_FW_ADDR /* Reserved */, /*30h*/ SECURE_BOOT_APP_ADDR , /*34h*/ IVT_RESERVED , /*38h*/ SECURE_BOOT_BACKUP_ADDR , /*3ch*/ IVT_RESERVED , /*f0h*/ IVT_GMAC , }; #endif
需要注意的是,IVT需要放置在闪存块的开始位置,它通常占据一个完整的扇区(对于S32K344,擦除操作在扇区中进行,一个扇区是8KB,0x2000B),尽管它的大小只有256字节。
显示了App工程中的AppBL内容,包括App代码启动地址、代码大小以及一些基本安全引导所需的信息。应用程序代码地址需要对齐,并通常放置在一个扇区的开始。在原始的工程基础上,需要创建以下格式在NVM中:
这个App的demo实现了一个run_crypto_example的简单功能:
#ifdef SECURE_BOOT_APP const char program_info[] = "APP"; /* * 0x100000 - 1024KB * 0x80000 - 512KB * 0x40000 - 256KB * 0x20000 - 128KB * 0x10000 - 64KB * */ extern uint32_t __text_start; extern uint32_t __text_size ; const hseAppHeader_t __attribute__((section("._app_boot_header"))) app_header = { .hdrTag = 0xD5 , .reserved1 = {0}, .hdrVersion = 0x60 , .pAppDestAddres = 0x00 , .pAppStartEntry = (uint32_t)( &__text_start ) , .codeLength = (uint32_t)( 0x80000u - APPBL_START_ADDR_OFFSET - APP_HEADER_LENGTH ), .coreId = 0x00u , .reserved2 = {0}, }; #endif
相应地map文件:
Demo是UART0,我的板子是UART3,需要改变一下mex的配置。调试之后烧录cfg工程,运行:
[S32K344] Secure Boot Application
1. Overall
本文来捋顺以下,Secure Boot如何使能。和其他MCU的Secure Boot不同,S32K344的固件需要SoC之上的HSE进行密钥管理和固件签名,而其他的MCU控制器通常是在编译固件的时候进行签名,接着使用烧录器烧录到芯片的NVM中。
对于一般的Secure Boot和S32K3系列的Secure Boot做以下对比:
1.1 流程概述
对于S32K344理论上需要编译两个工程:
首先,是App工程。该工程就是我们正常的S32K344的业务工程。不过相比于普通的业务工程,还需要定义包含App头的描述之类的,所以link文件和工程需要做一些适配;
然后,是Secure Boot配置工程。该工程用于配置Secure Boot,在编译阶段,我们需要把App工程的二进制指定到该工程中。通过烧录和运行该工程,该工程会完成:
当Secure Boot配置工程执行完成之后,在板子下一次reset之后,就完成了secure boot的使能,并且能正确引导App工程的启动。
如果需要重新烧录固件,则需要重新使用Secure Boot配置工程。
1.2 如何保证安全性
Secure Boot保证的是非法固件的启动和运行,安全性的保证是通过HSE的签名操作。
攻击1 : 在一个已经启动Secure Boot的设备上,替换NVM存储器(例如Flash)
通过SBAF(BootROM)程序强制从HSE启动,并利用HSE内置密钥进行固件验证,确实能够有效防止未经授权的固件运行。这种设计确保了攻击者即使通过物理手段替换NVM,也无法绕过HSE的签名验证,从而防止恶意固件的加载。因此,这种机制能够有效抵御通过NVM替换进行的攻击,提供了很强的安全性。
攻击2:通过JTAG接口下载恶意代码并尝试清空HSE的密钥
SoC启动HSE之后,需要开启Secure Debug功能。通过在eFUSE中烧录DAPK或AES密钥,或通过挑战响应模式来验证调试者的身份,这种机制能够有效地防止未经授权的JTAG访问。如果攻击者没有正确的密钥或身份验证手段,那么他们将无法通过JTAG接口重新烧录程序或清空HSE的密钥。因此,这种机制在防止物理调试接口攻击方面是安全的。参考: https://www.pemicro.com/blog/index.cfm?post_id=216
攻击3:通过App的外部接口进行反向固件注入
SBAF程序会强制通过HSE验证固件,并且MPU配置了对HSE区域的保护。对于普通应用程序区域,HSE在启动时验证固件的签名,防止未授权固件通过外部接口(如网络、串口)注入。而对于HSE固件,MPU的保护使得HSE区域无法被写入,从而防止通过应用程序进行的攻击。
攻击4:回滚攻击
攻击者可能尝试通过将固件或软件降级到一个存在已知漏洞的版本,从而利用这些漏洞进行攻击。启动HSE的固件,不可以卸载HSE,只能升级。
2. 使能Secure Boot
2.1 工程依赖配置
在使能Secure Boot基于 https://github.com/carloscn/libs/blob/master/nxp/s32k344/sw745310_SecureBootAppNoteDemo.zip 这个版本,手册对应AN13465 Rev. 0.1.1.0, 12/2021。S32K344无论是HSE还是RTD,都对版本比较敏感。因此,我们谨慎对待版本的选择。主要涉及:
RTD Driver的安装是通过S32DS安装,类似可以串口的工程: https://github.com/carloscn/blog/issues/240
HSE Firmware安装,请参考: https://github.com/carloscn/blog/issues/236
Secure Boot的工程我放在这里:
打开之后:
通过S32DS.3.5 IDE,import功能,打开exist project,导入工程:
需要先编译App (S32K344_SecureBootAppABSwap_Example_100_341_FW0110),再编译Cfg (S32K344_SecureBootCfgABSwap_Example_100_341_FW0110),因为Cfg需要依赖App的bin文件。
2.2 App工程编译
工程 S32K344_SecureBootAppABSwap_Example_100_341_FW0110 未来是我们自己的业务工程。在NXP的工程中 S32K344_SecureBootAppABSwap_Example_100_341_FW0110和S32K344_SecureBootCfgABSwap_Example_100_341_FW0110共用一个main.c文件,通过工程定义的宏定义隔离开功能。
NXP的Secure Boot的Demo工程环境变量有问题,修改成为:
我的S32DS.3.5安装路径并非是默认的路径,而是
C:\opt\NXP\S32DS.3.5
,所以环境变量应该替换成为正确的环境变量。Cfg工程分析
在原始的工程基础上,需要创建以下格式在NVM中:
需要注意的是,IVT需要放置在闪存块的开始位置,它通常占据一个完整的扇区(对于S32K344,擦除操作在扇区中进行,一个扇区是8KB,0x2000B),尽管它的大小只有256字节。
App工程分析
显示了App工程中的AppBL内容,包括App代码启动地址、代码大小以及一些基本安全引导所需的信息。应用程序代码地址需要对齐,并通常放置在一个扇区的开始。在原始的工程基础上,需要创建以下格式在NVM中:
这个App的demo实现了一个run_crypto_example的简单功能:
相应地map文件:
2.3 上板子测试
Demo是UART0,我的板子是UART3,需要改变一下mex的配置。调试之后烧录cfg工程,运行: