Changes between Version 30 and Version 31 of venice/secure_boot
- Timestamp:
- 05/02/2024 05:11:12 PM (7 months ago)
Legend:
- Unmodified
- Added
- Removed
- Modified
-
venice/secure_boot
v30 v31 427 427 428 428 This demonstration's main steps for implementing FDE will include: 429 1) Using Buildroot for Ramdisk Creation 430 429 1) Using Buildroot for Ramdisk Creation 431 430 2) Using the Ramdisk for Provisioning and unlocking the storage device via LUKS 432 431 432 We will be using many files here in the process which we will store in a 'blobs' directory we will refer to with an env variable called BLOBS: 433 {{{#!bash 434 export BLOBS=$PWD/blobs 435 mkdir $BLOBS 436 }}} 437 - make sure this is a full path as above to avoid potential problems where we use it 438 439 433 440 === Kernel and DTB 434 We are going to need a kernel and DTB for your board. For this demonstration we will use the kernel and DTB's from the pre-built Gateworks Linux tarball: 435 {{{#!bash 436 mkdir blobs 441 We are going to need a kernel Image, DTB for your board, and kernel modules (the modules are only needed if you are using something requiring modules like the TPM). For this demonstration we will use the the pre-built Gateworks Linux tarball and we will untar the contents of the boot dir (where the kernel Image and DTB's are) and the modules dir where the kernel modules are. We will place these in the $BLOBS directory for use later: 442 {{{#!bash 437 443 # grab the prebuilt gateworks kernel 438 444 wget https://dev.gateworks.com/venice/kernel/linux-venice-6.6.8.tar.xz 439 tar -C blobs/ --strip-components=2 -xvf linux-venice-6.6.8.tar.xz ./boot445 tar -C $BLOBS -xvf linux-venice-6.6.8.tar.xz ./boot ./lib/modules 440 446 # gzip the kernel 441 gzip -fk blobs/Image # creates blob/Image.gz447 gzip -fk $BLOBS/boot/Image # creates Image.gz 442 448 }}} 443 449 … … 758 764 759 765 760 ==== Option1: Downloading a prebuilt ramdisk 761 To download the prebuilt root file system and incorporate the needed overlayfiles manually, follow these steps:766 ==== Option1: Downloading a prebuilt ramdisk and modifying 767 To download the prebuilt root file system and incorporate the needed extra files manually, follow these steps: 762 768 763 769 Note: For Gateworks's standard BSP 6.6 Kernel to work seamlessly with the initialization scripts and enable TPM functionality, it's imperative to include the following kernel modules: 764 765 - spi-imx.ko 766 - tpm_tis_spi.ko 767 - virt-dma.ko 768 - imx-sdma.ko 770 - spi-imx.ko 771 - tpm_tis_spi.ko 772 - virt-dma.ko 773 - imx-sdma.ko 774 775 We will get these modules from the pre-built kernel that you downloaded and extracted to the 'blobs' directory. If you are using a different kernel set the KERNEL directory differently - just understand that the kernel Image version/signature used in the FIT image must match the kernel modules placed in the ramdisk. 776 769 777 Additionally, ensure that the firmware file sdma-imx7d.bin is located in the directory lib/firmware/imx/sdma/. These modules are crucial for proper TPM integration and operation within our secure setup. 770 778 {{{#!bash 771 # download theramdisk779 # download prebuilt ramdisk 772 780 wget https://dev.gateworks.com/buildroot/venice/minimal/rootfs.cpio.xz 773 781 # extract files from an existing gzipped cpio: 774 782 mkdir initrd 775 783 (cd initrd; xz -cd ../rootfs.cpio.xz | fakeroot -s ../initrd.fakeroot cpio -idmv) 776 777 #get all the custom files needed in one spot 778 mkdir overlay 779 cp fs.key init overlay/ 780 781 #utilize a bsp to copy in required kernel modules to be used for tpm in the init script 782 mkdir -p overlay/lib/firmware/imx/sdma/ 783 export VENICE_BSP=/path/to/venice_bsp 784 for i in virt-dma imx-sdma spi-imx tpm_tis_spi; do file=$(find $VENICE_BSP/linux/ -name $i.ko); [ -r "$file" ] && cp $file overlay && echo $file; done 785 wget https://git.kernel.org/pub/scm/linux/kernel/git/firmware/linux-firmware.git/plain/imx/sdma/sdma-imx7d.bin -O overlay/lib/firmware/imx/sdma/sdma-imx7d.bin 786 787 # copy needed files to initrd 788 cp -r overlay/* initrd/ 789 784 # copy the filesystem key and custom init script 785 cp fs.key init initrd/ 786 # copy any required kernel modules matching the kernel you are using (ie modules needed for TPM usage) from the $BLOBS dir we discussed earlier: 787 for i in virt-dma imx-sdma spi-imx tpm_tis_spi; do file=$(find $BLOBS -name $i.ko); [ -r "$file" ] && cp $file initrd && echo $file; done 788 # copy any required firmware files needed (ie SDMA used for SPI) 789 mkdir -p initrd/lib/firmware/imx/sdma/ 790 wget https://git.kernel.org/pub/scm/linux/kernel/git/firmware/linux-firmware.git/plain/imx/sdma/sdma-imx7d.bin -O initrd/lib/firmware/imx/sdma/sdma-imx7d.bin 790 791 # re-create initrd 791 792 (cd initrd; find | fakeroot -i ../initrd.fakeroot cpio -o -H newc | xz --check=crc32 -c > ../rootfs.cpio.xz) 792 }}} 793 This will produce the desired rootfs.cpio.xz artifact. 794 {{{#!bash 795 #copy it over to your tftp server (under the venice sub-dir) 796 cp rootfs.cpio.xz /tftpserver/venice 793 # copy it to your blobs directory for use when creating the FIT image 794 cp rootfs.cpio.xz $BLOBS 797 795 }}} 798 796 … … 821 819 - Buildroot's make command generates multiple artifacts, however, our focus is solely on the rootfs.cpio.xz file it produces 822 820 {{{#!bash 823 # make the custom filesystem821 # beging with the example venice defconfig 824 822 make venice_example_defconfig 825 823 make 826 }}} 827 828 This will produce output/images/rootfs.cpio.xz which we will copy to our blobs directory for safe keeping: 829 {{{#!bash 830 cp output/images/rootfs.cpio.xz blobs/ 824 # copy the cpio image to your blobs directory for use when creating the FIT image 825 cp output/images/rootfs.cpio.xz $BLOBS 831 826 }}} 832 827 … … 880 875 - copy the kernel Image, your dtb, and your rootfs.cpio.xz ramdisk to your tftp server venice directory 881 876 {{{#!bash 882 cp blobs/imx8mm-venice-gw73xx-0x.dtb blobs/Image blobs/rootfs.cpio.xz /tftpboot/venice/877 cp $BLOBS/boot/imx8mm-venice-gw73xx-0x.dtb $BLOBS/boot/Image $BLOBS/rootfs.cpio.xz /tftpboot/venice/ 883 878 }}} 884 879 - target; boot them via tftp … … 953 948 To create a new public/private 2048 bit key pair: 954 949 {{{#!bash 955 # on host machine 950 # on host machine create fit.key (or copy one here) 956 951 openssl genpkey -algorithm RSA -out fit.key -pkeyopt rsa_keygen_bits:2048 -pkeyopt rsa_keygen_pubexp:65537 957 # to create a certificate for this containing the public key:952 # create a certificate fit.crt from fit.key containing the public key 958 953 openssl req -batch -new -x509 -key fit.key -out fit.crt 959 954 # you can see the public key: … … 973 968 kernel { 974 969 description = "Linux Kernel"; 975 data = /incbin/(" blobs/Image.gz");970 data = /incbin/("$BLOBS/boot/Image.gz"); 976 971 type = "kernel"; 977 972 arch = "arm64"; … … 986 981 ramdisk { 987 982 description = "ramdisk"; 988 data = /incbin/(" blobs/rootfs.cpio.xz");983 data = /incbin/("$BLOBS/rootfs.cpio.xz"); 989 984 type = "ramdisk"; 990 985 arch = "arm64"; … … 998 993 fdt { 999 994 description = "fdt"; 1000 data = /incbin/(" blobs/imx8mm-venice-gw73xx-0x.dtb");995 data = /incbin/("$BLOBS/boot/imx8mm-venice-gw73xx-0x.dtb"); 1001 996 type = "flat_dt"; 1002 997 arch = "arm64"; … … 1028 1023 At this point we have a key (fit.key, fit.crt) and a template to create the FIT image from (fit.its). Note that we have elected above to use a compressed kernel (why not?) so we need to make sure we gzip the kernel to match the 'gzip' property value specified in its 'compression' node above. 1029 1024 1030 1031 Now we can now use the U-Boot mkimage tool (from the u-boot-tools package or from the u-boot build dir) to build the Image. We are going to use the '-K <dtb>' option to add a signature for the key into an existing DTB but U-Boot builds its control DTB itself so we will create a dummy DTB to put the key in then decompile it: 1032 {{{#!bash 1033 # create a dummy its file 1034 cat <<EOF> blobs/signature.dts 1035 /dts-v1/; 1036 1037 / { 1038 }; 1039 EOF 1040 # compile the dts to a dtb with device-tree compiler 1041 dtc -I dts -O dtb blobs/signature.dts > blobs/signature.dtb 1025 Now we can now use the U-Boot mkimage tool (from the u-boot-tools package or from the u-boot build dir) to build the Image to do two things: 1026 1. create a signed FIT image (fit.itb) 1027 2. store the signature in a 'signature.dtb' file (the '-K <dtb>' parameter) which we can decompile to obtain the signature node we need to put in our secure boot loader 1028 1029 Procedure: 1030 {{{#!bash 1031 # create a signature.dtb for 'mkimage -K <dtb>' to modify 1032 printf "/dts-v1/;\n/ {\n};\n" > signature.dts && dtc -I dts -O dtb signature.dts > signature.dtb 1042 1033 # create the fit image and add the signature to the dtb 1043 mkimage -f fit.its -k . -K blobs/signature.dtb -r fit.itb 1044 # decompile the dummy dtb 1045 dtc -I dtb -O dts blobs/signature.dtb > blobs/signature.dts 1034 mkimage -f fit.its -k . -K signature.dtb -r fit.itb 1046 1035 # now we have a signed fit.itb you can put on your board or tftp 1047 1036 cp fit.itb /tftpboot/venice 1048 }}} 1049 - Note: the -k parameter is the directory that the fit image key resides that is specified by key-name-hint. So for example with key-name-hint "fit" as above; fit.key will be in the directory specified by the -k parameter. 1037 # decompile the signature.dtb to signature.dts 1038 dtc -I dtb -O dts signature.dtb > signature.dts 1039 # then strip the first five lines and the last line out to just obtain the signature node 1040 cat signature.dts | tail -n +5 | head -n -1 > $BLOBS/signature.dts 1041 }}} 1042 - Note: the -k parameter provides the directory to look for the key file specified by key-name-hint. So for example with key-name-hint "fit" as above; fit.key will be in the directory specified by the -k parameter. 1050 1043 1051 1044 Before continuing with securing uboot, a quick check to make sure this fit image boots is a good idea. This step is strictly to help with debugging if there is an issue with your image blobs or an issue with u-boot's build configuration. … … 1056 1049 1057 1050 ==== Getting FIT key into U-Boot proper and verifying signed images 1058 In order for U-boot to validate a signed FIT image it must have access to the key used to sign that image. This is why we created a signature.dt b in the previous step by using ‘mkimage -K’ to ‘inject’ a node into our signature.dtb.1051 In order for U-boot to validate a signed FIT image it must have access to the key used to sign that image. This is why we created a signature.dts in the previous step by using ‘mkimage -K’ to ‘inject’ a node into our signature.dtb then decompiling it to a signature.dts. 1059 1052 1060 1053 Now we need to modify U-Boot to allow it to verify FIT images against that key: … … 1063 1056 - disable CONFIG_LEGACY_IMAGE_FORMAT so that unsigned (or signed images that failed verification!) are not allowed to boot 1064 1057 1065 Procedure: 1058 Procedure: (Note that we require some files from the Venice BSP with an env directory VENICE_BSP pointing to it) 1066 1059 1. Checkout U-Boot (or use your existing U-Boot that you have been working with): 1067 1060 {{{#!bash … … 1072 1065 cp $VENICE_BSP/atf/build/imx8mm/release/bl31.bin . # ATF 1073 1066 }}} 1067 - Note that if you needed to modify the ATF in some way, for example adding OPTEE, copy it from there instead 1074 1068 2. Make sure your environment is configured for cross-compiling: 1075 1069 {{{#!bash 1076 (cd $VENICE_BSP; . ./setup-environment) 1070 pushd .; cd $VENICE_BSP; . ./setup-environment; popd # do not do this in a subshell or the env vars will not be retained 1077 1071 make imx8mm_venice_defconfig 1078 1072 }}} 1079 3. Add the signature node from ../blobs/signature.dts to 'arch/arm/dts/imx8mm-venice-u-boot.dtsi' within the root node. You can position it either directly above or below the 'wdt-reboot' node. The 'imx8mm-venice-u-boot.dtsi' is included with all imx8mm-venice boards, which ensures that the signature node appears in all device tree blobs (dtbs) listed in CONFIG_OF_LIST. Placing it in 'imx8mm-venice-u-boot.dtsi' simplifies the process as there's no need to consider which specific board the user has.1073 3. Add the signature node from $BLOBS/signature.dts to 'arch/arm/dts/imx8mm-venice-u-boot.dtsi' within the root node. You can position it either directly above or below the 'wdt-reboot' node. The 'imx8mm-venice-u-boot.dtsi' is included with all imx8mm-venice boards, which ensures that the signature node appears in all device tree blobs (dtbs) listed in CONFIG_OF_LIST. Placing it in 'imx8mm-venice-u-boot.dtsi' simplifies the process as there's no need to consider which specific board the user has. 1080 1074 4. Use 'make menuconfig' to make the following changes: 1081 1075 - CONFIG_FIT_SIGNATURE=y - enable signature verification of FIT uImages using a hash signed and verified using RSA. 1082 - RSA=y1076 - CONFIG_RSA=y 1083 1077 - CONFIG_LEGACY_IMAGE_FORMAT is undefined - otherwise this allows booting unsigned images or any image if you lack a signature node 1084 1078 {{{#!bash … … 1090 1084 When complete your differences should look like this: 1091 1085 {{{#!bash 1092 $ git diff1086 $ diff configs/imx8mm_venice_defconfig configs/imx8mm_venice_signed_fit_defconfig 1093 1087 diff --git a/arch/arm/dts/imx8mm-venice-u-boot.dtsi b/arch/arm/dts/imx8mm-venice-u-boot.dtsi 1094 1088 index 6f786b9467..1dd642284f 100644 … … 1128 1122 CONFIG_SPL_LOAD_FIT_ADDRESS=0x44000000 1129 1123 CONFIG_OF_BOARD_SETUP=y 1130 1131 }}} 1132 1133 Now build it and update your board (by creating a JTAG image or using the 'update_firmware' script on the resulting flash.bin) 1134 1135 When uboot boots verify that the signature node is in the new controlling fdt: 1124 }}} 1125 - note you won't see CONFIG_RSA=y and CONFIG_LEGACY_IMAGE_FORMAT undefined in your diff because those options are now the default with the above change 1126 1127 Now build it and update the resulting flash.bin to your board (by creating a JTAG image or using the 'update_firmware' script on the resulting flash.bin): 1128 {{{#!bash 1129 make && cp flash.bin /tftpboot/venice/venice-imx8mm-flash.bin 1130 }}} 1131 1132 When you boot your updated firmware verify that the signature node is in the new controlling fdt: 1136 1133 {{{#!bash 1137 1134 u=boot-> fdt addr $fdtcontroladdr && fdt print /signature … … 1231 1228 U-Boot needs a special format for its ramdisk image to ensure proper booting and functionality of the system, and the mkimage command is used to create such images according to U-Boot's requirements. 1232 1229 {{{#!bash 1233 mkimage -A arm64 -T ramdisk -C none -d blobs/rootfs.cpio.xz blobs/uramdisk1230 mkimage -A arm64 -T ramdisk -C none -d $BLOBS/rootfs.cpio.xz $BLOBS/uramdisk 1234 1231 }}} 1235 1232 1. Modify the U-Boot device tree source per SoC (ie arch/arm/dts/imx8mm-u-boot.dtsi) and: … … 1244 1241 1245 1242 uboot-blob { 1246 filename = " blobs/Image";1243 filename = "$BLOBS/boot/Image"; 1247 1244 type = "blob-ext"; 1248 1245 }; … … 1257 1254 1258 1255 uboot-blob { 1259 filename = " blobs/imx8mm-venice-gw73xx-0x.dtb";1256 filename = "$BLOBS/boot/imx8mm-venice-gw73xx-0x.dtb"; 1260 1257 type = "blob-ext"; 1261 1258 }; … … 1270 1267 1271 1268 uboot-blob { 1272 filename = " blobs/uramdisk";1269 filename = "$BLOBS/uramdisk"; 1273 1270 type = "blob-ext"; 1274 1271 }; … … 1278 1275 1. U-Boot needs a special format for its ramdisk image to ensure proper booting and functionality of the system, and the mkimage command is used to create such images according to U-Boot's requirements. 1279 1276 {{{#!bash 1280 mkimage -A arm64 -T ramdisk -C none -d ../blobs/rootfs.cpio.xz ../blobs/uramdisk1277 mkimage -A arm64 -T ramdisk -C none -d $BLOBS/rootfs.cpio.xz $BLOBS/uramdisk 1281 1278 }}} 1282 1279 … … 1300 1297 + 1301 1298 + uboot-blob { 1302 + filename = " ../blobs/Image";1299 + filename = "$BLOBS/Image"; 1303 1300 + type = "blob-ext"; 1304 1301 + }; … … 1313 1310 + 1314 1311 + uboot-blob { 1315 + filename = " ../blobs/imx8mm-venice-gw73xx-0x.dtb";1312 + filename = "$BLOBS/imx8mm-venice-gw73xx-0x.dtb"; 1316 1313 + type = "blob-ext"; 1317 1314 + }; … … 1326 1323 + 1327 1324 + uboot-blob { 1328 + filename = " ../blobs/uramdisk";1325 + filename = "$BLOBS/uramdisk"; 1329 1326 + type = "blob-ext"; 1330 1327 + }; … … 1484 1481 Similarly to the meticulous steps outlined throughout this wiki article, it is essential to confirm the inclusion of the final desired blobs in the FIT Image, while also configuring our end u-boot environment with the specific settings we desire: 1485 1482 1486 For the FIT Image, you must use this rootfs.cpio.xz that we just created above, a standard (built from our BSP) or custom device tree blob specific to the board you are using, and you can use our Gateworks Kernel (built from our BSP) or other custom kernel:1487 {{{#!bash1488 mkdir blobs1489 cp $VENICE_BSP/linux/arch/arm64/boot/Image blobs/1490 cp $VENICE_BSP/linux/arch/arm64/boot/dts/freescale/imx8mm-venice-gw72xx-0x.dtb blobs/1491 cp rootfs.cpio.xz blobs/1492 # gzip the kernel1493 gzip -fk blobs/Image1494 }}}1495 1496 1483 Once you created a fit.itb comprised of these individual blobs by following the steps outlined in the "Generation of Signed FIT Image" section you just need to copy that FIT image to the tftp server you intend to use (same server ip that you define inside the init script). 1497 1484