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:
Generate template first
nxpimage sb21 get-template -o "sb2_config.yaml
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. |
|
fill |
Fill is a type of load command used for filling a region of memory with pattern. |
|
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. |
|
enable |
Enable statement is used for initialization of external memories using a parameter block that was previously loaded to RAM. |
|
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. |
|
keywrap |
Keywrap holds keyblob ID to be encoded by a value stored in load command and stored to address defined in the load command. |
|
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. |
|
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. |
|
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. |
|
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 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
::= 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
::= options_block
| constants_block
| sources_block
| keyblob_block
referenced by:
command_file
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
::= IDENT '=' const_expr ';'
referenced by:
options_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
::= IDENT '=' bool_expr ';'
referenced by:
constants_block
sources_block:
sources_block
::= SOURCES '{' source_def* '}'
referenced by:
pre_section_block
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
::= 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
::= IDENT '=' const_expr ( ',' IDENT '=' const_expr )*
referenced by:
keyblob_contents
section_options
source_def
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
::= '(' 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 '(' 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
::= ';' 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
::= '{' statement* '}'
| '<=' source_name ';'
referenced by:
section_block
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
::= 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 load_opt load_data load_target
referenced by:
basic_stmt
load_opt:
load_opt ::= IDENT
| int_const_expr
| empty
referenced by:
load_stmt
load_data:
load_data
::= int_const_expr
| STRING_LITERAL
| IDENT
| section_list ( FROM IDENT )?
| BINARY_BLOB
referenced by:
load_stmt
load_target:
load_target
::= '>' ( '.' | address_or_range )
referenced by:
load_stmt
section_list:
section_list
::= section_ref ( ',' section_ref )*
referenced by:
load_data
section_ref:
section_ref
::= '~'? SECTION_NAME
referenced by:
section_list
erase_stmt:
erase_stmt
::= ERASE ( address_or_range | ALL )
referenced by:
basic_stmt
address_or_range:
address_or_range
::= int_const_expr ( '..' int_const_expr )?
referenced by:
erase_stmt
keystore_stmt
load_target
symbol_ref:
symbol_ref
::= IDENT '?' ':' IDENT
referenced by:
call_target
load_ifr_stmt:
load_ifr_stmt
::= LOAD IFR int_const_expr '>' int_const_expr
referenced by:
basic_stmt
call_stmt:
call_stmt
::= call_type call_target call_arg?
referenced by:
basic_stmt
call_type:
call_type
::= CALL
| JUMP
referenced by:
call_stmt
call_target:
call_target
::= int_const_expr
| symbol_ref
| IDENT
referenced by:
call_stmt
jump_sp_stmt
call_arg:
call_arg ::= '(' int_const_expr? ')'
referenced by:
call_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 IDENT '{' in_from_stmt* '}'
referenced by:
statement
in_from_stmt:
in_from_stmt
::= basic_stmt ';'
| if_stmt
referenced by:
from_stmt
mode_stmt:
mode_stmt
::= MODE int_const_expr
referenced by:
basic_stmt
message_stmt:
message_stmt
::= message_type STRING_LITERAL
referenced by:
basic_stmt
message_type:
message_type
::= INFO
| WARNING
| ERROR
referenced by:
message_stmt
keystore_stmt:
keystore_stmt
::= ( KEYSTORE_TO_NV | KEYSTORE_FROM_NV ) mem_opt address_or_range
referenced by:
basic_stmt
mem_opt:
mem_opt ::= IDENT
| '@' int_const_expr
| empty
referenced by:
keystore_stmt
if_stmt:
if_stmt ::= IF bool_expr '{' statement* '}' else_stmt?
referenced by:
else_stmt
in_from_stmt
statement
else_stmt:
else_stmt
::= ELSE ( '(' statement* ')' | if_stmt )
referenced by:
if_stmt
keywrap_stmt:
keywrap_stmt
::= KEYWRAP '(' int_const_expr ')' '{' statement* '}'
referenced by:
statement
encrypt_stmt:
encrypt_stmt
::= ENCRYPT '(' int_const_expr ')' '{' statement* '}'
referenced by:
basic_stmt
enable_stmt:
enable_stmt
::= ENABLE AT_INT_LITERAL int_const_expr
referenced by:
basic_stmt
reset_stmt:
reset_stmt
::= RESET
referenced by:
basic_stmt
ver_check_stmt:
ver_check_stmt
::= VERSION_CHECK sec_or_nsec int_const_expr
sec_or_nsec:
sec_or_nsec
::= SEC
| NSEC
referenced by:
ver_check_stmt
const_expr:
const_expr
::= STRING_LITERAL
| bool_expr
referenced by:
option_def
option_list
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 | DEFINED '(' IDENT | IDENT '(' source_name ) ')'
| int_const_expr
referenced by:
bool_expr
const_expr
constant_def
if_stmt
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
::= ( '+' | '-' ) expr
referenced by:
expr
#
generated by RR - Railroad Diagram Generator