LPC55Sxx Secure Boot#

This notebook describes how to set up a basic secure boot on LPC55Sxx devices using the SPSDK command line utilities, it is based on the application note AN12283.

Secure Boot ensures authenticity, integrity and confidentiality of any software during the boot process and ensures that the intended secure level is reached. Secure Boot ensures that only properly signed (Original equipment manufacturer (OEM)-authentic) code can be executed on a device, protecting debug access is of utmost importance. Secure boot provides guarantee that unauthorized code cannot be executed on a given product.

At the end of this example, the signed application will be provided and the chip will be secured for that reason only application signed by key’s owner can boot.

1. Prerequisites#

  • SPSDK is needed with examples extension. pip install spsdk[examples] (Please refer to the installation documentation.)

FAMILY = "lpc55s69"
WORKSPACE = "workspace/"  # change this to path to your workspace
KEYS = "../_data/keys/rsa2048/"  # change this to path to your keys
VERBOSITY = (
    ""  # verbosity of commands, might be -v or -vv for debug or blank for no additional info
)

ELF_PATH = "lpcxpresso55s69_led_blinky.axf"
BINARY_FILE = WORKSPACE + "lpcxpresso55s69_led_blinky.bin"

2. Image preparation#

First step is to prepare a binary file in BIN or SREC format. Usually the output from the IDE is in ELF (AXF) format. ELF file cannot be used directly, it needs to be converted to plain (BIN) binary. To get the raw binary file you can for example use the arm-none-eabi-objcopy which is part of the armgcc toolchain. In MCUXpresso You can configure it as a post build step, this is better described here.

Another option is to use the SPSDK nxpimage tool that can convert ELF file to BIN.

# convert the elf file to bin using nxpimage
%! nxpimage $VERBOSITY utils binary-image convert -i $ELF_PATH -f BIN -o $BINARY_FILE

assert os.path.exists(BINARY_FILE)
nxpimage  utils binary-image convert -i lpcxpresso55s69_led_blinky.axf -f BIN -o workspace/lpcxpresso55s69_led_blinky.bin 
Success. (Converted file: workspace/lpcxpresso55s69_led_blinky.bin created.)

3. Prepare Master Boot Image (MBI)#

We used the nxpimage tool for image conversion. Plain binary file can be used directly for the unsecure boot. To setup a secure boot we need to generate Master Boot Image (MBI). MBI can also be used directly or as an output to Secure Binary container in addition to raw binary it might contain CRC checksum, certificates and ARM TrustZone configuration.

There are three types of MBI for LP55sxx based on the authentication type: Plain, CRC and Signed and two variants of CRC and Signed images based on the execution target, either XIP (Executed in place) or in RAM.

Plain Image

CRC Unsigned Image

These images contain a CRC32 field computed on the entire image (excluding the CRC32 field).

Signed Image

LPC55Sxx devices support booting of RSA2048 signed images using RSASSA-PKCS1-v1_5 signature verification. LPC55Sxx devices support 2048-bit or 4096-bit RSA keys and X.509 V3 certificates. Image validation is a two-step process. The first step is the validation of the X.509 certificate inserted in the image. This contains the image public key used in the second step to validate the entire image (including the certificate) to allow customers to add additional PKI structure. The signed image boot supports up to 4 Root of Trust (RoT) keys and up to 16 Image key certificates with image revocation feature.

3.1 Prepare Certificate Block v1.0#

In order to create signed MBI the certification block that keeps the RoT info must be prepared.

  • In our case we have already prepared certification block to simplify the example.

  • To learn how to create a certificate blok check the whole example is presented in dedicated notebook (see How-to-get-cert-block).

3.2 Prepare MBI Configuration file#

Generation of MBI is done with the nxpimage tool. First, we need to get the configuration template that will be used as a starting point.

Let’s begin by creating a template configuration file using the nxpimage mbi get-templates command. To simplify this example, we have already prepared a certificate block, which can be found in the mbi_config_lpc55s6x.yaml file. Below, we’ll compare the differences between the template and our customized example to highlight the additions we’ve made.

# Get difference of template and user YAML configuration
YamlDiffWidget("inputs/lpc55sxx_secure_boot.diffc").html
nxpimage mbi get-templates -f lpc55s69 -o workspace/ --force 
Creating workspace/lpc55s69_xip_plain.yaml template file.
Creating workspace/lpc55s69_xip_crc.yaml template file.
Creating workspace/lpc55s69_xip_signed.yaml template file.
Creating workspace/lpc55s69_load_to_ram_crc.yaml template file.
Creating workspace/lpc55s69_load_to_ram_signed.yaml template file.

Configuration Differences

3.3 MBI generation#

We have created certificates, keys and certificate block required for the creation of Master Boot Image. So now it’s time to create an MBI.

MBI_BIN_NAME = "lpc55s6x_mbi.bin"
MBI_CONFIG_PATH = "inputs/mbi_config_lpc55s6x.yaml"

# export Master Boot Image
%! nxpimage $VERBOSITY mbi export -c $MBI_CONFIG_PATH

BIN_OUTPUT_PATH = WORKSPACE + MBI_BIN_NAME
assert os.path.exists(BIN_OUTPUT_PATH)
nxpimage  mbi export -c inputs/mbi_config_lpc55s6x.yaml 
RKTH: 60a4d31a7a08825285e3d3e961c850f41876c384e20cf7037664c6aebecc8b88
Success. (Master Boot Image: workspace/lpc55s6x_mbi.bin created.)

Now we have a bootable MBI that we could test, but in order to do that we have to configure PFR.

4. PFR#

PFR - Protected Flash Region. LPC55Sxx contains configuration for the boot ROM in flash region which is protected. This protected region contains settings of boot configuration, security policy, PRINCE settings and so on.

Protected Flash Region with four regions:

  1. Customer in-field Programming Area (CFPA)

  • Image revoke

  • RoT key revoke

  1. Customer Manufacturing Programming Area (CMPA)

  • Boot configuration

  • RoT key table hash

  • Debug configuration

  • Prince configuration

  1. Key Storage for PUF

  2. NXP unique ID and manufacturing system

PFR

For PFR configuration there’s tool PFR. Let’s prepare PFR configuration for CFPA and CMPA pages.

4.1 CMPA page preparation#

ROTKH in CMPA must be set to get the secure boot working. There a three ways to accomplish that. You might set ROTKH in the PFR configuration directly as we did in this example or you might provide a path to the certificate block or master boot image configuration with (-e or –rot-config) option.

The last way is to use the –secret-file option, where you can specify paths to secret files (keys or certificates) that will be used for calculating the ROTKH value.

YamlDiffWidget("inputs/lpc55sxx_secure_boot_cmpa.diffc").html
pfr get-template -t cmpa -f lpc55s69 -o workspace/cmpa_lpc55s6x.yaml --force 
The PFR cmpa template for lpc55s69 has been saved into workspace/cmpa_lpc55s6x.yaml YAML file

Configuration Differences

CMPA_CONFIG_PATH = "inputs/cmpa_lpc55s6x.yaml"
CMPA_BIN = WORKSPACE + "cmpa.bin"

%! pfr $VERBOSITY generate-binary -c $CMPA_CONFIG_PATH -o $CMPA_BIN -e $MBI_CONFIG_PATH

assert os.path.exists(CMPA_BIN)
pfr  generate-binary -c inputs/cmpa_lpc55s6x.yaml -o workspace/cmpa.bin -e inputs/mbi_config_lpc55s6x.yaml 
WARNING:spsdk.pfr.pfr:The DCFG_CC_SOCU_PIN register has been recomputed, because it has been used in configuration and the bitfield INVERSE_VALUE has not been specified (786ms since start, pfr.py:206)
WARNING:spsdk.pfr.pfr:The DCFG_CC_SOCU_DFLT register has been recomputed, because it has been used in configuration and the bitfield INVERSE_VALUE has not been specified (786ms since start, pfr.py:206)
Success. (PFR binary has been generated)

4.2 CFPA page preparation#

By default, the CFPA (Customer field programmable area) page is cleared. There are registers related to secure boot. ROTKH_REVOKE field at CFPA page has to be set up to accept signed images with created certificates.

So we have to enable root key 0 (RoTK0_EN). Another important register is VERSION, it’s monotonic counter which needs to be incremented after every CFPA page update.

In this example we will create unsealed versions of CMPA and CFPA, it means that they could be updated. Sealed (locked) version of CFPA and CMPA might be generated using the -a or –add-seal option.

YamlDiffWidget("inputs/lpc55sxx_secure_boot_cfpa.diffc").html
pfr get-template -t cfpa -f lpc55s69 -o workspace/cfpa_lpc55s6x.yaml --force 
The PFR cfpa template for lpc55s69 has been saved into workspace/cfpa_lpc55s6x.yaml YAML file

Configuration Differences

5. Device preparation#

Now it’s time to prepare the device (enroll keys, load pfr…). In this example we will use LPCXpresso55S69 Evaluation kit.

First step is to enter ISP mode, this could be achieved by either shorting J10 or by simultaneously pressing ISP button and reset button.

LPCXpresso55S69 supports UART and USB-HID interface for the ISP programming. In the picture below we used UART, if you want to use USB, connect the cable to high speed USB port.

lpc55s69

We could use app nxpdevscan to check if the device is connected to the PC in ISP mode.

# check if the device is connected and detected by PC
%! nxpdevscan -u
nxpdevscan -u 
-------- Connected NXP USB Devices --------

USB COMPOSITE DEVICE - NXP SEMICONDUCTOR INC.
Vendor ID: 0x1fc9
Product ID: 0x0021
Path: HID\VID_1FC9&PID_0021\9&3AA499EB&0&0000
Path Hash: 694e4de1
Name: lpc55s69 | lpc5526 | lpc55s26 | lpc5528 | lpc55s28 | nhs52s04 | lpc55s66
Serial number: 
USB_CONNECTION = "-u lpc55s69"
# choose com port or /dev
UART_CONNECTION = "-p com21"

# comment if you want to use UART
# CONNECTION = USB_CONNECTION
CONNECTION = USB_CONNECTION

%! blhost $CONNECTION get-property current-version
blhost -u lpc55s69 get-property current-version 
Response status = 0 (0x0) Success.
Response word 1 = 1258487808 (0x4b030000)
Current Version = K3.0.0

5.1 Key store erase#

You might erase key store by writing a file containing zero bytes with size 3*512 = 1536 B.

# first you need to set property 29 - PFR key store update option
%! blhost $CONNECTION set-property 29 1

# now write the file containing zero bytes to the location of key store
%! blhost $CONNECTION write-memory 0x9E600 zero_1536.bin

# set the property 29 back to 0
%! blhost $CONNECTION set-property 29 0
blhost -u lpc55s69 set-property 29 1 
Response status = 0 (0x0) Success.
blhost -u lpc55s69 write-memory 0x9E600 zero_1536.bin 
Writing memory
Response status = 0 (0x0) Success.
Response word 1 = 1536 (0x600)
blhost -u lpc55s69 set-property 29 0 
Response status = 0 (0x0) Success.

5.3 Compare the CFPA page on target#

We can compare the CFPA page on the target to get the information about programmed version.

CFPA_BIN = WORKSPACE + "cfpa.bin"
CFPA_PARSED = WORKSPACE + "cfpa_parsed.yaml"

# First, read the current CFPA page on the processor and parse it to YAML
%! pfr read -f $FAMILY $CONNECTION -t cfpa -o $CFPA_BIN -y $CFPA_PARSED

# Now, we can manipulate the YAML file to make desired changes
# %! pfr $VERBOSITY generate-binary -c $CFPA_TEMPLATE_PATH -o $CFPA_BIN

assert os.path.exists(CFPA_BIN)

YamlDiffWidget("inputs/lpc55sxx_secure_boot_cfpa_diff.diffc").html
pfr read -f lpc55s69 -u lpc55s69 -t cfpa -o workspace/cfpa.bin -y workspace/cfpa_parsed.yaml 
CFPA page address on lpc55s69 is 0x9de00
CFPA data stored to workspace/cfpa.bin
Parsed config stored to workspace/cfpa_parsed.yaml
pfr get-template -t cfpa -f lpc55s69 -o workspace/cfpa_lpc55s6x.yaml --force 
The PFR cfpa template for lpc55s69 has been saved into workspace/cfpa_lpc55s6x.yaml YAML file

Configuration Differences

5.4 PFR write#

Now that we have enrolled key store, it’s time to write CFPA and CMPA pages. We could use pfr tool or blhost. It is not necessary to programm the CFPA page if the RoTk key is not revoked.

# write CFPA
# %! pfr write $CONNECTION -t cfpa -f $FAMILY -b $CFPA_BIN
# this is the same as
# %! blhost $CONNECTION write-memory 0x0009DE00 $CFPA_BIN

# write CMPA
%! pfr write $CONNECTION -t cmpa -f $FAMILY -b $CMPA_BIN
pfr write -u lpc55s69 -t cmpa -f lpc55s69 -b workspace/cmpa.bin 
CMPA page address on lpc55s69 is 0x9e400
CMPA data written to device.

6. Write MBI#

Last step is to write master boot image to device.

# Erase flash first
%! blhost $CONNECTION flash-erase-region 0 0x10000

# write MBI
%! blhost $CONNECTION write-memory 0 $BIN_OUTPUT_PATH
blhost -u lpc55s69 flash-erase-region 0 0x10000 
Response status = 0 (0x0) Success.
blhost -u lpc55s69 write-memory 0 workspace/lpc55s6x_mbi.bin 
Writing memory
Response status = 0 (0x0) Success.
Response word 1 = 10648 (0x2998)