Debug authentication on MCXN9XX#

Introduction#

The fundamental principles of debugging, which require access to the system state and system information, conflict with the principles of security, which require the restriction of access to assets. Thus, many products disable debug access completely before deploying the product. To address these challenges, the chip offers a debug authentication protocol as a mechanism to authenticate the debugger (an external entity) has the credentials approved by the product manufacturer before granting debug access to the device. The debug authentication is a challenge-response scheme and assures that only the debugger in possession of the required debug credentials can successfully authenticate over the debug interface and access restricted parts of the device.

The protocol is divided into steps as described below:

  1. The debugger initiates the Debug Mailbox message exchange by setting the CSW[RESYNCH_REQ] bit and CSW[CHIP_RESET_REQ] bit of DM-AP.

  2. The debugger waits (minimum 30 ms) for the devices to restart and enter debug mailbox request handling loop.

  3. The debugger sends Debug Authentication Start command (command code 10h) to the device.

  4. The device responds back with Debug Authentication Challenge (DAC) packet based on the debug access rights preconfigured in CMPA fields, which are collectively referred as Device Credential Constraints Configuration (DCFG_CC). The response packet also contains a 32 bytes random challenge vector.

  5. The debugger responds to the challenge with a Debug Authentication Response (DAR) message by using an appropriate debug certificate, matching the device identifier in the DAC. The DAR packet contains the debug access permission certificate, also referred as Debug Credential (DC), and a cryptographic signature binding the DC and the challenge vector provided in the DAC.

  6. The device on receiving the DAR, validates the contents by verifying the cryptographic signature of the message using the debugger’s public key present in the embedded the Debug Credential (DC). On successful validation of DAR, the device enables access to the debug domains permitted in the DC

debug_authentication_flow

WARNING!#

This configuration is used only for demonstration purpose. For final security device configuration go through all configuration possibilities and define your own specific config/keys.

1. Prerequisites#

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

  • This example uses FRDM-MCXN947 board. This is example board configuration without external debugger. It is also possible to use configuration with external debugger such as JLink debug probe.

  • The mcxn947 should be in Unsecure life cycle to proper example flow.

    frdm-mcxn947

1.1 Let’s prepare the environment#

from spsdk.utils.jupyter_utils import YamlDiffWidget

# This env variable sets colored logger output to STDOUT
%env JUPYTER_SPSDK=1
# Set a magic for command execution and echo
%alias execute echo %l && %l
%alias_magic ! execute

WORKSPACE = "workspace/"  # change this to path to your workspace
KEYS = "../_data/keys/ecc256/"  # change this to path to your keys
INPUTS = "inputs/"
DC_CONFIG = INPUTS + "dc_config.yaml"  # DC file config path
CMPA_CONFIG = INPUTS + "cmpa_mcxn9xx_debug_auth.yaml"
CFPA_CONFIG = INPUTS + "cfpa_mcxn9xx_debug_auth.yaml"
CERT_BLOCK_CONFIG = INPUTS + "cert_block_mcxn9xx.yaml"
VERBOSITY = (
    ""  # verbosity of commands, might be -v or -vv for debug or blank for no additional info
)
# choose family
FAMILY = "mcxn946"
INTERFACE = "pyocd"
env: JUPYTER_SPSDK=1
Created `%!` as an alias for `%execute`.

1.2 Let’s prepare the device#

Erase previous settings and use app nxpdevscan to check if the device is connected to the PC in ISP mode. The goal of device preparation is to have device in “virgin state” => erased, unsecured and ready to communicate over ISP to be able to show all steps to run up the NXP Debug Authentication feature.

# prepare the board so that there is no previous settings
%! nxpdebugmbox $VERBOSITY -f $FAMILY -i $INTERFACE cmd erase
# enter ISP mode
%! nxpdebugmbox $VERBOSITY -f $FAMILY -i $INTERFACE cmd ispmode -m 0
# check if the device is connected and detected by PC
%! nxpdevscan $VERBOSITY
nxpdebugmbox  -f mcxn946 -i pyocd cmd erase 
  #   Interface   Id              Description                                                       
----------------------------------------------------------------------------------------------------
  0   PyOCD       3NMDBGL2DLIM2   NXP Semiconductors MCU-LINK FRDM-MCXN947 (r0E7) CMSIS-DAP V3.140  
Mass flash erase succeeded
nxpdebugmbox  -f mcxn946 -i pyocd cmd ispmode -m 0 
  #   Interface   Id              Description                                                       
----------------------------------------------------------------------------------------------------
  0   PyOCD       3NMDBGL2DLIM2   NXP Semiconductors MCU-LINK FRDM-MCXN947 (r0E7) CMSIS-DAP V3.140  
Entering into ISP mode succeeded
nxpdevscan  
-------- Connected NXP USB Devices --------

LPCSIO - NXP Semiconductors
Vendor ID: 0x1fc9
Product ID: 0x0143
Path: HID\VID_1FC9&PID_0143&MI_04\9&5D50897&0&0000
Path Hash: 900a858e
Name: 
Serial number: 3NMDBGL2DLIM2

MCU-LINK NXP TRACE - NXP Semiconductors
Vendor ID: 0x1fc9
Product ID: 0x0143
Path: HID\VID_1FC9&PID_0143&MI_01\9&176FAA15&0&0000
Path Hash: 38fa47ea
Name: 
Serial number: 3NMDBGL2DLIM2

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

Port: COM116
Type: mboot device

-------- Connected NXP SIO Devices --------

LIBUSBSIO - NXP Semiconductors, LPCSIO
Vendor ID: 0x1fc9
Product ID: 0x0143
Path: HID\VID_1FC9&PID_0143&MI_04\9&5D50897&0&0000
Path Hash: 900a858e
Serial number: 3NMDBGL2DLIM2
Interface number: 4
Release number: 787

-------- Connected NXP UUU Devices --------
# choose USB or UART interface based on the result of nxpdevscan
# USB = "-u 0x1fc9,0x14f"
UART = "-p COM116"

# check if the board responds in ISP mode
%! blhost $VERBOSITY $UART get-property 1
# Response word 2 for get-property 17 is LC_STATE.
%! blhost $VERBOSITY $UART get-property 17
blhost  -p COM116 get-property 1 
Response status = 0 (0x0) Success.
Response word 1 = 1258488320 (0x4b030200)
Current Version = K3.2.0
blhost  -p COM116 get-property 17 
Response status = 0 (0x0) Success.
Response word 1 = 1520786085 (0x5aa55aa5)
Response word 2 = 3 (0x3)
Security State = UNSECURE

2. Generate RoT + Debug auth keys#

First we need to generate Root of Trust Keys (RoTKs)/Super Root Keys (SRKs), Debug Credential Key (DCK) and optionally Image Signing Key (ISK). Use nxpcrypto app to generate secp256r1 keys (see How-to-get-keys-using-nxpcrypto). We will need by default create 4 RoTKs, 1 DCK and 1 ISK. At least one RoTK is mandatory for this MCU.

The notebook is using pre-generated keys just for that example purposes from folder _data/keys/ecc256 in root of all SPSDK examples.

3. Generate debug credential file including its configuration file#

First we need to prepare the configuration file for debug credential file export. Let’s begin by creating a template configuration file using the nxpdebugmbox dat dc get-template command. To simplify this example, we have already prepared that configuration, which can be found in the ./inputs/dc_config.yaml file. Below, we’ll compare the differences between the template and our customized example to highlight the additions we’ve made.

Note: As is mentioned in introduction, the DC file should be created by owner of RoT credentials.

# Get difference of template and user YAML configuration
YamlDiffWidget("inputs/dc_config.diffc").html
nxpdebugmbox -f mcxn946 dat dc get-template -o workspace/dc_config.yaml --force 
The Debug Credentials template for mcxn946 has been saved into workspace/dc_config.yaml YAML file

Configuration Differences

Now we generate dc file based on yaml configuration.

DC_FILE_PATH = WORKSPACE + "debug_auth.dc"
%! nxpdebugmbox $VERBOSITY -f $FAMILY dat dc export -c $DC_CONFIG -o $DC_FILE_PATH --force
nxpdebugmbox  -f mcxn946 dat dc export -c inputs/dc_config.yaml -o workspace/debug_auth.dc --force 
RKTH: e2cca7cf09a45d2f1942969fda1c68ecaad78fad416d143292dad2f618291ddd
Creating Debug credential file succeeded

4. Generate debug authentication configuration file#

In advance we will prepare the configuration file for debug authentication procedure itself. Let’s begin again by creating a template configuration file using the nxpdebugmbox dat get-template command. To simplify this example, we have already prepared that configuration, which can be found in the ./inputs/dat_config.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/dat_config.diffc").html
nxpdebugmbox -f mcxn946 dat get-template -o workspace/dat_config.yaml --force 
Creating workspace/dat_config.yaml template file.

Configuration Differences

5. Generate CMPA + CFPA chip configuration for debug authentication#

As a next step we need to update MCU configuration to secure chip and its debug interface to final test of whole debug authentication process.

We need to prepare the configuration files for CMPA and CFPA blocks export. Let’s begin by creating a template configuration files using the pfr get-template command. This command we need to call twice to get templates for both type of configuration blocks (-t option). To simplify this example, we have already prepared that configuration, which can be found in the ./inputs/cmpa_mcxn9xx_debug_auth.yaml, ./inputs/cfpa_mcxn9xx_debug_auth.yaml files. Below, we’ll compare the differences between the templates and our customized examples to highlight the additions we’ve made.

# Get difference of template and user YAML configuration of CMPA
YamlDiffWidget("inputs/cmpa_mcxn9xx_debug_auth.diffc").html
pfr get-template -t cmpa -f mcxn946 -o workspace/cmpa_mcxn9xx_debug_auth.yaml --force 
The PFR cmpa template for mcxn946 has been saved into workspace/cmpa_mcxn9xx_debug_auth.yaml YAML file

Configuration Differences

# Get difference of template and user YAML configuration of CFPA
YamlDiffWidget("inputs/cfpa_mcxn9xx_debug_auth.diffc").html
pfr get-template -t cfpa -f mcxn946 -o workspace/cfpa_mcxn9xx_debug_auth.yaml --force 
The PFR cfpa template for mcxn946 has been saved into workspace/cfpa_mcxn9xx_debug_auth.yaml YAML file

Configuration Differences

5.1 Generate final PFR binaries#

# Generate PFR binaries
CMPA_BINARY_OUTPUT = WORKSPACE + "cmpa_mcxn9xx.bin"
CFPA_BINARY_OUTPUT = WORKSPACE + "cfpa_mcxn9xx.bin"

%! pfr $VERBOSITY generate-binary -c $CMPA_CONFIG -e $CERT_BLOCK_CONFIG -o $CMPA_BINARY_OUTPUT
%! pfr $VERBOSITY generate-binary -c $CFPA_CONFIG -o $CFPA_BINARY_OUTPUT
pfr  generate-binary -c inputs/cmpa_mcxn9xx_debug_auth.yaml -e inputs/cert_block_mcxn9xx.yaml -o workspace/cmpa_mcxn9xx.bin 
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 (613ms 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 (613ms since start, pfr.py:206)
Success. (PFR binary has been generated)
pfr  generate-binary -c inputs/cfpa_mcxn9xx_debug_auth.yaml -o workspace/cfpa_mcxn9xx.bin 
WARNING:spsdk.pfr.pfr:The DCFG_CC_SOCU_NS_PIN register has been recomputed, because it has been used in configuration and the bitfield INVERSE_VALUE has not been specified (596ms since start, pfr.py:206)
WARNING:spsdk.pfr.pfr:The DCFG_CC_SOCU_NS_DFLT register has been recomputed, because it has been used in configuration and the bitfield INVERSE_VALUE has not been specified (596ms since start, pfr.py:206)
Success. (PFR binary has been generated)

6. Load binary image + debug auth config into PFR#

IMAGE = INPUTS + "frdm_mcxn947_led_blinky.bin"
# Write test image to flash
%! blhost $UART write-memory 0x0 $IMAGE

# Write CMPA / CFPA configuration blocks to flash
%! pfr $VERBOSITY write $UART -t cfpa -f $FAMILY -b $CFPA_BINARY_OUTPUT
%! pfr $VERBOSITY write $UART -t cmpa -f $FAMILY -b $CMPA_BINARY_OUTPUT

#  Reset to device to run test application and apply settings of configuration blocks
%! blhost $UART reset
blhost -p COM116 write-memory 0x0 inputs/frdm_mcxn947_led_blinky.bin 
Writing memory
Response status = 0 (0x0) Success.
Response word 1 = 4072 (0xfe8)
pfr  write -p COM116 -t cfpa -f mcxn946 -b workspace/cfpa_mcxn9xx.bin 
CFPA page address on mcxn946 is 0x1000000
CFPA data written to device.
pfr  write -p COM116 -t cmpa -f mcxn946 -b workspace/cmpa_mcxn9xx.bin 
CMPA page address on mcxn946 is 0x1004000
CMPA data written to device.
blhost -p COM116 reset 
Response status = 0 (0x0) Success.

7. Test debug authentication#

Now we can call authentication command for nxpdebugmbox. Since the board is in the LC=0x3, we need to set value for beacon in order to verify that the authentication truly succeeded. Let’s set beacon to 1.

DAT_CONFIG = INPUTS + "dat_config.yaml"
%! nxpdebugmbox $VERBOSITY -f $FAMILY -i $INTERFACE dat auth -c $DAT_CONFIG
nxpdebugmbox  -f mcxn946 -i pyocd dat auth -c inputs/dat_config.yaml 
  #   Interface   Id              Description                                                       
----------------------------------------------------------------------------------------------------
  0   PyOCD       3NMDBGL2DLIM2   NXP Semiconductors MCU-LINK FRDM-MCXN947 (r0E7) CMSIS-DAP V3.140  
Debug Authentication ends successfully.

Now read beacon from the memory. The value from the memory should have same values as the value from the config file.

%! nxpdebugmbox $VERBOSITY -f $FAMILY -i $INTERFACE mem-tool read-memory -a 0x40000FC0 -c 4
nxpdebugmbox  -f mcxn946 -i pyocd mem-tool read-memory -a 0x40000FC0 -c 4 
  #   Interface   Id              Description                                                       
----------------------------------------------------------------------------------------------------
  0   PyOCD       3NMDBGL2DLIM2   NXP Semiconductors MCU-LINK FRDM-MCXN947 (r0E7) CMSIS-DAP V3.140  
00 00 01 00