How to implement Secure Boot in S32K1 using CSEc?

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

How to implement Secure Boot in S32K1 using CSEc?

2,140 Views
kual_gettobyte
Contributor III

I want to implement Secure Boot in S32K1 MCU's using CSEc Peripheral. But not able to get what would be intended demo and flow for it.

 

What mu understadning is on configuring secure boot, CSEc peripheral will calculate the CMAC onto the application binary using Boot key.

1) In which API, do we refer or how we send the application binary information. In API CSEC_DRV_BootDefine() we only mention size and type of secure boot.  But where will we tell, at which address application binary is of which CMAC has to be calculated.

2) What my understanding, CSEc will calculate the CMAC of the application binary and store it in Boot_MAC_Slot. This will be happening by which API? As their are 3 API's for secure boot in CSEc: CSEC_DRV_BootDefine(), CSEC_DRV_BootOK() and CSEC_DRV_BootFailure(). Out of these which one?

3) What would be flow of API's to use the secure boot.?

 

i have written a piece of code that i will dump at 0x00 address. In that piece of code i have written following API's:

int main(void)
{
	uint32_t u32BootSize = 0x00018000U;
	  status_t statusVal;
  /* Write your code here */
  /* Initialize and configure clocks
   * 	-	see clock manager component for details
   */
  CLOCK_SYS_Init(g_clockManConfigsArr, CLOCK_MANAGER_CONFIG_CNT,
						g_clockManCallbacksArr, CLOCK_MANAGER_CALLBACK_CNT);
  CLOCK_SYS_UpdateConfiguration(0U, CLOCK_MANAGER_POLICY_FORCIBLE);

  status_t flash_init_for_csec;


  /* Initialize pins */
  PINS_DRV_Init(NUM_OF_CONFIGURED_PINS0, g_pin_mux_InitConfigArr0);

  /* Turn off the leds */
  PINS_DRV_SetPins(LED_PORT, (1 << LED_ERROR) | (1 << LED_OK));

  bool keyLoaded;
  uint8_t key[16] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
              0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f};

  /* Initialize CSEc driver */
  CSEC_DRV_Init(&csecState);

  /* Initialize Flash for CSEc operation */
    flash_init_for_csec = initFlashForCsecOperation();

  /* Load the MASTER_ECU key with a known value, which will be used as Authorization
   * key (a secret key known by the application in order to configure other user keys) */
   keyLoaded = setAuthKey();
  /* Load the selected key */

   //load the BOOT_MAC_KEY
   keyLoaded = loadKey(CSEC_BOOT_MAC_KEY, key, 1);

  statusVal = CSEC_DRV_BootDefine(u32BootSize, CSEC_BOOT_SERIAL);


  statusVal =  CSEC_DRV_BootOK();

 

lets say this piece of code occupies memory till 0x100. 

 

4) Now, i just run this piece of code first time. It will store the Boot MAC value. And then run this again, that will perform secure boot mechanism?

5) And now lets say my main application is at address 0x300. So i will dump the application binary at 0x300. But how and where should i put logic that if CMAC is not verified or equal then perform x set of instruction or code. Like i Dont want the application to get execute if CMAC does not matches.

6) Will this logic be implemented in application fw, just at the starting of its main()? Is yes, then how will i get the value of newly generated CMAC and stored CMAC value to compare? OR i have to check the FCSESTAT register's in application binary?

 

0 Kudos
Reply
8 Replies

2,108 Views
kual_gettobyte
Contributor III

[NXP] SEC_DRV_BootOK() and CSEC_DRV_BootFailure() are for something different, it can be used to create a chain of trust. That means the autonomous SHE secure boot will check bootloader only (that's typical use-case).

So did u mean that after 2 resets, it will check the authenticity of the code flashed at address 0x00 flash. Lets name this code as bootloader code( It is flashed from 0x00 to 0x100 address). If secure boot passes, so we will get corresponding secure bits set at FCSESTAT register( In this i will pass CMD_BOOT_OK ). If secure boot fails i will get corresponding bits set at FCSESTAT register.( in this i will pass CMD_BOOT_FAILURE.).

[NXP] Then the bootloader can check CMAC of your application.

So now code flashed at 0x00, that is my bootloader code, i will now calculate CMAC of application binary...lets say (application binary is at 0x300). So i  will calculate CMAC using BOOT MAC Key over the data of the address 0x300. And will check that, if that CMAC matches with application CMAC (the CMAC of application will be calculated and stored separately) then my actual secure boot is done and verified. As now we have verified application as well.

 

 

Some progress in execution end.

I have made this secure boot code using CSEc API's. I run this code from RAM( at some address of 0x1FFFff91, using S32 design Studio) ( Before this i have partioned CSEc and loaded the Master ECU Key).

int main(void)
{
  /* Initialize CSEc driver */
  CSEC_DRV_Init(&csecState);

// keyLoaded = setAuthKey();

// statusVal = CSEC_DRV_BootFailure();

// statusVal =  CSEC_DRV_BootOK();

// load the BOOT_MAC_KEY

  keyLoaded = loadKey(CSEC_BOOT_MAC_KEY, boot_key, 1);
  statusVal = CSEC_DRV_BootDefine(u32BootSize, CSEC_BOOT_SERIAL);

 

and at flash address: 0x00, i have dumpled hello world example. ( via external debugger tool Jlink Lite)

Now when i reset the device 2 times and Debug the code from RAM (via S32 Design Studio) i can see FCSESTAT register values in which secure boot is successfully done.

 

Now i change the application at address 0x00 of flash by dumping adc demo code via jlink flash tool, and then again debug the secure boot code from RAM via S32 Design Studio, i can see FCSESTAT register values in which secure boot is successfully not done.

 

But then when i change back the original hello world application at 0x00 address via jlink and debug the secure boot code again from RAM, it should show success secure boot bits in FCSESTAT register values. As now my original application is being booted at address 0x00. 

 

Correct? Is this analogy and understanding correct!?

If yes, then in last step i get FCSESTAT register values of secure boot as not successfull( CMAC doesnt matches). Why is it so??? Technically and logically it should pass...

Let me know if you are able to get my flow and query, otherwise will send this flow with pics.!

0 Kudos
Reply

2,090 Views
kual_gettobyte
Contributor III

and at flash address: 0x00, i have dumpled hello world example. ( via external debugger tool Jlink Lite)

Now when i reset the device 2 times and Debug the code from RAM (via S32 Design Studio) i can see FCSESTAT register values in which secure boot is successfully done.

kual_gettobyte_1-1742648448655.png

 

 

Now i change the application at address 0x00 of flash by dumping adc demo code via jlink flash tool, and then again debug the secure boot code from RAM via S32 Design Studio, i can see FCSESTAT register values in which secure boot is successfully not done.

kual_gettobyte_2-1742648856193.png

 

 

But then when i change back the original hello world application at 0x00 address via jlink and debug the secure boot code again from RAM, it should show success secure boot bits in FCSESTAT register values. As now my original application is being booted at address 0x00. 

kual_gettobyte_3-1742649145146.png

 

Correct? Is this analogy and understanding correct!?

If yes, then in last step i get FCSESTAT register values of secure boot as not successfull( CMAC doesnt matches). Why is it so??? Technically and logically it should pass...

Let me know if you are able to get my flow and query, otherwise will send this flow with pics.!

0 Kudos
Reply

2,033 Views
lukaszadrapa
NXP TechSupport
NXP TechSupport

Hi @kual_gettobyte 

I think it's because you are calling CSEC_DRV_BootFailure like this in your RAM application:

lukaszadrapa_0-1742801537771.png

You are not supposed to to that in this way.

If you are NOT creating chain of trust, the procedure should be:

1. Check if secure boot was successful (BOK == 1).

2. If it was successful, run CSEC_DRV_BootOK to finish the secure boot. If it failed, run CSEC_DRV_BootFailure.

If you are creating chain of trust:

1. Check if secure boot was successful (BOK == 1).

2. If it failed, run CSEC_DRV_BootFailure. Do not proceed to next steps.

3. If it was successful, verify MAC over your application.

4. If it is OK, run CSEC_DRV_BootOK to finish the secure boot. If it failed, run CSEC_DRV_BootFailure.

 

In other words, I guess that the secure boot was successful but you cleared the BOK  flag by running CSEC_DRV_BootFailure.

Regards,

Lukas

 

0 Kudos
Reply

1,993 Views
kual_gettobyte
Contributor III

Well i tried your suggestion, but still it was same!!!

 

 

0 Kudos
Reply

1,986 Views
lukaszadrapa
NXP TechSupport
NXP TechSupport

I'm sure this works as expected. I even tested it on my side. I had some application in flash. I configured secure boot by an application running from RAM (I re-used project from AN5401). The secure boot is successful after reset. Then I modified the flash content. Secure boot is not successful now, as expected. I loaded original application to the flash and secure boot is successful again.

So, either the flash content is not the same or you have executed CSEC_DRV_BootFailure. I can't see other option.

Regards,

Lukas

0 Kudos
Reply

1,979 Views
kual_gettobyte
Contributor III

Hi Luka, yes with examples of AN514 it works, i guess i missed that to inform earlier.

But in my application development i am using S32K1 Autosar RTD 2.0.1 and using CSEc Non Autosar Driver.

 

With Those API's it is not working as per the flow of demo examples of AN514...

what can be reason for that!??

0 Kudos
Reply

1,962 Views
lukaszadrapa
NXP TechSupport
NXP TechSupport

The only problem I can see is that there was wrong description of u32BootSize (parameter for Csec_Ip_BootDefine function) in RTD 2.0.0. There was a description in the manual that it's "Number of blocks of 128-bit data to check on boot". This is wrong, it's number of bits. It was fixed in version 2.0.0 QLP1 where it says: "Number of bits of data to be checked on boot"

So, this is the only catch. Otherwise it does not matter which SW was used to configure the software. Still the same command is called.

 

 

0 Kudos
Reply

2,117 Views
lukaszadrapa
NXP TechSupport
NXP TechSupport

Hi

Please see my answers below:

1) In which API, do we refer or how we send the application binary information. In API CSEC_DRV_BootDefine() we only mention size and type of secure boot. But where will we tell, at which address application binary is of which CMAC has to be calculated.

[NXP] It always starts from address 0x0. This is hardwired, it cannot be changed. Here is a screenshot from the reference manual:
image.png

2) What my understanding, CSEc will calculate the CMAC of the application binary and store it in Boot_MAC_Slot. This will be happening by which API? As their are 3 API's for secure boot in CSEc: CSEC_DRV_BootDefine(), CSEC_DRV_BootOK() and CSEC_DRV_BootFailure(). Out of these which one?

[NXP] User is supposed to load a BOOT_MAC_KEY and then run CSEC_DRV_BootDefine function to define the size and secure boot mode. After next reset, CSEc will automatically calculate the BOOT_MAC and it will store it to corresponding slot in secure memory. No action is required from user. After second reset, everything is already set up, so CSEc will run secure boot first time.
CSEC_DRV_BootOK() and CSEC_DRV_BootFailure() are for something different, it can be used to create a chain of trust. That means the autonomous SHE secure boot will check bootloader only (that's typical use-case). Then the bootloader can check CMAC of your application. If the check passes, execute CMD_BOOT_OK command to finish the SHE secure boot. If the check fails, execute CMD_BOOT_FAILURE.
This is defined by SHE specification - first stage of the secure boot is autonomous and the others can be done manually. The final status is then provided to SHE by CMD_BOOT_OK or CMD_BOOT_FAILURE commands.

3) What would be flow of API's to use the secure boot.?

[NXP] Take a look at SW example in SDK:
c:\NXP\S32DS.3.4\S32DS\software\S32SDK_S32K1XX_RTM_4.0.3\examples\S32K144\demo_apps\csec_boot_protection\
And also at description of the example in user manual:
c:\NXP\S32DS.3.4_RTD_200\S32DS\software\S32SDK_S32K1XX_RTM_4.0.3\doc\S32SDK_S32K144_UserManual.pdf
In short:
- enable CSEc by parition command
- import MASTER_ECU_KEY
- import other keys you want and configure key attributes as needed (including boot protection attribute BOOT_PROT)
- import BOOT_MAC_KEY
- run CSEC_DRV_BootDefine
- reset the device - it will calculate and store BOOT_MAC
- reset the device - the secure boot will run first time


4) Now, i just run this piece of code first time. It will store the Boot MAC value. And then run this again, that will perform secure boot mechanism?

[NXP] As described above, two resets are needed to run secure boot first time.

5) And now lets say my main application is at address 0x300. So i will dump the application binary at 0x300. But how and where should i put logic that if CMAC is not verified or equal then perform x set of instruction or code. Like i Dont want the application to get execute if CMAC does not matches.

[NXP] If secure boot fails (sequential or parallel boot mode), the only consequence is that boot protected keys cannot be used. The idea behind this is that it does not protect the device or your code, it protects only the keys. If you don't want to allow execution at all, configure strict sequential boot mode. In this case, the device will hang in reset forever. Warning - there's no way to recover. The only option is to replace the device. If you want to use strict mode, I recommend to test everything in normal sequential mode to be sure it works and then switch to strict mode. Notice that it's not possible to get back once strict mode is set.

6) Will this logic be implemented in application fw, just at the starting of its main()? Is yes, then how will i get the value of newly generated CMAC and stored CMAC value to compare? OR i have to check the FCSESTAT register's in application binary?

[NXP] This is done automatically by CSEc on background. You are not supposed to compare the BOOT_MAC manually (you can't read it anyway). You can just check the result in FCSESTAT (if strict mode is not used).

 


I recommend to thoroughly read application note AN5401 and to get familiar with associated examples:
https://www.nxp.com/webapp/Download?colCode=AN5401&location=null
https://www.nxp.com/webapp/Download?colCode=AN5401SW&location=null
It contains all necessary details you need to know. The SW examples were written before the SDK was available, so the API is different. But it is still very useful to understand how it works.

Regards,
Lukas

0 Kudos
Reply