Secure Binary 2.1#

Version 2.1 added support for digital signatures.

The SB 2.0 and 2.1 file format also uses AES encryption for confidentiality and HMAC for extending trust from the signed part of the SB file to the command and data part of the SB file. These two keys (AES decrypt key and HMAC key) are wrapped in the RFC3394 key blob, for which the key wrapping key is the SBKEK key

SB2 generation using YAML file#

Since version 2.0 it is possible to generate SB file using the YAML configuration in the similar manner as SB 3.1.

Example of use:

  1. Generate template first

nxpimage sb21 get-template -o "sb2_config.yaml

  1. Fill the configuration and export to binary

nxpimage sb21 export-yaml "sb2_config.yaml

SB2 generation using BD file#

The tool uses an input command file to control the sequence of bootloader commands present in the output file. This command file is called a “boot descriptor file” or BD file for short. The image location is stated in the “sources” section of the .bd file. The SB key in the text file is used for encryption with the nxpimage command line tool.

It is possible to use NXP elftosb tool user guide located here.

Note

Please note that some functionality described in the UG may not be supported in SPSDK SB2 parser.

For more information about the Secure boot setup for LPC55Sxx family follow the AN12283.

Supported Commands

Supported commands for SB2.1#

Command

Description

Example

load

The load statement is used to store data into the memory. The load command is also used to write to the flash memory. When loading to the flash memory, the region being loaded to must be erased before to the load operation. The most common form of a load statement is loading a source file by name. Only plain binary images are supported.

Example:
section (0) {
// load an entire binary file to an address
load myBinFile > 0x70000000;
// load an eight byte blob
load {{ ff 2e 90 07 77 5f 1d 20 }} > 0xa0000000;
// 4 byte load IFR statement
load ifr 0x1234567 > 0x30;
// Program fuse statement
load fuse {{00 00 00 01}} > 0x01000188;
// load to sdcard
load sdcard {{aa bb cc dd}} > 0x08000188;
load @288 {{aa bb cc dd}} > 0x08000188;
}

fill

Fill is a type of load command used for filling a region of memory with pattern.

Example:
section(0) {
// pattern fill
load 0x55.b > 0x2000..0x3000;
// load two bytes at an address
load 0x1122.h > 0xf00;
}

erase

The erase statement inserts a bootloader command to erase the flash memory. There are two forms of the erase statement. The simplest form (erase all) creates a command that erases the available flash memory. The actual effect of this command depends on the runtime settings of the bootloader and whether the bootloader resides in the flash, ROM, or RAM.

Example:
section (0){
// Erase all
erase all;
// Erase unsecure all
erase unsecure all;
// erase statements specifying memory ID and range
erase @8 all;
erase @288 0x8001000..0x80074A4;
erase sdcard 0x8001000..0x80074A4;
erase mmccard 0x8001000..0x80074A4;
}

enable

Enable statement is used for initialization of external memories using a parameter block that was previously loaded to RAM.

Example:
section (0){
# Load quadspi config block bin file to RAM, use it to enable QSPI.
load myBinFile > 0x20001000;
enable qspi 0x20001000;
}

encrypt

Encrypt holds an ID, which is a reference to keyblob to be used for encryption. So the encrypt command requires a list of keyblobs, the keyblob ID and load command.

e.g.
encrypt (0){
load myImage > 0x0810000;
}

keywrap

Keywrap holds keyblob ID to be encoded by a value stored in load command and stored to address defined in the load command.

Example:
keywrap (0) {
load {{ 00000000 }} > 0x08000000;
}

keystore_to_nv

The keystore_to_nv statement instructs the bootloader to load the backed up keystore values back into keystore memory region on non-volatile memory.

Example:
section (0) {
keystore_to_nv @9 0x8000800;

keystore_from_nv

The keystore_to_nv statement instructs the bootloader to load the backed up keystore values back into keystore memory region on non-volatile memory.

Example:
section (0) {
keystore_from_nv @9 0x8000800;

version_check

Validates version of secure or non-secure firmware version with the value stored in the OTP or PFR, to prevent the FW rollback. The command fails if version provided in command is lower than version stored in the OTP/PFR.

Example:
section (0) {
version_check sec 0x2;
version_check nsec 2;
}

jump

The “jump” command produces the ROM_JUMP_CMD. See the boot image format design document for specific details about these commands, such as the function prototypes they expect. Jump to entrypoint is not supported. Only fixed address is supported.

Example:
section (0) {
# jump to a fixed address
jump 0xffff0000;
}

Example of SB2 generation for 4 root keys

nxpimage: nxpimage sb21 export -k "sbkek.txt" -c "commandFile.bd" -o "output.sb2" -s private_key_1_2048.pem -S certificate_1_2048.der.crt -R certificate_1_2048.der.crt -R certificate_2_2048.der.crt -R certificate_3_2048.der.crt -R certificate_4_2048.der.crt -h "RHKT.bin" "input.bin"

Created SB2 file can be loaded into the device using blhost receive-sb-file command. blhost -p COMxx receive-sb-file <path to the secured binary(.sb2)>

Description of how to use BD file is in bellow chapter.

Parser grammar#

This is a user guide describing how to generate a secure binary rev. 2.1 based on a configuration file (a so called BD file or command file) and additional inputs like certificates, keys, binary files etc.

Supported Syntax#

The syntax is written in EBNF (Extended Backus Naur Form), however, the application uses (namely SLY - python implementation of Lex/Yacc) only BNF. From this perspective the graphs visualize the EBNF form with the grammar and the conversion into BNF as well as remarks what is supported.

command_file:

command_file

command_file
         ::= pre_section_block* section_block*

Comments:

The options block, constants block, sources block and keyblob block must be defined prior to the section block. There may be multiple blocks in any order, but all must precede the section blocks.

# options, sources, keyblob & constants must precede section block, but there may be
# multiple definitions in any order
options {

}

sources {

}

keyblob (0) {

}

constants {

}

options {

}

# Section blocks must be the very last blocks defined
section (1) {

}

section (2) {

}

pre_section_block:

pre_section_block

pre_section_block
         ::= options_block
           | constants_block
           | sources_block
           | keyblob_block

referenced by:

  • command_file

options_block:

options_block

options_block
         ::= OPTIONS '{' option_def* '}'

Comments:

Example:

options {
    opt1 = "some_string";
    opt2 = 1234;
    opt3 = 1 > 3;
    ...
}

referenced by:

  • pre_section_block

option_def:

option_def

option_def
         ::= IDENT '=' const_expr ';'

referenced by:

  • options_block

constants_block:

constants_block

constants_block
         ::= CONSTANTS '{' constant_def* '}'

referenced by:

  • pre_section_block

Comments: Only numbers can be assigned to identifiers in the constants block.

constant_def:

constant_def

constant_def
         ::= IDENT '=' bool_expr ';'

referenced by:

  • constants_block

sources_block:

sources_block

sources_block
         ::= SOURCES '{' source_def* '}'

referenced by:

  • pre_section_block

source_def:

source_def

source_def
         ::= IDENT '=' source_value ( '(' option_list? ')' )? ';'

referenced by:

  • sources_block

Comments:

option_list in source_def is not supported and raises syntax error when used! According to the grammar, identifiers defined in source block are referenced in the grammar as source_name, however, the grammar can’t be defined using this type of token, as there is no rule to distinguish between an identifier token and a source name token. So the grammar uses the IDENT token instead and documents this fact in description, that it’s a source_name identifier.

source_value:

source_value

source_value
         ::= STRING_LITERAL
           | EXTERN '(' int_const_expr ')'

referenced by:

  • source_def

Comments:

The EXTERN keyword references source files defined on the command line as the very last arguments indexed from 0. In the example below, extern(1) would reference the “./file2” file provided on command line.

Command file example:

sources {
    my_binary_file = extern(1); # my_binary_file = file2.bin
}

Command line usage:

elf2sb -c.. -o.. "some/path/to/file1.bin" "./file2.bin"

option_list:

option_list

option_list
         ::= IDENT '=' const_expr ( ',' IDENT '=' const_expr )*

referenced by:

  • keyblob_contents

  • section_options

  • source_def

keyblob_block:

keyblob_block

keyblob_block
         ::= KEYBLOB '(' int_const_expr ')' '{' keyblob_contents '}'

referenced by:

  • pre_section_block

Comments:

The keyblob block grammar has been modified and it supports only single keyblob_contents definition, which must not be empty!

Example

keyblob (1) {
    (
        start = 0x0800000,
        end = 0x08001000,
        key = "12345678901234567890123456789012",
        counter = "1122334455667788",
        byteSwap = False
    )
    # No further definitions allowed, if present, syntax error will be raised!
}

keyblob_contents:

keyblob_contents

keyblob_contents
         ::= '(' option_list* ')'

referenced by:

  • keyblob_block

Comments:

The keyblob contents must define:

start [integer] - start address 'maintained' by this keyblob
end [integer] - end address 'maintained' by this keyblob
key [string] - key used to encode data stored into address range defined by this keyblob
counter [string] - counter value
byteSwap [boolean, optional] - true for byte swap

Anything else defined under keyblob is ignored. If definition of keywords listed above, except ‘byteSwap’ is missing, a syntax error will be raised.

section_block:

section_block

section_block
         ::= SECTION '(' int_const_expr section_options? ')' section_contents

referenced by:

  • command_file

Comments:

section_options is not supported and raises syntax error when used!

section_options:

section_options

section_options
         ::= ';' option_list?

referenced by:

  • section_block

Comments:

<= IDENT is not supported and raises syntax error when used!

The IDENT in <= IDENT must be an identifier defined in the sources block, otherwise an error is raised.

section_contents:

section_contents

section_contents
         ::= '{' statement* '}'
           | '<=' source_name ';'

referenced by:

  • section_block

statement:

statement

statement
         ::= basic_stmt ';'
           | from_stmt
           | if_stmt
           | keywrap_stmt

referenced by:

  • else_stmt

  • encrypt_stmt

  • if_stmt

  • keywrap_stmt

  • section_contents

basic_stmt:

basic_stmt

basic_stmt
         ::= load_stmt
           | load_ifr_stmt
           | call_stmt
           | jump_sp_stmt
           | mode_stmt
           | message_stmt
           | erase_stmt
           | enable_stmt
           | reset_stmt
           | encrypt_stmt
           | keystore_stmt

referenced by:

  • in_from_stmt

  • statement

load_stmt:

load_stmt

load_stmt
         ::= LOAD load_opt load_data load_target

referenced by:

  • basic_stmt

load_opt:

load_opt

load_opt ::= IDENT
           | int_const_expr
           | empty

referenced by:

  • load_stmt

load_data:

load_data

load_data
         ::= int_const_expr
           | STRING_LITERAL
           | IDENT
           | section_list ( FROM IDENT )?
           | BINARY_BLOB

referenced by:

  • load_stmt

load_target:

load_target

load_target
         ::= '>' ( '.' | address_or_range )

referenced by:

  • load_stmt

section_list:

section_list

section_list
         ::= section_ref ( ',' section_ref )*

referenced by:

  • load_data

section_ref:

section_ref

section_ref
         ::= '~'? SECTION_NAME

referenced by:

  • section_list

erase_stmt:

erase_stmt

erase_stmt
         ::= ERASE ( address_or_range | ALL )

referenced by:

  • basic_stmt

address_or_range:

address_or_range

address_or_range
         ::= int_const_expr ( '..' int_const_expr )?

referenced by:

  • erase_stmt

  • keystore_stmt

  • load_target

symbol_ref:

symbol_ref

symbol_ref
         ::= IDENT '?' ':' IDENT

referenced by:

  • call_target

load_ifr_stmt:

load_ifr_stmt

load_ifr_stmt
         ::= LOAD IFR int_const_expr '>' int_const_expr

referenced by:

  • basic_stmt

call_stmt:

call_stmt

call_stmt
         ::= call_type call_target call_arg?

referenced by:

  • basic_stmt

call_type:

call_type

call_type
         ::= CALL
           | JUMP

referenced by:

  • call_stmt

call_target:

call_target

call_target
         ::= int_const_expr
           | symbol_ref
           | IDENT

referenced by:

  • call_stmt

  • jump_sp_stmt

call_arg:

call_arg

call_arg ::= '(' int_const_expr? ')'

referenced by:

  • call_stmt

  • jump_sp_stmt

jump_sp_stmt:

jump_sp_stmt

jump_sp_stmt
         ::= JUMP_SP int_const_expr call_target call_arg?

referenced by:

  • basic_stmt

from_stmt:

from_stmt

from_stmt
         ::= FROM IDENT '{' in_from_stmt* '}'

referenced by:

  • statement

in_from_stmt:

in_from_stmt

in_from_stmt
         ::= basic_stmt ';'
           | if_stmt

referenced by:

  • from_stmt

mode_stmt:

mode_stmt

mode_stmt
         ::= MODE int_const_expr

referenced by:

  • basic_stmt

message_stmt:

message_stmt

message_stmt
         ::= message_type STRING_LITERAL

referenced by:

  • basic_stmt

message_type:

message_type

message_type
         ::= INFO
           | WARNING
           | ERROR

referenced by:

  • message_stmt

keystore_stmt:

keystore_stmt

keystore_stmt
         ::= ( KEYSTORE_TO_NV | KEYSTORE_FROM_NV ) mem_opt address_or_range

referenced by:

  • basic_stmt

mem_opt:

mem_opt

mem_opt  ::= IDENT
           | '@' int_const_expr
           | empty

referenced by:

  • keystore_stmt

if_stmt:

if_stmt

if_stmt  ::= IF bool_expr '{' statement* '}' else_stmt?

referenced by:

  • else_stmt

  • in_from_stmt

  • statement

else_stmt:

else_stmt

else_stmt
         ::= ELSE ( '(' statement* ')' | if_stmt )

referenced by:

  • if_stmt

keywrap_stmt:

keywrap_stmt

keywrap_stmt
         ::= KEYWRAP '(' int_const_expr ')' '{' statement* '}'

referenced by:

  • statement

encrypt_stmt:

encrypt_stmt

encrypt_stmt
         ::= ENCRYPT '(' int_const_expr ')' '{' statement* '}'

referenced by:

  • basic_stmt

enable_stmt:

enable_stmt

enable_stmt
         ::= ENABLE AT_INT_LITERAL int_const_expr

referenced by:

  • basic_stmt

reset_stmt:

reset_stmt

reset_stmt
         ::= RESET

referenced by:

  • basic_stmt

ver_check_stmt:

ver_check_stmt

ver_check_stmt
         ::= VERSION_CHECK sec_or_nsec int_const_expr

sec_or_nsec:

sec_or_nsec

sec_or_nsec
         ::= SEC
           | NSEC

referenced by:

  • ver_check_stmt

const_expr:

const_expr

const_expr
         ::= STRING_LITERAL
           | bool_expr

referenced by:

  • option_def

  • option_list

int_const_expr:

int_const_expr

int_const_expr
         ::= expr

referenced by:

  • address_or_range

  • bool_expr

  • call_arg

  • call_target

  • enable_stmt

  • encrypt_stmt

  • jump_sp_stmt

  • keyblob_block

  • keywrap_stmt

  • load_data

  • load_ifr_stmt

  • load_opt

  • mem_opt

  • mode_stmt

  • section_block

  • source_value

  • ver_check_stmt

bool_expr:

bool_expr

bool_expr
         ::= ( bool_expr ( '<' | '<=' | '>' | '>=' | '==' | '!=' | '&&' | '||' ) | '!' ) bool_expr
           | ( '(' bool_expr | DEFINED '(' IDENT | IDENT '(' source_name ) ')'
           | int_const_expr

referenced by:

  • bool_expr

  • const_expr

  • constant_def

  • if_stmt

expr:

expr

expr     ::= expr ( ( '+' | '-' | '*' | '/' | '%' | '<<' | '>>' | '&' | '|' | '^' ) expr | '.' INT_SIZE )
           | ( '(' expr | SIZEOF '(' ( SYMBOL_REF | IDENT ) ) ')'
           | INT_LITERAL
           | IDENT
           | SYMBOL_REF
           | unary_expr

referenced by:

  • expr

  • int_const_expr

  • unary_expr

unary_expr:

unary_expr

unary_expr
         ::= ( '+' | '-' ) expr

referenced by:

  • expr

#

rr-2.0 generated by RR - Railroad Diagram Generator