I have some questions about securing bootloader & application code on a RT1064 using signing and BEE encryption which I hope you can help with.
From a prototype running a second bootloader from FlexSPI Flash and then application code, I need a path to tens of products requiring signed, encrypted images, onto potentially thousands of products. So I'm interested in what descisions need to be made now, regarding choices on which keys and configurations to use, which will allow a smooth scale-up of the project.
Currently, the prototype runs a second bootloader, which runs the application. I have the MCUXpresso Secure Provisioning Tool, which I can use to encrypt an image and generate a key. However, I'm not clear here on the "Boot Type" choice: There are two XIP options given,
"BEE OTPMK Key", and
"(BEE User Keys) Authenicated"
What considerations would affect whether to choose one over the other here? The Keys Management tab allows the generation of (what I assume is) the master key, with a given passphrase and serial number. I assume the passphrase and serial number need to be kept confidential and will be common to all products with images encrypted with this key. What effect does the serial number value have?
If the "(BEE User Keys) Authenicated" option is chosen, another key has to be specified, for which there are several options for configuration, for example "User Key Data". Is there any advantage on choosing this option as I assume this will require this data to be stored confidentially also? I there a scenario where this key is needed later?
I watched the webinar on the NXP website showing some demos of signed & encrypted applications. But it didn't touch on how to have a signed & encrypted second bootloader then run a signed & encrypted application. In this scenario, is the application image generated in the same way using the Secure Provisioning Tool and how does the bootloader code verify and run this? Is there an application note which has examples of this?
Looking further ahead to production units where JTAG is not available, then what mechanisms can be employed to program the key data in the eFuses? Is this something that NXP would do before shipping an order of RT1064s, or would this be done programatically the first time the bootloader is run? Are there examples available for this?
Thanks in advance for any comments.
已解决! 转到解答。
This has been a long thread with a number of questions.
I have some comments for NXP:
For the use-case of using a signed second bootloader, which then executes an encrypted main application: I would think this is common, but seems really unsupported by NXP. The solution given by NXP in AN12604 is good - or should be, except that it is not supported by NXP tools. The image_generate.exe tool attached in AN12604SW is Windows-only and there is no documentation showing what it does - really, this cannot be used. And the image_enc tool, which is cross-platform, does something different, but there is no documentation for this tool, and NXP provide no help for how a second bootloader might call an application image generated from image_enc.
Basically, all the NXP tools assume the user wants to create one boot-able image, to be uploaded using their RAM Flashloader. This is fine if there is no second bootloader and if the serial/USB interface is available. Again, I would think it is quite common that the user wants to create a binary file to be flashed using JTAG. This method seems unsupported by NXP.
For your reference, I have managed to create a signed binary file for a second bootloader image, to be flashed via JTAG, using these steps:
Build the second bootloader image in full in MCUXpresso, Leave XIP_BOOT_HEADER_ENABLE set to 1.
Add a post-build step in MCUXpresso to produce a SREC file output
Use the "SRecord" utility to extract the FCB section (0x0 - 0x1FF) and save it ("fcb.srec")
Use the "SRecord" utllity to remove the FCB, IVT & BD sections from the bootloader image (exclude 0x0 - 0x1FFF)
Use the elftosb tool or Secure Provisioning Tool (SPT) to generate the signed image ("bootloader.bin")
Use the "SRecord" utility to merge the saved FCB section and the output from the tool ("fcb.srec" + "bootloader.bin").
This works fine.
I also created an encrypted application image, which can be called from this bootloader. The NXP tools are not used here, rather openssl:
openssl enc -e -aes-128-ctr -nopad -nosalt -K 11223344556677889900aabbccddeeff -iv 1234567890ABCDEF0102030406002000 -in application.bin -out application_enc.bin
The Initial Vector (iv) used is 1234567890ABCDEF01020304 with (<start-address> >> 4) appended. So in this case, the start address is 0x60020000.
In the bootloader, setup BEE to decrypt over the memory starting at 0x60020000, using the following code:
#include "fsl_bee.h"
#define FLEXSPI_START_ADDR 0x60020000U
#define REG0_START_ADDR_GPR GPR18
#define REG0_END_ADDR_GPR GPR19
#define REG0_DECRYPT_EN_GPR GPR11
#define REG0_DECRYPT_EN IOMUXC_GPR_GPR11_BEE_DE_RX_EN(1)
#define AES_KEY_LEN 16
#define AES_NONCE_LEN 16
#define BEE_REGION_SIZE 0x10000U
static const uint8_t aesKey[] = {0xFF, 0xEE, 0xDD, 0xCC, 0xBB, 0xAA, 0x00, 0x99, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11};
static const uint8_t aesNonce[] = {0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x02, 0x01, 0xEF, 0xCD, 0xAB, 0x90, 0x78, 0x56, 0x34, 0x12};
bee_region_config_t beeConfig;
IOMUXC_GPR_Type *iomuxc = IOMUXC_GPR;
BEE_Init(BEE);
BEE_GetDefaultConfig(&beeConfig);
beeConfig.region0Mode = kBEE_AesCtrMode;
beeConfig.region1Bot = 0U;
beeConfig.region1Top = 0U;
iomuxc->REG0_START_ADDR_GPR = FLEXSPI_START_ADDR;
iomuxc->REG0_END_ADDR_GPR = FLEXSPI_START_ADDR + BEE_REGION_SIZE;
iomuxc->REG0_DECRYPT_EN_GPR = REG0_DECRYPT_EN;
BEE_SetConfig(BEE, &beeConfig);
BEE_SetRegionKey(BEE, kBEE_Region0, aesKey, AES_KEY_LEN);
BEE_SetRegionNonce(BEE, kBEE_Region0, aesNonce, AES_NONCE_LEN);
BEE_Enable(BEE);
BEE_Deinit(BEE);
This works fine.
So please feedback to NXP internally that the tools and methods recommended by NXP are too focused on creating one bootable image, there seems to be too many ways of doing the same thing with different tools, but not enough ways of doing what you want. There is also missing documentation and application notes which provide only part of a solution.
Hi,
After checking, the image_enc.exe and image_generate.exe actually generate different results when inputting the same parameters, I guess it's related to the ways of parsing the key of the image_enc.exe and image_generate.exe.
In my opinion, I'd like to suggest you use the MCUXpresso Secure Provisioning tool to build an encrypted image from a raw image (as the figure shows),
1) load the raw image;
2) Configure the XIP keys;
3) Clicking the Bulid image, then the tool will generate an encrypted image.
Have a great day,
TIC
-------------------------------------------------------------------------------
Note:
- If this post answers your question, please click the "Mark Correct" button. Thank you!
- We are following threads for 7 weeks after the last post, later replies are ignored
Please open a new thread and refer to the closed one, if you have a related question at a later point in time.
-------------------------------------------------------------------------------
This has been a long thread with a number of questions.
I have some comments for NXP:
For the use-case of using a signed second bootloader, which then executes an encrypted main application: I would think this is common, but seems really unsupported by NXP. The solution given by NXP in AN12604 is good - or should be, except that it is not supported by NXP tools. The image_generate.exe tool attached in AN12604SW is Windows-only and there is no documentation showing what it does - really, this cannot be used. And the image_enc tool, which is cross-platform, does something different, but there is no documentation for this tool, and NXP provide no help for how a second bootloader might call an application image generated from image_enc.
Basically, all the NXP tools assume the user wants to create one boot-able image, to be uploaded using their RAM Flashloader. This is fine if there is no second bootloader and if the serial/USB interface is available. Again, I would think it is quite common that the user wants to create a binary file to be flashed using JTAG. This method seems unsupported by NXP.
For your reference, I have managed to create a signed binary file for a second bootloader image, to be flashed via JTAG, using these steps:
Build the second bootloader image in full in MCUXpresso, Leave XIP_BOOT_HEADER_ENABLE set to 1.
Add a post-build step in MCUXpresso to produce a SREC file output
Use the "SRecord" utility to extract the FCB section (0x0 - 0x1FF) and save it ("fcb.srec")
Use the "SRecord" utllity to remove the FCB, IVT & BD sections from the bootloader image (exclude 0x0 - 0x1FFF)
Use the elftosb tool or Secure Provisioning Tool (SPT) to generate the signed image ("bootloader.bin")
Use the "SRecord" utility to merge the saved FCB section and the output from the tool ("fcb.srec" + "bootloader.bin").
This works fine.
I also created an encrypted application image, which can be called from this bootloader. The NXP tools are not used here, rather openssl:
openssl enc -e -aes-128-ctr -nopad -nosalt -K 11223344556677889900aabbccddeeff -iv 1234567890ABCDEF0102030406002000 -in application.bin -out application_enc.bin
The Initial Vector (iv) used is 1234567890ABCDEF01020304 with (<start-address> >> 4) appended. So in this case, the start address is 0x60020000.
In the bootloader, setup BEE to decrypt over the memory starting at 0x60020000, using the following code:
#include "fsl_bee.h"
#define FLEXSPI_START_ADDR 0x60020000U
#define REG0_START_ADDR_GPR GPR18
#define REG0_END_ADDR_GPR GPR19
#define REG0_DECRYPT_EN_GPR GPR11
#define REG0_DECRYPT_EN IOMUXC_GPR_GPR11_BEE_DE_RX_EN(1)
#define AES_KEY_LEN 16
#define AES_NONCE_LEN 16
#define BEE_REGION_SIZE 0x10000U
static const uint8_t aesKey[] = {0xFF, 0xEE, 0xDD, 0xCC, 0xBB, 0xAA, 0x00, 0x99, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11};
static const uint8_t aesNonce[] = {0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x02, 0x01, 0xEF, 0xCD, 0xAB, 0x90, 0x78, 0x56, 0x34, 0x12};
bee_region_config_t beeConfig;
IOMUXC_GPR_Type *iomuxc = IOMUXC_GPR;
BEE_Init(BEE);
BEE_GetDefaultConfig(&beeConfig);
beeConfig.region0Mode = kBEE_AesCtrMode;
beeConfig.region1Bot = 0U;
beeConfig.region1Top = 0U;
iomuxc->REG0_START_ADDR_GPR = FLEXSPI_START_ADDR;
iomuxc->REG0_END_ADDR_GPR = FLEXSPI_START_ADDR + BEE_REGION_SIZE;
iomuxc->REG0_DECRYPT_EN_GPR = REG0_DECRYPT_EN;
BEE_SetConfig(BEE, &beeConfig);
BEE_SetRegionKey(BEE, kBEE_Region0, aesKey, AES_KEY_LEN);
BEE_SetRegionNonce(BEE, kBEE_Region0, aesNonce, AES_NONCE_LEN);
BEE_Enable(BEE);
BEE_Deinit(BEE);
This works fine.
So please feedback to NXP internally that the tools and methods recommended by NXP are too focused on creating one bootable image, there seems to be too many ways of doing the same thing with different tools, but not enough ways of doing what you want. There is also missing documentation and application notes which provide only part of a solution.
Thanks for sharing this information!
Do you know where you found the information about what the IV should be? I've tried to encrypt my main application image and flashed it, but my bootloader doesn't seem to accept it. I haven't done anything in the bootloader wrt. configuring the BEE, but in the Secure Provisioning Tool I increased the size of the encrypted region to encompass both my bootloader and application, so I thought it might no be necessary?