64 | | ** |
65 | | The hw-rot-private.pem and bdk-sign-private.pem files must be stored in a secure database preferably indexed by board serial number in case you even need to change them. |
66 | | ** |
67 | | |
68 | | [=#dtb] |
69 | | == Adding signature node to DTB for booting signed FIT images |
70 | | To add the kernel, fdt, and ramdisk to the chain of trust you can use a signed fit image (see [wiki:secure_boot#fit]). This requires that the FDT controlling U-Boot have a signature node containing the key data used to verify the FIT image. |
71 | | |
72 | | To accomplish this you must alter your board dtb in the boot firmware FATFS using the method discussed in [wiki:secure_boot#fit]. |
73 | | |
74 | | You can do this using the fatfs-tool which is built by the Newport BSP. For example, if your board is a GW6304 thus uses the gw6304-linux.dtb, your Newport BSP is in /usr/src/newport/bsp, and your FIT key is ~/keys/fit.key |
75 | | {{{#!bash |
76 | | # define vars used in commands below |
77 | | BSP_DIR=/usr/src/newport/bsp |
78 | | DTB=gw6304-linux.dtb |
79 | | KEY_DIR=~/keys |
| 68 | |
| 69 | [=#otp] |
| 70 | == Blowing Fuses to lock a device to use trusted boot |
| 71 | |
| 72 | **Important Note: Once boards have been configured for trusted-mode boot by hard blowing fuses the JTAG chain is disabled and boards can not be re-tested by Gateworks and as a result returns (RMA) will not be accepted. It is recommended that OEM's test board functionality before permanently setting trusted-mode boot fuses.** |
| 73 | |
| 74 | In order to enable trusted boot you must: |
| 75 | * program the ROTPK 256bit hash into OTP |
| 76 | * enable the tz-force bit |
| 77 | * enable the fj-dis bit if you want to disable a fallback to insecure boot firmware if secure boot fails |
| 78 | |
| 79 | The 256bit ROTPK that needs to be used for trusted boot can be found using the following in the Newport BSP directory: |
| 80 | {{{#!bash |
| 81 | ./newport/getkey.py bdk/trust-keys/hw-rot-private.pem |
| 82 | }}} |
| 83 | |
| 84 | Before doing this permanently there is a way to 'soft' blow the fuses where you can perform a warm reset to verify everything boots as expected. |
| 85 | |
| 86 | Gateworks provides an [https://dev.gateworks.com/buildroot/newport/minimal/octeontxotp.c octeontxotp] application on its pre-built buildroot based minimal kernel+ramdisk that can be used for provisioning boards. |
| 87 | |
| 88 | To boot this on a Newport board download the kernel [https://dev.gateworks.com/buildroot/newport/minimal/Image Image] (which contains a ramdisk rootfs) and boot via something like: |
| 89 | {{{#!bash |
| 90 | tftpboot $kernel_addr_r 192.168.1.146:newport/Image.rescue && booti $kernel_addr_r - $fdtcontroladdr |
| 91 | }}} |
| 92 | |
| 93 | This program can be used to blow the fuses necessary to enable trusted boot: |
| 94 | * soft blow (for testing) |
| 95 | {{{#!bash |
| 96 | octeontxotp --rotpk $ROTPK |
| 97 | octeontxotp --tz_force |
| 98 | octeontxotp --fj_dis |
| 99 | i2cset -f -y 0 0x20 0 0 # disable power-cycle on reset |
| 100 | octeontxotp --reset |
| 101 | }}} |
| 102 | - replace $ROTPK above with the value output from './newport/getkey.py bdk/trust-keys/hw-rot-private.pem' in your BSP build directory |
| 103 | - the i2cset command above disables a board power-cycle on CPU reset so that the soft fuses are used |
| 104 | |
| 105 | After the {{{octeontxotp --reset}}} you should see the following which indicates a clean and successful trusted boot: |
| 106 | {{{#!bash |
| 107 | WARNING: |
| 108 | WARNING: ******************************************************** |
| 109 | WARNING: * Configured for soft blow of secure NV counter. This |
| 110 | WARNING: * build is not suitable for production trusted boot. |
| 111 | WARNING: ******************************************************** |
| 112 | WARNING: |
| 113 | |
| 114 | |
| 115 | |
| 116 | Gateworks Newport SPL (12.7.0-7647df8 Wed Sep 4 20:36:41 UTC 2024) |
| 117 | |
| 118 | GSC : v61 0xfa4b RST:VIN Thermal Protection Enabled at board temp of 96C |
| 119 | Temp : Board:29C/96C CPU:56C/95C |
| 120 | Model : GW6905-SP435-A2 |
| 121 | MFGDate : 07-11-2024 |
| 122 | Serial : 448336 |
| 123 | RTC : 51 |
| 124 | SoC : CN8030-1500BG676-AUS-P12-G 1024KB 1500/550MHz 0xa2 Pass 1.2 |
| 125 | MMC1 : not detected |
| 126 | MMC0 : eMMC |
| 127 | Boot : eMMC trusted, Secure Boot |
| 128 | DTB : gw6404.dtb |
| 129 | DRAM : 4096 MB, 2133 MT/s, DDR4 UDIMM |
| 130 | J9 : PCI |
| 131 | J10 : PCI (hwconfig options:PCI,SATA,USB2) |
| 132 | J11 : PCI |
| 133 | QLM0 : PCIE_X1@8000MHz J9 |
| 134 | QLM1 : QSGMII@5000MHz |
| 135 | QLM2 : PCIE_X1@8000MHz J11 |
| 136 | QLM3 : PCIE_X1@8000MHz J10 |
| 137 | Serial : 2x RS232 without flow control |
| 138 | MDIO0 : DP83867 (RGMII) |
| 139 | MDIO1 : VSC8574 (QSGMII) |
| 140 | temp : 29.4C |
| 141 | vdd_bat : 0.000V |
| 142 | fan_tach: 0 RPM |
| 143 | vdd_vin : 17.070V |
| 144 | vdd_5p0 : 5.062V |
| 145 | vdd_3p3 : 3.348V |
| 146 | vdd_2p5 : 2.506V |
| 147 | vdd_core: 0.891V |
| 148 | vdd_0p9 : 0.902V |
| 149 | vdd_1p0 : 0.999V |
| 150 | vdd_1p2 : 1.193V |
| 151 | vdd_1p5 : 1.483V |
| 152 | vdd_an1 : 1.394V |
| 153 | vdd_gsc : 3.162V |
| 154 | NOTICE: Booting Trusted Firmware |
| 155 | NOTICE: BL1: v1.5(release):e1ffc601 (Marvell-12.1.0) |
| 156 | NOTICE: BL1: Built : 20:36:52, Sep 4 2024 |
| 157 | NOTICE: CHIP UniqueID not set |
| 158 | NOTICE: BL1: Booting BL2 |
| 159 | NOTICE: BL2: v1.5(release):e1ffc601 (Marvell-12.1.0) |
| 160 | NOTICE: BL2: Built : 20:37:09, Sep 4 2024 |
| 161 | NOTICE: BL1: Booting BL31 |
| 162 | NOTICE: BL31: v1.5(release):e1ffc601 (Marvell-12.1.0) |
| 163 | NOTICE: BL31: Built : 20:37:17, Sep 4 2024 |
| 164 | |
| 165 | |
| 166 | U-Boot 2021.01-g4ba8e461cc (Sep 04 2024 - 20:37:51 +0000) |
| 167 | |
| 168 | Model: Gateworks Newport CN80XX GW6404 |
| 169 | Board: GW6905-SP435-A2 |
| 170 | DRAM: 4 GiB |
| 171 | WDT: Started with servicing (60s timeout) |
| 172 | MMC: octeontx-mmc0: 0 |
| 173 | Loading Environment from MMC... OK |
| 174 | In: serial@87e028000000 |
| 175 | Out: serial@87e028000000 |
| 176 | Err: serial@87e028000000 |
| 177 | BGX0 QLM1 LMAC2 mode: QSGMII |
| 178 | BGX0 LMACs: 4 |
| 179 | XCV_DLL_CTL: TX_BYP=0 RX_BYP=1 |
| 180 | BGX2 LMAC0 mode: RGMII |
| 181 | BGX2 LMACs: 1 |
| 182 | Net: eth0: vnic0, eth1: vnic1, eth2: vnic2, eth3: vnic3, eth4: vnic4 |
| 183 | Thermal protection:enabled at 96C |
| 184 | Hit any key to stop autoboot: 0 |
| 185 | }}} |
| 186 | |
| 187 | If you use a $ROTPK value that differs from that which was used to build your image you will see no output from the UART as the board does not boot. |
| 188 | |
| 189 | After testing via soft blow above you can now hard blow the fuses (**this is permanent and you will no longer be able to JTAG program or RMA your board**). Repeat the boot to the rescue image and blow the fuses with: |
| 190 | {{{#!bash |
| 191 | octeontxotp --hard --force --rotpk $ROTPK |
| 192 | octeontxotp --hard --force --lock rotpk |
| 193 | octeontxotp --hard --force --tz_force |
| 194 | octeontxotp --hard --force --fj_dis |
| 195 | }}} |
| 196 | - replace $ROTPK above with the value output from './newport/getkey.py bdk/trust-keys/hw-rot-private.pem' in your BSP build directory |
| 197 | |
| 198 | At this point you have trusted boot all the way to the bootloader and can follow-up with a signed FIT image. |
| 199 | |
| 200 | |
| 201 | [=#fit] |
| 202 | == Signed FIT Image (kernel and optional ramdisk) |
| 203 | To add the kernel and an optional ramdisk to the chain of trust you can use a signed FIT image (see [wiki:/secure_boot#fit]). This requires that the FDT controlling U-Boot have a signature node containing the key data used to verify the FIT image. |
| 204 | |
| 205 | For this you need the following: |
| 206 | * A key for your FIT image |
| 207 | * Add a signature node with the key details in the linux dtb used by U-Boot which resides in the FATFS |
| 208 | * Create a FIT image with a kernel, optional ramdisk and optional configuration |
| 209 | |
| 210 | Example Procedure: |
| 211 | 1. Define some env variables used in commands below (altered for your needs): |
| 212 | {{{#!bash |
| 213 | DTB=gw6404-linux.dtb |
| 214 | KEY_DIR=$PWD/bdk/trust-keys/ |
138 | | $BSP_DIR/bin/fatfs-tool -i firmware-newport.img cp $DTB $DTB.sign / |
139 | | }}} |
140 | | |
141 | | |
142 | | [=#otp] |
143 | | == Blowing Fuses to lock a device to use trusted boot |
144 | | |
145 | | **Important Note: Once boards have been configured for trusted-mode boot by hard blowing fuses the JTAG chain is disabled and boards can not be re-tested by Gateworks and as a result returns (RMA) will not be accepted. It is recommended that OEM's test board functionality before permanently setting trusted-mode boot fuses.** |
146 | | |
147 | | In order to enable trusted boot you must: |
148 | | * program the ROTPK 256bit hash into OTP |
149 | | * enable the tz-force bit |
150 | | * enable the fj-dis bit if you want to disable a fallback to insecure boot firmware if secure boot fails |
151 | | |
152 | | The 256bit ROTPK that needs to be used for trusted boot can be found using the following in the Newport BSP directory: |
153 | | {{{#!bash |
154 | | ./newport/getkey.py bdk/trust-keys/hw-rot-private.pem |
155 | | }}} |
156 | | |
157 | | Before doing this permanently there is a way to 'soft' blow the fuses where you can perform a warm reset to verify everything boots as expected. |
158 | | |
159 | | Gateworks provides an octeontxotp application on its pre-built buildroot based minimal kernel+ramdisk that can be used for provisioning boards. This program can be used to blow the fuses necessary to enable trusted boot: |
160 | | * soft blow (for testing) |
161 | | {{{#!bash |
162 | | octeontxotp --rotpk $ROTPK |
163 | | octeontxotp --tz_force |
164 | | octeontxotp --fj_dis |
165 | | i2cset -f -y 0 0x20 0 0 # disable power-cycle on reset |
166 | | octeontxotp --reset |
167 | | }}} |
168 | | * hard blow (after testing via soft blow) **this is permanent and you will no longer be able to JTAG program or RMA your board**) |
169 | | {{{#!bash |
170 | | octeontxotp --hard --force --rotpk $ROTPK |
171 | | octeontxotp --hard --force --lock rotpk |
172 | | octeontxotp --hard --force --tz_force |
173 | | octeontxotp --hard --force --fj_dis |
174 | | }}} |
| 276 | fatfs-tool -i firmware-newport.img cp ./$DTB ./$DTB.sign / |
| 277 | |
| 278 | # copy the FIT image into the FATFS |
| 279 | fatfs-tool -i firmware-newport.img cp fit.itb / |
| 280 | |
| 281 | # create a JTAG binary image |
| 282 | ./mkimage_jtag --soc cn803x --emmc -s --partconf=user firmware-newport.img@user:erase_part:0-32768 > firmware-newport.bin |
| 283 | }}} |
| 284 | - Note placing the FIT image containing the kernel in the FATFS is just one option. You may want to put it someplace dedicated in FLASH due to size or other prefrences. |
| 285 | |
| 286 | Now you can JTAG program the updated firmware-newport.bin and boot it via: |
| 287 | 1. verify the signature node is in the controlling dtb |
| 288 | {{{#!bash |
| 289 | GW6905-SP435-A2> fdt addr $fdtcontroladdr && fdt print /signature |
| 290 | signature { |
| 291 | key-fit { |
| 292 | required = "conf"; |
| 293 | algo = "sha256,rsa2048"; |
| 294 | rsa,r-squared = <0xaf3ca3f0 0x73f28178 0x88f0aee0 0xaa2d9d2d 0xb1f4a926 0xfb94185f 0xf006b370 0xfe24b6f3 0x0f93dc67 0x49638257 0x33d2b04e 0xcf70c6b4 0x3abfda78 0xdbe6a1d7 0xd2a119fa 0x6e2efea8 0x359492a2 0x634dd1bf 0x5e3f1248 0x135cc54a 0x8b92f034 0xdf4b3525 0x99668d2b 0xd1b5c5cf 0xeb5a84a6 0x958edc0f 0x37bca5ee 0xb64b4b56 0x28c7b114 0x2771edde 0xd87b1b68 0x1b2c22d9 0xd44242d9 0xa3f5749d 0xa3ca7b86 0xe31923d7 0x6cf1d2c9 0x685a79f5 0x27576cea 0xa33a4be0 0x3ce85721 0xb8a1b9a1 0xe54acf5b 0x098d2201 0x0b768b19 0x9be17c61 0xb5540e51 0xe9f89f54 0xc6d69841 0x7a4a79f2 0xf9e10893 0x992f120d 0xeb874b8e 0xa1017e7c 0x5f60874a 0xf78d9b6a 0xc6b8b64f 0x4fcad653 0xdaa9f618 0x1ff8e9fc 0x5ee19772 0x5c3c66f0 0x5a006dec 0xddc182ff>; |
| 295 | a6d 0x5a4e6f90 0xe31b9d42 0xcefa7d1f 0x6b757a25 0xcafe13b5 0x3b0eb7ff 0xfc281541 0xd8765ac3 0x5f19110a 0x381aac24 0xaa69c335 0x3aaddfe1 0x48bc4576 0x7c725b55 0x3a006181 0x4439a5d6 0x6a6523f2 0xeff42f8f 0x9f927be6 0xbc88d703 0xd264bc4c 0x1be6fad9 0x24e157e8 0x365f4765 0x7c63c31d 0xac83d338 0x0da0eedb 0xa2102d3a 0xf826be86 0xcd6d5e02 0x6bacb3f3 0xb82f7982 0x8fedc29e 0x81764654 0x6c4a8ce0 0x5d8bfdda 0xcb2b3973 0x8247809e 0x9abdbdd1 0x98155cc1 0x1ac51a84 0xcd6e87b2 0xf1a656e4 0x68b3cc9f 0x655ba517 0x9f6841dd 0x48de6550 0x5869179a 0x84e68b6d 0xeabd5b4c 0x146448ec 0x37d11af4 0x8e715f05>; |
| 296 | rsa,exponent = <0x00000000 0x00010001>; |
| 297 | rsa,n0-inverse = <0xde6a6a33>; |
| 298 | rsa,num-bits = <0x00000800>; |
| 299 | key-name-hint = "fit"; |
| 300 | }; |
| 301 | }; |
| 302 | }}} |
| 303 | 1. Boot the FIT image |
| 304 | {{{#!bash |
| 305 | # boot FIT image |
| 306 | setenv bootargs "root=/dev/mmcblk0p2 rootwait rw" |
| 307 | load mmc 0:1 $loadaddr fit.itb && bootm $loadaddr - $fdtcontroladdr |
| 308 | }}} |
| 309 | |
| 310 | Note that Newport's U-Boot already has the things defined necessary for signed FIT images (CONFIG_FIT_SIGNATURE, CONFIG_RSA, CONFIG_LEGACY_IMAGE_FORMAT) |
| 311 | |
| 312 | You can continue the process of securing your firmware image by locking down U-Boot's environment and using a ramdisk to mount an encrypted filesystem. For detailed examples of that see [wiki:/venice/secure_boot venice/secure_boot] |