电子说
1. 4kB EERAM上的CSEc密钥和用户数据
使用S32K148,将启用CSE模块进行安全引导。根据应用说明(“使用S32K148 FlexNVM存储器”,AN12003,版本0,2017年7月),在第3.3节中,64 kB的FlexNVM用作闪存(EEPROM备份和密钥存储在一起),CSEc使用最多512字节的密钥存储,剩下的3.5 kB EERAM用于EEPROM和启用CSEc。在这种用法中,用户数据是否以某种方式通过覆盖或删除注册密钥而保留。简而言之,记录密钥的512字节是随机记录在EERAM中,还是记录在特定位置,如4KB FlexRAM的开始/结束位置?
-> 如果分配的CSEc空间为512B,则FlexRAM(EEPROM)中将无法访问空间0x14000E00-0x14000FFF。对该区域的任何访问都会生成总线故障异常。
2. 关于CSEc安全引导和顺序引导模式的问题。
测量从复位引脚释放到高电平的安全启动时间,不同boot_SIZE和Clock时钟对于安全启动时间有所不同。当安全启动开始启动时(即CSEc正在计算CMAC),MCU内核保持在复位状态,复位引脚也保持在低电平状态,直到CMAC计算完成。
3. 实现 SHA256
在S32K1上面的CSEc 模块支持 AES128 引擎,但不支持 SHA256。但是用户可以参考如下代码实现它。
https://github.com/ARMmbed/mbedtls/blob/v2.16.8/library/sha256.c
4. 当在 S32K146中使用 CSEc模块的时候,程序访问 CSE_PRAM 空间,在调试模式下它将进入异常中断。
#define REG_WRITE32(address, value) ((*(volatile uint32*)(address))= (value))
#define CRYPTO_PRAM_HDR_ADDR32 (0x14001000u)
REG_WRITE32(CRYPTO_PRAM_HDR_ADDR32, u32CommandHeader);
上述代码高亮部分表示写入 PRAM命令,会导致程序进入异常中断。
-> 通过检查SIM_SDID[FEATURES]寄存器,判断S32K芯片是否支持 CSEc。为了使能 CSEc 模块,内存需要分区用于EEPROM,FTFC寄存器需要编程。
5. CSEC模块PRAM格式
在应用笔记 AN5401中,有的是通过 PRAM 页1读取数据,而有的是通过 PRAM页2输出数据,这两种方法有什么不同的吗?
-> 参考手册里面的 CSEc命令
https://www.nxp.com/docs/en/reference-manual/S32K-RM.pdf
这是CMD_GET_ID命令的描述,可以在其中看到使用了哪些页及其目的是什么:
如下是 AN5401文档中的参考代码部分。
6. CSEc不能恢复到工厂模式
通过 CSEC_DRV_DbgChal恢复到工厂模式失败,返回 "STATUS_SEC_KEY_WRITE_PROTECTED"。这里Keys不能被配置为写保护,否则将不能被擦除。
https://www.nxp.com/docs/en/application-note/AN12130.pdf
7. S32K144 闪存分区问题
使用S32K144EVB-Q100和SDK3.0.0以及S32DS进行ARM调试。当使用OpenSDA工具调试闪存时,可以擦除闪存并完成分区闪存,但当使用J-Link调试闪存时无法再次擦除闪存和分区闪存,必须先使用类似J-Flash的工具擦除闪存。如何使用J-Link擦除闪存和分区闪存。是否有调试配置的任何设置?
->在使用SDK API对FlexNVM进行分区时,由于启用了CSEc。
如果启用CSEc,则无法通过命令“全部擦除”或其他FTFC命令擦除FlexNVM。如果要擦除FlexNVM,唯一的方法是使用CSEc命令将FlexNVM复位为出厂状态。有关更多信息,请参阅AN5401。
https://www.nxp.com/webapp/Download?colCode=AN5401
https://www.nxp.com/webapp/Download?colCode=AN5401SW&docLang=en
#include "CSEc_functions.h"
#include "CSEc_macros.h"
#include "CSEc_keys.h"
uint32_t dbg_challenge_out[4] = {0,0,0,0};
int main(void)
{
uint16_t __attribute__((unused)) csec_error = 0; //1 means No Error
csec_error = INIT_RNG(); /* Initialize the Random Number Generator before generating challenge */
//To Erase all keys and reset the part to the factory state
csec_error = DBG_CHAL(dbg_challenge_out); /* Generate the Challenge */
csec_error = DBG_AUTH(dbg_challenge_out); /* Issue the Authorization */
while(1);
/* to avoid the warning message for GHS and IAR: statement is unreachable*/
#if defined (__ghs__)
#pragma ghs nowarning 111
#endif
#if defined (__ICCARM__)
#pragma diag_suppress=Pe111
#endif
return 0;
}
由于 CSEc 模块所有密钥都只能 CSEc 模块管理,这样才能确保密钥安全的安全性。虽然密钥实际存储区域是在模拟 EEPROM 中,但由于这段区域是由 CSEc 管理并且对用户是不可见的,所以也无法通过直接对 DFlash 编程的方式写入密钥。在量产时,可以使用一份专用于写入密钥的程序,通过先刷写这份程序,等写入密钥后,再刷写正式的应用程序即可。需要注意的时,两份程序需要有一致的 D-Flash 分区策略。当然也可以通过诊断服务的方式加载密钥。先脱机计算出密钥的 M1~M5 值,然后通过诊断服务(如 2Eh服务)将 M1~M3 加载至 CSEc 模块中,并通过 M4 和 M5 验证是否加载成功。由于不能通过 M1~M3 值逆推算出密钥值,所以这种方式也是安全的。由于使能 CSEc 模块后,只能通过 CSEc 模块的恢复命令(使用调试器也不行)才能擦除 D-Flash 数据并恢复 D-Flash 至出厂状态,所以如果在量产后需要再次擦除 D-Flash,或者重新对 D-Flash 进行分区等,可以在用户代码中加入相关程序,通过触发这段程序来使用 CSEc 模块的命令擦除 D-Flash。CSEc 模块对 P-Flash的重新编程没有影响。
7. 为CSEc操作分配密钥大小后,需要按照AN5401 4.5中列出的步骤将闪存重置为出厂状态。此外,还提供了一些连接/擦除/编程到S32K器件的提示。
(https://www.nxp.com/docs/en/application-note/AN12130.pdf )
如果没有按照正确的步骤在分配密钥后擦除Flash,器件可能会被锁定,并且无法解锁。
如参考手册所述,分区操作在整个产品周期中最好只执行一次。
可以通过DBG_CHAL 和 DBG_AUTH 销毁分区,不用擦除Flash。
当未分配CSEc时,没有办法在不擦除所有键的情况下删除分区? 因为只需要擦除数据Flash 以及Flash IFR。但是,一旦数据Flash 已经为EEPROM分区,FTFC擦除Flash 块命令就不能擦除数据Flash。
运行DBG_CHAL和DBG_ AUTH命令会擦除所有密钥,包括BOOT_MAC和BOOT_ MAC_KEY。在没有这两个参数的情况下,不会执行安全引导过程,因此应用程序可以自由执行,并且MCU 不会处于复位状态。
DBG_CHAL/DBG_ AUTH即使在严格启动模式处于活动状态时也可以工作,假设所有密钥都没有写保护。这不会锁定 MCU。
成功执行DBG_CHAL/DBG_ AUTH后,所有密钥将被擦除,安全引导处于非活动状态。可以使用任何方式(串行、并行、严格顺序)再次激活安全引导。
注意:对于严格顺序模式,自动MAC计算是不可能的。在激活严格顺序引导之前,必须计算并存储BOOT_MAC。否则将锁定器件。MAC可通过CSEc本身或PC离线计算。有关更多详细信息和代码示例,请参阅 AN5401。
8. 当执行FLASH_DRV_DEFlashPartition 函数的时候, FTFx_FSTAT 是FTFx_FSTAT_ACCERR_MASK。
While((FTFC->FSTAT&FTFC_FSTAT_CCIF_MASK)==0U)
FTFC_FSTAT – 异常时,Flash状态寄存器是 160, Flash Access Error
Flag 标志是 '1',但是正常状态是 128。Flash已经分区,有如下原因导致 ACCERR位被置位。
已通过分区命令启用CSEc,则此时擦除所有块命令将无效(它也应返回ACCERR)。是否加载了密钥并不重要。一旦Flash 分区,并且密钥大小不是 0,则需要使用CMD_DBG_CHAL和CMD_ DBG_ AUTH命令来销毁分区。为此,需要知道MASTER_ECU_KEY。如果尚未加载MASTER_ECU_KEY,则需要加载,然后可以使用CMD_DBG_CHAL和CMD_ DBG_ AUTH命令,别无选择。可以检查SIM模块中的闪存配置寄存器1(FCFG1),查看器件是否已分区。
如果Flash已经分区、CSEc已经使能,FLASH_DRV_EraseAllBlock不能工作。唯一的方案是在了解MASTER_ECU_KEY的情况下使用DBG_CHAL 和 DBG_AUTH 命令恢复。
可以参考如下例子中的 eraseKeys()函数。S32DS.3.4S32DSsoftwareS32SDK_S32K1XX_RTM_4.0.2examplesS32K144driver_examplessystemcsec_keyconfig
在HSRUN模式(112MHz下),CSEc (安全) 或者 EEPROM 擦写将触发错误标志。因为在这种情况下不允许同时使用。器件需要切回到 RUN模式 (80 Mhz) 来执行 CSEc(安全) 或者 EEPROM 写/擦除。
Flash 内存安全在 CSEc 和non-CSEc 器件上都支持,SIM_SDID[7]表示 CSEc 是否在器件上支持。CSEc 和non CSEc 用户需要运行 PGMPART 命令来配置 KeySize。针对 non CSEc 用户,Key Size 必须配置为 0。
整个 EEERAM的空间是减小,为了存储用户 Keys的需要。用户密钥空间实际上成为EEERAM中的不可寻址空间。 针对具有 CSEc或者没有 CSEc的器件,如果 Key size为0,则CSEc_PRAM访问是不允许的。Keysize为零时,是普通EEPROM分区么,直接mass erase就恢复了。通过操作 FLASH_DRV_EraseAllBlockUnsecure函数恢复,或者硬件将Reset引脚短接,然后通过JLINK等外部工具擦除MCU内部的 Flash。
如果S32K146板默认存在分区,通过判断(SIM->FCFG1[FEATURE])确定分区,如果要使用新的分区操作,需要擦除旧的分区,如果不擦,在调试CSEc init_rng或者erase all key的时候会进入defaultISR中断,可以通过上述mass erase方式恢复(keysize为零的情况)。然后重新分区使能 CSEc模块,操作初始化随机数以及加解密,预置秘钥操作。
程序分区命令准备FlexNVM块用作数据闪存、模拟EEPROM备份或两者的组合,并初始化FlexRAM。程序分区命令不能从Flash 启动,因为在程序分区命令执行期间无法访问Flash 资源。与程序分区命令的执行相关的更改在下次复位后生效。在启动其他FTFC和CSEc命令之前,预计将为新器件运行程序分区命令。
注意:虽然FlexNVM可以用不同分区,但其目的是在给定应用程序的整个生命周期中使用一次分区选择。FlexNVM分区代码选择影响器件的耐久性和数据保留特性。中断程序分区操作(由于断电、复位、电源超出指定的操作范围或任何其他原因)会使分区代码处于不确定状态。用户必须采取适当的应对措施,以防止程序分区操作中断时数据丢失。
对于未启用CSEc的部件,Flash KeySize的数量必须配置为2'b00。对于启用CSEc的器件,Flash密钥的数量是用户可配置的,但该空间将假设存在MASTER_ECU_KEY、BOOT_MAC_KEY和BOOT_ MAC(如果启用了任何密钥),因此将占用可用20个密钥槽空间中的3个密钥槽。这导致在1到17个用户keys的范围内留下键槽。对于未启用CSEc的部件,密钥分配必须设置为零密钥(2'b00),否则该命令将返回错误。
注:对于具有CSEc的器件,一旦分配了Flash密钥(无论是否初始化),SHE规范中不带认证将不能擦除Flash 密钥的要求将适用。这意味着在擦除数据Flash(所有Flash 密钥都备份在数据Flash中的模拟EEPROM中)之前,必须运行并通过身份验证(DBG_CHAL和DBG_ AUTH)命令(删除所有 Flash密钥)。因此,擦除所有块和擦除所有块解锁将不起作用,如果所选块/扇区包括存储密钥,则擦除Flash 块或扇区也不起作用。此外,如果任何 Flash密钥受写保护,则无法擦除/删除它们,因此无法擦除数据 Flash,身份验证过程也不会通过。
9. 在S32DS环境下,使用如下 RTM3.0.0的example flash_partitioning_s32k144的例子,在debug RAM下运行就可以擦除以前老的 EEPROM分区。(如果keysize为零,没有使用 CSEc的情况下)
/* Including needed modules to compile this module/procedure */
#include "Cpu.h"
#include "clockMan1.h"
#include "Flash.h"
volatile int exit_code = 0;
/* User includes (#include below this line is not maintained by Processor Expert) */
#include
#include
/* Declare a FLASH config struct which initialized by FlashInit, and will be used by all flash operations */
flash_ssd_config_t flashSSDConfig;
/* Data source for program operation */
#define BUFFER_SIZE 0x100u /* Size of data source */
#define FLASH_TARGET1
uint8_t sourceBuffer[BUFFER_SIZE];
/* Function declarations */
void CCIF_Handler(void);
/* If target is flash, insert this macro to locate callback function into RAM */
void CCIF_Callback(void)
int main(void)
{
/* Write your local variable definition here */
status_t ret; /* Store the driver APIs return code */
uint32_t address;
uint32_t size;
uint32_t failAddr;
uint32_t i;
flash_callback_t pCallBack;
#if (FEATURE_FLS_HAS_PROGRAM_PHRASE_CMD == 1u)
#ifndef FLASH_TARGET
uint8_t unsecure_key[FTFx_PHRASE_SIZE] = {0xFFu, 0xFFu, 0xFFu, 0xFFu, 0xFEu, 0xFFu, 0xFFu, 0xFFu};
#endif
#else /* FEATURE_FLASH_HAS_PROGRAM_LONGWORD_CMD */
uint8_t unsecure_key[FTFx_LONGWORD_SIZE] = {0xFEu, 0xFFu, 0xFFu, 0xFFu};
#endif /* FEATURE_FLS_HAS_PROGRAM_PHRASE_CMD */
/*** Processor Expert internal initialization. DON'T REMOVE THIS CODE!!! ***/
#ifdef PEX_RTOS_INIT
PEX_RTOS_INIT(); /* Initialization of the selected RTOS. Macro is defined by the RTOS component. */
#endif
/*** End of Processor Expert internal initialization. ***/
CLOCK_SYS_Init(g_clockManConfigsArr, CLOCK_MANAGER_CONFIG_CNT,
g_clockManCallbacksArr, CLOCK_MANAGER_CALLBACK_CNT);
CLOCK_SYS_UpdateConfiguration(0U, CLOCK_MANAGER_POLICY_AGREEMENT);
/* Init source data */
for (i = 0u; i < BUFFER_SIZE; i++)
{
sourceBuffer[i] = i;
}
/* Disable cache to ensure that all flash operations will take effect instantly,
* this is device dependent */
#ifndef FLASH_TARGET
#ifdef S32K144_SERIES
MSCM->OCMDR[0u] |= MSCM_OCMDR_OCM1(0x3u);
MSCM->OCMDR[1u] |= MSCM_OCMDR_OCM1(0x3u);
#endif /* S32K144_SERIES */
#endif /* FLASH_TARGET */
/* Install interrupt for Flash Command Complete event */
INT_SYS_InstallHandler(FTFC_IRQn, CCIF_Handler, (isr_t*) 0);
INT_SYS_EnableIRQ(FTFC_IRQn);
/* Enable global interrupt */
INT_SYS_EnableIRQGlobal();
/* Always initialize the driver before calling other functions */
ret = FLASH_DRV_Init(&Flash_InitConfig0, &flashSSDConfig);
DEV_ASSERT(STATUS_SUCCESS == ret);
#if ((FEATURE_FLS_HAS_FLEX_NVM == 1u) & (FEATURE_FLS_HAS_FLEX_RAM == 1u))
/* Config FlexRAM as EEPROM if it is currently used as traditional RAM */
if (flashSSDConfig.EEESize == 0u)
{
#ifndef FLASH_TARGET
/* First, erase all Flash blocks if code is placed in RAM to ensure
* the IFR region is blank before partitioning FLexNVM and FlexRAM */
ret = FLASH_DRV_EraseAllBlock(&flashSSDConfig);
DEV_ASSERT(STATUS_SUCCESS == ret);
/* Verify the erase operation at margin level value of 1 */
ret = FLASH_DRV_VerifyAllBlock(&flashSSDConfig, 1u);
DEV_ASSERT(STATUS_SUCCESS == ret);
/* Reprogram secure byte in Flash configuration field */
#if (FEATURE_FLS_HAS_PROGRAM_PHRASE_CMD == 1u)
address = 0x408u;
size = FTFx_PHRASE_SIZE;
#else /* FEATURE_FLASH_HAS_PROGRAM_LONGWORD_CMD == 1u */
address = 0x40Cu;
size = FTFx_LONGWORD_SIZE;
#endif /* FEATURE_FLS_HAS_PROGRAM_PHRASE_CMD */
ret = FLASH_DRV_Program(&flashSSDConfig, address, size, unsecure_key);
DEV_ASSERT(STATUS_SUCCESS == ret);
#endif /* FLASH_TARGET */
/* Configure FlexRAM as EEPROM and FlexNVM as EEPROM backup region,
* DEFlashPartition will be failed if the IFR region isn't blank.
* Refer to the device document for valid EEPROM Data Size Code
* and FlexNVM Partition Code. For example on S32K144:
* - EEEDataSizeCode = 0x02u: EEPROM size = 4 Kbytes
* - DEPartitionCode = 0x08u: EEPROM backup size = 64 Kbytes */
ret = FLASH_DRV_DEFlashPartition(&flashSSDConfig, 0x02u, 0x08u, 0x0u, false, true);
DEV_ASSERT(STATUS_SUCCESS == ret);
/* Re-initialize the driver to update the new EEPROM configuration */
ret = FLASH_DRV_Init(&Flash_InitConfig0, &flashSSDConfig);
DEV_ASSERT(STATUS_SUCCESS == ret);
/* Make FlexRAM available for EEPROM */
ret = FLASH_DRV_SetFlexRamFunction(&flashSSDConfig, EEE_ENABLE, 0x00u, NULL);
DEV_ASSERT(STATUS_SUCCESS == ret);
}
else /* FLexRAM is already configured as EEPROM */
{
ret = FLASH_DRV_EraseAllBlockUnsecure(&flashSSDConfig);
DEV_ASSERT(STATUS_SUCCESS == ret);
/* Re-initialize the driver to update the new EEPROM configuration */
ret = FLASH_DRV_Init(&Flash_InitConfig0, &flashSSDConfig);
DEV_ASSERT(STATUS_SUCCESS == ret);
}
#endif /* (FEATURE_FLS_HAS_FLEX_NVM == 1u) & (FEATURE_FLS_HAS_FLEX_RAM == 1u) */
/* Set callback function before a long time consuming flash operation
* (ex: erasing) to let the application code do other tasks while flash
* in operation. In this case we use it to enable interrupt for
* Flash Command Complete event */
pCallBack = (flash_callback_t)CCIF_Callback;
flashSSDConfig.CallBack = pCallBack;
/* Erase the last PFlash sector */
address = FEATURE_FLS_PF_BLOCK_SIZE - FEATURE_FLS_PF_BLOCK_SECTOR_SIZE;
size = FEATURE_FLS_PF_BLOCK_SECTOR_SIZE;
ret = FLASH_DRV_EraseSector(&flashSSDConfig, address, size);
DEV_ASSERT(STATUS_SUCCESS == ret);
/* Disable Callback */
flashSSDConfig.CallBack = NULL_CALLBACK;
/* Verify the erase operation at margin level value of 1, user read */
ret = FLASH_DRV_VerifySection(&flashSSDConfig, address, size / FTFx_DPHRASE_SIZE, 1u);
DEV_ASSERT(STATUS_SUCCESS == ret);
/* Write some data to the erased PFlash sector */
size = BUFFER_SIZE;
ret = FLASH_DRV_Program(&flashSSDConfig, address, size, sourceBuffer);
DEV_ASSERT(STATUS_SUCCESS == ret);
/* Verify the program operation at margin level value of 1, user margin */
ret = FLASH_DRV_ProgramCheck(&flashSSDConfig, address, size, sourceBuffer, &failAddr, 1u);
DEV_ASSERT(STATUS_SUCCESS == ret);
/* Try to write data to EEPROM if FlexRAM is configured as EEPROM */
if (flashSSDConfig.EEESize != 0u)
{
address = flashSSDConfig.EERAMBase;
size = sizeof(uint32_t);
ret = FLASH_DRV_EEEWrite(&flashSSDConfig, address, size, sourceBuffer);
DEV_ASSERT(STATUS_SUCCESS == ret);
/* Verify the written data */
if (*((uint32_t *)sourceBuffer) != *((uint32_t *)address))
{
/* Failed to write data to EEPROM */
exit_code = 1u;
return exit_code;
}
/* Try to update one byte in an EEPROM address which isn't aligned */
address = flashSSDConfig.EERAMBase + 1u;
size = sizeof(uint8_t);
sourceBuffer[0u] = 0xFFu;
ret = FLASH_DRV_EEEWrite(&flashSSDConfig, address, size, sourceBuffer);
DEV_ASSERT(STATUS_SUCCESS == ret);
/* Then verify */
if (sourceBuffer[0u] != *((uint8_t *)address))
{
/* Failed to update data to EEPROM */
exit_code = 1u;
return exit_code;
}
}
else
{
#if (FEATURE_FLS_HAS_FLEX_NVM == 1u)
/* Erase a sector in DFlash */
address = flashSSDConfig.DFlashBase;
size = FEATURE_FLS_DF_BLOCK_SECTOR_SIZE;
ret = FLASH_DRV_EraseSector(&flashSSDConfig, address, size);
DEV_ASSERT(STATUS_SUCCESS == ret);
/* Verify the erase operation at margin level value of 1, user read */
ret = FLASH_DRV_VerifySection(&flashSSDConfig, address, size / FTFx_PHRASE_SIZE, 1u);
DEV_ASSERT(STATUS_SUCCESS == ret);
/* Write some data to the erased DFlash sector */
address = flashSSDConfig.DFlashBase;
size = BUFFER_SIZE;
ret = FLASH_DRV_Program(&flashSSDConfig, address, size, sourceBuffer);
DEV_ASSERT(STATUS_SUCCESS == ret);
/* Verify the program operation at margin level value of 1, user margin */
ret = FLASH_DRV_ProgramCheck(&flashSSDConfig, address, size, sourceBuffer, &failAddr, 1u);
DEV_ASSERT(STATUS_SUCCESS == ret);
#endif /* FEATURE_FLS_HAS_FLEX_NVM */
}
#ifdef PEX_RTOS_START
PEX_RTOS_START(); /* Startup of the selected RTOS. Macro is defined by the RTOS component. */
#endif
for(;;) {
if(exit_code != 0) {
break;
}
}
return exit_code;
/*** Processor Expert end of main routine. DON'T WRITE CODE BELOW!!! ***/
} /*** End of main routine. DO NOT MODIFY THIS TEXT!!! ***/
void CCIF_Handler(void)
{
/* Disable Flash Command Complete interrupt */
FTFx_FCNFG &= (~FTFx_FCNFG_CCIE_MASK);
return;
}
void CCIF_Callback(void)
{
/* Enable interrupt for Flash Command Complete */
if ((FTFx_FCNFG & FTFx_FCNFG_CCIE_MASK) == 0u)
{
FTFx_FCNFG |= FTFx_FCNFG_CCIE_MASK;
}
}
运行调试模式,停止,然后再次运行会进入FLASH_DRV_EraseAllBlockUnsecure,关于 Flash组件配置如下。
全部0条评论
快来发表一下你的评论吧 !