Boot Time Security

Xilinx® supports secure booting on all devices using latest authentication methods to prevent unathorized or modified code from being run on Xilinx devices. Xilinx supports various encryption techniques to make sure only authorized programs access the images. For hardware security features by device, see the following sections.

Secure and Non-Secure Modes in Zynq-7000 SoC Devices

For security reasons, CPU 0 is always the first device out of reset among all master modules within the PS. CPU 1 is held in an WFE state. While the BootROM is running, the JTAG is always disabled, regardless of the reset type, to ensure security. After the BootROM runs, JTAG is enabled if the boot mode is non-secure.

The BootROM code is also responsible for loading the FSBL/User code. When the BootROM releases control to stage 1, the user software assumes full control of the entire system. The only way to execute the BootROM again is by generating one of the system resets. The FSBL/User code size, encrypted and unencrypted, is limited to 192 KB. This limit does not apply with the non-secure execute-in-place option.

The PS boot source is selected using the BOOT_MODE strapping pins (indicated by a weak pull-up or pull-down resistor), which are sampled once during power-on reset (POR). The sampled values are stored in the slcr.BOOT_MODE register.

The BootROM supports encrypted/authenticated, and unencrypted images referred to as secure boot and non-secure boot, respectively. The BootROM supports execution of the stage 1 image directly from NOR or Quad-SPI when using the execute-in-place (xip_mode) option, but only for non-secure boot images. Execute-in-place is possible only for NOR and Quad-SPI boot modes.

  • In secure boot, the CPU, running the BootROM code decrypts and authenticates the user PS image on the boot device, stores it in the OCM, and then branches to it.
  • In non-secure boot, the CPU, running the BootROM code disables all secure boot features including the AES unit within the PL before branching to the user image in the OCM memory or the flash device (if execute-in-place (XIP) is used).

Any subsequent boot stages for either the PS or the PL are the responsibility of you, the developer, and are under your control. The BootROM code is not accessible to you. Following a stage 1 secure boot, you can proceed with either secure or non-secure subsequent boot stages. Following a non-secure first stage boot, only non-secure subsequent boot stages are possible.

Zynq UltraScale+ MPSoC Device Security

In a Zynq® UltraScale+™ MPSoC device, the secure boot is accomplished by using the hardware root of trust boot mechanism, which also provides a way to encrypt all of the boot or configuration files. This architecture provides the required confidentiality, integrity, and authentication to host the most secure of applications.

See this link in the Zynq UltraScale+ Device Technical Reference Manual (UG1085) for more information.

Versal ACAP Security

On Versal™ ACAPs, secure boot ensures the confidentiality, integrity, and authentication of the firmware and software loaded onto the device. The root of trust starts with the PMC ROM, which authentications and/or decrypts the PLM software. Now that the PLM software is trusted, the PLM handles loading the rest of the firmware and software in a secure manner. Additionally, if secure boot is not desired then software can at least be validated with a simple checksum.

See Versal ACAP Technical Reference Manual (AM011) for more information.

Using Encryption

Secure booting, which validates the images on devices before they are allowed to execute, has become a mandatory feature for most electronic devices being deployed in the field. For encryption, Xilinx supports an advanced encryption standard (AES) algorithm AES encryption.

AES provides symmetric key cryptography (one key definition for both encryption and decryption). The same steps are performed to complete both encryption and decryption in reverse order.

AES is an iterated symmetric block cipher, which means that it does the following:

  • Works by repeating the same defined steps multiple times
  • Uses a secret key encryption algorithm
  • Operates on a fixed number of bytes

Encryption Process

Bootgen can encrypt the boot image partitions based on the user-provided encryption commands and attributes in the BIF file. AES is a symmetric key encryption technique; it uses the same key for encryption and decryption. The key used to encrypt a boot image should be available on the device for the decryption process while the device is booting with that boot image. Generally, the key is stored either in eFUSE or BBRAM, and the source of the key can be selected during boot image creation through BIF attributes, as shown in the following figure.

Figure 1: Encryption Process Diagram

Decryption Process

For SoC devices, the BootROM and the FSBL decrypt partitions during the booting cycle. The BootROM reads FSBL from flash, decrypts, loads, and hands off the control. After FSBL start executing, it reads the remaining partitions, decrypts, and loads them. The AES key needed to decrypt the partitions can be retrieved from either eFUSE or BBRAM. The key source field of the boot header table in the boot image is read to know the source of the encryption key. Each encrypted partition is decrypted using a AES hardware engine.

Figure 2: Decryption Process Diagram

Encrypting Zynq-7000 Device Partitions

Zynq®-7000 SoC devices use the embedded, Progammable Logic (PL), hash-based message authentication code (HMAC) and an advanced encryption standard (AES) module with a cipher block chaining (CBC) mode.

Example BIF File

To create a boot image with encrypted partitions, the AES key file is specified in the BIF using the aeskeyfile attribute. Specify an encryption=aes attribute for each image file listed in the BIF file to be encrypted. The example BIF file (secure.bif) is shown below:

image: 
{
	[aeskeyfile] secretkey.nky
	[keysrc_encryption] efuse
	[bootloader, encryption=aes] fsbl.elf
	[encryption=aes] uboot.elf
}
From the command line, use the following command to generate a boot image with encrypted fsbl.elf and uboot.elf.
bootgen -arch zynq -image secure.bif -w -o BOOT.bin

Key Generation

Bootgen can generate AES-CBC keys. Bootgen uses the AES key file specified in the BIF for encrypting the partitions. If the key file is empty or non-existent, Bootgen generates the keys in the file specified in the BIF file. If the key file is not specified in the BIF, and encryption is requested for any of the partitions, then Bootgen generates a key file with the name of the BIF file with extension .nky in the same directory as of BIF. The following is a sample key file.

Figure 3: Sample Key File

Encrypting Zynq MPSoC Device Partitions

The Zynq® UltraScale+™ MPSoC device uses the AES-GCM core, which has a 32-bit, word-based data interface with support for a 256-bit key. The AES-GCM mode supports encryption and decryption, multiple key sources, and built-in message integrity check.

Operational Key

A good key management practice includes minimizing the use of secret or private keys. This can be accomplished using the operational key option enabled in Bootgen.

Bootgen creates an encrypted, secure header that contains the operational key (opt_key), which is user-specified, and the initialization vector (IV) needed for the first block of the configuration file when this feature is enabled. The result is that the AES key stored on the device, in either the BBRAM or eFUSEs, is used for only 384 bits, which significantly limits its exposure to side channel attacks. The attribute opt_key is used to specify operational key usage. See fsbl_config for more information about the opt_key value that is an argument to the fsbl_config attribute. The following is an example of using the opt_key attribute.

image:
{
	[fsbl_config] opt_key
	[keysrc_encryption] bbram_red_key 
	 
	[bootloader, 
	 destination_cpu = a53-0,
	 encryption      = aes, 
	 aeskeyfile      = aes_p1.nky]fsbl.elf
	 
	[destination_cpu = a53-3,
	 encryption      = aes, 
	 aeskeyfile      = aes_p2.nky]hello.elf
	 
}

The operation key is given in the AES key (.nky) file with name Key Opt as shown in the following example.

Figure 4: Operational Key

Bootgen generates the encryption key file. The operational key opt_key is then generated in the .nky file, if opt_key has been enabled in the BIF file, as shown in the previous example.

For another example of using the operational key, refer to Using Op Key to Protect the Device Key in a Development Environment.

For more details about this feature, see the Key Management section of the "Security" chapter in the Zynq UltraScale+ Device Technical Reference Manual (UG1085).

Rolling Keys

The AES-GCM also supports the rolling keys feature, where the entire encrypted image is represented in terms of smaller AES encrypted blocks/modules. Each module is encrypted using its own unique key. The initial key is stored at the key source on the device, while keys for each successive module are encrypted (wrapped) in the previous module. The boot images with rolling keys can be generated using Bootgen. The BIF attribute blocks is used to specify the pattern to create multiple smaller blocks for encryption.

image:
{
	[keysrc_encryption] bbram_red_key
		
	[
		bootloader, 
		destination_cpu = a53-0,
		encryption      = aes, 
		aeskeyfile      = aes_p1.nky,
		blocks          = 1024(2);2048;4096(2);8192(2);4096;2048;1024 
	]    fsbl.elf
	 	
	[
		destination_cpu = a53-3,
		encryption      = aes, 
		aeskeyfile      = aes_p2.nky,
		blocks          = 4096(1);1024 
	]    hello.elf
}
Note:
  • Number of keys in the key file should always be equal to the number of blocks to be encrypted.
    • If the number of keys are less than the number of blocks to be encrypted, Bootgen returns an error.
    • If the number of keys are more than the number of blocks to be encrypted, Bootgen ignores (does not read) the extra keys.
  • If you want to specify multiple Key/IV Pairs, you should specify no. of blocks + 1 pairs
    • The extra Key/IV pair is to encrypt the secure header.
    • No Key/IV pair should be repeated in a any of the aes key files given in a single bif except the Key0 and IV0.

Gray/Obfuscated Keys

The user key is encrypted with the family key, which is embedded in the metal layers of the device. This family key is the same for all devices in the Zynq® UltraScale+™ MPSoC. The result is referred to as the obfuscated key. The obfuscated key can reside in either the Authenticated Boot Header or or in eFUSEs.

image:
{
	[keysrc_encryption] efuse_gry_key 
	[bh_key_iv] bhiv.txt
	[
		bootloader, 
		destination_cpu = a53-0,
		encryption      = aes, 
		aeskeyfile      = aes_p1.nky
	]    fsbl.elf 
	[
		destination_cpu = r5-0,
		encryption      = aes,
		aeskeyfile      = aes_p2.nky 
	]    hello.elf
}

Bootgen does the following while creating an image:

  1. Places the IV from bhiv.txt in the field BH IV in Boot Header.
  2. Places the IV 0 from aes.nky in the field "Secure Header IV" in Boot Header.
  3. Encrypts the partition, with Key0 and IV0 from aes.nky.

Another example of using the gray/family key is found in Use Cases and Examples.

For more details about this feature, refer to the Zynq UltraScale+ Device Technical Reference Manual (UG1085).

Key Generation

Bootgen has the capability of generating AES-GCM keys. It uses the NIST-approved Counter Mode KDF, with CMAC as the pseudo random function. Bootgen takes seed as input in case the user wants to derive multiple keys from seed due to key rolling. If a seed is specified, the keys are derived using the seed. If seeds are not specified, keys are derived based on Key0. If an empty key file is specified, Bootgen generates a seed with time based randomization (not KDF), which in turn is the input for KDF to generate other the Key/IV pairs.

Note:
  • If one encryption file is specified and others are generated, Bootgen can make sure to use the same Key0/IV0 pair for the generated keys as in the encryption file for first partition. For example, in the case of a full boot image, the first partition is the bootloader.
  • If an encryption file is generated for the first partition and other encryption file with Key0/IV0 is specified for a later partition, then Bootgen exits and returns the error that an incorrect Key0/IV0 pair was used.
Key Generation

A sample key file is shown below.

Figure 5: Sample Key File
Obfuscated Key Generation

Bootgen can generate the Obfuscated key by encrypting the red key with the family key and a user-provided IV. The family key is delivered by the Xilinx® Security Group. For more information, see familykey. To generate an obfuscated key, Bootgen takes the following inputs from the BIF file.

obf_key:
{
	[aeskeyfile] aes.nky  
	[familykey] familyKey.cfg 
	[bh_key_iv] bhiv.txt
}

The command to generate the Obfuscated key is:

bootgen -arch zynqmp -image all.bif -generate_keys obfuscatedkey

Black/PUF Keys

The black key storage solution uses a cryptographically strong key encryption key (KEK), which is generated from a PUF, to encrypt the user key. The resulting black key can then be stored either in the eFUSE or as a part of the authenticated boot header.

image:
{ 
	[puf_file] pufdata.txt
	[bh_key_iv] black_iv.txt
	[bh_keyfile] black_key.txt
	[fsbl_config] puf4kmode, shutter=0x0100005E, pufhd_bh
	[keysrc_encryption] bh_blk_key 
	
	[
	  bootloader,
	  destination_cpu = a53-0,
	  encryption      = aes, 
	  aeskeyfile      = aes_p1.nky
	] fsbl.elf
		 
	[
	  destination_cpu = r5-0,
	  encryption      = aes,
	  aeskeyfile      = aes_p2.nky
	] hello.elf
}

For another example of using the black key, see Use Cases and Examples.

Multiple Encryption Key Files

Earlier versions of Bootgen supported creating the boot image by encrypting multiple partitions with a single encryption key. The same key is used over and over again for every partition. This is a security weakness and not recommended. Each key should be used only once in the flow.

Bootgen supports separate encryption keys for each partition. In case of multiple key files, ensure that each encryption key file uses the same Key0 (device key), IV0, and Operational Key. Bootgen does not allow creating boot images if these are different in each encryption key file. You must specify multiple encryption key files, one for each of partition in the image. The partitions are encrypted using the key that is specified for the partition.

Note: You can have unique key files for each of the partition created due to multiple loadable sections by having key file names appended with .1, .2, .n, and so on in the same directory of the key file meant for that partition.

The following snippet shows a sample encryption key file:

all:
{
	[keysrc_encryption] bbram_red_key
	// FSBL (Partition-0)
	[
		bootloader, 
		destination_cpu = a53-0, 
		encryption = aes,
		aeskeyfile = key_p0.nky
		
	]fsbla53.elf
				 
	// application (Partition-1)
	[
		destination_cpu = a53-0,
		encryption = aes,
		aeskeyfile = key_p1.nky
			
	]hello.elf  
}
  • The partition fsbla53.elf is encrypted using the keys from key_p0.nky file.
  • Assuming hello.elf has three partitions because it has three loadable sections, then partition hello.elf.0 is encrypted using keys from the test2.nky file.
  • Partition hello.elf.1 is then encrypted using keys from test2.1.nky.
  • Partition hello.elf.2 is encrypted using keys from test2.2.nky.

Encrypting Versal Device Partitions

The Versal™ device uses the AES-GCM core, which has support for a 256-bit key. When creating a secure image, each partition in a boot image can be optionally encrypted. Key source and aes key file are the prerequisites for encryption.

Note: For Versal ACAP, it is mandatory to specify AES key file and the key source for each partition when encryption is enabled. Based on the key source used, same Key0 should be used in the aes key files specified respectively and vice-versa.

Key Management

Good key management practice includes minimizing the use of secret or private keys. This can be accomplished this by using different key/IV pairs across different partitions in the boot image. The result is that the AES key stored on the device, in either the BBRAM or eFUSEs, is used for only 384 bits, which significantly limits its exposure to side channel attacks.

all: {
  image
  {
    {type=bootloader, encryption=aes, keysrc=bbram_red_key, aeskeyfile=plm.nky, dpacm_enable, file=plm.elf}
    {type=pmcdata, load=0xf2000000, aeskeyfile = pmc_data.nky, file=pmc_data.cdo}
    {core=psm, file=psm.elf}
    {type=cdo, encryption=aes, keysrc=bbram_red_key, aeskeyfile=ps_data.nky, file=ps_data.cdo}
    {type=cdo, file=subsystem.cdo}
    {core=a72-0, exception_level = el-3, file=a72-app.elf}
  }
}

Rolling Keys

The AES-GCM also supports the rolling keys feature, where the entire encrypted image is represented in terms of smaller AES encrypted blocks/modules. Each module is encrypted using its own unique key. The initial key is stored at the key source on the device, while keys for each successive module are encrypted (wrapped) in the previous module. You can generate the boot images with rolling keys using Bootgen. The BIF attribute blocks is used to specify the pattern to create multiple smaller blocks for encryption.

Note: For Versal ACAP, a default key rolling is done on 32 KB of data. The key rolling you choose with the attribute blocks is applied in each 32 KB chunk. This is to compliment the hashing scheme used. If the DPA key rolling countermeasure is enabled, boot time is impacted. Refer to the boot time estimator spreadsheet for calculations.
all:
{
	id_code = 0x04ca8093
	extended_id_code = 0x01
	id = 0x2

	metaheader
	{
		encryption = aes,
		keysrc = bbram_red_key,
		aeskeyfile = efuse_red_metaheader_key.nky,
		dpacm_enable
	}

	image
	{
		name = pmc_subsys, id = 0x1c000001
		partition
		{
			id = 0x01, type = bootloader,
			encryption = aes,
			keysrc = bbram_red_key,
			aeskeyfile = bbram_red_key.nky,
			dpacm_enable,
			blocks = 4096(2);1024;2048(2);4096(*),
			file = executable.elf
		}
		partition
		{
			id = 0x09, type = pmcdata, load = 0xf2000000,
			aeskeyfile = pmcdata.nky,
			file = topology_xcvc1902.v1.cdo,
			file = pmc_data.cdo
		}
	}

	image
	{
		name = lpd, id = 0x4210002
		partition
		{
			id = 0x0C, type = cdo,
			encryption = aes,
			keysrc = bbram_red_key,
			aeskeyfile = key1.nky,
			dpacm_enable,
			blocks = 8192(20);4096(*),
			file = lpd_data.cdo
		}
		partition
		{
			id = 0x0B, core = psm,
			encryption = aes,
			keysrc = bbram_red_key,
			aeskeyfile = key2.nky,
			dpacm_enable,
			blocks = 4096(2);1024;2048(2);4096(*),
			file = psm_fw.elf
		}
	}

	image
	{
		name = fpd, id = 0x420c003
		partition
		{
			id = 0x08, type = cdo,
			encryption = aes,
			keysrc = bbram_red_key,
			aeskeyfile = key5.nky,
			dpacm_enable,
			blocks = 8192(20);4096(*),
			file = fpd_data.cdo
		}
	}
}
Note:
  • Number of keys in the key file should always be equal to the number of blocks to be encrypted.
  • If the number of keys are less than the number of blocks to be encrypted, Bootgen returns an error.
  • If the number of keys are more than the number of blocks to be encrypted, Bootgen ignores the extra keys.

Key Generation

Bootgen can generate AES-GCM keys. It uses the NIST-approved Counter Mode KDF, with CMAC as the pseudo random function. Bootgen takes seed as input in case you want to derive multiple keys from seed due to key rolling. If a seed is specified, the keys are derived using the seed. If seeds are not specified, keys are derived based on Key0. If an empty key file is specified, Bootgen generates a seed with time based randomization (not KDF), which in turn is the input for KDF to generate other the Key/IV pairs. The following conditions apply.

  • If one encryption file is specified and others are generated, Bootgen can make sure to use the same Key0/IV0 pair for the generated keys as in the encryption file for first partition.
  • If an encryption file is generated for the first partition and other encryption file with Key0/IV0 is specified for a later partition, then Bootgen exits and returns the error that an incorrect Key0/IV0 pair was used.
  • If no key file is specified and encryption is opted for a partition, bootgen by default generated an aes key file with the name of the partition. By doing this, Bootgen makes sure that a different aeskeyfile is used for each partition.
  • Bootgen enables the usage of unique key files for each of the partition created due to multiple loadable sections by reading/generating key file names appended with ".1", ".2"...".n" so on in the same directory of the key file meant for that partition.

Black/PUF Keys

The black key storage solution uses a cryptographically strong key encryption key (KEK), which is generated from a PUF, to encrypt the user key. The resulting black key can then be stored either in the eFUSE or as a part of the authenticated boot header. Example:

test:
{
  bh_kek_iv = black_iv.txt
  bh_keyfile = black_key.txt
  puf_file = pufdata.txt
  boot_config {puf4kmode}
  image
  { 
    {type=bootloader, encryption = aes, keysrc=bh_blk_key, pufhd_bh, aeskeyfile = red_grey.nky, file=plm.elf}
    {type=pmcdata,load=0xf2000000, aeskeyfile = pmcdata.nky, file=pmc_data.cdo}
    {core=psm, file=psm.elf}
    {type=cdo, file=ps_data.cdo}
    {type=cdo, file=subsystem.cdo}
    {core=a72-0, exception_level = el-3, file=hello_world.elf}
  }
}

Meta Header Encryption

For a Versal ACAP, bootgen encrypts the meta header when encryption is specifically mentioned under the "metaheader" attribute. The aeskeyfile that is to be used can be specified in the bif using the parameters under "metaheader". A snippet of the usage is shown below.

metaheader
{
  encryption = aes,
  keysrc = bbram_red_key,
  aeskeyfile = headerkey.nky,
}

The following conditions apply.

  • If a specific aeskeyfile is not specified for meta header, Bootgen generates a file named meta_header.nky, and uses it during encryption.
  • If a boot loader is present in the bif, it is mandatory to encrypt boot loader to encrypt meta header. For a partial PDI, meta header can be optionally chosen to be encrypted.

Using Authentication

AES encryption is a self-authenticating algorithm with a symmetric key, meaning that the key to encrypt is the same as the one to decrypt. This key must be protected as it is secret (hence storage to internal key space). There is an alternative form of authentication in the form of RSA (Rivest-Shamir-Adleman). RSA is an asymmetric algorithm, meaning that the key to verify is not the same key used to sign. A pair of keys are needed for authentication.

  • Signing is done using Secret Key/ Private Key
  • Verification is done using a Public Key

This public key does not need to be protected, and does not need special secure storage. This form of authentication can be used with encryption to provide both authenticity and confidentiality. RSA can be used with either encrypted or unencrypted partitions.

RSA not only has the advantage of using a public key, it also has the advantage of authenticating prior to decryption. The hash of the RSA Public key must be stored in the eFUSE. Xilinx® SoC devices support authenticating the partition data before it is sent to the AES decryption engine. This method can be used to help prevent attacks on the decryption engine itself by ensuring that the partition data is authentic before performing any decryption.

In Xilinx SoCs, two pairs of public and secret keys are used - primary and secondary. The function of the primary public/secret key pair is to authenticate the secondary public/secret key pair. The function of the secondary key is to sign/verify partitions.

The first letter of the acronyms used to describe the keys is either P for primary or S for secondary. The second letter of the acronym used to describe the keys is either P for public or S for secret. There are four possible keys:

  • PPK = Primary Public Key
  • PSK = Primary Secret Key
  • SPK = Secondary Public Key
  • SSK = Secondary Secret Key

Bootgen can create a authentication certificate in two ways:

  • Supply the PSK and SSK. The SPK signature is calculated on-the-fly using these two inputs.
  • Supply the PPK and SSK and the SPK signature as inputs. This is used in cases where the PSK is not known.

The primary key is hashed and stored in the eFUSE. This hash is compared against the hash of the primary key stored in the boot image by the FSBL. This hash can be written to the PS eFUSE memory using standalone driver provided along with Vitis.

The following is an example BIF file:

image:
{ 
	[pskfile]primarykey.pem
	[sskfile]secondarykey.pem
	[bootloader,authentication=rsa] fsbl.elf
	[authentication=rsa]uboot.elf
}

For device-specific Authentication information, see the following:

Signing

The following figure shows RSA signing of partitions. From a secure facility, Bootgen signs partitions using the Secret key. The signing process is described in the following steps:

  1. PPK and SPK are stored in the Authentication Certificate (AC).
  2. SPK is signed using PSK to get SPK signature; also stored as part of the AC.
  3. Partition is signed using SSK to get Partition signature, populated in the AC.
  4. The AC is appended or prepended to each partition that is opted for authentication depending on the device.
  5. PPK is hashed and stored in eFUSE.
Figure 6: RSA Partition Signature

The following table shows the options for Authentication.

Table 1. Supported File Formats for Authentication Keys
Key Name Description Supported File Format
PPK Primary Public Key This key is used to authenticate a partition.

It should always be specified when authenticating a partition.

*.txt

*.pem

*.pub

*.pk1

PSK Primary Secret Key This key is used to authenticate a partition.

It should always be specified when authenticating a partition.

*.txt

*.pem

*.pk1

SPK Secondary Public Key This key, when specified, is used to authenticate a partition. *.txt

*.pem

*.pub

*.pk1

SSK Secondary Secret Key This key, when specified, is used to authenticate a partition. *.txt

*.pem

*.pk1

Verifying

In the device, the BootROM verifies the FSBL, and either the FSBL or U-Boot verifies the subsequent partitions using the Public key.

  1. Verify PPK: This step establishes the authenticity of primary key, which is used to authenticate secondary key.
    1. PPK is read from AC in boot image
    2. Generate PPK hash
    3. Hashed PPK is compared with the PPK hash retrieved from eFUSE
    4. If same, then primary key is trusted, else secure boot fail
  2. Verify secondary keys: This step establishes the authenticity of secondary key, which is used to authenticate the partitions.
    1. SPK is read from AC in boot image
    2. Generate SPK hashed
    3. Get the SPK hash, by verifying the SPK signature stored in AC, using PPK
    4. Compare hashes from step (b) and step (c)
    5. If same, then secondary key is trusted, else secure boot fail.
  3. Verify partitions: This step establishes the authenticity of partition which is being booted.
    1. Partition is read from the boot image.
    2. Generate hash of the partition.
    3. Get the partition hash, by verifying the Partition signature stored in AC, using SPK.
    4. Compare the hashes from step (b) and step (c)
    5. If same, then partition is trusted, else secure boot fail
Figure 7: Verification Flow Diagram

Bootgen can create a authentication certificate in two ways:

  • Supply the PSK and SSK. The SPK signature is calculated on-the-fly using these two inputs.
  • Supply the PPK and SSK and the SPK signature as inputs. This is used in cases where the PSK is not known.

Zynq UltraScale+ MPSoC Authentication Support

The Zynq® UltraScale+™ MPSoC device uses RSA-4096 authentication, which means the primary and secondary key sizes are 4096-bit.

NIST SHA-3 Support

Note: For SHA-3 Authentication, always use Keccak SHA-3 to calculate hash on boot header, PPK hash and boot image. NIST-SHA3 is used for all other partitions which are not loaded by ROM.

The generated signature uses the Keccak-SHA3 or NIST-SHA3 based on following table:

Table 2. Authentication Signatures
Which Authentication Certificate (AC)? Signature SHA Algorithm and SPK eFUSE Secret Key used for Signature Generation
Partitions header AC (loaded by FSBL/FW) SPK Signature If SPKID eFUSEs, then Keccak; If User eFUSE, then NIST PSK
BH Signature Always Keccak SSKheader
Header Signature Always Nist SSKheader
BootLoader (FSBL) AC (loaded by ROM) SPK Signature Always Keccak; Always SPKID eFUSE for SPK PSK
BH Signature Always Keccak SSKBootloader
FSBL Signature Always Keccak SSKBootloader
Other Partition AC (loaded by FSBL FW) SPK Signature If SPKID eFUSEs then Keccak; If User eFUSE then NIST PSK
BH Signature Always Keccak padding SSKPartition
Partition Signature Always NIST padding SSKPartition
Examples

Example 1: BIF file for authenticating the partition with single set of key files:

image:
{
	[fsbl_config] bh_auth_enable
	[auth_params] ppk_select=0; spk_id=0x00000000
	[pskfile] primary_4096.pem
	[sskfile] secondary_4096.pem
	[pmufw_image] pmufw.elf
	[bootloader, authentication=rsa, destination_cpu=a53-0] fsbl.elf
	[authenication=rsa, destination_cpu=r5-0] hello.elf
}

Example 2: BIF file for authenticating the partitions with separate secondary key for each partition:

image:
{
	[auth_params] ppk_select=1
	[pskfile] primary_4096.pem
	[sskfile] secondary_4096.pem
	
	// FSBL (Partition-0)
	[
	  bootloader,
	  destination_cpu = a53-0,
	  authentication = rsa,
	  spk_id = 0x01,
	  sskfile = secondary_p1.pem
	] fsbla53.elf

	// ATF (Partition-1)
	[
	  destination_cpu = a53-0,
	  authentication = rsa,
	  exception_level = el-3,
	  trustzone = secure,
	  spk_id = 0x01,
	  sskfile = secondary_p2.pem
	] bl31.elf
	
	// UBOOT (Partition-2)
	[
	  destination_cpu = a53-0, 
	  authentication = rsa,
	  exception_level = el-2,
	  spk_id = 0x01,
	  sskfile = secondary_p3.pem
	] u-boot.elf
}

Bitstream Authentication Using External Memory

The authentication of a bitstream is different from other partitions. The FSBL can be wholly contained within the OCM, and therefore authenticated and decrypted inside of the device. For the bitstream, the size of the file is so large that it cannot be wholly contained inside the device and external memory must be used. The use of external memory creates a challenge to maintain security because an adversary may have access to this external memory. When bitstream is requested for authentication, Bootgen divides the whole bitstream into 8MB blocks and has an authentication certificate for each block. If a bitstream is not in multiples of 8MB, the last block contains the remaining bitstream data. When authentication and encryption are both enabled, encryption is first done on the bitstream, then Bootgen divides the encrypted data into blocks and places an authentication certificate for each block.

Figure 8: Bitstream Authentication Using External Memory

User eFUSE Support with Enhanced RSA Key Revocation

Enhanced RSA Key Revocation Support

The RSA key provides the ability to revoke the secondary keys of one partition without revoking the secondary keys for all partitions.

Note: The primary key should be the same across all partitions.

This is achieved by using USER_FUSE0 to USER_FUSE7 eFUSEs with the BIF parameter spk_select.

Note: You can revoke up to 256 keys, if all are not required for their usage.

The following BIF file sample shows enhanced user fuse revocation. Image header and FSBL uses different SSKs for authentication (ssk1.pem and ssk2.pem respectively) with the following BIF input.

the_ROM_image:
{
	[auth_params]ppk_select = 0
	[pskfile]psk.pem
	[sskfile]ssk1.pem
	[
	  bootloader,
	  authentication = rsa,
	  spk_select = spk-efuse,
	  spk_id = 0x8,
	  sskfile = ssk2.pem
	] zynqmp_fsbl.elf
	[
	  destination_cpu = a53-0,
	  authentication = rsa,
	  spk_select = user-efuse,
	  spk_id = 0x100,
	  sskfile = ssk3.pem
	] application.elf
	[
	  destination_cpu = a53-0,
	  authentication = rsa,
	  spk_select = spk-efuse,
	  spk_id = 0x8,
	  sskfile = ssk4.pem
	] application2.elf
} 
  • spk_select = spk-efuse indicates that spk_id eFUSE will be used for that partition.
  • spk_select = user-efuse indicates that user eFUSE will be used for that partition.

Partitions loaded by CSU ROM will always use spk_efuse.

Note: The spk_id eFUSE specifies which key is valid. Hence, the ROM checks the entire field of spk_id eFUSE against the SPK ID to make sure its a bit for bit match.

The user eFUSE specifies which key ID is NOT valid (has been revoked). Therefore, the firmware (non-ROM) checks to see if a given user eFUSE that represents the SPK ID has been programmed.

Key Generation

Bootgen has the capability of generating RSA keys. Alternatively, you can create keys using external tools such as OpenSSL. Bootgen creates the keys in the paths specified in the BIF file.

The figure shows the sample RSA private key file.
Figure 9: Sample RSA Private Key File
Note: The public component is usually referred with the extension .pub. This can be extracted from the private key which has both the public and private components. The private keys usually have extension .pem. To generate public key components use ppkfile/spkfile instead of pskfile/sskfile in the above example.
BIF Example

A sample BIF file, generate_pem.bif:

generate_pem:
{
	[pskfile] psk0.pem
	[sskfile] ssk0.pem
}
Command

The command to generate keys is, as follows:

bootgen -generate_keys pem -arch zynqmp -image generate_pem.bif

PPK Hash for eFUSE

Bootgen generates the PPK hash for storing in eFUSE for PPK to be trusted. This step is required only for RSA Authentication with eFUSE mode, and can be skipped for RSA Boot Header Authentication for the Zynq® UltraScale+™ MPSoC device. The value from efuseppksha.txt can be programmed to eFUSE for RSA authentication with the eFUSE mode.

For more information about BBRAM and eFUSE programming, see Programming BBRAM and eFUSEs (XAPP1319).

BIF File Example

The following is a sample BIF file, generate_hash_ppk.bif.

generate_hash_ppk:
{
	[pskfile] psk0.pem
	[sskfile] ssk0.pem
	[bootloader, destination_cpu=a53-0, authentication=rsa] fsbl_a53.elf
}
Command

The command to generate PPK hash for eFUSE programming is:

bootgen –image generate_hash_ppk.bif –arch zynqmp –w –o /
test.bin –efuseppkbits efuseppksha.txt

Versal Authentication Support

Bootgen supports RSA-4096 and ECDSA P384 and P521 curves for Versal ACAP authentication. NIST SHA-3 is used to calculate hash on all partitions/headers. The signature calculated on the hash is placed in the PDI.

Note: Unlike Zynq devices and Zynq UltraScale+ MPSoC, for Versal ACAPs, the authentication certificate is placed prior to the partition. The ECDSA P521 curve is not supported for authentication of the bootloader partition (PLM) because the BootROM only supports RSA-4096 or ECDSA-P384 authentication. P521 can, however, be used to authenticate any other partition.

Meta Header Authentication

For a Versal ACAP, Bootgen authenticates the meta header based on the parameters under the bif attribute "metaheader". A snippet of the usage is shown below.

metaheader
{
	authentication = rsa,
	pskfile = psk.pem,
	sskfile = ssk.pem
}

PPK Hash for eFUSE

Bootgen generates the PPK hash for storing in eFUSE for PPK to be trusted. This step is required only for authentication with eFUSE mode, and can be skipped for Boot Header Authentication. The value from efuseppksha.txt can be programmed to eFUSE for authentication with the eFUSE mode.

BIF File Example

The following is a sample BIF file, generate_hash_ppk.bif.

generate_hash_ppk:
{
    pskfile = primary0.pem
    sskfile = secondary0.pem
    image
    {
        name = pmc_ss, id = 0x1c000001
        { type=bootloader, authentication=rsa, file=plm.elf}
        { type=pmcdata, load=0xf2000000, file=pmc_cdo.bin}
    }
}

Command

The command to generate PPK hash for eFUSE programming is:

bootgen –image generate_hash_ppk.bif –arch versal –w –o test.bin –efuseppkbits efuseppksha.txt

Cumulative Secure Boot Operations for Versal ACAP

Table 3. Cumulative Secure Boot Operations
Boot Type Operations Hardware Crypto Engines
Authentication Decryption Integrity (Checksum Verification)
Non-secure boot No No No None
Asymmetric Hardware Root-of-Trust (A-HWRoT) Yes (Required) No No RSA/ECDSA along with SHA3
Symmetric Hardware Root-of-Trust (S-HWRoT) (Forces decryption of PDI with eFUSE black key) No Yes (Required PLM and Meta Header should be encrypted with eFUSE KEK) No AES-GCM
A-HWRoT + S-HWRoT Yes (Required) Yes (Required) No RSA/ECDSA along with SHA3 and AES-GCM
Authentication + Decryption of PDI Yes Yes (Key source can be either from BBRAM or eFUSE) No RSA/ECDSA along with SHA3 and AES-GCM
Decryption (Uses user-selected key. The key source can be of any type such as BBRAM/BHDR or even eFUSE) No Yes No AES-GCM
Checksum Verification No No Yes SHA3

Using HSM Mode

In current cryptography, all the algorithms are public, so it becomes critical to protect the private/secret key. The hardware security module (HSM) is a dedicated crypto-processing device that is specifically designed for the protection of the crypto key lifecycle, and increases key handling security, because only public keys are passed to the Bootgen and not the private/secure keys. A standard mode is also available; this mode does not require passing keys.

In some organizations, an infosec staff is responsible for the production release of a secure embedded product. The infosec staff might use a HSM for digital signatures and a separate secure server for encryption. The HSM and secure server typically reside in a secure area. The HSM is a secure key/signature generation device which generates private keys, signs the partitions using the private key, and provides the public part of the RSA key to Bootgen. The private keys reside in the HSM only.

Bootgen in HSM mode uses only RSA public keys and the signatures that were created by the HSM to generate the boot image. The HSM accepts hash values of partitions generated by Bootgen and returns a signature block, based on the hash and the secret RSA key.

In contrast to the HSM mode, Bootgen in its Standard mode uses AES encryption keys and the RSA Secret keys provided through the BIF file, to encrypt and authenticate the partitions in the image, respectively. The output is a single boot image, which is encrypted and authenticated. For authentication, the user has to provide both sets of public and private/secret keys. The private/secret keys are used by the Bootgen to sign the partitions and create signatures. These signatures along with the public keys are embedded into the final boot image.

For more information about the HSM mode for FPGAs, see the HSM Mode.

Using Advanced Key Management Options

The public keys associated with the private keys are ppk.pub and spk.pub. The HSM accepts hash values of partitions generated by Bootgen and returns a signature block, based on the hash and the secret key.

Creating a Boot Image Using HSM Mode: PSK is not Shared

The following figure shows a Stage 0 to Stage 2 Boot stack that uses the HSM mode. It reduces the number of steps by distributing the SSK.

This figure uses the Zynq® UltraScale+™ MPSoC device to illustrate the stages.

Figure 10: Generic 3-stage boot image

Boot Process

Creating a boot image using HSM mode is similar to creating a boot image using a standard flow with following BIF file.

all:
{
	[auth_params] ppk_select=1;spk_id=0x8
	[keysrc_encryption]bbram_red_key
	[pskfile]primary.pem
	[sskfile]secondary.pem
	[
	 bootloader,
	 encryption=aes,
 	aeskeyfile=aes.nky,
	 authentication=rsa
	]fsbl.elf
	[destination_cpu=a53-0,authentication=rsa]hello_a53_0_64.elf
}

Stage 0: Create a boot image using HSM Mode

A trusted individual creates the SPK signature using the Primary Secret Key. The SPK Signature is on the Authentication Certificate Header, SPK, and SPK ID. To generate a hash for the above, use the following BIF file snippet.

stage 0:
{
	[auth_params] ppk_select=1;spk_id=0x3
	[spkfile]keys/secondary.pub
}

The following is the Bootgen command:

bootgen -arch zynqmp -image stage0.bif -generate_hashes

The output of this command is: secondary.pub.sha384.

Stage 1: Distribute the SPK Signature

The trusted individual distributes the SPK Signature to the development teams.

openssl rsautl -raw -sign -inkey keys/primary0.pem -in secondary.pub.sha384 > secondary.pub.sha384.sig 

The output of this command is: secondary.pub.sha384.sig

Stage 2: Encrypt using AES in FSBL

The development teams use Bootgen to create as many boot images as needed. The development teams use:

  • The SPK Signature from the Trusted Individual.
  • The Secondary Secret Key (SSK), SPK, and SPKID
Stage2:
{
	[keysrc_encryption]bbram_red_key 
	[auth_params] ppk_select=1;spk_id=0x3
	[ppkfile]keys/primary.pub
	[sskfile]keys/secondary0.pem
	[spksignature]secondary.pub.sha384.sig 
	[bootloader,destination_cpu=a53-0, encryption=aes, aeskeyfile=aes0.nky, authentication=rsa] fsbl.elf 
	[destination_cpu=a53-0, authentication=rsa] hello_a53_0_64.elf 
}
The Bootgen command is:
bootgen -arch zynqmp -image stage2.bif -o final.bin

Creating a Zynq-7000 SoC Device Boot Image using HSM Mode

The following figure provides a diagram of an HSM mode boot image for a Zynq®-7000 SoC device. The steps to create this boot image are immediately after the diagram.

Figure 11: Stage 0 to 8 Boot Process

The process to create a boot image using HSM mode for a Zynq®-7000 SoC device is similar to that of a boot image created using a standard flow with the following BIF file. These examples, where needed, use the OpenSSL program to generate hash files.

all:
{
	[aeskeyfile]my_efuse.nky 
	[pskfile]primary.pem 
	[sskfile]secondary.pem
	[bootloader,encryption=aes,authentication=rsa] zynq_fsbl_0.elf
	[authentication=rsa]system.bit
}

Stage 0: Generate a hash for SPK

This stage generates the hash of the SPK key.

stage0:
{
	[ppkfile] primary.pub
	[spkfile] secondary.pub
}

The following is the Bootgen command.

bootgen -image stage0.bif –w -generate_hashes

Stage 1: Sign the SPK Hash

This stage creates the signatures by signing the SPK hash

xil_rsa_sign.exe -gensig -sk primary.pem -data secondary.pub.sha256 -out secondary.pub.sha256.sig
Or by using the following OpenSSL program.
#Swap the bytes in SPK hash
objcopy -I binary -O binary --reverse-bytes=256 secondary.pub.sha256

#Generate SPK signature using OpenSSL
openssl rsautl -raw -sign -inkey primary.pem -in secondary.pub.sha256 > secondary.pub.sha256.sig

#Swap the bytes in SPK signature
objcopy -I binary -O binary --reverse-bytes=256 secondary.pub.sha256.sig

Stage 2: Encrypt using AES

This stage encrypts the partition. The stage2.bif is as follows.

stage2:
{
	[aeskeyfile] my_efuse.nky
	[bootloader, encryption=aes] zynq_fsbl_0.elf
}
The Bootgen command is as follows.
bootgen -image stage2.bif -w -o fsbl_e.bin -encrypt efuse
The output is the encrypted file fsbl_e.bin.

Stage 3: Generate Partition Hashes

This stage generates the hashes of different partitions.

Stage 3a: Generate the FSBL Hash

The BIF file is as follows:

stage3a:
{
	[ppkfile] primary.pub
	[spkfile] secondary.pub
	[spksignature] secondary.pub.sha256.sig
	[bootimage, authentication=rsa] fsbl_e.bin
}
The Bootgen command is as follows.
bootgen -image stage3a.bif -w -generate_hashes

The output is the hash file zynq_fsbl_0.elf.0.sha256.

Stage 3b: Generate the bitstream hash

The stage3b BIF file is as follows:

stage3b:
{
	[ppkfile] primary.pub
	[spkfile] secondary.pub
	[spksignature] secondary.pub.sha256.sig
	[authentication=rsa] system.bit
}
The Bootgen command is as follows.
bootgen -image stage3b.bif -w -generate_hashes
The output is the hash file system.bit.0.sha256.

Stage 4: Sign the Hashes

This stage creates signatures from the partition hash files created.

Stage 4a: Sign the FSBL partition hash
xil_rsa_sign.exe -gensig -sk secondary.pem -data zynq_fsbl_0.elf.0.sha256 -out zynq_fsbl_0.elf.0.sha256.sig
Or by using the following OpenSSL program.
#Swap the bytes in FSBL hash
objcopy -I binary -O binary --reverse-bytes=256 zynq_fsbl_0.elf.0.sha256

#Generate FSBL signature using OpenSSL
openssl rsautl -raw -sign -inkey secondary.pem -in zynq_fsbl_0.elf.0.sha256 > zynq_fsbl_0.elf.0.sha256.sig

#Swap the bytes in FSBL signature
objcopy -I binary -O binary --reverse-bytes=256 zynq_fsbl_0.elf.0.sha256.sig

The output is the signature file zynq_fsbl_0.elf.0.sha256.sig.

Stage 4b: Sign the bitstream hash
xil_rsa_sign.exe -gensig -sk secondary.pem -data system.bit.0.sha256 -out system.bit.0.sha256.sig
Or by using the following OpenSSL program.
#Swap the bytes in bitstream hash
objcopy -I binary -O binary --reverse-bytes=256 system.bit.0.sha256

#Generate bitstream signature using OpenSSL
openssl rsautl -raw -sign -inkey secondary.pem -in system.bit.0.sha256 > system.bit.0.sha256.sig

#Swap the bytes in bitstream signature
objcopy -I binary -O binary --reverse-bytes=256 system.bit.0.sha256.sig
The output is the signature file system.bit.0.sha256.sig.

Stage 5: Insert Partition Signatures

Insert partition signatures created above are changed into authentication certificates.

Stage 5a: Insert the FSBL signature

The stage5a.bif is as follows.

stage5a:
{
	[ppkfile] primary.pub
	[spkfile] secondary.pub
	[spksignature] secondary.pub.sha256.sig
	[bootimage, authentication=rsa, presign=zynq_fsbl_0.elf.0.sha256.sig] fsbl_e.bin
}
The Bootgen command is as follows.
bootgen -image stage5a.bif -w -o fsbl_e_ac.bin -efuseppkbits efuseppkbits.txt -nonbooting
The authenticated output files are fsbl_e_ac.bin and efuseppkbits.txt.
Stage 5b: Insert the bitstream signature
The stage5b.bif is as follows.
stage5b:
{
	[ppkfile] primary.pub
	[spkfile] secondary.pub
	[spksignature] secondary.pub.sha256.sig
	[authentication=rsa, presign=system.bit.0.sha256.sig] system.bit
}
The Bootgen command is as follows.
bootgen -image stage5b.bif -o system_e_ac.bin –nonbooting
The authenticated output file is system_e_ac.bin.

Stage 6: Generate Header Table Hash

This stage generates the hash for the header tables.

The stage6.bif is as follows.
stage6:
{
	[bootimage] fsbl_e_ac.bin
	[bootimage] system_e_ac.bin
}
The Bootgen command is as follows.
bootgen -image stage6.bif -generate_hashes
The output hash file is ImageHeaderTable.sha256.

Stage 7: Generate Header Table Signature

This stage generates the header table signature.

xil_rsa_sign.exe -gensig -sk secondary.pem -data ImageHeaderTable.sha256 -out ImageHeaderTable.sha256.sig
Or by using the following OpenSSL program:
#Swap the bytes in header table hash
objcopy -I binary -O binary --reverse-bytes=256 ImageHeaderTable.sha256

#Generate header table signature using OpenSSL
openssl rsautl -raw -sign -inkey secondary.pem -in ImageHeaderTable.sha256 > ImageHeaderTable.sha256.sig

#Swap the bytes in header table signature
objcopy -I binary -O binary --reverse-bytes=256 ImageHeaderTable.sha256.sig
The output is the signature file ImageHeaderTable.sha256.sig.

Stage 8: Combine Partitions, Insert Header Table Signature

The stage8.bif is as follows:

stage8:
{
	[headersignature] ImageHeaderTable.sha256.sig
	[bootimage] fsbl_e_ac.bin
	[bootimage] system_e_ac.bin
}
The Bootgen command is as follows:
bootgen -image stage8.bif -w -o final.bin
The output is the boot image file final.bin.

Creating a Zynq UltraScale+ MPSoC Device Boot Image using HSM Mode

The following figure provides a diagram of an HSM mode boot image.

Figure 12: 0 to 10 Stage Boot Process

To create a boot image using HSM mode for a Zynq® UltraScale+™ MPSoC device, it would be similar to a boot image created using a standard flow with the following BIF file. These examples, where needed, use the OpenSSL program to generate hash files.

all:
{
	[fsbl_config] bh_auth_enable
	[keysrc_encryption] bbram_red_key
	[pskfile] primary0.pem
	[sskfile] secondary0.pem
	
	[
	  bootloader,
	  destination_cpu=a53-0,
	  encryption=aes,
	  aeskeyfile=aes0.nky,
	  authentication=rsa
	] fsbl.elf

	[
	  destination_device=pl,
	  encryption=aes,
	  aeskeyfile=aes1.nky,
 	 authentication=rsa
	] system.bit

	[
	  destination_cpu=a53-0,
	  authentication=rsa,
	  exception_level=el-3,
	  trustzone=secure
	] bl31.elf

	[
	  destination_cpu=a53-0,
	  authentication=rsa,
	  exception_level=el-2
	] u-boot.elf
}
Note: To use pmufw_image in HSM flow, add [pmufw_image] pmufw.elf to the above bif. In similar lines, this should be added in the stage2a bif, where FSBL is encrypted. The rest of the flow remains same.

Stage 0: Generate a hash for SPK

The following is the snippet from the BIF file.

stage0:
{
	[ppkfile]primary.pub
	[spkfile]secondary.pub
}

The following is the Bootgen command:

bootgen -arch zynqmp -image stage0.bif -generate_hashes -w on -log error

Stage 1: Sign the SPK Hash (encrypt the partitions)

The following is a code snippet using OpenSSL to generate the SPK hash:

openssl rsautl -raw -sign -inkey primary0.pem -in secondary.pub.sha384 > secondary.pub.sha384.sig

The output of this command is secondary.pub.sha384.sig.

Stage 2a: Encrypt the FSBL

Encrypt the FSBL using the following snippet in the BIF file.

Stage 2a:
{
	[keysrc_encryption] bbram_red_key

	[
	  bootloader,destination_cpu=a53-0,
	  encryption=aes,
	  aeskeyfile=aes0.nky
	] fsbl.elf
}

The Bootgen command is:

bootgen -arch zynqmp -image stage2a.bif -o fsbl_e.bin -w on -log error

Stage 2b: Encrypt Bitstream

Generate the following BIF file entry:

stage2b:
{
	[
	  encryption=aes,
	  aeskeyfile=aes1.nky,
	  destination_device=pl,
	  pid=1
	] system.bit
}

The Bootgen command is:

bootgen -arch zynqmp -image stage2b.bif -o system_e.bin -w on -log error

Stage 3: Generate Boot Header Hash

Generate the boot header hash using the following BIF file:

stage3:
{
 	[fsbl_config] bh_auth_enable
 	[ppkfile] primary.pub
 	[spkfile] secondary.pub
 	[spksignature]secondary.pub.sha384.sig
 	[bootimage,authentication=rsa]fsbl_e.bin
}

The Bootgen command is:

bootgen -arch zynqmp -image stage3.bif -generate_hashes -w on -log error

Stage 4: Sign Boot Header Hash

Generate the boot header hash with the following OpenSSL command:

openssl rsautl -raw -sign -inkey secondary0.pem -in bootheader.sha384 > bootheader.sha384.sig

Stage 5: Get Partition Hashes

Get partition hashes using the following command in a BIF file:

stage5:
{		
	[ppkfile]primary.pub
	[spkfile]secondary.pub
	[spksignature]secondary.pub.sha384.sig
	[bhsignature]bootheader.sha384.sig 
	[bootimage,authentication=rsa]fsbl_e.bin
	[bootimage,authentication=rsa]system_e.bin
	
	[
	  destination_cpu=a53-0,
	  authentication=rsa,
	  exception_level=el-3,
	  trustzone=secure
	] bl31.elf

	[
	  destination_cpu=a53-0,
	  authentication=rsa,
	  exception_level=el-2
	] u-boot.elf
}

The Bootgen command is:

bootgen -arch zynqmp -image stage5.bif -generate_hashes -w on -log error

Multiple hashes will be generated for a bitstream partition. For more details, see Bitstream Authentication Using External Memory.

The Boot Header hash is also generated from in this stage5; which is different from the one generated in stage3, because the parameter bh_auth_enable is not used in stage5. This can be added in stage5 if needed, but does not have a significant impact because the Boot Header hash generated using stage3 is signed in stage4 and this signature will only be used in the HSM mode flow.

Stage 6: Sign Partition Hashes

Create the following files using OpenSSL:

openssl rsautl -raw -sign -inkey secondary0.pem -in fsbl.elf.0.sha384 > fsbl.elf.0.sha384.sig
openssl rsautl -raw -sign -inkey secondary0.pem -in system.bit.0.sha384 > system.bit.0.sha384.sig
openssl rsautl -raw -sign -inkey secondary0.pem -in system.bit.1.sha384 > system.bit.1.sha384.sig
openssl rsautl -raw -sign -inkey secondary0.pem -in system.bit.2.sha384 > system.bit.2.sha384.sig
openssl rsautl -raw -sign -inkey secondary0.pem -in system.bit.3.sha384 > system.bit.3.sha384.sig
openssl rsautl -raw -sign -inkey secondary0.pem -in u-boot.elf.0.sha384 > u-boot.elf.0.sha384.sig
openssl rsautl -raw -sign -inkey secondary0.pem -in bl31.elf.0.sha384 > bl31.elf.0.sha384.sig
openssl rsautl -raw -sign -inkey secondary0.pem -in bl31.elf.1.sha384 > bl31.elf.1.sha384.sig

Stage 7: Insert Partition Signatures into Authentication Certificate

Stage 7a: Insert the FSBL signature by adding this code to a BIF file:

Stage7a:
{
	[fsbl_config] bh_auth_enable
	[ppkfile] primary.pub
	[spkfile] secondary.pub
	[spksignature]secondary.pub.sha384.sig
	[bhsignature]bootheader.sha384.sig
	[bootimage,authentication=rsa,presign=fsbl.elf.0.sha384.sig]fsbl_e.bin
}
The Bootgen command is as follows:
bootgen -arch zynqmp -image stage7a.bif -o fsbl_e_ac.bin -efuseppkbits 
efuseppkbits.txt -nonbooting -w on -log error

Stage 7b: Insert the bitstream signature by adding the following to the BIF file:

stage7b:
{
	[ppkfile]primary.pub
	[spkfile]secondary.pub
	[spksignature]secondary.pub.sha384.sig
	[bhsignature]bootheader.sha384.sig
	[
	  bootimage,
	  authentication=rsa,
	  presign=system.bit.0.sha384.sig
	] system_e.bin
}

The Bootgen command is:

bootgen -arch zynqmp -image stage7b.bif -o system_e_ac.bin -nonbooting -w on -log error

Stage 7c: Insert the U-Boot signature by adding the following to the BIF file:

stage7c:
{
	[ppkfile] primary.pub
	[spkfile] secondary.pub
	[spksignature]secondary.pub.sha384.sig
	[bhsignature]bootheader.sha384.sig
	[
	  destination_cpu=a53-0,
	  authentication=rsa,
	  exception_level=el-2,
	  presign=u-boot.elf.0.sha384.sig
	] u-boot.elf
}

The Bootgen command is:

bootgen -arch zynqmp -image stage7c.bif -o u-boot_ac.bin -nonbooting -w on -log error

Stage 7d: Insert the ATF signature by entering the following into a BIF file:

stage7d:
{
	[ppkfile] primary.pub
	[spkfile] secondary.pub
	[spksignature]secondary.pub.sha384.sig
	[bhsignature]bootheader.sha384.sig
	[
	  destination_cpu=a53-0,
	  authentication=rsa,
	  exception_level=el-3,
	  trustzone=secure,
	  presign=bl31.elf.0.sha384.sig
	] bl31.elf
}

The Bootgen command is:

bootgen -arch zynqmp -image stage7d.bif -o bl31_ac.bin -nonbooting -w on -log error

Stage 8: Combine Partitions, Get Header Table Hash

Enter the following in a BIF file:

stage8: 
{
	[bootimage]fsbl_e_ac.bin
	[bootimage]system_e_ac.bin
	[bootimage]bl31_ac.bin
	[bootimage]u-boot_ac.bin
}

The Bootgen command is:

bootgen -arch zynqmp -image stage8.bif -generate_hashes -o stage8.bin -w on -log error

Stage 9: Sign Header Table Hash

Generate the following files using OpenSSL:

openssl rsautl -raw -sign -inkey secondary0.pem -in ImageHeaderTable.sha384 > ImageHeaderTable.sha384.sig

Stage 10: Combine Partitions, Insert Header Table Signature

Enter the following in a BIF file:

stage10: 
{
	[headersignature]ImageHeaderTable.sha384.sig
	[bootimage]fsbl_e_ac.bin
	[bootimage]system_e_ac.bin
	[bootimage]bl31_ac.bin
	[bootimage]u-boot_ac.bin
}

The Bootgen command is:

bootgen -arch zynqmp -image stage10.bif -o final.bin -w on -log error
Note: At the moment, there is no support for the HSM mode on Versal devices.

Creating a Versal Device Boot Image using HSM

The following figure provides a diagram of an HSM mode boot image for a Versal device.

Figure 13: 0 to 12 Stage Boot Process
Note: The PMC subsystem includes PLM, PMC_CDO, and topology CDO.

Generating the PDI

Generate the PDI using the standard BIF.

command : bootgen -arch versal -image all.bif -w on -o final_ref.bin -log error
 
 
all:
{
 id_code = 0x04ca8093
 extended_id_code = 0x01
 id = 0x2
 boot_config {bh_auth_enable}
  
 metaheader
 {
  authentication = rsa,
  pskfile = rsa-keys/PSK2.pem,
  sskfile = rsa-keys/SSK2.pem
  encryption = aes,
  keysrc = bbram_red_key,
  aeskeyfile = enc_keys/efuse_red_metaheader_key.nky,
  dpacm_enable
 }
 
 image
 {
  name = pmc_subsys, id = 0x1c000001
  partition
  {
   id = 0x01, type = bootloader,
   authentication = rsa,
   pskfile = rsa-keys/PSK1.pem,
   sskfile = rsa-keys/SSK1.pem,
   encryption = aes,
   keysrc = bbram_red_key,
   aeskeyfile = encr_keys/bbram_red_key.nky,
   dpacm_enable,
   file = images/gen_files/executable.elf
  }
  partition
  {
   id = 0x09, type = pmcdata, load = 0xf2000000,
   aeskeyfile = gen_keys/pmcdata.nky,
   file = images/gen_files/topology_xcvc1902.v1.cdo,
   file = images/gen_files/pmc_data.cdo
  }
 }
  
 image
 {
  name = lpd, id = 0x4210002
  partition
  {
   id = 0x0C, type = cdo,
   authentication = rsa,
   pskfile = rsa-keys/PSK3.pem,
   sskfile = rsa-keys/SSK3.pem,
   encryption = aes,
   keysrc = bbram_red_key,
   aeskeyfile = gen_keys/key1.nky,
   dpacm_enable,
   file = images/gen_files/lpd_data.cdo
  }
  partition
  {
   id = 0x0B, core = psm,
   authentication = rsa,
   pskfile = rsa-keys/PSK1.pem,
   sskfile = rsa-keys/SSK1.pem,
   encryption = aes,
   keysrc = bbram_red_key,
   aeskeyfile = gen_keys/key2.nky,
   dpacm_enable,
   blocks = 8192(20);4096(*),
   file = images/static_files/psm_fw.elf
  }
 }
 
 image
 {
  name = fpd, id = 0x420c003
  partition
  {
   id = 0x08, type = cdo,
   authentication = rsa,
   pskfile = rsa-keys/PSK3.pem,
   sskfile = rsa-keys/SSK3.pem,
   encryption = aes,
   keysrc = bbram_red_key,
   aeskeyfile = gen_keys/key5.nky,
   dpacm_enable,
   file = images/gen_files/fpd_data.cdo
  }
 }
 
 image
 {
  name = ss, id = 0x1c000033
  partition
  {
   id = 0x0D, type = cdo,
   authentication = rsa,
   pskfile = rsa-keys/PSK2.pem,
   sskfile = rsa-keys/SSK2.pem,
   encryption = aes,
   keysrc = bbram_red_key,
   aeskeyfile = gen_keys/key6.nky,
   dpacm_enable,
   file = images/gen_files/subsystem.cdo
  }
 }
}

HSM Mode Steps

Stage 0: Generate SPK Hash
Generate hash for SSK1:
command : bootgen -arch versal -image stage0-SSK1.bif -generate_hashes -w on -log error
 
stage0-SSK1:
{
  spkfile = rsa-keys/SSK1.pub
}
Generate hash for SSK2:
command : bootgen -arch versal -image stage0-SSK2.bif -generate_hashes -w on -log error
 
stage0-SSK2:
{
  spkfile = rsa-keys/SSK2.pub
}
Generate hash for SSK3:
command : bootgen -arch versal -image stage0-SSK3.bif -generate_hashes -w on -log error
 
stage0-SSK3:
{
  spkfile = rsa-keys/SSK3.pub
}
Stage 1: Sign SPK hash
Sign the generated hashes:
openssl rsautl -raw -sign -inkey rsa-keys/PSK1.pem -in SSK1.pub.sha384 > SSK1.pub.sha384.sig
openssl rsautl -raw -sign -inkey rsa-keys/PSK2.pem -in SSK2.pub.sha384 > SSK2.pub.sha384.sig
openssl rsautl -raw -sign -inkey rsa-keys/PSK3.pem -in SSK3.pub.sha384 > SSK3.pub.sha384.sig
Stage 2: Encrypt Individual Partitions
Encrypt partition 1:
command : bootgen -arch versal -image stage2a.bif -o pmc_subsys_e.bin -w on -log error
 
stage2a:
{
 image
 {
  name = pmc_subsys, id = 0x1c000001
  partition
  {
   id = 0x01, type = bootloader,
   encryption=aes,
   keysrc = bbram_red_key,
   aeskeyfile = encr_keys/bbram_red_key.nky,
   dpacm_enable,
   file = images/gen_files/executable.elf
  }
  partition
  {
   id = 0x09, type = pmcdata,
   load = 0xf2000000,
   aeskeyfile = encr_keys/pmcdata.nky,
   file = images/gen_files/topology_xcvc1902.v1.cdo,
   file = images/gen_files/pmc_data.cdo
  }
 }
}
Encrypt partition 2:
command : bootgen -arch versal -image stage2b-1.bif -o lpd_lpd_data_e.bin -w on -log error
 
stage2b-1:
{
 image
 {
  name = lpd, id = 0x4210002
  partition
  {
   id = 0x0C, type = cdo,
   encryption=aes,
   keysrc = bbram_red_key,
   aeskeyfile = encr_keys/key1.nky,
   dpacm_enable,
   file = images/gen_files/lpd_data.cdo
  }
 }
}
Encrypt partition 3:
command : bootgen -arch versal -image stage2b-2.bif -o lpd_psm_fw_e.bin -w on -log error
 
stage2b-2:
{
 image
 {
  name = lpd, id = 0x4210002
  partition
  {
   id = 0x0B, core = psm,
   encryption = aes,
   keysrc = bbram_red_key,
   aeskeyfile = encr_keys/key2.nky,
   dpacm_enable,
   file = images/static_files/psm_fw.elf
  }
 }
}
Encrypt partition 4:
command : bootgen -arch versal -image stage2c.bif -o fpd_e.bin -w on -log error
 
stage2c:
{
 image
 {
  name = fpd, id = 0x420c003
  partition
  {
   id = 0x08, type = cdo,
   encryption=aes,
   keysrc = bbram_red_key,
   aeskeyfile = encr_keys/key5.nky,
   dpacm_enable,
   file = images/gen_files/fpd_data.cdo
  }
 }
}
Stage 3: Generate Boot Header Hash
command : bootgen -arch versal -image stage3.bif -generate_hashes -w on -log error
 
stage3:
{
    image_config {bh_auth_enable}  
    image
    {
      name = pmc_subsys, id = 0x1c000001
      {
        type = bootimage,
        authentication=rsa,
        ppkfile = rsa-keys/PSK1.pub,
        spkfile = rsa-keys/SSK1.pub,
        spksignature = SSK1.pub.sha384.sig,
        file = pmc_subsys_e.bin
      }
    }
}
Stage 4: Sign Boot Header Hash
Sign the generated hashes:
openssl rsautl -raw -sign -inkey rsa-keys/SSK1.pem -in bootheader.sha384 > bootheader.sha384.sig
Stage 5: Generate Partition Hashes
command : bootgen -arch versal -image stage5.bif -generate_hashes -w on -log error
 
stage5:
{
    bhsignature = bootheader.sha384.sig
     
    image
    {
      name = pmc_subsys, id = 0x1c000001
      {
        type = bootimage,
        authentication=rsa,
        ppkfile = rsa-keys/PSK1.pub,
        spkfile = rsa-keys/SSK1.pub,
        spksignature = SSK1.pub.sha384.sig,
        file = pmc_subsys_e.bin
      }
    }
     
    image
    {
     name = lpd, id = 0x4210002
     partition
     {
      type = bootimage,
      authentication = rsa,
      ppkfile = rsa-keys/PSK3.pub,
      spkfile = rsa-keys/SSK3.pub,
      spksignature = SSK3.pub.sha384.sig,
      file = lpd_lpd_data_e.bin
     }
     partition
     {
      type = bootimage,
      authentication = rsa,
      ppkfile = rsa-keys/PSK1.pub,
      spkfile = rsa-keys/SSK1.pub,
      spksignature = SSK1.pub.sha384.sig,
      file = lpd_psm_fw_e.bin
     }
    }  
    
    image
    {
      id = 0x1c000000, name = fpd
      {
        type = bootimage,       
        authentication=rsa,
        ppkfile = rsa-keys/PSK3.pub,
        spkfile = rsa-keys/SSK3.pub,
        spksignature = SSK3.pub.sha384.sig,
        file = fpd_e.bin  
      }
    }
     
    image
    {
     id = 0x1c000033, name = ss
     {
       type = bootimage,
       authentication = rsa,
       ppkfile = rsa-keys/PSK2.pub,
       spkfile = rsa-keys/SSK2.pub,
       spksignature = SSK2.pub.sha384.sig,
       file = subsystem_e.bin
     }
    }
}
Stage 6: Sign Partition Hashes
openssl rsautl -raw -sign -inkey rsa-keys/SSK1.pem -in pmc_subsys_1.0.sha384 > pmc_subsys.0.sha384.sig
 
openssl rsautl -raw -sign -inkey rsa-keys/SSK3.pem -in lpd_12.0.sha384 > lpd.0.sha384.sig
openssl rsautl -raw -sign -inkey rsa-keys/SSK1.pem -in lpd_11.0.sha384 > psm.0.sha384.sig
openssl rsautl -raw -sign -inkey rsa-keys/SSK1.pem -in lpd_11.1.sha384 > psm.1.sha384.sig
openssl rsautl -raw -sign -inkey rsa-keys/SSK1.pem -in lpd_11.2.sha384 > psm.2.sha384.sig
openssl rsautl -raw -sign -inkey rsa-keys/SSK1.pem -in lpd_11.3.sha384 > psm.3.sha384.sig
openssl rsautl -raw -sign -inkey rsa-keys/SSK1.pem -in lpd_11.4.sha384 > psm.4.sha384.sig
 
openssl rsautl -raw -sign -inkey rsa-keys/SSK3.pem -in fpd_8.0.sha384 > fpd_data.cdo.0.sha384.sig
openssl rsautl -raw -sign -inkey rsa-keys/SSK2.pem -in ss_13.0.sha384 > ss.0.sha384.sig
Stage 7: Insert Partition Signatures into Authentication Certificates
Insert partition 1 signature:
command : bootgen -arch versal -image stage7a.bif -o pmc_subsys_e_ac.bin -w on -log error
 
stage7a:
{
    bhsignature = bootheader.sha384.sig
    image_config {bh_auth_enable}
     
    image
    {
      name = pmc_subsys, id = 0x1c000001
      {
        type = bootimage,
        authentication=rsa,
        ppkfile = rsa-keys/PSK1.pub,
        spkfile = rsa-keys/SSK1.pub,
        spksignature = SSK1.pub.sha384.sig,
        presign = pmc_subsys.0.sha384.sig,
        file = pmc_subsys_e.bin
      }
    }
}
Insert partition 2 signature:
command : bootgen -arch versal -image stage7b-1.bif -o lpd_lpd_data_e_ac.bin -w on -log error
 
stage7b-1:
{  
    image
    {
     name = lpd, id = 0x4210002
     partition
     {
      type = bootimage,
      authentication = rsa,
      ppkfile = rsa-keys/PSK3.pub,
      spkfile = rsa-keys/SSK3.pub,
      spksignature = SSK3.pub.sha384.sig,
      presign = lpd.0.sha384.sig,
      file = lpd_lpd_data_e.bin
     }
    }  
}
Insert partition 3 signature:
command : bootgen -arch versal -image stage7b-2.bif -o lpd_psm_fw_e_ac.bin -w on -log error
 
stage7b-2:
{  
    image
    {
     name = lpd, id = 0x4210002
     partition
     {
      type = bootimage,
      authentication = rsa,
      ppkfile = rsa-keys/PSK1.pub,
      spkfile = rsa-keys/SSK1.pub,
      spksignature = SSK1.pub.sha384.sig,
      presign = psm.0.sha384.sig,
      file = lpd_psm_fw_e.bin
     }
    }  
}
Insert partition 4 signature:
command : bootgen -arch versal -image stage7c.bif -o fpd_e_ac.bin.bin -w on -log error
 
stage7c:
{
    image
    {
      id = 0x1c000000, name = fpd
      { type = bootimage,       
        authentication=rsa,
        ppkfile = rsa-keys/PSK3.pub,
        spkfile = rsa-keys/SSK3.pub,
        spksignature = SSK3.pub.sha384.sig,
        presign = fpd_data.cdo.0.sha384.sig,
        file = fpd_e.bin  
      }
    }
}
Insert partition 5 signature:
command : bootgen -arch versal -image stage7d.bif -o subsystem_e_ac.bin -w on -log error
 
stage7d:
{
    image
    {
     id = 0x1c000033, name = ss
     { type = bootimage,
       authentication = rsa,
       ppkfile = rsa-keys/PSK2.pub,
       spkfile = rsa-keys/SSK2.pub,
       spksignature = SSK2.pub.sha384.sig,
       presign = ss.0.sha384.sig,
       file = subsystem_e.bin
     }
    }
}
Stage 8: Generate Image Header Table Hash
command : bootgen -arch versal -image stage8a.bif -generate_hashes -w on -log error
 
stage8:
{
  id_code = 0x04ca8093
  extended_id_code = 0x01
  id = 0x2
     
  metaheader
  {
   authentication = rsa,
   ppkfile = rsa-keys/PSK2.pub,
   spkfile = rsa-keys/SSK2.pub,
   spksignature = SSK2.pub.sha384.sig,
   encryption=aes,
   keysrc = bbram_red_key,
   aeskeyfile = encr_keys/efuse_red_metaheader_key.nky,
   dpacm_enable,
   revoke_id = 0x00000002
  }
 
  image
  {
    {type = bootimage, file = pmc_subsys_e_ac.bin}
  }
   
  image
  {
    {type = bootimage, file = lpd_lpd_data_e_ac.bin}
    {type = bootimage, file = lpd_psm_fw_e_ac.bin}
  }
   
  image
  {
    {type = bootimage, file = fpd_e_ac.bin}
  }
   
  image
  {
    {type = bootimage, file = subsystem_e_ac.bin}
  }
}
Stage 9: Sign Image Header Table Hash
Sign the generated hashes:
openssl rsautl -raw -sign -inkey rsa-keys/SSK2.pem -in imageheadertable.sha384 > imageheadertable.sha384.sig
Stage 10: Generate Meta Header Hash
command : bootgen -arch versal -image stage8b.bif -generate_hashes -w on -log error
 
stage8b:
{
  headersignature = imageheadertable.sha384.sig
  id_code = 0x04ca8093
  extended_id_code = 0x01
  id = 0x2
     
  metaheader
  {
   authentication = rsa,
   ppkfile = rsa-keys/PSK2.pub,
   spkfile = rsa-keys/SSK2.pub,
   spksignature = SSK2.pub.sha384.sig,
   encryption=aes,
   keysrc = bbram_red_key,
   aeskeyfile = encr_keys/efuse_red_metaheader_key.nky,
   dpacm_enable
  }
 
  image
  {
    {type = bootimage, file = pmc_subsys_e_ac.bin}
  }
   
  image
  {
    {type = bootimage, file = lpd_lpd_data_e_ac.bin}
    {type = bootimage, file = lpd_psm_fw_e_ac.bin}
  }
   
  image
  {
    {type = bootimage, file = fpd_e_ac.bin}
  }
   
  image
  {
    {type = bootimage, file = subsystem_e_ac.bin}
  }
}
Stage 11: Sign Meta Header Hash
openssl rsautl -raw -sign -inkey rsa-keys/SSK2.pem -in MetaHeader.sha384 > metaheader.sha384.sig
Stage 12: Combine Partitions and Insert Header Signature
Build the complete PDI:
command : bootgen -arch versal -image stage10.bif -o final.bin -w on -log error
 
stage10:
{
  headersignature = imageheadertable.sha384.sig
  id_code = 0x04ca8093
  extended_id_code = 0x01
  id = 0x2
   
  metaheader
  {
   authentication = rsa,
   ppkfile = rsa-keys/PSK2.pub,
   spkfile = rsa-keys/SSK2.pub
   spksignature = SSK2.pub.sha384.sig,
   presign = metaheader.sha384.sig
   encryption=aes,
   keysrc = bbram_red_key,
   aeskeyfile = encr_keys/efuse_red_metaheader_key.nky,
   dpacm_enable
  }
 
  image
  {
    {type = bootimage, file = pmc_subsys_e_ac.bin}
  }
   
  image
  {
    {type = bootimage, file = lpd_lpd_data_e_ac.bin}
    {type = bootimage, file = lpd_psm_fw_e_ac.bin}
  }
   
  image
  {
    {type = bootimage, file = fpd_e_ac.bin}
  }
   
  image
  {
    {type = bootimage, file = subsystem_e_ac.bin}
  }
}