KW45xx and K32W1xx Secure Boot#

This notebook describes how to how to set up a basic secure boot on KW45xx/K32W1xx devices using the SPSDK command line utilities.

Keys preparation#

First we need to generate RoTKs (Root of Trust Keys) and optionally ISK (Image Signing Certificate). We will use nxpcrypto app for this purpose. Script by default generates 4 RoTKs and 1 ISK key (full set of possible keys). Feel free to modify it according your needs. RoTK 0 generation is mandatory.

See the script’s comments and modify the script according to the application security requirements. Key generation is done only once on the beginning. Based on generated keys, RoTKTH value is calculated and loaded in the device fuses so that’s why keys cannot be changed anymore for the device.

%run ../init_notebook.ipynb

import os
import pprint

pp = pprint.PrettyPrinter(indent=4)

WORKSPACE = "workspace/" # change this to path to your workspace
VERBOSITY = "-v" # verbosity of commands, might be -v or -vv for debug or blank for no additional info
# choose family (kw45xx or k32w1xx)
FAMILY = "kw45xx"
env: JUPYTER_SPSDK=1
Created `%!` as an alias for `%execute`.
# generate private key based on secp384r1 curve - ROTK0
ROTK0_PRIVATE_KEY_PATH = WORKSPACE + "ec_pk_secp384r1_cert0.pem"
ROTK0_PUBLIC_KEY_PATH = WORKSPACE + "ec_pk_secp384r1_cert0.pub"

%! nxpcrypto $VERBOSITY key generate -k secp384r1 -o $ROTK0_PRIVATE_KEY_PATH --force

# verify that keys were generated
assert os.path.exists(ROTK0_PRIVATE_KEY_PATH)
assert os.path.exists(ROTK0_PUBLIC_KEY_PATH)


# generate private key based on secp384r1 curve - ROTK1
ROTK1_PRIVATE_KEY_PATH = WORKSPACE + "ec_pk_secp384r1_cert1.pem"
ROTK1_PUBLIC_KEY_PATH = WORKSPACE + "ec_pk_secp384r1_cert1.pub"

%! nxpcrypto $VERBOSITY key generate -k secp384r1 -o $ROTK1_PRIVATE_KEY_PATH --force

# verify that keys were generated
assert os.path.exists(ROTK1_PRIVATE_KEY_PATH)
assert os.path.exists(ROTK1_PUBLIC_KEY_PATH)


# generate private key based on secp384r1 curve - ROTK2
ROTK2_PRIVATE_KEY_PATH = WORKSPACE + "ec_pk_secp384r1_cert2.pem"
ROTK2_PUBLIC_KEY_PATH = WORKSPACE + "ec_pk_secp384r1_cert2.pub"

%! nxpcrypto $VERBOSITY key generate -k secp384r1 -o $ROTK2_PRIVATE_KEY_PATH --force

# verify that keys were generated
assert os.path.exists(ROTK2_PRIVATE_KEY_PATH)
assert os.path.exists(ROTK2_PUBLIC_KEY_PATH)


# generate private key based on secp384r1 curve - ROTK3
ROTK3_PRIVATE_KEY_PATH = WORKSPACE + "ec_pk_secp384r1_cert3.pem"
ROTK3_PUBLIC_KEY_PATH = WORKSPACE + "ec_pk_secp384r1_cert3.pub"

%! nxpcrypto $VERBOSITY key generate -k secp384r1 -o $ROTK3_PRIVATE_KEY_PATH --force

# verify that keys were generated
assert os.path.exists(ROTK3_PRIVATE_KEY_PATH)
assert os.path.exists(ROTK3_PUBLIC_KEY_PATH)


# generate private key based on secp384r1 curve - ISK
ISK_PRIVATE_KEY_PATH = WORKSPACE + "ec_pk_secp384r1_sign_cert.pem"
ISK_PUBLIC_KEY_PATH = WORKSPACE + "ec_pk_secp384r1_sign_cert.pub"

%! nxpcrypto $VERBOSITY key generate -k secp384r1 -o $ISK_PRIVATE_KEY_PATH --force

# verify that keys were generated
assert os.path.exists(ISK_PRIVATE_KEY_PATH)
assert os.path.exists(ISK_PUBLIC_KEY_PATH)
nxpcrypto -v key generate -k secp384r1 -o workspace/ec_pk_secp384r1_cert0.pem --force 
The key pair has been created: C:\spsdk\examples\jupyter_examples\kw45xx_k32w1xx\workspace\ec_pk_secp384r1_cert0.pub, C:\spsdk\examples\jupyter_examples\kw45xx_k32w1xx\workspace\ec_pk_secp384r1_cert0.pem
nxpcrypto -v key generate -k secp384r1 -o workspace/ec_pk_secp384r1_cert1.pem --force 
The key pair has been created: C:\spsdk\examples\jupyter_examples\kw45xx_k32w1xx\workspace\ec_pk_secp384r1_cert1.pub, C:\spsdk\examples\jupyter_examples\kw45xx_k32w1xx\workspace\ec_pk_secp384r1_cert1.pem
nxpcrypto -v key generate -k secp384r1 -o workspace/ec_pk_secp384r1_cert2.pem --force 
The key pair has been created: C:\spsdk\examples\jupyter_examples\kw45xx_k32w1xx\workspace\ec_pk_secp384r1_cert2.pub, C:\spsdk\examples\jupyter_examples\kw45xx_k32w1xx\workspace\ec_pk_secp384r1_cert2.pem
nxpcrypto -v key generate -k secp384r1 -o workspace/ec_pk_secp384r1_cert3.pem --force 
The key pair has been created: C:\spsdk\examples\jupyter_examples\kw45xx_k32w1xx\workspace\ec_pk_secp384r1_cert3.pub, C:\spsdk\examples\jupyter_examples\kw45xx_k32w1xx\workspace\ec_pk_secp384r1_cert3.pem
nxpcrypto -v key generate -k secp384r1 -o workspace/ec_pk_secp384r1_sign_cert.pem --force 
The key pair has been created: C:\spsdk\examples\jupyter_examples\kw45xx_k32w1xx\workspace\ec_pk_secp384r1_sign_cert.pub, C:\spsdk\examples\jupyter_examples\kw45xx_k32w1xx\workspace\ec_pk_secp384r1_sign_cert.pem

Certificates preparation#

Generate self-signed x509 certificate(s) containing public key for private key generated in previous step (ROTKX). Application nxpcrypto will be used. First step is to get a template.

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

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

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

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

# obtain a template for root cert ISK
ISK_CERT_CONFIG_PATH = WORKSPACE + "sign_cert_template.yml"
%! nxpcrypto $VERBOSITY cert get-template -o $ISK_CERT_CONFIG_PATH --force
nxpcrypto -v cert get-template -o workspace/cert0_template.yml --force 
INFO:spsdk.apps.nxpcertgen:Creating Certificate template...
The configuration template file has been created: C:\spsdk\examples\jupyter_examples\kw45xx_k32w1xx\workspace\cert0_template.yml
nxpcrypto -v cert get-template -o workspace/cert1_template.yml --force 
INFO:spsdk.apps.nxpcertgen:Creating Certificate template...
The configuration template file has been created: C:\spsdk\examples\jupyter_examples\kw45xx_k32w1xx\workspace\cert1_template.yml
nxpcrypto -v cert get-template -o workspace/cert2_template.yml --force 
INFO:spsdk.apps.nxpcertgen:Creating Certificate template...
The configuration template file has been created: C:\spsdk\examples\jupyter_examples\kw45xx_k32w1xx\workspace\cert2_template.yml
nxpcrypto -v cert get-template -o workspace/cert3_template.yml --force 
INFO:spsdk.apps.nxpcertgen:Creating Certificate template...
The configuration template file has been created: C:\spsdk\examples\jupyter_examples\kw45xx_k32w1xx\workspace\cert3_template.yml
nxpcrypto -v cert get-template -o workspace/sign_cert_template.yml --force 
INFO:spsdk.apps.nxpcertgen:Creating Certificate template...
The configuration template file has been created: C:\spsdk\examples\jupyter_examples\kw45xx_k32w1xx\workspace\sign_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_0_CERT_PATH = WORKSPACE + "ec_secp384r1_cert0.pem"
ROOT_1_CERT_PATH = WORKSPACE + "ec_secp384r1_cert1.pem"
ROOT_2_CERT_PATH = WORKSPACE + "ec_secp384r1_cert2.pem"
ROOT_3_CERT_PATH = WORKSPACE + "ec_secp384r1_cert3.pem"
ISK_CERT_PATH = WORKSPACE + "ec_secp384r1_sign_cert.pem"

# Fill the configuration file accordingly
import yaml

assert os.path.exists(ROOT0_CERT_CONFIG_PATH)
assert os.path.exists(ROOT1_CERT_CONFIG_PATH)
assert os.path.exists(ROOT2_CERT_CONFIG_PATH)
assert os.path.exists(ROOT3_CERT_CONFIG_PATH)

# Create configuration for root certificate 0 
with open(ROOT0_CERT_CONFIG_PATH) as cert_config:
    # load yaml configuration to dictionary
    cert = yaml.safe_load(cert_config)
    # change path to private and public keys
    cert['issuer_private_key'] = ROTK0_PRIVATE_KEY_PATH
    cert['subject_public_key'] = ROTK0_PUBLIC_KEY_PATH

with open(ROOT0_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 root certificate 1
with open(ROOT1_CERT_CONFIG_PATH) as cert_config:
    # load yaml configuration to dictionary
    cert = yaml.safe_load(cert_config)
    # change path to private and public keys
    cert['issuer_private_key'] = ROTK1_PRIVATE_KEY_PATH
    cert['subject_public_key'] = ROTK1_PUBLIC_KEY_PATH

with open(ROOT1_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 root certificate 2
with open(ROOT2_CERT_CONFIG_PATH) as cert_config:
    # load yaml configuration to dictionary
    cert = yaml.safe_load(cert_config)
    # change path to private and public keys
    cert['issuer_private_key'] = ROTK2_PRIVATE_KEY_PATH
    cert['subject_public_key'] = ROTK2_PUBLIC_KEY_PATH

with open(ROOT2_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 root certificate 3
with open(ROOT3_CERT_CONFIG_PATH) as cert_config:
    # load yaml configuration to dictionary
    cert = yaml.safe_load(cert_config)
    # change path to private and public keys
    cert['issuer_private_key'] = ROTK3_PRIVATE_KEY_PATH
    cert['subject_public_key'] = ROTK3_PUBLIC_KEY_PATH

with open(ROOT3_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 ISK certificate 
with open(ISK_CERT_CONFIG_PATH) as cert_config:
    # load yaml configuration to dictionary
    cert = yaml.safe_load(cert_config)
    # change path to private and public keys
    cert['issuer_private_key'] = ISK_PRIVATE_KEY_PATH
    cert['subject_public_key'] = ISK_PUBLIC_KEY_PATH

with open(ISK_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)


# Generate root certificates 0
%! nxpcrypto $VERBOSITY cert generate -c $ROOT0_CERT_CONFIG_PATH -o $ROOT_0_CERT_PATH --force
# Generate root certificates 1
%! nxpcrypto $VERBOSITY cert generate -c $ROOT1_CERT_CONFIG_PATH -o $ROOT_1_CERT_PATH --force
# Generate root certificates 2
%! nxpcrypto $VERBOSITY cert generate -c $ROOT2_CERT_CONFIG_PATH -o $ROOT_2_CERT_PATH --force
# Generate root certificates 3
%! nxpcrypto $VERBOSITY cert generate -c $ROOT3_CERT_CONFIG_PATH -o $ROOT_3_CERT_PATH --force

# Generate ISK certificate
%! nxpcrypto $VERBOSITY cert generate -c $ISK_CERT_CONFIG_PATH -o $ISK_CERT_PATH --force

# verify that certificates were generated
assert os.path.exists(ROOT_0_CERT_PATH)
assert os.path.exists(ROOT_1_CERT_PATH)
assert os.path.exists(ROOT_2_CERT_PATH)
assert os.path.exists(ROOT_3_CERT_PATH)
assert os.path.exists(ISK_CERT_PATH)
Root 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/ec_pk_secp384r1_cert0.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/ec_pk_secp384r1_cert0.pub'}
Root 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/ec_pk_secp384r1_cert1.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/ec_pk_secp384r1_cert1.pub'}
Root 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/ec_pk_secp384r1_cert2.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/ec_pk_secp384r1_cert2.pub'}
Root 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/ec_pk_secp384r1_cert3.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/ec_pk_secp384r1_cert3.pub'}
Root 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/ec_pk_secp384r1_sign_cert.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/ec_pk_secp384r1_sign_cert.pub'}
nxpcrypto -v cert generate -c workspace/cert0_template.yml -o workspace/ec_secp384r1_cert0.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: C:\spsdk\examples\jupyter_examples\kw45xx_k32w1xx\workspace\ec_secp384r1_cert0.pem
nxpcrypto -v cert generate -c workspace/cert1_template.yml -o workspace/ec_secp384r1_cert1.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: C:\spsdk\examples\jupyter_examples\kw45xx_k32w1xx\workspace\ec_secp384r1_cert1.pem
nxpcrypto -v cert generate -c workspace/cert2_template.yml -o workspace/ec_secp384r1_cert2.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: C:\spsdk\examples\jupyter_examples\kw45xx_k32w1xx\workspace\ec_secp384r1_cert2.pem
nxpcrypto -v cert generate -c workspace/cert3_template.yml -o workspace/ec_secp384r1_cert3.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: C:\spsdk\examples\jupyter_examples\kw45xx_k32w1xx\workspace\ec_secp384r1_cert3.pem
nxpcrypto -v cert generate -c workspace/sign_cert_template.yml -o workspace/ec_secp384r1_sign_cert.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: C:\spsdk\examples\jupyter_examples\kw45xx_k32w1xx\workspace\ec_secp384r1_sign_cert.pem

Prepare MBI configuration file#

In order to generate MBI file, npximage tool is used. The nxpimage tool generates the MBI file according to the configuration file. Let’s create a template for MBI. Modify examples according your needs.

MBI_PATH = WORKSPACE + "MBI"
%! nxpimage $VERBOSITY mbi get-templates -f $FAMILY -o $MBI_PATH --force
# For K32W1XX device:
# %! nxpimage $VERBOSITY mbi get-templates -f $FAMILY -o $MBI_PATH --force
nxpimage -v mbi get-templates -f kw45xx -o workspace/MBI --force 
Creating C:\spsdk\examples\jupyter_examples\kw45xx_k32w1xx\workspace\MBI\kw45xx_xip_plain.yaml template file.
Creating C:\spsdk\examples\jupyter_examples\kw45xx_k32w1xx\workspace\MBI\kw45xx_xip_crc.yaml template file.
Creating C:\spsdk\examples\jupyter_examples\kw45xx_k32w1xx\workspace\MBI\kw45xx_xip_signed.yaml template file.
Creating C:\spsdk\examples\jupyter_examples\kw45xx_k32w1xx\workspace\MBI\kw45xx_xip_nxp_signed.yaml template file.

For signed images, we need to create a certificate blok separately. In order to do this, use nxpimage cert-block get-template command as described below.

CERT_BLOCK_TEMPLATE = WORKSPACE +"cert_block_kw45.yaml"
%! nxpimage $VERBOSITY cert-block get-template -f $FAMILY -o $CERT_BLOCK_TEMPLATE --force
nxpimage -v cert-block get-template -f kw45xx -o workspace/cert_block_kw45.yaml --force 
Creating C:\spsdk\examples\jupyter_examples\kw45xx_k32w1xx\workspace\cert_block_kw45.yaml template file.

And update template accordingly.

assert os.path.exists(CERT_BLOCK_TEMPLATE)
CERT_BLOCK_BIN = WORKSPACE + "cert_block.bin"

# Create configuration for Certificate Block
with open(CERT_BLOCK_TEMPLATE) as cert_block_config:
    # load yaml configuration to dictionary
    ct = yaml.safe_load(cert_block_config)
    # change paths
    ct['rootCertificate0File'] = ROTK0_PUBLIC_KEY_PATH
    ct['rootCertificate1File'] = ROTK1_PUBLIC_KEY_PATH
    ct['rootCertificate2File'] = ROTK2_PUBLIC_KEY_PATH
    ct['rootCertificate3File'] = ROTK3_PUBLIC_KEY_PATH
    ct['mainRootCertId'] = 0
    ct['iskPublicKey'] = ISK_PUBLIC_KEY_PATH
    ct['containerOutputFile'] = CERT_BLOCK_BIN
    del ct['iskCertData']
    del ct['signPrivateKey']
    del ct['signProvider']  
with open(CERT_BLOCK_TEMPLATE, "w+") as cert_block_config:
    print("Certificate Block:")
    pp.pprint(ct)
    # dump the dictionary back to YAML
    yaml.dump(ct, cert_block_config)
Certificate Block:
{   'containerOutputFile': 'workspace/cert_block.bin',
    'iskCertificateConstraint': 0,
    'iskPublicKey': 'workspace/ec_pk_secp384r1_sign_cert.pub',
    'mainRootCertId': 0,
    'rootCertificate0File': 'workspace/ec_pk_secp384r1_cert0.pub',
    'rootCertificate1File': 'workspace/ec_pk_secp384r1_cert1.pub',
    'rootCertificate2File': 'workspace/ec_pk_secp384r1_cert2.pub',
    'rootCertificate3File': 'workspace/ec_pk_secp384r1_cert3.pub',
    'useIsk': False}
MBI_TEMPLATE = MBI_PATH + "/" + "kw45xx_xip_signed.yaml"
MBI_OUTPUT_FILE = MBI_PATH + "/" + "my_mbi.bin"
INPUT_IMAGE_FILE = "hello_world_UART0.bin"
assert os.path.exists(MBI_TEMPLATE)

# Create configuration for MBI
with open(MBI_TEMPLATE) as mbi_config:
    # load yaml configuration to dictionary
    mbi = yaml.safe_load(mbi_config)
    # change paths
    mbi['mainRootCertPrivateKeyFile'] = ROTK0_PRIVATE_KEY_PATH
    mbi['inputImageFile'] = INPUT_IMAGE_FILE
    mbi['certBlock'] = CERT_BLOCK_TEMPLATE
    del mbi['signPrivateKey']
    del mbi['signProvider']
    del mbi['trustZonePresetFile']

with open(MBI_TEMPLATE, "w+") as mbi_config:
    print("MBI:")
    pp.pprint(mbi)
    # dump the dictionary back to YAML
    yaml.dump(mbi, mbi_config)
MBI:
{   'certBlock': 'workspace/cert_block_kw45.yaml',
    'enableTrustZone': False,
    'family': 'kw45xx',
    'firmwareVersion': 0,
    'inputImageFile': 'hello_world_UART0.bin',
    'mainRootCertPrivateKeyFile': 'workspace/ec_pk_secp384r1_cert0.pem',
    'manifestDigestHashAlgorithm': 'sha256',
    'masterBootOutputFile': 'my_mbi.bin',
    'noSignature': False,
    'outputImageAuthenticationType': 'signed',
    'outputImageExecutionAddress': 0,
    'outputImageExecutionTarget': 'xip'}

MBI generation#

We have created certificates and keys required for the creation of MBI file. Let’s create a MBI.

# Verbosity needs to be at least info (-vv) in order to get RoTKTH value
%! nxpimage $VERBOSITY mbi export -c $MBI_TEMPLATE
assert os.path.exists(MBI_OUTPUT_FILE)
nxpimage -v mbi export -c workspace/MBI/kw45xx_xip_signed.yaml 
RKTH: 9190e396af98dad7e32c0cf238e405033e9c39e8d1163891f34016086f6737b5d5d6b0867dc813b5e71fb8ccccc53d62
Success. (Master Boot Image: C:/spsdk/examples/jupyter_examples/kw45xx_k32w1xx/workspace/MBI/my_mbi.bin created.)

Device preparation#

Now it’s time to prepare the device. In this example we will use KW45xx-EVK/K32W1xx board.

First step is to enter ISP mode, this could be achieved by:

1 ) Put JP25 to (1-2)

2 ) Reset the board with SW4 pressed

KW45xx-EVK

K32W1xx-EVK

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

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

Port: COM10
Type: mboot device

-------- Connected NXP SIO Devices --------
# choose com port
UART_CONNECTION = "-p com10"

%! blhost $UART_CONNECTION get-property current-version
blhost -p com10 get-property current-version 
Response status = 0 (0x0) Success.
Response word 1 = 1258488064 (0x4b030100)
Current Version = K3.1.0

Program device fuses with keys/RoTKTH generated in previous steps#

To program fuses blhost tool is used. Device needs to be in ISP mode, where it can communicate with blhost and process blhost commands. To serve the purpose of this document, ISP communication only over UART peripheral is considered for scripts. Also, accurate COMx port must be used.

  • WARNING!!! This step is destructive operation (burning fuses), be sure that you set value of RoTKH correctly in script as printed in output from nxpimage

# Increase voltage for fuse burning
%! blhost $UART_CONNECTION set-property 0x16 1
# program RoTKTH (CUST_PROD_OEMFW_AUTH_PUK)
# put value RoTKTH generated by nxpimage
%! blhost $UART_CONNECTION fuse-program 0x1F [[9190e396af98dad7e32c0cf238e405033e9c39e8d1163891f34016086f6737b5d5d6b0867dc813b5e71fb8ccccc53d62]]
# Set voltage to normal value
%! blhost $UART_CONNECTION set-property 0x16 0
blhost -p com10 set-property 0x16 1 
Response status = 0 (0x0) Success.
blhost -p com10 fuse-program 0x1F [[9190e396af98dad7e32c0cf238e405033e9c39e8d1163891f34016086f6737b5d5d6b0867dc813b5e71fb8ccccc53d62]] 
Response status = 0 (0x0) Success.
Response word 1 = 48 (0x30)
blhost -p com10 set-property 0x16 0 
Response status = 0 (0x0) Success.

Send MBI file to device#

Last step is to uploads MBI file with NBU image to device.

# uploads MBI
%! blhost $UART_CONNECTION write-memory 0x0 $MBI_OUTPUT_FILE
blhost -p com10 write-memory 0x0 workspace/MBI/my_mbi.bin 
Writing memory
Response status = 0 (0x0) Success.
Response word 1 = 2904 (0xb58)
%! blhost $UART_CONNECTION reset
blhost -p com10 reset 
Response status = 0 (0x0) Success.