RW61x Debug Authentication#

Introduction#

This jupyter notebook describes the steps for debug authentication (DAT) using the nxpdebugmbox app away from SPSDK team. The fundamental principles of debugging conflict with the principles of security: debugging requires access to the system state and system information, security requires the restriction of access to assets. Often, debug access is disabled completely before the products are deployed. This causes challenges for product design teams to complete the return material analysis. To address these challenges, the device supports a DAT protocol as a mechanism to authenticate the debugger. The product manufacturer approves the credentials before granting debug access to the device. So DAT is a key feature as it enables security during the complete lifecycle of a product.

An example for implementing DAT has already been presented for MCXN9xx devices, so you can study the general principles of DAT from Debug-authentication-on-MCXN9XX. The reason for creating this jupyter notebook was the numerous inquiries regarding the use of DAT on rw61x devices, considering the necessary configuration of registers, which MCXN9xx does not have, and the procedure was therefore not entirely clear to some users.

Let’s prepare the environment#

%run ../init_notebook.ipynb

import os
import yaml
import pprint

WORKSPACE = "workspace/" # change this to path to your workspace
KEYS = "../_data/keys/ecc256/" # change this to path to your keys
INPUTS = "inputs/"

pp = pprint.PrettyPrinter(indent=4)

# choose debug interface
INTERFACE = "jlink"
# choose family
FAMILY = "rw61x"
env: JUPYTER_SPSDK=1
Created `%!` as an alias for `%execute`.

Generate root of trust keys and debug credential key#

Root of Trust Keys (RoTKs)

  • The device supports up to four RoTKs. At least one key pair is required.

  • Supported key types: secp256r1, secp384r1.

Debug Credential key (DCK)

  • The public part of the key is associated with a debug credential (DC).

  • The private part is held by the user and used to produce signatures during authentication.

In this example, we will use nxpcrypto app to generate secp256r1 keys (see How-to-get-keys-using-nxpcrypto).

# load generated key pair for ROTK0
ROTK0_PRIVATE_KEY_PATH = os.path.join(KEYS, "srk0_ecc256.pem")
ROTK0_PUBLIC_KEY_PATH = os.path.join(KEYS, "srk0_ecc256.pub")
# verify that keys were loaded
assert os.path.exists(ROTK0_PRIVATE_KEY_PATH)
assert os.path.exists(ROTK0_PUBLIC_KEY_PATH)

# load generated key pair for DCK
DCK_PRIVATE_KEY_PATH = os.path.join(KEYS, "dck_ecc256.pem")
DCK_PUBLIC_KEY_PATH = os.path.join(KEYS,"dck_ecc256.pub")
# verify that keys were loaded
assert os.path.exists(DCK_PRIVATE_KEY_PATH)
assert os.path.exists(DCK_PUBLIC_KEY_PATH)

Generate debug credential file#

Debug Credential (DC) configuration including:

  • socc: Specifies the device family.

  • uuid: Universally Unique Identifier (UUID) is 128-bit IETF RFC4122 compliant. Controls whether to enforce UUID check during DC validation or not. If this field is set, only the DC with matching device UUID can unlock the debug access.

  • cc_socu: SoC Usage controls which debug domains are accessed via the authentication protocol.

  • cc_vu: Vendor Usage can be leveraged by vendors in product-specific ways.

  • cc_beacon: Credential beacon is associated with DC and system product. With credential beacon, debug authentication can be restricted to specific parts having matching system product ID in OTP.

  • rot_meta: Includes public parts of RoT key(s).

  • rot_id: Defines the root of trust identifier. Allows the debugger to infer which RoT public key(s) are acceptable to the device. The rot_id field is used to bind the devices to specific certificate authority (CA) keys issuing the debug credentials.

  • dck: The public part of DCK.

  • rotk: RoT signature private key for the RoT meta chosen by rot_id to sign the image.

  • sign_provider: Signature provider configuration in format ‘type=<sp_type>;<key_number>=<rot_id>”.

# generate and modify DC config
DC_CONFIG_DEFAULT_RW61X = os.path.join(WORKSPACE, "dc_config_default_rw61x.yml")

%! nxpdebugmbox get-template -f $FAMILY -o $DC_CONFIG_DEFAULT_RW61X --force
nxpdebugmbox get-template -f rw61x -o workspace/dc_config_default_rw61x.yml --force 
The configuration template file has been created.
# modified DC config for this example
# A1: socc = 0x0004; A2: socc = 0x000A 
DC_CONFIG_RW61X = os.path.join(INPUTS, "dc_config_rw61x.yml")

with open(DC_CONFIG_RW61X, "r") as dc_file:
    print("Modified DC config:")
    pp.pprint(yaml.safe_load(dc_file))
Modified DC config:
{   'cc_beacon': 0,
    'cc_socu': 65535,
    'cc_vu': 0,
    'dck': '../../_data/keys/ecc256/dat_ecc256.pub',
    'rot_id': 0,
    'rot_meta': ['../../_data/keys/ecc256/srk0_ecc256.pub'],
    'rotk': '../../_data/keys/ecc256/srk0_ecc256.pem',
    'socc': 4,
    'uuid': '00000000000000000000000000000000'}

NOTICE: Based on the chip revision choose socc. A1: socc = 0x4; A2: socc = 0xA!

# generate DC file according to exemplary config
DC_FILE_RW61X = os.path.join(WORKSPACE, "rw61x.dc")

%! nxpdebugmbox -p 2.0 gendc -c $DC_CONFIG_RW61X -o $DC_FILE_RW61X --force
nxpdebugmbox -p 2.0 gendc -c inputs/dc_config_rw61x.yml -o workspace/rw61x.dc --force 
RKTH: dc41dd48d79b99ac8b91194483fc477c632d0b5632ae8a439476a98872971d3d
Creating Debug credential file succeeded
# save RKTH
RKTH_PATH = os.path.join(WORKSPACE, "rkth.txt")

%! nxpcrypto rot calculate-hash -f rw61x -k $ROTK0_PUBLIC_KEY_PATH -o $RKTH_PATH

# read RKTH
with open(RKTH_PATH, 'rb') as rkth:
    rkth_val = f"0x{rkth.read().hex()}"
nxpcrypto rot calculate-hash -f rw61x -k ../_data/keys/ecc256/srk0_ecc256.pub -o workspace/rkth.txt 
Result has been stored in: workspace\rkth.txt
RoT hash: dc41dd48d79b99ac8b91194483fc477c632d0b5632ae8a439476a98872971d3d

Device preparation#

  • Have the device in debug mode.

RW61X-EVK

# check availability of debug probe 
%! nxpdebugmbox -i $INTERFACE test-connection
nxpdebugmbox -i jlink test-connection 
  #   Interface   Id           Description             
-------------------------------------------------------
  0   Jlink       1061995210   Segger J-Link MCU-Link  
The device is accessible for debugging.

Shadow registers configuration#

The following is an introduction to one of the variants of the shadow register configuration for DAT. The illustrative use case that is presented is based on disabling the debug access control registers.

  • The debug access control rights and security policies are configurable.

  • The configuration fields are referred to as device configuration for credential constraints (DCFG_CC).

  • Life Cycle (LC) state in shadow registers to be configured should be either Develop2 (0x0707) or In-Field (0x0F0F).

  • The RKTH value must be specified.

# verify that your shadowregs are in the default state
SR_DIFF_PATH = os.path.join(WORKSPACE, "sr_diff_rw61x.yml")

%! shadowregs -i $INTERFACE -f $FAMILY saveconfig -o $SR_DIFF_PATH -d
shadowregs -i jlink -f rw61x saveconfig -o workspace/sr_diff_rw61x.yml -d 
  #   Interface   Id           Description             
-------------------------------------------------------
  0   Jlink       1061995210   Segger J-Link MCU-Link  
The Shadow registers has been saved into workspace\sr_diff_rw61x.yml YAML file
# optional but recommended: reset connected device
%! shadowregs -i $INTERFACE -f $FAMILY reset
shadowregs -i jlink -f rw61x reset 
  #   Interface   Id           Description             
-------------------------------------------------------
  0   Jlink       1061995210   Segger J-Link MCU-Link  
The target has been reset.
# generate and modify shadowregs config
SR_TEMPLATE_DEFAULT_PATH = os.path.join(WORKSPACE, "sr_template_default_rw61x.yml")

%! shadowregs -f $FAMILY get-template -o $SR_TEMPLATE_DEFAULT_PATH --force
shadowregs -f rw61x get-template -o workspace/sr_template_default_rw61x.yml --force 
The Shadow registers template for rw61x has been saved into workspace\sr_template_default_rw61x.yml YAML file
# modified shadowregs config for this example
SR_TEMPLATE_PATH = os.path.join(INPUTS, "sr_template_rw61x.yml")

with open(SR_TEMPLATE_PATH, "r") as sr_file:
    print("Modified SR config:")
    pp.pprint(yaml.safe_load(sr_file))
Modified SR config:
{   'description': {   'author': 'NXP',
                       'device': 'rw61x',
                       'release': 'beta',
                       'version': '2.1.0'},
    'registers': {   'BOOT_CFG0': {   'bitfields': {   'BOOT_CLK_SPEED': '0x0',
                                                       'BOOT_FAIL_PIN': '0x0',
                                                       'BOOT_FAIL_PORT': '0x0',
                                                       'DEFAULT_ISP_MODE': 'AUTO_ISP',
                                                       'DICE_INC_OTP': 'NOT_INCLUDED',
                                                       'DICE_SKIP': 'ENABLED',
                                                       'PRIMARY_BOOT_SOURCE': 'ISP_PIN_BOOT',
                                                       'REDUNDANT_SPI_PORT': 'FC0',
                                                       'SECURE_BOOT_EN': 'DISABLED',
                                                       'STOP_ON_FAILURE': '0x0',
                                                       'TZM_IMAGE_TYPE': 'IGNORED'}},
                     'BOOT_CFG1': {   'bitfields': {   'FLEXSPI_AUTO_PROBE_EN': 'FLASH_AUTO_PROBE',
                                                       'FLEXSPI_DUMMY_CYCLES': 'AUTO_PROB',
                                                       'FLEXSPI_FLASH_TYPE': 'FLEXSPI_SDR_3B',
                                                       'FLEXSPI_FREQUENCY': 'FLEXSPI_100MHZ',
                                                       'FLEXSPI_HOLD_TIME': 'NO_DELAY',
                                                       'FLEXSPI_PROBE_TYPE': 'QSPI_NOR',
                                                       'FLEXSPI_PWR_HOLD_TIME': 'NO_DELAY',
                                                       'FLEXSPI_RST_HOLD_TIME': 'NO_DELAY',
                                                       'FLEXSPI_RST_SEQ': 'NO_RESET_PERFORMED',
                                                       'FLEXSPI_WUP_HOLD_TIME': 'NO_DELAY',
                                                       'FLEXSPI_WUP_SEQ': 'NO_RESET_PERFORMED'}},
                     'BOOT_CFG2': {   'bitfields': {   'FLEXSPI_DELAY_CELL_NUM': '0x0',
                                                       'FLEXSPI_IMAGE_OFFSET': '0x00',
                                                       'FLEXSPI_IMAGE_SIZE': 'SIZE_OFFSET'}},
                     'BOOT_CFG3': {   'bitfields': {   'ENABLE_CRC_CHECK': '0x0',
                                                       'ENF_CNSA': 'P-256_KEY',
                                                       'FIPS_AES_STEN': 'SKIP_SELF_TEEST_RUN',
                                                       'FIPS_CMAC_STEN': 'SKIP_SELF_TEEST_RUN',
                                                       'FIPS_DRBG_STEN': 'SKIP_SELF_TEEST_RUN',
                                                       'FIPS_ECDSA_STEN': 'SKIP_SELF_TEEST_RUN',
                                                       'FIPS_KDF_STEN': 'SKIP_SELF_TEEST_RUN',
                                                       'FIPS_SHA_STEN': 'SKIP_SELF_TEEST_RUN',
                                                       'ROTK0_USAGE': 'DebugCA_ImageCA_FwCA_ImageKey_FwKey',
                                                       'ROTK1_USAGE': 'Unused',
                                                       'ROTK2_USAGE': 'Unused',
                                                       'ROTK3_USAGE': 'Unused',
                                                       'SKIP_PM_SIGN_VERIFCATION': '0x0'}},
                     'BOOT_CFG5': {   'bitfields': {   'USB_PID': '0x0000',
                                                       'USB_VID': '0x0000'}},
                     'BOOT_CFG6': {   'bitfields': {   'SDIO_PID': '0x0000',
                                                       'SDIO_VID': '0x0000'}},
                     'DCFG_CC_SOCU': {   'bitfields': {   'CRC8[7:0]': '0x00',
                                                          'DFLT_CPU1DBGEN': 'DISABLED',
                                                          'DFLT_CPU1NIDEN': 'DISABLED',
                                                          'DFLT_CPU2DBGEN': 'DISABLED',
                                                          'DFLT_CPU2NIDEN': 'DISABLED',
                                                          'DFLT_DBGEN': 'DISABLED',
                                                          'DFLT_FACMDEN': 'DISABLED',
                                                          'DFLT_ISPCMDEN': 'DISABLED',
                                                          'DFLT_NIDEN': 'DISABLED',
                                                          'DFLT_SPIDEN': 'DISABLED',
                                                          'DFLT_SPNIDEN': 'DISABLED',
                                                          'DFLT_TAPEN': 'DISABLED',
                                                          'FORCE_UUID_MATCH': '0x0',
                                                          'PINNED_CPU1DBGEN': 'DAR_CC',
                                                          'PINNED_CPU1NIDEN': 'DAR_CC',
                                                          'PINNED_CPU2DBGEN': 'DAR_CC',
                                                          'PINNED_CPU2NIDEN': 'DAR_CC',
                                                          'PINNED_DBGEN': 'DAR_CC',
                                                          'PINNED_FACMDEN': 'DAR_CC',
                                                          'PINNED_ISPCMDEN': 'DAR_CC',
                                                          'PINNED_NIDEN': 'DAR_CC',
                                                          'PINNED_SPIDEN': 'DAR_CC',
                                                          'PINNED_SPNIDEN': 'DAR_CC',
                                                          'PINNED_TAPEN': 'DAR_CC'}},
                     'DCFG_CC_SOCU_NS': {   'bitfields': {   'CRC8_NS[7:0]': '0x00',
                                                             'DFLT_CPU1DBGEN_NS': 'DISABLED',
                                                             'DFLT_CPU1NIDEN_NS': 'DISABLED',
                                                             'DFLT_CPU2DBGEN_NS': 'DISABLED',
                                                             'DFLT_CPU2NIDEN_NS': 'DISABLED',
                                                             'DFLT_DBGEN_NS': 'DISABLED',
                                                             'DFLT_FACMDEN_NS': 'DISABLED',
                                                             'DFLT_ISPCMDEN_NS': 'DISABLED',
                                                             'DFLT_NIDEN_NS': 'DISABLED',
                                                             'DFLT_SPIDEN_NS': 'DISABLED',
                                                             'DFLT_SPNIDEN_NS': 'DISABLED',
                                                             'DFLT_TAPEN_NS': 'DISABLED',
                                                             'FORCE_UUID_MATCH_NS': '0x0',
                                                             'PINNED_CPU1DBGEN_NS': 'DAR_CC',
                                                             'PINNED_CPU1NIDEN_NS': 'DAR_CC',
                                                             'PINNED_CPU2DBGEN_NS': 'DAR_CC',
                                                             'PINNED_CPU2NIDEN_NS': 'DAR_CC',
                                                             'PINNED_DBGEN_NS': 'DAR_CC',
                                                             'PINNED_FACMDEN_NS': 'DAR_CC',
                                                             'PINNED_ISPCMDEN_NS': 'DAR_CC',
                                                             'PINNED_NIDEN_NS': 'DAR_CC',
                                                             'PINNED_SPIDEN_NS': 'DAR_CC',
                                                             'PINNED_SPNIDEN_NS': 'DAR_CC',
                                                             'PINNED_TAPEN_NS': 'DAR_CC'}},
                     'LIFE_CYCLE_STATE': {   'bitfields': {   'LCS[7:0]': 'In-Field',
                                                              'LCS_REDUNDANT[7:0]': 'In-Field',
                                                              'Redundancy': '0x0000'}},
                     'RKTH': {   'value': '0000000000000000000000000000000000000000000000000000000000000000'},
                     'SEC_BOOT_CFG0': {   'bitfields': {   'FA_MODE_EN': '0x0',
                                                           'REVOKE_ROOTKEY0': 'ENABLED',
                                                           'REVOKE_ROOTKEY1': 'ENABLED',
                                                           'REVOKE_ROOTKEY2': 'ENABLED',
                                                           'REVOKE_ROOTKEY3': 'ENABLED',
                                                           'Redundancy': '0x0000'}},
                     'SEC_BOOT_CFG1': {   'bitfields': {   'DAP_VENDOR_USAGE': '0x0000',
                                                           'Redundancy': '0x0000'}},
                     'SEC_BOOT_CFG2': {   'bitfields': {   'REVOKE_IMG_KEY[15:0]': '0x0000',
                                                           'Redundancy': '0x0000'}},
                     'SEC_BOOT_CFG3': {   'bitfields': {   'REVOKE_IMG_KEY[31:16]': '0x0000',
                                                           'Redundancy': '0x0000'}}}}
# load modified shadowregs
%! shadowregs -i $INTERFACE -f $FAMILY loadconfig -c $SR_TEMPLATE_PATH
shadowregs -i jlink -f rw61x loadconfig -c workspace/sr_template_rw61x.yml 
  #   Interface   Id           Description             
-------------------------------------------------------
  0   Jlink       1061995210   Segger J-Link MCU-Link  
The Shadow registers has been loaded by configuration in workspace\sr_template_rw61x.yml YAML file
# RKTH specification
%! shadowregs -i $INTERFACE -f $FAMILY setreg -r RKTH -v $rkth_val
shadowregs -i jlink -f rw61x setreg -r RKTH -v 0xdc41dd48d79b99ac8b91194483fc477c632d0b5632ae8a439476a98872971d3d 
  #   Interface   Id           Description             
-------------------------------------------------------
  0   Jlink       1061995210   Segger J-Link MCU-Link  
The Shadow register RKTH has been set to 0xdc41dd48d79b99ac8b91194483fc477c632d0b5632ae8a439476a98872971d3d value
# reset the device to load modified shodowregs
%! shadowregs -i $INTERFACE -f $FAMILY reset
shadowregs -i jlink -f rw61x reset 
  #   Interface   Id           Description             
-------------------------------------------------------
  0   Jlink       1061995210   Segger J-Link MCU-Link  
The target has been reset.
# check the device is not accessible for debugging
%! nxpdebugmbox -i $INTERFACE test-connection
nxpdebugmbox -i jlink test-connection 
  #   Interface   Id           Description             
-------------------------------------------------------
  0   Jlink       1061995210   Segger J-Link MCU-Link  
The device is not-accessible for debugging.

Debug authentication challenge#

In the previous steps, we loaded a configuration with all the keys and enabled the debug authentication in the device. We have also created the DC certificate and private key for the debug authentication challenge. In addition, a protocol version and a beacon must be specified.

RW61x devices support two instantiations of debug authentication protocol versions (-p option). The versions are defined based on the different-sized ECDSA keys:

  • 2.0: Uses ECDSA P-256 signature verification RoT key(s)

  • 2.1: Uses ECDSA P-384 signature verification RoT key(s)

The debug authentication process can be extended with beacons. The authentication beacon defines the system-specific debug policy use case such as: restricting debug authentication to only certain devices having specific system product ID during manufacturing phase.

%! nxpdebugmbox -i $INTERFACE -p 2.0 auth -b 0 -c $DC_FILE_RW61X -k $DCK_PRIVATE_KEY_PATH
nxpdebugmbox -i jlink -p 2.0 auth -b 0 -c workspace/rw61x.dc -k keys/dck_ecc256.pem 
  #   Interface   Id           Description             
-------------------------------------------------------
  0   Jlink       1061995210   Segger J-Link MCU-Link  
WARNING:spsdk.dat.dac_packet:The DAC(Debug Authentication Challenge) RKTH doesn't match with DC(Debug Credential).For RW61x devices, this is correct behaviour. For LPC55S3x it indicates incorrect DC file,and needs to be fixed. (2251ms since start, dac_packet.py:98)
Debug Authentication ends successfully.
# check the device is accessible for debugging
%! nxpdebugmbox -i $INTERFACE test-connection
nxpdebugmbox -i jlink test-connection 
  #   Interface   Id           Description             
-------------------------------------------------------
  0   Jlink       1061995210   Segger J-Link MCU-Link  
The device is accessible for debugging.