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 https://www.nxp.com/docs/en/application-note/AN12283.pdf.

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: https://mcuoneclipse.com/2017/03/29/mcuxpresso-ide-s-record-intel-hex-and-binary-files/

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

%run ../init_notebook.ipynb

import os
import pprint

pp = pprint.PrettyPrinter(indent=4)

WORKSPACE = "workspace/" # change this to path to your workspace
KEYS = "../_data/keys/rsa2048/" # change this to path to your keys
VERBOSITY = "-v" # 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"

# 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)
env: JUPYTER_SPSDK=1
Created `%!` as an alias for `%execute`.
nxpimage -v utils binary-image convert -i lpcxpresso55s69_led_blinky.axf -f BIN -o workspace/lpcxpresso55s69_led_blinky.bin 
INFO:spsdk.apps.nxpimage:
+==0x0000_0000= lpcxpresso55s69_led_blinky.axf ==+
|             Size: 8.8 kB; 8,820 B              |
|The image loaded from: c:/Users/nxf91894/spsdk/e|
|xamples/lpc55sxx_secure_boot/lpcxpresso55s69_led|
|                 _blinky.axf .                  |
|+==0x0000_0000= Segment 0 =====================+|
||            Size: 8.8 kB; 8,820 B             ||
|+==0x0000_2273=================================+|
+==0x0000_2273===================================+

Success. (Converted file: C:\Users\nxf91894\spsdk\examples\lpc55sxx_secure_boot\workspace\lpcxpresso55s69_led_blinky.bin created.)

MBI preparation#

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.

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

# generate template for mbi
TEMPLATES_PATH = WORKSPACE + "templates"
# choose family for the MCU
FAMILY = "lpc55s6x"

%! nxpimage $VERBOSITY mbi get-templates -f $FAMILY -o $TEMPLATES_PATH --force
# just for verification that the template was generated
assert os.path.exists(os.path.join(TEMPLATES_PATH, "lpc55s6x_xip_signed.yaml"))
nxpimage -v mbi get-templates -f lpc55s6x -o workspace/templates --force
Creating /Users/macbook-m1/spsdk_test/spsdk/examples/jupyter_examples/lpc55sxx_secure_boot/workspace/templates/lpc55s6x_xip_plain.yaml template file.
Creating /Users/macbook-m1/spsdk_test/spsdk/examples/jupyter_examples/lpc55sxx_secure_boot/workspace/templates/lpc55s6x_xip_crc.yaml template file.
Creating /Users/macbook-m1/spsdk_test/spsdk/examples/jupyter_examples/lpc55sxx_secure_boot/workspace/templates/lpc55s6x_xip_signed.yaml template file.
Creating /Users/macbook-m1/spsdk_test/spsdk/examples/jupyter_examples/lpc55sxx_secure_boot/workspace/templates/lpc55s6x_load_to_ram_crc.yaml template file.
Creating /Users/macbook-m1/spsdk_test/spsdk/examples/jupyter_examples/lpc55sxx_secure_boot/workspace/templates/lpc55s6x_load_to_ram_signed.yaml template file.

Now open the lpc55s6x_xip_signed.yml with your favorite text editor. You should see a similar file to this:

# ==================  Master Boot Image Configuration template for lpc55s6x, Plain Signed XIP Image.  ==================

# ======================================================================================================================
#                                                  == Basic Settings ==                                                 
# ======================================================================================================================
# ------------------------------------------===== MCU family [Required] =====-------------------------------------------
# Description: MCU family name.
# Possible options: <lpc55s2x, lpc55s6x, nhs52sxx>
family: lpc55s6x
# --------------------------------------===== Application target [Required] =====---------------------------------------
# Description: Definition if application is Execute in Place(XiP) or loaded to RAM during reset sequence.
# Possible options: <xip, load-to-ram>
outputImageExecutionTarget: xip
# -------------------------------===== Type of boot image authentication [Required] =====-------------------------------
# Description: Specification of final master boot image authentication.
# Possible options: <plain, crc, signed, signed-encrypted, signed-nxp>
outputImageAuthenticationType: signed
# ------------------------------------===== Master Boot Image name [Required] =====-------------------------------------
# Description: The file for Master Boot Image result file.
masterBootOutputFile: my_mbi.bin
# ------------------------------------===== Plain application image [Required] =====------------------------------------
# Description: The input application image to by modified to Master Boot Image.
inputImageFile: my_application.bin
# ======================================================================================================================
#                                               == Trust Zone Settings ==                                               
# ======================================================================================================================
# ------------------------------------===== TrustZone enable option [Optional] =====------------------------------------
# Description: If not specified, the Trust zone is disabled.
enableTrustZone: false
# ---------------------------------===== TrustZone Customization file [Optional] =====----------------------------------
# Description: If not specified, but TrustZone is enabled(enableTrustZone) the default values are used.
trustZonePresetFile: my_tz_custom.yaml
# ======================================================================================================================
#                                               == Certificate Block V1 ==                                              
# ======================================================================================================================
# -----------------------------===== Certificate Block binary/config file [Required] =====------------------------------
# Description: Path to certificate block binary or config file.
certBlock: cert_block.bin
# ======================================================================================================================
#                                              == Image Signing Settings ==                                             
# ======================================================================================================================
# --------------------------===== Main Certificate private key [Conditionally required] =====---------------------------
# Description: Main Certificate private key used to sign certificate. It can be replaced by signProvider key.
signPrivateKey: main_prv_key.pem
# -------------------------------===== Signature Provider [Conditionally required] =====--------------------------------
# Description: Signature provider configuration in format 'type=<sp_type>;<key1>=<value1>;<key2>=<value2>".
signProvider: type=file;file_path=my_prv_key.pem

Required fields are marked with [Required] in the comment. We have to change path to masterBootOutputFile that will contain our resulting MBI and inputImageFile which is source image. In this example we won’t enable TrustZone.

SPSDK 2.0 brought a new way of configuration of certificate block. Configuration is now supplied as a separate configuration file. We will handle it later in this notebook.

Keys preparation#

First we need to generate private key that will be used to sign certificates. In this example, we will use nxpcrypto app to generate 2048-bit RSA keys (see How-to-get-keys-using-nxpcrypto).

# load generated key pair for ISK
PRIVATE_KEY_PATH = KEYS + "imgkey_rsa2048.pem"
PUBLIC_KEY_PATH = KEYS + "imgkey_rsa2048.pub"
# verify that keys were loaded
assert os.path.exists(PRIVATE_KEY_PATH)
assert os.path.exists(PUBLIC_KEY_PATH)

Certificates preparation#

Then we need to create certificates. As we already mentioned we will create one root certificate and one chain certificate. We will again use nxpcrypto app. First we need to get template.

# obtain a template for root cert
ROOT_CERT_CONFIG_PATH = WORKSPACE + "root_cert_template.yml"
%! nxpcrypto $VERBOSITY cert get-template -o $ROOT_CERT_CONFIG_PATH --force

# obtain a template for root cert
CHAIN_CERT_CONFIG_PATH = WORKSPACE + "chain_cert_template.yml"
%! nxpcrypto $VERBOSITY cert get-template -o $CHAIN_CERT_CONFIG_PATH --force
nxpcrypto -v cert get-template -o workspace/root_cert_template.yml --force
INFO:spsdk.apps.nxpcertgen:Creating Certificate template...
The configuration template file has been created: /Users/macbook-m1/spsdk_test/spsdk/examples/jupyter_examples/lpc55sxx_secure_boot/workspace/root_cert_template.yml
nxpcrypto -v cert get-template -o workspace/chain_cert_template.yml --force
INFO:spsdk.apps.nxpcertgen:Creating Certificate template...
The configuration template file has been created: /Users/macbook-m1/spsdk_test/spsdk/examples/jupyter_examples/lpc55sxx_secure_boot/workspace/chain_cert_template.yml

Configuration template for certificates should look like this:

# This is template for configuration file used for generating certificates

# ==============================================
# Issuer identification fields
# ==============================================
# All available option can be found within class NameOID in
# cryptography/src/cryptography/x509/oid.py at https://github.com/pyca/cryptography

issuer:
  COMMON_NAME: NXP
  COUNTRY_NAME: CZ
  LOCALITY_NAME: Roznov pod Radhostem
  STATE_OR_PROVINCE_NAME: Morava
  STREET_ADDRESS: 1.maje 1009
  ORGANIZATION_NAME: SPSDK Team

# ==============================================
# Subject identification fields
# ==============================================
# All available option can be found within class NameOID in
# cryptography/src/cryptography/x509/oid.py at https://github.com/pyca/cryptography
subject:
  COMMON_NAME: NXP - SPSDK
  COUNTRY_NAME: CZ
  LOCALITY_NAME: Roznov pod Radhostem
  STATE_OR_PROVINCE_NAME: Morava
  STREET_ADDRESS: 1.maje 1009
  ORGANIZATION_NAME: SPSDK Team
  POSTAL_CODE: 756 61

# ==============================================
# The certificate settings
# ==============================================

# Path, where issuer private key is stored
issuer_private_key: issuer_key.pem
# Path, where subject public key is stored
subject_public_key: subject_key.pub
# Serial number of certificate
serial_number: 12346578
# Validity duration in days
duration: 3650

# ==============================================
# Certificate basic extensions
# ==============================================
extensions:
  BASIC_CONSTRAINTS:
    # Delegate certificate as a signing authority to create an intermediate certificates.
    ca: false  # Valid values true|false
    # Integer length of the path of certificate signature from a given certificate, back to the root certificate
    path_length: 0

Certificates are in x.509 format and should be DER encoded. Root certificates must have ca (Certificate authority) set to true and must be self-signed. That means that issuer must be same as a subject.

ROOT_0_CERT_PATH = WORKSPACE + "ROT1_sha256_2048_65537_v3_ca_crt.der"
CHAIN_CERT_0 = WORKSPACE + "IMG1_1_sha256_2048_65537_v3_usr_key.pem"

import yaml

assert os.path.exists(ROOT_CERT_CONFIG_PATH)
assert os.path.exists(CHAIN_CERT_CONFIG_PATH)

# Create configuration for root certificate
with open(ROOT_CERT_CONFIG_PATH) as cert_config:
    # load yaml configuration to dictionary
    cert = yaml.safe_load(cert_config)
    # make certificate self-signed
    cert['subject'] = cert['issuer'] 
    # change certificate authority to True
    cert['extensions']['BASIC_CONSTRAINTS']['ca'] = True
    # change path to private and public keys
    cert['issuer_private_key'] = PRIVATE_KEY_PATH
    cert['subject_public_key'] = PUBLIC_KEY_PATH

with open(ROOT_CERT_CONFIG_PATH, "w+") as cert_config:
    print("Root Certificate config:")
    pp.pprint(cert)
    # dump the dictionary back to YAML
    yaml.dump(cert, cert_config)

# Create configuration for chain certificate
with open(CHAIN_CERT_CONFIG_PATH) as cert_config:
    # load yaml configuration to dictionary
    cert = yaml.safe_load(cert_config)
    # change certificate authority to False
    cert['extensions']['BASIC_CONSTRAINTS']['ca'] = False
    # change path to private and public keys
    cert['issuer_private_key'] = PRIVATE_KEY_PATH
    cert['subject_public_key'] = PUBLIC_KEY_PATH

with open(CHAIN_CERT_CONFIG_PATH, "w+") as cert_config:
    print("Chain certificate config:")
    pp.pprint(cert)
    # dump the dictionary back to YAML
    yaml.dump(cert, cert_config)
    
# Generate root certificate
%! nxpcrypto $VERBOSITY cert generate -c $ROOT_CERT_CONFIG_PATH -e DER -o $ROOT_0_CERT_PATH --force
# Generate chain certificate
%! nxpcrypto $VERBOSITY cert generate -c $CHAIN_CERT_CONFIG_PATH -e DER -o $CHAIN_CERT_0 --force

# verify that certificates were generated
assert os.path.exists(ROOT_0_CERT_PATH)
assert os.path.exists(CHAIN_CERT_0)
Root Certificate config:
{   'duration': 3650,
    'extensions': {'BASIC_CONSTRAINTS': {'ca': True, 'path_length': 0}},
    'issuer': {   'COMMON_NAME': 'NXP',
                  'COUNTRY_NAME': 'CZ',
                  'LOCALITY_NAME': 'Roznov pod Radhostem',
                  'ORGANIZATION_NAME': 'SPSDK Team',
                  'STATE_OR_PROVINCE_NAME': 'Morava',
                  'STREET_ADDRESS': '1.maje 1009'},
    'issuer_private_key': 'workspace/rsa2048_key.pem',
    'serial_number': 12346578,
    'subject': {   'COMMON_NAME': 'NXP',
                   'COUNTRY_NAME': 'CZ',
                   'LOCALITY_NAME': 'Roznov pod Radhostem',
                   'ORGANIZATION_NAME': 'SPSDK Team',
                   'STATE_OR_PROVINCE_NAME': 'Morava',
                   'STREET_ADDRESS': '1.maje 1009'},
    'subject_public_key': 'workspace/rsa2048_key.pub'}
Chain certificate config:
{   'duration': 3650,
    'extensions': {'BASIC_CONSTRAINTS': {'ca': False, 'path_length': 0}},
    'issuer': {   'COMMON_NAME': 'NXP',
                  'COUNTRY_NAME': 'CZ',
                  'LOCALITY_NAME': 'Roznov pod Radhostem',
                  'ORGANIZATION_NAME': 'SPSDK Team',
                  'STATE_OR_PROVINCE_NAME': 'Morava',
                  'STREET_ADDRESS': '1.maje 1009'},
    'issuer_private_key': 'workspace/rsa2048_key.pem',
    'serial_number': 12346578,
    'subject': {   'COMMON_NAME': 'NXP - SPSDK',
                   'COUNTRY_NAME': 'CZ',
                   'LOCALITY_NAME': 'Roznov pod Radhostem',
                   'ORGANIZATION_NAME': 'SPSDK Team',
                   'POSTAL_CODE': '756 61',
                   'STATE_OR_PROVINCE_NAME': 'Morava',
                   'STREET_ADDRESS': '1.maje 1009'},
    'subject_public_key': 'workspace/rsa2048_key.pub'}
nxpcrypto -v cert generate -c workspace/root_cert_template.yml -e DER -o workspace/ROT1_sha256_2048_65537_v3_ca_crt.der --force
INFO:spsdk.apps.nxpcertgen:Generating Certificate...
INFO:spsdk.apps.nxpcertgen:Loading configuration from yml file...
INFO:spsdk.apps.nxpcertgen:Saving the generated certificate to the specified path...
INFO:spsdk.apps.nxpcertgen:Certificate generated successfully...
The certificate file has been created: /Users/macbook-m1/spsdk_test/spsdk/examples/jupyter_examples/lpc55sxx_secure_boot/workspace/ROT1_sha256_2048_65537_v3_ca_crt.der
nxpcrypto -v cert generate -c workspace/chain_cert_template.yml -e DER -o workspace/IMG1_1_sha256_2048_65537_v3_usr_key.pem --force
INFO:spsdk.apps.nxpcertgen:Generating Certificate...
INFO:spsdk.apps.nxpcertgen:Loading configuration from yml file...
INFO:spsdk.apps.nxpcertgen:Saving the generated certificate to the specified path...
INFO:spsdk.apps.nxpcertgen:Certificate generated successfully...
The certificate file has been created: /Users/macbook-m1/spsdk_test/spsdk/examples/jupyter_examples/lpc55sxx_secure_boot/workspace/IMG1_1_sha256_2048_65537_v3_usr_key.pem

Certificate Block preparation#

SPSDK 2.0 made a change in the way how the configuration for certificate block is prepared. Configuration is now separated from the MBI configuration file into separate configuration file. In this way it could be shared between SB 2.1 and MBI.

Configuration template for certificates should look like this:

# =========================================  Certification Block V1 template  ==========================================

# ======================================================================================================================
#                                             == Certificate V1 Settings ==                                             
# ======================================================================================================================
# --------------------------------------===== Image Build Number [Optional] =====---------------------------------------
# Description: If it's omitted, it will be used 0 as default value.
imageBuildNumber: 0
# --------------------------------===== Chain certificate 0 for root 0 [Optional] =====---------------------------------
# Description: Chain certificate 0 for root certificate 0
chainCertificate0File0: chain_certificate0_depth0.pem
# --------------------------------===== Chain certificate 1 for root 0 [Optional] =====---------------------------------
# Description: Chain certificate 1 for root certificate 0
chainCertificate0File1: chain_certificate0_depth1.pem
# --------------------------------===== Chain certificate 2 for root 0 [Optional] =====---------------------------------
# Description: Chain certificate 2 for root certificate 0
chainCertificate0File2: chain_certificate0_depth2.pem
# --------------------------------===== Chain certificate 3 for root 0 [Optional] =====---------------------------------
# Description: Chain certificate 3 for root certificate 0
chainCertificate0File3: chain_certificate0_depth3.pem
# --------------------------------===== Chain certificate 0 for root 1 [Optional] =====---------------------------------
# Description: Chain certificate 0 for root certificate 1
chainCertificate1File0: chain_certificate1_depth0.pem
# --------------------------------===== Chain certificate 1 for root 1 [Optional] =====---------------------------------
# Description: Chain certificate 1 for root certificate 1
chainCertificate1File1: chain_certificate1_depth1.pem
# --------------------------------===== Chain certificate 2 for root 1 [Optional] =====---------------------------------
# Description: Chain certificate 2 for root certificate 1
chainCertificate1File2: chain_certificate1_depth2.pem
# --------------------------------===== Chain certificate 3 for root 1 [Optional] =====---------------------------------
# Description: Chain certificate 3 for root certificate 1
chainCertificate1File3: chain_certificate1_depth3.pem
# --------------------------------===== Chain certificate 0 for root 2 [Optional] =====---------------------------------
# Description: Chain certificate 0 for root certificate 2
chainCertificate2File0: chain_certificate2_depth0.pem
# --------------------------------===== Chain certificate 1 for root 2 [Optional] =====---------------------------------
# Description: Chain certificate 1 for root certificate 2
chainCertificate2File1: chain_certificate2_depth1.pem
# --------------------------------===== Chain certificate 2 for root 2 [Optional] =====---------------------------------
# Description: Chain certificate 2 for root certificate 2
chainCertificate2File2: chain_certificate2_depth2.pem
# --------------------------------===== Chain certificate 3 for root 2 [Optional] =====---------------------------------
# Description: Chain certificate 3 for root certificate 2
chainCertificate2File3: chain_certificate2_depth3.pem
# --------------------------------===== Chain certificate 0 for root 3 [Optional] =====---------------------------------
# Description: Chain certificate 0 for root certificate 3
chainCertificate3File0: chain_certificate3_depth0.pem
# --------------------------------===== Chain certificate 1 for root 3 [Optional] =====---------------------------------
# Description: Chain certificate 1 for root certificate 3
chainCertificate3File1: chain_certificate3_depth1.pem
# --------------------------------===== Chain certificate 2 for root 3 [Optional] =====---------------------------------
# Description: Chain certificate 2 for root certificate 3
chainCertificate3File2: chain_certificate3_depth2.pem
# --------------------------------===== Chain certificate 3 for root 3 [Optional] =====---------------------------------
# Description: Chain certificate 3 for root certificate 3
chainCertificate3File3: chain_certificate3_depth3.pem
# ======================================================================================================================
#                                                == Root Keys Settings ==                                               
# ======================================================================================================================
# -----------------------------===== Root Certificate File 0 [Conditionally required] =====-----------------------------
# Description: Root certificate file index 0.
rootCertificate0File: my_certificate0.pub
# ------------------------------------===== Root Certificate File 1 [Optional] =====------------------------------------
# Description: Root certificate file index 1.
rootCertificate1File: my_certificate1.pub
# ------------------------------------===== Root Certificate File 2 [Optional] =====------------------------------------
# Description: Root certificate file index 2.
rootCertificate2File: my_certificate2.pub
# ------------------------------------===== Root Certificate File 3 [Optional] =====------------------------------------
# Description: Root certificate file index 3.
rootCertificate3File: my_certificate3.pub
# -----------------------------===== Main Certificate Index [Conditionally required] =====------------------------------
# Description: Index of certificate that is used as a main. If not defined, the certificate matching private key will be
# selected.
mainRootCertId: 0
# ======================================================================================================================
#                                                  == Basic Settings ==                                                 
# ======================================================================================================================
# --------------------------------------===== cert block filename [Required] =====--------------------------------------
# Description: Generated cert block filename.
containerOutputFile: cert_block.bin
CERT_BLOCK_TEMPLATE = WORKSPACE + "cert_block_template.yaml"
CERT_BLOCK_CONFIG_PATH = WORKSPACE + "cert_block_lpc55s6x.yml"
CERT_BLOCK_BIN_NAME = "cert_block.bin"

# Prepare a template first
%! nxpimage $VERBOSITY cert-block get-template -f lpc55s6x -o $CERT_BLOCK_TEMPLATE --force
assert os.path.exists(CERT_BLOCK_TEMPLATE)

cert_block_config = f"""# =========================================  Certification Block V1 template  ==========================================

# ======================================================================================================================
#                                             == Certificate V1 Settings ==                                             
# ======================================================================================================================
# --------------------------------------===== Image Build Number [Optional] =====---------------------------------------
# Description: If it's omitted, it will be used 0 as default value.
imageBuildNumber: 0
# --------------------------------===== Chain certificate 0 for root 0 [Optional] =====---------------------------------
# Description: Chain certificate 0 for root certificate 0
chainCertificate0File0: {CHAIN_CERT_0}
# ======================================================================================================================
#                                                == Root Keys Settings ==                                               
# ======================================================================================================================
# -----------------------------===== Root Certificate File 0 [Conditionally required] =====-----------------------------
# Description: Root certificate file index 0.
rootCertificate0File: {ROOT_0_CERT_PATH}
# -----------------------------===== Main Certificate Index [Conditionally required] =====------------------------------
# Description: Index of certificate that is used as a main. If not defined, the certificate matching private key will be
# selected.
mainRootCertId: 0
# ======================================================================================================================
#                                                  == Basic Settings ==                                                 
# ======================================================================================================================
# --------------------------------------===== cert block filename [Required] =====--------------------------------------
# Description: Generated cert block filename.
containerOutputFile: {CERT_BLOCK_BIN_NAME}
"""

# write configuration as file
with open(CERT_BLOCK_CONFIG_PATH, "w+") as cert_file:
    cert_file.write(cert_block_config)
    
assert os.path.exists(CERT_BLOCK_CONFIG_PATH)

# export Master Boot Image
%! nxpimage $VERBOSITY cert-block export -c $CERT_BLOCK_CONFIG_PATH -f lpc55s6x


BIN_OUTPUT_PATH = WORKSPACE + CERT_BLOCK_BIN_NAME
assert os.path.exists(BIN_OUTPUT_PATH)
nxpimage -v cert-block get-template -f lpc55s6x -o workspace/cert_block_template.yaml --force
Creating /Users/macbook-m1/spsdk_test/spsdk/examples/jupyter_examples/lpc55sxx_secure_boot/workspace/cert_block_template.yaml template file.
nxpimage -v cert-block export -c workspace/cert_block_lpc55s6x.yml -f lpc55s6x
Success. (Certificate Block: /Users/macbook-m1/spsdk_test/spsdk/examples/jupyter_examples/lpc55sxx_secure_boot/workspace/cert_block.bin created.)

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 = WORKSPACE + "mbi_config_lpc55s6x.yml"


mbi_config = f"""
# ==================  Master Boot Image Configuration template for lpc55s6x, Plain Signed XIP Image.  ==================

# ======================================================================================================================
#                                                  == Basic Settings ==                                                 
# ======================================================================================================================
# ------------------------------------------===== MCU family [Required] =====-------------------------------------------
# Description: MCU family name.
# Possible options: <lpc55s2x, lpc55s6x, nhs52sxx>
family: lpc55s6x
# --------------------------------------===== Application target [Required] =====---------------------------------------
# Description: Definition if application is Execute in Place(XiP) or loaded to RAM during reset sequence.
# Possible options: <xip, load-to-ram>
outputImageExecutionTarget: xip
# -------------------------------===== Type of boot image authentication [Required] =====-------------------------------
# Description: Specification of final master boot image authentication.
# Possible options: <plain, crc, signed, signed-encrypted, signed-nxp>
outputImageAuthenticationType: signed
# ------------------------------------===== Master Boot Image name [Required] =====-------------------------------------
# Description: The file for Master Boot Image result file.
masterBootOutputFile: {MBI_BIN_NAME}
# ------------------------------------===== Plain application image [Required] =====------------------------------------
# Description: The input application image to by modified to Master Boot Image.
inputImageFile: {BINARY_FILE}
# ======================================================================================================================
#                                               == Trust Zone Settings ==                                               
# ======================================================================================================================
# ------------------------------------===== TrustZone enable option [Optional] =====------------------------------------
# Description: If not specified, the Trust zone is disabled.
enableTrustZone: false
# ---------------------------------===== TrustZone Customization file [Optional] =====----------------------------------
# Description: If not specified, but TrustZone is enabled(enableTrustZone) the default values are used.
# trustZonePresetFile: my_tz_custom.yaml
# ======================================================================================================================
#                                               == Certificate Block V1 ==                                              
# ======================================================================================================================
# -----------------------------===== Certificate Block binary/config file [Required] =====------------------------------
# Description: Path to certificate block binary or config file.
certBlock: {CERT_BLOCK_CONFIG_PATH}
# ======================================================================================================================
#                                              == Image Signing Settings ==                                             
# ======================================================================================================================
# --------------------------===== Main Certificate private key [Conditionally required] =====---------------------------
# Description: Main Certificate private key used to sign certificate. It can be replaced by signProvider key.
signPrivateKey: {PRIVATE_KEY_PATH}
# -------------------------------===== Signature Provider [Conditionally required] =====--------------------------------
# Description: Signature provider configuration in format 'type=<sp_type>;<key1>=<value1>;<key2>=<value2>".
# signProvider: type=file;file_path=my_prv_key.pem
"""

# write configuration as file
with open(MBI_CONFIG_PATH, "w+") as mbi_file:
    mbi_file.write(mbi_config)
    
assert os.path.exists(MBI_CONFIG_PATH)

# 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 -v mbi export -c workspace/mbi_config_lpc55s6x.yml
INFO:spsdk.utils.crypto.rkht:ROTKH: 153a7b9f9e6bdc7facc4431e93a4f1c2b16a3dfe4cbaf4e0e3265c4993cd59f1
INFO:spsdk.utils.crypto.rkht:ROTKH: 153a7b9f9e6bdc7facc4431e93a4f1c2b16a3dfe4cbaf4e0e3265c4993cd59f1
RKHT: 153a7b9f9e6bdc7facc4431e93a4f1c2b16a3dfe4cbaf4e0e3265c4993cd59f1
Success. (Master Boot Image: /Users/macbook-m1/spsdk_test/spsdk/examples/jupyter_examples/lpc55sxx_secure_boot/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.

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.

CMPA_TEMPLATE_PATH = WORKSPACE + "cmpa_lpc55s6x.yml"
CFPA_TEMPLATE_PATH = WORKSPACE + "cfpa_lpc55s6x.yml"

# get CMPA template
%! pfr get-template -t cmpa -f $FAMILY -o $CMPA_TEMPLATE_PATH --force

# get CFPA template
%! pfr get-template -t cfpa -f $FAMILY -o $CFPA_TEMPLATE_PATH --force
pfr get-template -t cmpa -f lpc55s6x -o workspace/cmpa_lpc55s6x.yml
Output file already exists. Please use --force is you want to overwrite existing files.
Aborted!
pfr get-template -t cfpa -f lpc55s6x -o workspace/cfpa_lpc55s6x.yml
Output file already exists. Please use --force is you want to overwrite existing files.
Aborted!

CMPA page preparation#

assert os.path.exists(CMPA_TEMPLATE_PATH)
    
CMPA_BIN = WORKSPACE + "cmpa.bin"

with open(CMPA_TEMPLATE_PATH) as cmpa_config:
    # load yaml configuration to dictionary
    cmpa = yaml.safe_load(cmpa_config)
    # Enable secure boot
    cmpa['settings']['SECURE_BOOT_CFG']['bitfields']['SEC_BOOT_EN'] = "SECURE_BOOT_CFG_SEC_BOOT_EN_ENABLE_0"
    # disable DICE
    cmpa['settings']['SECURE_BOOT_CFG']['bitfields']['SKIP_DICE'] = "SECURE_BOOT_CFG_SKIP_DICE_DISABLE_0"

with open(CMPA_TEMPLATE_PATH, "w+") as cmpa_config:
    print("CMPA config:")
    pp.pprint(cmpa)
    # dump the dictionary back to YAML
    yaml.dump(cmpa, cmpa_config)

# Generate CMPA binary
%! pfr $VERBOSITY generate-binary -c $CMPA_TEMPLATE_PATH -o $CMPA_BIN -e $MBI_CONFIG_PATH

assert os.path.exists(CMPA_BIN)
CMPA config:
{   'description': {   'device': 'lpc55s6x',
                       'revision': '1b',
                       'type': 'CMPA',
                       'version': '2.0.0'},
    'settings': {   'BOOT_CFG': {   'bitfields': {   'BOOT_FAILURE_PIN': '0x00',
                                                     'BOOT_SPEED': 'SYSTEM_SPEED_CODE',
                                                     'DEFAULT_ISP_MODE': 'AUTO_ISP',
                                                     'USB_SPEED': 'USB_SPEED_0'}},
                    'CUSTOMER_DEFINED0': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED1': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED10': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED11': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED12': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED13': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED14': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED15': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED16': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED17': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED18': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED19': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED2': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED20': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED21': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED22': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED23': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED24': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED25': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED26': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED27': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED28': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED29': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED3': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED30': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED31': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED32': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED33': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED34': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED35': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED36': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED37': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED38': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED39': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED4': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED40': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED41': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED42': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED43': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED44': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED45': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED46': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED47': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED48': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED49': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED5': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED50': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED51': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED52': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED53': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED54': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED55': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED6': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED7': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED8': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED9': {'value': '0x00000000'},
                    'DCFG_CC_SOCU_DFLT': {   'bitfields': {   'CPU1_DBGEN': 'DISABLED',
                                                              'CPU1_NIDEN': 'DISABLED',
                                                              'DBGEN': 'DISABLED',
                                                              'FA_ME_CMD_EN': 'DISABLED',
                                                              'ISP_CMD_EN': 'DISABLED',
                                                              'NIDEN': 'DISABLED',
                                                              'SPIDEN': 'DISABLED',
                                                              'SPNIDEN': 'DISABLED',
                                                              'TAPEN': 'DISABLED'}},
                    'DCFG_CC_SOCU_PIN': {   'bitfields': {   'CPU1_DBGEN': 'USE_DAP',
                                                             'CPU1_NIDEN': 'USE_DAP',
                                                             'DBGEN': 'USE_DAP',
                                                             'FA_ME_CMD_EN': 'USE_DAP',
                                                             'ISP_CMD_EN': 'USE_DAP',
                                                             'NIDEN': 'USE_DAP',
                                                             'SPIDEN': 'USE_DAP',
                                                             'SPNIDEN': 'USE_DAP',
                                                             'TAPEN': 'USE_DAP',
                                                             'UUID_CHECK': 'DISABLED'}},
                    'PRINCE_BASE_ADDR': {   'bitfields': {   'ADDR0_PRG': '0x0',
                                                             'ADDR1_PRG': '0x0',
                                                             'ADDR2_PRG': '0x0',
                                                             'LOCK_REG0': 'UNLOCK',
                                                             'LOCK_REG1': 'UNLOCK',
                                                             'REG0_ERASE_CHECK_EN': 'DISABLE',
                                                             'REG1_ERASE_CHECK_EN': 'DISABLE',
                                                             'REG2_ERASE_CHECK_EN': 'DISABLE'}},
                    'PRINCE_SR_0': {'value': '0x00000000'},
                    'PRINCE_SR_1': {'value': '0x00000000'},
                    'PRINCE_SR_2': {'value': '0x00000000'},
                    'ROTKH': {   'value': '0000000000000000000000000000000000000000000000000000000000000000'},
                    'SDIO_CFG': {'value': '0x00000000'},
                    'SECURE_BOOT_CFG': {   'bitfields': {   'BLOCK_ENROLL': 'ALLOW',
                                                            'BLOCK_SET_KEY': 'ALLOW',
                                                            'DICE_CUST_CFG': 'NOT_INCLUDE',
                                                            'DICE_INC_NXP_CFG': 'NOT_INCLUDE',
                                                            'DICE_INC_SEC_EPOCH': '0x0',
                                                            'RSA4K': 'RSA2048',
                                                            'SEC_BOOT_EN': 'SECURE_BOOT_CFG_SEC_BOOT_EN_ENABLE_0',
                                                            'SKIP_DICE': 'SECURE_BOOT_CFG_SKIP_DICE_DISABLE_0',
                                                            'TZM_IMAGE_TYPE': 'HEADER'}},
                    'SPI_FLASH_CFG': {   'bitfields': {   'SPI_RECOVERY_BOOT_EN': '0x0'}},
                    'USB_ID': {   'bitfields': {   'USB_PRODUCT_ID': '0x0000',
                                                   'USB_VENDOR_ID': '0x0000'}},
                    'VENDOR_USAGE': {'bitfields': {'VENDOR_USAGE': '0x0000'}},
                    'XTAL_16MHZ_CAPABANK_TRIM': {   'bitfields': {   'PCB_XIN_PARA_CAP_PF_X100': '0x00',
                                                                     'PCB_XOUT_PARA_CAP_PF_X100': '0x00',
                                                                     'TRIM_VALID': 'NOT_TRIM',
                                                                     'XTAL_LOAD_CAP_IEC_PF_X100': '0x00'}},
                    'XTAL_32KHZ_CAPABANK_TRIM': {   'bitfields': {   'PCB_XIN_PARA_CAP_PF_X100': '0x00',
                                                                     'PCB_XOUT_PARA_CAP_PF_X100': '0x00',
                                                                     'TRIM_VALID': 'NOT_TRIM',
                                                                     'XTAL_LOAD_CAP_IEC_PF_X100': '0x00'}}}}
pfr -v generate-binary -c workspace/cmpa_lpc55s6x.yml -o workspace/cmpa.bin -e workspace/mbi_config_lpc55s6x.yml
WARNING:spsdk.utils.registers:Bitfield SECURE_BOOT_CFG_SEC_BOOT_EN_ENABLE_0 not found, trying backward compatibility mode with ENABLE_0 (183ms since start, registers.py:1230)
WARNING:spsdk.utils.registers:Bitfield SECURE_BOOT_CFG_SKIP_DICE_DISABLE_0 not found, trying backward compatibility mode with DISABLE_0 (183ms since start, registers.py:1230)
INFO:spsdk.pfr.pfrc:OK: Brick condition not fulfilled
INFO:spsdk.pfr.pfrc:OK: Brick condition not fulfilled
INFO:spsdk.pfr.pfrc:OK: Brick condition not fulfilled
Success. (PFR binary has been generated)
Result has been stored in: /Users/macbook-m1/spsdk_test/spsdk/examples/jupyter_examples/lpc55sxx_secure_boot/workspace/cmpa.bin

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
nxpdevscan
-------- Connected NXP SDIO Devices --------

-------- Connected NXP USB Devices --------

USB COMPOSITE DEVICE - NXP SEMICONDUCTOR INC.
Vendor ID: 0x1fc9
Product ID: 0x0021
Path: DevSrvsID:4294982445
Path Hash: 9b3224ce
Name: LPC55, RT6xx
Serial number: 

-------- Connected NXP UART Devices --------

-------- Connected NXP SIO Devices --------
USB_CONNECTION = "-u lpc55" 
# choose com port or /dev
UART_CONNECTION = "-p com24"

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

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

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 lpc55 set-property 29 1
Response status = 0 (0x0) Success.
blhost -u lpc55 write-memory 0x9E600 zero_1536.bin
?25lWriting memory  [####################################]  100%          ?25h
Response status = 0 (0x0) Success.
Response word 1 = 1536 (0x600)
blhost -u lpc55 set-property 29 0
Response status = 0 (0x0) Success.

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.

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 --show-diff

assert os.path.exists(CFPA_TEMPLATE_PATH)
assert os.path.exists(CFPA_PARSED)

with open(CFPA_PARSED) as cfpa_parsed:
    # load yaml configuration to dictionary
    cfpa = yaml.safe_load(cfpa_parsed)
    print("Parsed CFPA from the processor")
    pp.pprint(cfpa)
    # parse actual value of the VERSION monotonic counter
    CFPA_VERSION = int(cfpa['settings']['VERSION']['value'], 16)
with open(CFPA_TEMPLATE_PATH) as cfpa_config:
    # load yaml configuration to dictionary
    cfpa = yaml.safe_load(cfpa_config)
    # Enable root certificate 0
    cfpa['settings']['ROTKH_REVOKE']['bitfields']['RoTK0_EN'] = "ROTKH_REVOKE_RoTK0_EN_ENABLED"
    # VERSION monotonic counter has to be increased after every CFPA page update
    CFPA_VERSION += 1
    cfpa['settings']['VERSION']['value'] = hex(CFPA_VERSION)

with open(CFPA_TEMPLATE_PATH, "w+") as cfpa_config:
    print("CFPA config:")
    pp.pprint(cfpa)
    # dump the dictionary back to YAML
    yaml.dump(cfpa, cfpa_config)
    

# Generate CFPA binary
%! pfr $VERBOSITY generate-binary -c $CFPA_TEMPLATE_PATH -o $CFPA_BIN

assert os.path.exists(CFPA_BIN)
pfr read -f lpc55s6x -u lpc55 -t cfpa -o workspace/cfpa.bin -y workspace/cfpa_parsed.yaml --show-diff
CFPA page address on lpc55s6x is 0x9de00
CFPA data stored to /Users/macbook-m1/spsdk_test/spsdk/examples/jupyter_examples/lpc55sxx_secure_boot/workspace/cfpa.bin
Parsed config stored to /Users/macbook-m1/spsdk_test/spsdk/examples/jupyter_examples/lpc55sxx_secure_boot/workspace/cfpa_parsed.yaml
Parsed CFPA from the processor
{   'description': {   'device': 'lpc55s6x',
                       'revision': '1b',
                       'type': 'CFPA',
                       'version': '2.0.0'},
    'settings': {   'CMPA_PROG_IN_PROGRESS': {'value': '0x5CC55AA5'},
                    'ROTKH_REVOKE': {   'bitfields': {   'RoTK0_EN': 'ENABLED',
                                                         'RoTK1_EN': 'ENABLED',
                                                         'RoTK2_EN': 'ENABLED',
                                                         'RoTK3_EN': 'ENABLED'}},
                    'VERSION': {'value': '0x00001167'}}}
CFPA config:
{   'description': {   'device': 'lpc55s6x',
                       'revision': '1b',
                       'type': 'CFPA',
                       'version': '2.0.0'},
    'settings': {   'CMPA_PROG_IN_PROGRESS': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED0': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED1': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED10': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED11': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED12': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED13': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED14': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED15': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED16': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED17': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED18': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED19': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED2': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED20': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED21': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED22': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED23': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED24': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED25': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED26': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED27': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED28': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED29': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED3': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED30': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED31': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED32': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED33': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED34': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED35': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED36': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED37': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED38': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED39': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED4': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED40': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED41': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED42': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED43': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED44': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED45': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED46': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED47': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED48': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED49': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED5': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED50': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED51': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED52': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED53': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED54': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED55': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED6': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED7': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED8': {'value': '0x00000000'},
                    'CUSTOMER_DEFINED9': {'value': '0x00000000'},
                    'DCFG_CC_SOCU_NS_DFLT': {   'bitfields': {   'CPU1_DBGEN': 'DISABLED',
                                                                 'CPU1_NIDEN': 'DISABLED',
                                                                 'DBGEN': 'DISABLED',
                                                                 'FA_ME_CMD_EN': 'DISABLED',
                                                                 'ISP_CMD_EN': 'DISABLED',
                                                                 'NIDEN': 'DISABLED',
                                                                 'SPIDEN': 'DISABLED',
                                                                 'SPNIDEN': 'DISABLED',
                                                                 'TAPEN': 'DISABLED'}},
                    'DCFG_CC_SOCU_NS_PIN': {   'bitfields': {   'CPU1_DBGEN': 'USE_DAP',
                                                                'CPU1_NIDEN': 'USE_DAP',
                                                                'DBGEN': 'USE_DAP',
                                                                'FA_ME_CMD_EN': 'USE_DAP',
                                                                'ISP_CMD_EN': 'USE_DAP',
                                                                'NIDEN': 'USE_DAP',
                                                                'SPIDEN': 'USE_DAP',
                                                                'SPNIDEN': 'USE_DAP',
                                                                'TAPEN': 'USE_DAP',
                                                                'UUID_CHECK': 'DISABLED'}},
                    'ENABLE_FA_MODE': {'value': '0x00000000'},
                    'HEADER': {'value': '0x00000000'},
                    'IMAGE_KEY_REVOKE': {'value': '0x00000000'},
                    'NS_FW_Version': {'value': '0x00000000'},
                    'PRINCE_REGION0_IV_BODY0': {'value': '0x00000000'},
                    'PRINCE_REGION0_IV_BODY1': {'value': '0x00000000'},
                    'PRINCE_REGION0_IV_BODY10': {'value': '0x00000000'},
                    'PRINCE_REGION0_IV_BODY11': {'value': '0x00000000'},
                    'PRINCE_REGION0_IV_BODY2': {'value': '0x00000000'},
                    'PRINCE_REGION0_IV_BODY3': {'value': '0x00000000'},
                    'PRINCE_REGION0_IV_BODY4': {'value': '0x00000000'},
                    'PRINCE_REGION0_IV_BODY5': {'value': '0x00000000'},
                    'PRINCE_REGION0_IV_BODY6': {'value': '0x00000000'},
                    'PRINCE_REGION0_IV_BODY7': {'value': '0x00000000'},
                    'PRINCE_REGION0_IV_BODY8': {'value': '0x00000000'},
                    'PRINCE_REGION0_IV_BODY9': {'value': '0x00000000'},
                    'PRINCE_REGION0_IV_HEADER0': {'value': '0x00000000'},
                    'PRINCE_REGION0_IV_HEADER1': {   'bitfields': {   'INDEX': '0x0',
                                                                      'SIZE': '0x0',
                                                                      'TYPE': '0x0'}},
                    'PRINCE_REGION1_IV_BODY0': {'value': '0x00000000'},
                    'PRINCE_REGION1_IV_BODY1': {'value': '0x00000000'},
                    'PRINCE_REGION1_IV_BODY10': {'value': '0x00000000'},
                    'PRINCE_REGION1_IV_BODY11': {'value': '0x00000000'},
                    'PRINCE_REGION1_IV_BODY2': {'value': '0x00000000'},
                    'PRINCE_REGION1_IV_BODY3': {'value': '0x00000000'},
                    'PRINCE_REGION1_IV_BODY4': {'value': '0x00000000'},
                    'PRINCE_REGION1_IV_BODY5': {'value': '0x00000000'},
                    'PRINCE_REGION1_IV_BODY6': {'value': '0x00000000'},
                    'PRINCE_REGION1_IV_BODY7': {'value': '0x00000000'},
                    'PRINCE_REGION1_IV_BODY8': {'value': '0x00000000'},
                    'PRINCE_REGION1_IV_BODY9': {'value': '0x00000000'},
                    'PRINCE_REGION1_IV_HEADER0': {'value': '0x00000000'},
                    'PRINCE_REGION1_IV_HEADER1': {   'bitfields': {   'INDEX': '0x0',
                                                                      'SIZE': '0x0',
                                                                      'TYPE': '0x0'}},
                    'PRINCE_REGION2_IV_BODY0': {'value': '0x00000000'},
                    'PRINCE_REGION2_IV_BODY1': {'value': '0x00000000'},
                    'PRINCE_REGION2_IV_BODY10': {'value': '0x00000000'},
                    'PRINCE_REGION2_IV_BODY11': {'value': '0x00000000'},
                    'PRINCE_REGION2_IV_BODY2': {'value': '0x00000000'},
                    'PRINCE_REGION2_IV_BODY3': {'value': '0x00000000'},
                    'PRINCE_REGION2_IV_BODY4': {'value': '0x00000000'},
                    'PRINCE_REGION2_IV_BODY5': {'value': '0x00000000'},
                    'PRINCE_REGION2_IV_BODY6': {'value': '0x00000000'},
                    'PRINCE_REGION2_IV_BODY7': {'value': '0x00000000'},
                    'PRINCE_REGION2_IV_BODY8': {'value': '0x00000000'},
                    'PRINCE_REGION2_IV_BODY9': {'value': '0x00000000'},
                    'PRINCE_REGION2_IV_HEADER0': {'value': '0x00000000'},
                    'PRINCE_REGION2_IV_HEADER1': {   'bitfields': {   'INDEX': '0x0',
                                                                      'SIZE': '0x0',
                                                                      'TYPE': '0x0'}},
                    'ROTKH_REVOKE': {   'bitfields': {   'RoTK0_EN': 'ROTKH_REVOKE_RoTK0_EN_ENABLED',
                                                         'RoTK1_EN': 'INVALID',
                                                         'RoTK2_EN': 'INVALID',
                                                         'RoTK3_EN': 'INVALID'}},
                    'S_FW_Version': {'value': '0x00000000'},
                    'VENDOR_USAGE': {   'bitfields': {   'DBG_VENDOR_USAGE': '0x0000'}},
                    'VERSION': {'value': '0x1168'}}}
pfr -v generate-binary -c workspace/cfpa_lpc55s6x.yml -o workspace/cfpa.bin
WARNING:spsdk.utils.registers:Bitfield ROTKH_REVOKE_RoTK0_EN_ENABLED not found, trying backward compatibility mode with ENABLED (184ms since start, registers.py:1230)
INFO:spsdk.pfr.pfrc:OK: Brick condition not fulfilled
INFO:spsdk.pfr.pfrc:OK: Brick condition not fulfilled
INFO:spsdk.pfr.pfrc:OK: Brick condition not fulfilled
INFO:spsdk.pfr.pfrc:OK: Brick condition not fulfilled
INFO:spsdk.pfr.pfrc:OK: Brick condition not fulfilled
Success. (PFR binary has been generated)
Result has been stored in: /Users/macbook-m1/spsdk_test/spsdk/examples/jupyter_examples/lpc55sxx_secure_boot/workspace/cfpa.bin

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.

# 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 lpc55 -t cfpa -f lpc55s6x -b workspace/cfpa.bin
CFPA page address on lpc55s6x is 0x9de00
CFPA data written to device.
pfr write -u lpc55 -t cmpa -f lpc55s6x -b workspace/cmpa.bin
CMPA page address on lpc55s6x is 0x9e400
CMPA data written to device.

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 lpc55 flash-erase-region 0 0x10000
Response status = 0 (0x0) Success.
blhost -u lpc55 write-memory 0 workspace/lpc55s6x_mbi.bin
?25lWriting memory  [####################################]  100%          ?25h
Response status = 0 (0x0) Success.
Response word 1 = 11064 (0x2b38)