LAN966x Secure Boot
1. Introduction
The LAN966x SoC contains an internal CPU which has secure boot capabilities with an implementation based on TF-A (Trusted Firmware for ARM).
This document uses many abbreviations, see the terms and abbreviations section for details. |
The BootROM in LAN966x offers the following high-level features:
-
Boot firmware from:
-
SPI-NOR
-
SD-Card
-
eMMC
-
-
Firmware authentication based on public key ECDSA algorithm
-
Firmware encryption using AES encryption with
-
Secret Symmetric Key (SSK)
-
Per-device unique key (BSSK)
-
-
A bootrom UART monitor (fwu.html) with support for:
-
Secure JTAG unlock
-
Firmware update over UART
-
OTP programming
-
-
PCIe end-point initialization
LAN966x always boots from the BootROM using the TF-A based boot stages. This is the case regardless of if secure boot is needed (enabled) or not. This means that it will be the TF-A Bootloaders that boots either U-Boot, the Linux kernel or another OS directly.
This document, and the referenced sources are provided under the BSD-3-Clause license. This means that the content is provided as-is, and that Microchip cannot be held liable. See the License section for details. |
In LAN996x the DDR initialization is done as part of TF-A/BL2 and not in U-Boot. If you need to change DDR settings, then this shall be done in TF-A. |
The sources and binaries provided to enable secure boot contains demo keys which are not handled in a secure way. The symmetric shared keys, and the private keys are publicly available. If any of the advertised security features in this document are needed, then the demo keys must be replaced with new keys which shall then be kept confidential. |
1.1. TF-A architecture
The Trusted Firmware-A (TF-A) SW project is a multi-stage bootloader which utilizes the ARM TrustZone feature in ARM CPUs as an important part of the security concept.
The TrustZone feature in ARM CPUs introduce the concept of a Secure-World (S
)
and Non-Secure-World (NS
) and the ability to switch between these worlds. The
various CPU peripherals inside the SoC, or connected to the SoC, are then
classified as secure or non-secure. Secure-World has access to everything, while
Non-Secure world only has access to the non-secure peripherals.
In HW this is implemented as an additional bit in the address bus to specify the Secure/Non-Secure mode. Only Secure-World bus controllers can issue transactions with the Secure-Bit set.
| S-Peripheral NS-Peripheral --------------------------+--------------------------------- S-World Bus Controller | Access Access NS-World Bus Controller | No Access Access
When zooming in on the CPU, the S/NS worlds are often seen as an additional dimension to the exception levels (EL3 - EL0). This is illustrated below:
The CPU can jump between the secure and non-secure worlds, and the two worlds can communicate with each other by using a shared buffer. This allows the same kind of application and use-cases as when having a dedicated security processor.
1.2. TF-A Bootloaders (BLx)
The TF-A framework provides a multi-stage bootloader concept. There are many good reasons to go with a multi stage approach. To name a few points:
-
Make the amount of code/functionality in the ROM as small as possible.
-
Make components running within a given exception level (or having different life-time) self-contained. TF-A provides different bootloader stages for the different levels.
-
Breaking complex stuff into smaller problems is always a good idea.
Here is a list with an explanation of the different boot-loader stages:
-
Trusted ROM Firmware (
BL1
)-
This is a binary built from the TF-A sources.
-
Embedded as ROM code in the chip, execute in secure world EL3/SVC-MON.
-
Purpose:
-
Do basic platform initialization
-
Read BL2 from boot media into secure memory, authenticate it, run it.
-
-
-
Trusted Boot Firmware (
BL2
)-
This is a binary built from the TF-A sources.
-
Loaded from a FIP (see below), and runs from on-chip secure memory, execute in secure world EL1/SVC-MON.
-
Purpose:
-
Will do additional platform initialization including:
-
TrustZone configuration
-
DDR initialization
-
-
Load BL3x images into DDR memory, authenticate, decrypt etc.
-
Run EL3 Runtime Software
-
-
-
EL3 Runtime Software (
BL32
)-
This is a binary built from the TF-A sources.
-
Loaded from from a FIP and runs as Secure EL3/SVC. This firmware stays resident in memory, and the services offered here can be called later on.
-
Purpose:
-
Initialize the secure run-time service, typically PSCI and Trusted HW RNG.
-
Authenticate, decrypt and run BL33.
-
-
-
Non-trusted Firmware (
BL33
)-
BL33 is not built from the TF-A sources, but is a binary which is stored in a FIP and will be loaded (and executed) by TF-A. This is typically U-Boot, a direct booting Linux kernel or some other OS.
-
Runs from DDR memory in non-secure world as EL1/SVC
-
-
Firmware update image (
BL2u
)-
This is a binary built from the TF-A sources.
-
Compared to the other images, this is special, as it is not used during normal boot, and it is not loaded from a FIP stored in flash.
-
This image replaces the normal
BL2
. It is loaded by BL1 via the UART-monitor using a Serial port. Like BL2, it is authenticated by BL1 before it is being executed. -
Purpose: Provide an updateable stepping stone for board provisioning.
-
1.3. Firmware Image Package (FIP)
The FIP or Firmware Image Package is the file format TF-A uses to contain all the artifacts. This includes the BL2 and BL3x images, certificates, and configuration files.
The FIP is generated as part of the build process. It is written in flash in binary format without any transformation, and the BL1 ROM knows how to locate and load a particular image type in the FIP.
It can be compared to a very simple read-only file-system, as it contains only very basic information of the individual files: type, offset and size.
The TF-A project includes 2 host tools:
-
fiptool
: which makes it easy to perform common operations (create, display, add/del/mod individual images) infip
files. -
cert_create
: which makes it easy to generate the keys and certificates needed to establish the chain of trust.
In the build process the make target is called certtool , but the
resulting binary is called cert_create .
|
The FIP generation process where the fiptool
and cert_create
are used is
shown below:
As shown above, the cert_create
tool reads the BLOBs as input, it reads the
keys from the disk (or generate them on the fly), and creates the needed
certificates. Once the certificates have been generated, the normal fiptool
can
bundle both the original BLOBs and the associated certificates into the FIP which
can then be authenticated. To bind devices to this chain of trust, the SHA or
the public root key needs to be written into OTP.
1.3.1. FIP Image IDs
When reading console output, browsing the source code, or when using the
fiptool
or the cert_create
tool, it is often necessary to reference the
individual images. The table below provide the mapping between the defines used
in the C
code, the numeric values as they will appear in the trace output, and
finally the command-line argument which is understood by the fiptool
(and
cert_create
).
C-Define | Num | fiptool arg |
---|---|---|
|
1 |
|
|
4 |
|
|
5 |
|
|
6 |
|
|
7 |
|
|
10 |
|
|
11 |
|
|
14 |
|
|
15 |
|
|
31 |
|
2. Getting started with TF-A for LAN966x
This section provides the hands-on steps needed to build TF-A for LAN966x.
2.1. Build environment
Most modern Linux distributions can be used for building TF-A, but to ensure consistent results a docker image can be used for running all the build-commands.
This project provides a dr
(docker run) script to make it easy to run a
command in the desired docker container.
The dr
script is provided by the https://github.com/microchip-ung/docker-run
project which also offers more details on how it works.
The folder /opt/mscc
must exist before you can use the dr
script. This
folder is used for caching BSP packages.
The short story is that prefixing a command with dr
will cause it to run
in a docker container.
You can test if it works just by typing dr ls
and check the result.
2.2. Getting sources and releases
Sources can be obtained from
https://github.com/microchip-ung/arm-trusted-firmware using git clone
.
A release with both source packages and binaries are provided as release artifacts and can be found at https://github.com/microchip-ung/arm-trusted-firmware/releases.
2.3. Building
To build the TF-A binaries for LAN966x, navigate to the root of the project and run the following command:
$ dr ./scripts/build.rb -p lan966x_b0
This will by default do incremental builds. The --clean
flag will delete the
artifacts for a given platform/variant and cause the next build to be complete
rebuild.
This will use the demo keys from the ./keys folder, which are not
kept confidential. Any secure products must generate new keys and keep them
secret.
|
By default the build script will load a pre-build U-Boot binary into the BL33 blob. |
The build.rb
script offers a set of options to tweak the default settings.
The --help
option shown below provides an overview of possible options, and
the following sub-sections provides some additional details.
$ dr ./scripts/build.rb --help Usage: build.rb [options] -p, --platform <platform> Build for given platform: lan966x_b0, lan966x_lm, lan969x_sr, lan969x_a0, lan969x_svb, lan969x_lm, lan969x_pcie -r, --root-of-trust <keyfile> Set ROT key file --create_keys Create new keys --bl31-key <keyfile> Set BL31 key --bl32-key <keyfile> Set BL32 key --bl33-key <keyfile> Set BL33 key --non_trusted_world-key <keyfile> Set non_trusted_world key --scp_bl2-key <keyfile> Set scp_bl2 key --trusted_world-key <keyfile> Set trusted_world key --encrypt-images <imagelist> List of encrypted images, eg BL2,BL32,BL33 --encrypt-ssk <keyfile> Enable encryption with SSK --encrypt-bssk <keyfile> Enable encryption with BSSK --fw-nvctr <counter> Set Secure FW NV counter for FIP --ntfw-nvctr <counter> Set Non-trusted FW NV counter for FIP --bl33_blob <file> BL33 binary -d, --debug Enable DEBUG --release Disable DEBUG -g, --[no-]gptimg Create a GPT image file with the FIP (obsoleted) --gpt-data <file> Add GPT payload -c, --clean Do a 'make clean' instead of normal build -C, --coverity stream Enable coverity scan -R, --[no-]ramusage Report RAM usage --extra1 <file> Add BL32 EXTRA1 image to FIP --extra2 <file> Add BL32 EXTRA2 image to FIP
2.3.1. Platform selection
The --platform
option is used to select the desired platform. This argument
must be provided, and when building for LAN966x it must be set to: lan966x_b0
:
2.3.2. BL33 content
By default the U-Boot binary provided by the BSP will be used as BL33 content. As
an alternative to U-Boot, the --linux-as-bl33
option can be used which will
cause the BSP provided brsdk_standalone_arm.itb
blob to be used as BL33
content. This itb
file contains a Linux kernel and a Device Tree, and will
allow the system to boot Linux without U-Boot.
Sometimes it is desirable to provide the BL33 content directly, this can be done
using --bl33-blob <file>
. The blob can be either a itb
/fit
image or a
executable binary. If it is not a fit
then it will be relocated to address
0x60200000
(in DDR) and once authenticated the BL32 will do a memory-jump
to
that address. If it is a fit
then is is handled as described in the following
section.
Be aware that the BL33 blob will be aggregated into the FIP
, and if the blob
is sufficiently large the resulting image may not fit into the NOR
flash (in
this case eMMC can be used for storing the FIP
).
2.3.2.1. Loading FIT/ITBs as BL33
When using a fit
image, the FIT image is placed in DDR NS start
(0x60200000
), just like the "flat" binary type image.
When the fit
image is parsed, individual components are identified
in this order:
-
Device tree
-
Root FS (optional)
-
Kernel
The two first components need to be moved to an area outside where the
fit
image itself resides - i.e. the load address cannot overwrite
the fit
image itself.
The kernel (being loaded last) is allowed to overwrite the fit
image
itself, so the load address will typically be the NS DDR start.
Apart from the above guides, the following fit
image restrictions
apply:
-
Compression is not supported for any data (the kernel loader itself may use compression).
-
A
load
address outside NS DDR area is not allowed.
Configuration selection
If the fit
image contain more than one configuration node, the
fit_config
OTP tag can be use to name the fit
configuration node
to use. Otherwise, the default
config will be used - as is custom
with fit
images.
Device Tree modifications
Once the device tree according to the chosen configuration is loaded into the proper place, the device tree is "fixed up" with these changes:
-
A
/memory
node is added/modified to containing the memory size according to the platform NS DDR location and size. -
If the device tree property
/chosen/bootargs
is not present, a default command line according to the platform is added. (LAN966X:console=ttyS0,115200 root=/dev/mmcblk0p4 rw rootwait loglevel=8
).
/dts-v1/;
/ {
description = "Image Tree Source file for lan966x direct BL33 boot";
#address-cells = <1>;
images {
kernel {
description = "Kernel";
data = /incbin/("arch/arm/boot/zImage");
type = "kernel";
arch = "arm";
os = "linux";
compression = "none";
load = <0x60200000>;
entry = <0x60200000>;
};
fdt_lan9662_ung8291_0_at_lan966x {
description = "Flattened Device Tree";
data = /incbin/("arch/arm/boot/dts/lan966x_pcb8291.dtb");
type = "flat_dt";
arch = "arm";
load = <0x67e00000>;
compression = "none";
};
fdt_lan9662_ung8290_0_at_lan966x {
description = "Flattened Device Tree";
data = /incbin/("arch/arm/boot/dts/lan966x_pcb8290.dtb");
type = "flat_dt";
arch = "arm";
load = <0x67e00000>;
compression = "none";
};
... more device trees ...
ramdisk {
description = "Ramdisk";
data = /incbin/("rootfs.squashfs");
type = "ramdisk";
arch = "arm";
os = "linux";
compression = "none";
load = <0x68000000>;
};
};
configurations {
default = "lan9662_ung8291_0_at_lan966x";
lan9662_ung8291_0_at_lan966x {
description = "Kernel with DT fdt_lan9662_ung8291_0_at_lan966x";
kernel = "kernel";
fdt = "fdt_lan9662_ung8291_0_at_lan966x";
ramdisk = "ramdisk";
};
lan9662_ung8290_0_at_lan966x {
description = "Kernel with DT fdt_lan9662_ung8290_0_at_lan966x";
kernel = "kernel";
fdt = "fdt_lan9662_ung8290_0_at_lan966x";
ramdisk = "ramdisk";
};
... more configuration nodes for other device trees ...
};
};
The unpacking of the fit
image will display trace log messages if
trace is enabled. And example is shown here.
INFO: Unpacking FIT image @ 0x60200000 INFO: fit: Looking for 'default' config INFO: fit: Using 'lan9662_ung8291_0_at_lan966x' config INFO: fit: Loading fdt from 0x6063c340 to 0x67e00000, 13615 bytes INFO: fit: Loading kernel from 0x602000c8 to 0x60200000, 4440496 bytes INFO: fit: Adding DT bootargs 'console=ttyS0,115200 root=/dev/mmcblk0p4 rw rootwait loglevel=8' INFO: Preparing to boot 32-bit Linux kernel INFO: SP_MIN: Preparing exit to normal world INFO: Enabling SRAM NS access [ 0.000000] Booting Linux on physical CPU 0x0
2.3.3. Authentication keys
By default the keys used for authentication are loaded from the files in the
./keys
folder. The following table provides an overview of the command-line
options, the default file and a description of its usage:
CMD-option | Default value | Description |
---|---|---|
|
|
Confidential key used to sign the |
|
|
Non-confidential public key derived from |
|
|
Non-confidential SHA of the public key. This is the key which needs to be loaded into the |
|
|
Not in use for LAN966x, but part of TF-A framework. |
|
|
Confidential key used to sign the |
|
|
Confidential key used to sign the |
|
|
Confidential key used to sign the |
|
|
Not in use for LAN966x, but part of TF-A framework. |
|
|
Confidential key used to sign the |
The list of keys above are provided in demo versions as part of the sources and build artifacts. The demo keys are not kept confidential (in fact they are published), and must be replaced with a new set of keys.
To generate new keys, delete they above keys in the ./keys
folder, and run the
build script with the --create_keys
options, like show below:
$ dr ./scripts/build.rb --create_keys
The tool will not update existing keys. Existing keys must be deleted before new keys can be generated. |
Check the time stamp and the content of the newly generated keys to confirm that they have been updated.
The key content can be show using the openssl
command:
$ dr openssl ec -in ./keys/rotprivk_ecdsa.pem -text read EC key Private-Key: (256 bit) priv: cb:eb:29:43:74:12:54:96:43:e6:42:48:13:8f:5b: cf:8d:c7:8b:da:b8:c8:64:ae:f7:43:c1:94:ce:a6: 11:fb pub: 04:02:a6:68:7e:f2:fe:c9:07:1a:2c:a9:c2:33:b4: bb:89:34:99:7d:b6:30:f9:1f:6c:a8:ae:5c:6d:c5: 28:04:48:47:66:1e:e4:36:26:ad:5d:1d:83:45:41: 7d:f2:62:e6:e1:a9:2e:d1:c7:cd:0e:c2:62:01:db: 94:53:ca:46:c5 ASN1 OID: prime256v1 NIST CURVE: P-256 writing EC key -----BEGIN EC PRIVATE KEY----- MHcCAQEEIMvrKUN0ElSWQ+ZCSBOPW8+Nx4vauMhkrvdDwZTOphH7oAoGCCqGSM49 AwEHoUQDQgAEAqZofvL+yQcaLKnCM7S7iTSZfbYw+R9sqK5cbcUoBEhHZh7kNiat XR2DRUF98mLm4aku0cfNDsJiAduUU8pGxQ== -----END EC PRIVATE KEY-----
2.3.4. Rollback protection (NV-Counters)
By default the build script is using the default trusted and
non-trusted counters for the platform. (2
and 3
for LAN966X).
In order to create a new firmware version that cannot be downgraded, you can set the specifically by incrementing the counter for the environment that has been fixed.
Use
-
--fw-nvctr <counter>
to explicitly set the "Trusted FW NV counter" -
--ntfw-nvctr <counter>
to explicitly set the "Non-Trusted FW NV counter"
to explictly set the version counter embedded in the FIP.
Example:
$ dr ./scripts/build.rb -p lan966x_b0 --fw-nvctr 3 --ntfw-nvctr 4
2.3.5. Image encryption
By default images are signed but not encrypted. Image encryption can be enabled
using the --encrypt-images <imagelist>
argument. The listed images will then
be encrypted using the key provided with --encrypt-ssk <keyfile>
.
Example:
$ dr ./scripts/build.rb -p lan966x_b0 \ --encrypt-images BL2,BL32,BL33 \ --encrypt-ssk ./keys/ssk.bin
The ssk
key is symmetric, which means that the same key used for encryption
must also be programmed into the OTP (OTP_TBBR_SSK
) where it is used for
decryption. The key can be any 32byte value, and is typically randomly
generated.
The build.rb tool offer a --encrypt-bssk flag. This is for
debug/development usage and should never be used in production. Instead the
image should be bound by the bl2u utility or via bl32 using the HUK
generated in OTP.
|
2.3.6. Image generation
The build.rb
script will always build a FIP
image. This FIP
can be
programmed directly into the NOR image, but to be able to boot from eMMC, the
eMMC image needs to be prepared with a partition table (gpt
) , and the FIP
needs to be written into a partition (as opposed to being written to a fixed offset
in the eMMC). The build script can prepare a complete image file with gpt
partition table and the FIP
image filled in the fip
and the fip.bak
partition.
the -n, --[no-]norimg is only for internal prototypes and should not be
used.
|
3. TF-A in Details
This chapter provides a more in-depth description of TF-A technology used in LAN966x. Understanding these details are the essential prerequisites to design secure products based on LAN966x, and to understand the following sections with LAN966x specific implementation.
3.1. Certificate hierarchy
TF-A uses a hierarchy of certificates to authenticate the different images in the FIP. This hierarchy is shown at the following image:
As shown on the drawing, BL2 is authenticated by TRUSTED_BOOT_FW_CERT
.
TRUSTED_BOOT_FW_CERT
is authenticated by the root of trust (the
ROT_PUB_KEY
). And the ROT_PUB_KEY
is finally authenticated by the OTP SHA
provided by the platform.
The key hierarchy limits the usage of the root key, and therefore also the attack surface. If one of the downstream keys is leaked, it is possible to do key revocation.
3.2. Revocation and Rollback protection
Besides the certificate based authentication, the authentication framework will also check the version number of the certificates against a non-volatile counter, provided by the platform. The version number in the certificate is covered by the signature which ensures the integrity, and the platform provides non-volatile counters that are created in such way that they can only increment.
The authentication process will first validate the signature and then continue to compare the version of the certificate against the platform counter. Here is how the comparison is performed:
-
certificate_version == platform_counter
: All is good: The boot process can continue. -
certificate_version > platform_counter
: Theplatform_counter
will be incremented to the value ofcertificate_version
: The boot process can continue. -
certificate_version < platform_counter
: Fail as this is considered a rollback attack: The boot process will stop here, and the system needs to be updated with a new image matching the version of the platform counter.
The purpose of this mechanism is to have a way of performing revocation of certificates. If one of the private keys has been revealed, new certificates needs to be issued and provisioned. But the old firmware will still pass the public key authentication, and the only way to prevent an attacker from rolling back the firmware, is to have such a counter.
The ROT (root of trust) key does not have any version numbers as it cannot be updated.
TF-A uses 2 none-volatile counters: trusted_nv_ctr
and non_trusted_nv_ctr
.
The non_trusted_fw_key_cert
and non_trusted_fw_content_cert
certificates are
checked against the non_trusted_nv_ctr
, all other (except ROT
) are evaluated
against trusted_nv_ctr
.
3.3. Image signing in details
To sign a certificate the private key is needed, but to authenticate a
certificate only the public key is needed. The cert_create
tool needs access
to both the public and private keys. The public keys are needed, because they are
aggregated into the certificates, and the private keys are needed to do the
signing.
The following picture illustrates the entire signing process done by
cert_create
.
The green boxes are binaries generated by the compiler. cert_create
will
calculate the SHA, feed the SHA into the certificate, and sign the certificate.
The trusted and non-trusted counters is version numbers. These version numbers
are given at the command-line, and will be stored in the certificates as well.
The trust hierarchy is created by feeding the SHA of 1 public key, into a parent
certificate. The 2 certificates: TRUSTED_BOOT_FW_CERT
and TRUSTED_KEY_CERT
are authenticated by the root-of-trust public certificate.
3.4. BL1 Chain of Trust verification
When BL1
loads the BL2
and the FW_CONFIG
images from the FIP, it needs to
authenticate the images, and the related certificates to establish a chain of
trust. This is shown in the image below:
3.5. BL2 Chain of Trust verification
When BL2
loads the BL32
and BL33
images from the FIP, it needs to
authenticate the images, and the related certificates to establish a chain of
trust. This is shown in the image below:
3.6. Firmware encryption
Firmware encryption can be used to keep the firmware confidential, and protect against an attacker reading the content of the flash devices and extracting information from that.
When enabled, firmware will be encrypted using AES-128-GCM, which uses symmetric keys.
Two types of firmware keys are supported:
-
ssk
(secret symmetric key): Here the same key is used to encrypt the firmware (when creating the FIP image) and decrypting the firmware when loading running on the target. -
bssk
(binding secret symmetric key): Here thessk
is used when encrypting the image and generating the FIP. But when the image is loaded on the board, it is bound to the board before it is being programmed to the flash. The binding operation will use thessk
to decrypt the image in memory, and then encrypt the image using a key derived from thehuk
(hardware unique key). When the system is booting, the BL1/BL2 will decrypt the image using the key derived from thehuk
.
Only the individual images are encrypted, but the FIP container stays unencrypted. This is not a security risk, as the FIP is just a container that does not have any sensitive information.
When images are encrypted an encryption header is prepended to the
image. This header contains a flag indicating if the image has been
bound or not. (Indicating using ssk
or bssk
).
Using bssk
for firmware encryption instead of ssk
have the following
advantages:
-
Firmware cannot be copied/cloned from one board to another using an external flash programmer. If the firmware are licensed to a specific board, then it is an advantage to ensure that board firmware cannot be copied.
-
If the
ssk
is leaked, an attacker cannot decrypt the image found in the flash memory of a board - the attacker will have to find another way to get the image before it is programmed (intercept an update session). -
If a
bssk
key is leaked, it will only impact one board.
The disadvantage of using bssk
is the additional complications of
manufacturing the boards, as it is not possible to do this with pre-programmed
images.
Firmware binding can be done from the fwu.html
tool or from Linux following the
guide here.
4. LAN966x TF-A Platform support
The core of TF-A is platform independent, and each platform needs to provide the platform specific implementation and drivers.
The platform specific layer defines how the SW (and ROM) interface with the hardware, and how the keys in the system are kept safe.
4.1. Strapping modes
See table in LAN966x Strapping Pins
4.2. Booting
See this section and the following.
4.3. OTP
The one-time-programmable memory provided by the SoC is an important source of configuration data. It is the only persistent memory not depending on any external components and it is used for many different purposes.
The OTP can be divided into regions, and each region can be write protected, and if write-protected, also read-protected.
The OTP contains secret keys, which must be protected to keep
firmware confidential. The offered mechanism to keep such keys confidential is
the read-protect setting on the given region. The region containing the keys
must be marked as read-protected by the BL2 before it hands over control to BL32.
|
Each OTP region contains a number of OTP attributes, which may then contain a number of OTP fields.
This is all covered in the following subsections.
4.3.1. OTP Regions
The OTP shall be divided into the following 8 regions:
REG. START END Secure Emu Description ---- ------ ------ ------ --- ----------------------------------------- 0 0x0000 0x003F No No Manufacturing data 1 0x0040 0x0043 No No OTP Write protect 2 0x0044 0x0063 No No OTP Region Definitions 3 0x0064 0x00FF No No Insecure configuration without emulation 4 0x0100 0x01FF Yes Yes Keys and other security related 5 0x0200 0x023F No Yes Non-volatile secure counters 6 0x0240 0x07FF No No Fixed position user-space / custom usage 7 0x0800 0x2000 No No Key-value store (semi-updateable)
The secure
flag indicates if the area contains secret information, and
hence must be configured to remove read access before leaving the BL2. The
Emu
flag indicate if OTP emulation can be supported.
The following sub-section documents the intended use of the regions, and highlights some important points for each of these.
The configuration of OTP-regions are kept in the OTP itself. It is the customer responsibility to program the regions. The Linux user-space otp tool can be used for this purpose. |
4.3.2. OTP attributes
The following OTP table shows the pre-defined OTP attributes, used by either HW, BL1 and/or BL2.
BL3x, U-Boot, Linux or other clients can also access the OTP, if the access control of the given regions allow it.
Begin End Size RTL EMU REG. Name ------ ------ ---- --- --- ---- ---------------- 0x0000 0x0003 4 X 0 OTP_PRG 0x0004 0x0004 1 X 0 FEAT_DIS 0x0005* 0x0006 2 X 0 PARTID 0x0007 0x0007 1 0 TST_TRK 0x0008 0x000f 8 0 SERIAL_NUMBER 0x0010 0x0013 4 X 0 SECURE_JTAG 0x0014 0x001a 7 0 WAFER_TRK reserved 5 bytes 0x0020 0x0029 10 X 0 JTAG_UUID reserved 6 bytes 0x0030 0x0037 8 0 TRIM reserved 8 bytes 0x0040 0x0043 4 X 1 PROTECT_OTP_WRITE 0x0044 0x0063 32 X 2 PROTECT_REGION_ADDR 0x0064 0x0067 4 3 OTP_PCIE_FLAGS 0x0068 0x006B 4 3 OTP_PCIE_DEV 0x006c 0x0073 8 3 OTP_PCIE_ID 0x0074 0x009b 40 3 OTP_PCIE_BARS reserved 100 bytes 0x0100 0x011f 32 X 4 OTP_TBBR_ROTPK 0x0120 0x013f 32 X 4 OTP_TBBR_HUK 0x0140 0x015f 32 X 4 OTP_TBBR_EK 0x0160 0x017f 32 X 4 OTP_TBBR_SSK 0x0180 0x019f 32 X 4 OTP_SJTAG_SSK reserved 4 bytes 0x01a4 0x01a5 2 X 4 OTP_STRAP_DISABLE_MASK reserved 90 bytes 0x0200 0x021f 32 X 5 OTP_TBBR_NTNVCT 0x0220 0x023f 32 X 5 OTP_TBBR_TNVCT
In the above table the RTL
column indicate that the OTP value is read and used
by the digital HW in the SoC before SW is running (under reset).
4.3.3. OTP attribute: PROTECT_OTP_WRITE
This attribute is a 32 bit mask and each bit enables write protection for the region with the index that corresponds to the bit index, e.g. BIT(0) protects Region 0 and so forth.
4.3.4. OTP attribute: PROTECT_REGION_ADDR
This attribute consists of an array of 8 items where each element defines a region:
-
Start address of a protected region (16 bits)
-
End address of a protected region (16 bits)
The region ranges are defined here: OTP Regions
4.3.5. OTP attribute: OTP_STRAP_DISABLE_MASK
This attribute is a 16 bit mask. Each bit in the mask corresponds to one of the strapping modes. By default the mask is set to all zeroes which means that all strapping modes are allowed. If a customer wants to disable one or more strapping modes the corresponding bits can be set in the mask and the ROM code will refuse to boot into the indicated modes.
4.3.6. OTP attribute: OTP_PCIE_FLAGS
This attribute sets the maximum supported link speed
-
1 = 2.5 GT/s
-
2 = 5.0 GT/s
Any higher value will automatically be downgraded to 5.0 GT/s
4.3.7. OTP attribute: OTP_PCIE_DEV
This attribute sets the basic PCIe device information. See https://pcisig.com/sites/default/files/files/PCI_Code-ID_r_1_11__v24_Jan_2019.pdf for details on the fields.
It is a 32 bit word that consists of 4 fields of 8 bit each that encodes:
-
device base class code (at bit offset 24)
-
device sub class code (at bit offset 16)
-
device programming interface (at bit offset 8)
-
device programming interface revision id (at bit offset 0)
4.3.8. OTP attribute: OTP_PCIE_ID
This attribute sets the PCIe device ID information.
It consists of a 64 bit word that hold 4 16 bit fields:
-
device id (bit offset 0)
-
vendor id (bit offset 16)
-
subsystem device id (bit offset 32)
-
subsystem vendor id (bit offset 48)
4.3.9. OTP attribute: OTP_PCIE_BARS
This attribute sets the PCIe device Base Address Register information.
The layout consists of 10 32 bit words like this:
-
bar0 address
-
bar1 address
-
bar2 address
-
bar3 address
-
bar4 address
-
bar5 address
-
bar0 size
-
bar1 size
-
bar2 size
-
bar3 size
-
bar4 size
-
bar5 size
If both BAR address and size are 0 then a suitable default will be used instead. If a BAR address is non-zero and the size is zero then the BAR is disabled. If a BAR address and size both are non-zero then these will configure the BAR.
4.3.10. OTP attribute: TRIM
This 8 byte attribute consists of a set of bitfields that are programmed in the factory at production time, based on measurements on the device.
These values will be read at boot and applied as 'corrections' to various hardware features.
This is the table of bitfields in the TRIM attribute:
Bits | Name | Description |
---|---|---|
|
Reserved |
Not programmed |
|
|
Trimming value for |
|
|
Trimming value for |
|
|
Trimming value for |
|
|
Trimming value for |
4.4. Firmware Config (FW_CONFIG
)
In LAN966x FW_CONFIG
is a binary blob, created during firmware compilation.
The format of the blob is as follows:
Byte range Size Description =========== ====== ================== 0x000-0x17F 0x0180 OTP-Emulation data 0x180-0x1FF 0x0080 Config space
The image must at-least be at 512 (0x200) bytes. Only the first 512 bytes are used by BL1. The image can be extended at a later point in time, but this will only affect the BL2 usage.
The OTP Emulation portion is covered in details in the OTP Emulation section.
The content of the configuration space is generated based on the content from
the scripts/fw_data.yaml
file.
- field: LAN966X_FW_CONF_MMC_CLK_RATE size: 32 value: 25000000 - field: LAN966X_FW_CONF_MMC_BUS_WIDTH size: 8 value: 0 # MMC_BUS_WIDTH_4 - field: LAN966X_FW_CONF_QSPI_CLK size: 8 value: 30 - field: LAN966X_FW_CONF_MMC_SPEED_MODE size: 8 value: 3 # SDMMC_TIMING_HS - field: LAN966X_FW_CONF_MMC_TX_TUNING_PHASE size: 8 value: 12 # Maserati HW Tx phase default value
4.4.1. OTP Emulation
OTP Emulation is a facility to experiment with OTP settings, without making them permanent. The settings are stored in flash memory, and logical or-ed with the data from the HW OTP. If the HW OTP is empty (all zeros), then all bits can be emulated.
The OTP emulation loads data from the FW_CONFIG_ID
image.
This feature is intended for 2 scenarios:
-
Developers wanting to try out many different OTP configurations, but only having a limited amount of boards: OTP emulation makes it possible to test many new sets of configurations before selecting the optimal set.
-
Users that are about to program the OTP, but want to test out the settings before committing changes that cannot be reversed.
The OTP emulation data can be comitted using the fwu.html
tool, or manually
applied using the Linux otp
command.
Only the fields marked in the EMU column in the OTP attributes table can
be emulated.
|
4.4.2. Loading of FW_CONFIG_ID
Loading the FW_CONFIG_ID
image is tricky because:
-
When the board is provisioned for secure boot, this image must be authenticated.
-
This image includes OTP emulation data, which may influence if the board shall be considered as provisioned for secure boot.
The procedure to load this image is illustrated at the figure below:
4.5. Secure RAM
To ensure that keys are kept private, and that the execution of BL1, BL2 and BL32 cannot be tampered with these images must be run from secure memory.
LAN966x have 128kb of on-chip SRAM (Secure RAM), and on-the-fly DDR memory encryption.
BL1 executes from ROM directly, but uses the SRAM for static RW data and stack. BL1 will then load BL2 from flash memory into SRAM, and BL2 will then execute from SRAM and also use it for its static RW data and stack.
BL2 will initialize the DDR memory, and setup a secure and a non-secure partition. The secure partition uses on-the-fly DDR encryption, and can only be accessed from the secure world. Once completed the BL2 loads the BL32 from flash memory into the secure DDR memory.
DDR encryption causes a longer latency to the DDR memory, and is therefore not used for the entire DDR memory. |
BL32, which is executing from secure DDR memory, will then wipe the contents of the SRAM, and reconfigure the Trust Zone Controller to let all of the SRAM be accessible from the Non-Secure world.
This is important for users of the RTE, as the RTE feature needs access to the SRAM.
4.6. Secure JTAG
LAN966x supports a secure JTAG port which is configured via the SECURE_JTAG
OTP
attribute. The data-sheet documents the encoding of SECURE_JTAG
. Once
programmed the JTAG port HW will wake up in one of the following modes:
-
Open: The JTAG port is operating normally.
-
Secure mode 1: The JTAG port will respond to a boundary scan, but is otherwise unresponsive (locked down).
-
In this mode it is possible to unlock the port (move the JTAG port to the open state) using a challenge-response mechanism running over JTAG.
-
-
Secure mode 2: The JTAG port will be completely unresponsive (locked down).
-
In this mode it is possible to unlock it (move it to open state) using a challenge-response mechanism running over JTAG.
-
-
Closed: The JTAG port is disabled and cannot be enabled.
If one of the secure-modes is enabled, then the JTAG port can be unlocked using a
challenge/response. The challenges is a random 32 byte blob generated by the
LAN996x device, and the response to unlock is a sha256(challenge-data
(where
OTP_SJTAG_SSK)OTP_SJTAG_SSK
is the content of the OTP field, and +
is a concatenation of the 2 blobs).
The scripts/sjtag-challenge.rb
in the TF-A repository can be used to calculate
the response to a challenge.
The fwu.html
tool can be used to generate the challenge and unlock the JTAG
port if the correct response is given.
Unlock from Linux can be done using the instructions here.
5. Guidelines for preparing secure artifacts
The TF-A project for LAN966x provides a template to lower the effort to build a set of secure artifacts. But the deliverables from Microchip are from an open and transparent system, which with a few changes can be turned into a secure set of artifacts.
Following is a set of guidelines on how to turn the open-system into a set of secure boot artifacts:
-
Understand what you are doing, and do not blindly trust us.
-
Generate new keys and keep the private and the shared/symmetric keys secret (but still available as they will be needed to build potential new versions).
-
Review how keys are generated, and evaluate if the methods provided in here are good enough for you need.
-
How to keep keys secret is beyond the scope of this document, but look for good praxis in the industry.
-
-
Use the certificate hierarchy to limit the exposure of the private keys. The root-of-trust should only be used very rarely and can be kept offline.
-
Only increment the NV counters when a released version poses a security breach.
-
The BL2U functionality provided in this project is a potential security breach, as it can expose the content of the OTP. Do one of the following:
-
Change it to make it such that it will not be able to dump the OTP content.
-
Do not generate it (delete it after each build).
-
Treat it as a shared/symmetric key as it can be used to read out the keys from OTP. Do not give it to anyone who do not have these keys already.
-
6. Guideline for secure provisioning
To build a secure product the manufacturing procedure must include the steps to program the OTP with needed keys and settings.
A pre-request for this is to generate the keys and secure artifacts as explained in Secure artifacts |
-
Move to a trusted environment, where private and shared keys can be handled without risk of leaks.
-
Initialize the OTP with the following content (either via
BL2U
/fwu.html
or by using theotp
Linux user-space utility.-
Regions must be defined (program
PROTECT_REGION_ADDR
) -
Following keys shall be programmed with the prepared content:
OTP_TBBR_ROTPK
,OTP_TBBR_SSK
andOTP_SJTAG_SSK
. -
Enable secure JTAG by programming
SECURE_JTAG
. -
Program the
OTP_TBBR_HUK
with unknown random data. -
Optional: disable any strap modes not needed by writing
OTP_STRAP_DISABLE_MASK
. -
Write protect region 4 by updating the content of
PROTECT_OTP_WRITE
.-
IMPORTANT: This is not only for write-protect, this is also needed to prevent non-secure read-access of region
4
. -
NOTE: Additional regions can be write protected, but region 5 must remain writeable!
-
-
-
Provision the firmware image in flash as needed.
There are currently two ways to program OTP data:
Here are some important facts about the different OTP items:
OTP item | Description | FWU | OTP Tool |
---|---|---|---|
Regions |
PROTECT_REGION_ADDR |
FWU will currently not program the regions |
"otp init" will program the regions |
Keys |
OTP_TBBR_ROTPK, OTP_TBBR_SSK, OTP_SJTAG_SSK |
Can program keys |
Can program keys |
JTAG |
JTAG_UUID, SECURE_JTAG You need to set both JTAG mode and JTAG key (depending on preferences) |
Allows only to program the key |
Can program both |
HUK |
OTP_TBBR_HUK |
Allows to program random data to HUK without exposing the actual value |
Will only program explicit data |
Strap disable |
OTP_STRAP_DISABLE_MASK |
Can program this |
Can program this |
Write Protect Regions |
PROTECT_OTP_WRITE |
Does not support programming this |
Can program this |
7. TERMS and ABBREVIATIONS
AES Advanced Encryption Standards ATE Automatic Test Equipment. Device used in SoC production and test. BL1 Boot Loader 1: In secure immutable ROM (Trusted ROM Firmware) BL2 Boot Loader 2: In secure on-chip RAM, temporary (Trusted Boot Firmware) BL31 Boot Loader 31: Resident secure services (ARM v8) BL32 Boot Loader 32: Resident secure services (ARM v7) BL33 Boot Loader 33: Typically U-Boot. trusted Firmware) BSSK Binding Secret Symmetric Key DT Device Tree eMMC Embedded MultiMediaCard FIP Firmware Image Package FIT Flattened Image Tree GPT GUID Partition Table HUK Hardware Unique Key JTAG Joint Test Action Group, interface for testing and debugging NS Non-Secure World OP-TEE Open Portable Trusted Execution Environment OS Operation System OTP One-Time-Programmable Memory PCIe Peripheral Component Interconnect Express PSCI Power State Coordination Interface RNG Random Number Generator ROT Root of Trust RTE Real-Time Engine. Device used for real-time equipment control. RTL Register-Transfer Level S Secure World SD-Card Secure Digital Card SHA Secure Hash Algorithm family SJTAG Secure JTAG SPI Serial Peripheral Interface SRAM Secure Ram SSK Secret Symmetric Key TBBR Trusted Board Boot Requirements TF-A Trusted Firmware for ARM UART Universal Asynchronous Receiver-Transmitter
8. License
This document is provided under the BSP-3-Clause license (where swoftware is replaced with document). The BSD-3-Clause license has been chosen here as it is the same license used by the TF-A project.
Here is the license covering this file/document:
Copyright (c) 2022, Microchip Technology Inc. and its subsidiaries. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - Neither the name of Arm nor the names of its contributors may be used to endorse or promote products derived from this document without specific prior written permission. THIS DOCUMENT IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS DOCUMENT, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.