Changes between Version 30 and Version 31 of venice/secure_boot


Ignore:
Timestamp:
05/02/2024 05:11:12 PM (7 months ago)
Author:
Tim Harvey
Comment:

remove extra directory from ramdisk modification step and make minor changes for clarity

Legend:

Unmodified
Added
Removed
Modified
  • venice/secure_boot

    v30 v31  
    427427
    428428This demonstration's main steps for implementing FDE will include:
    429  1) Using Buildroot for Ramdisk Creation
    430  
     429 1) Using Buildroot for Ramdisk Creation
    431430 2) Using the Ramdisk for Provisioning and unlocking the storage device via LUKS
    432431
     432We 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
     434export BLOBS=$PWD/blobs
     435mkdir $BLOBS
     436}}}
     437 - make sure this is a full path as above to avoid potential problems where we use it
     438
     439
    433440=== 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
     441We 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
    437443# grab the prebuilt gateworks kernel
    438444wget 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 ./boot
     445tar -C $BLOBS -xvf linux-venice-6.6.8.tar.xz ./boot ./lib/modules
    440446# gzip the kernel
    441 gzip -fk blobs/Image # creates blob/Image.gz
     447gzip -fk $BLOBS/boot/Image # creates Image.gz
    442448}}}
    443449
     
    758764
    759765
    760 ==== Option1: Downloading a prebuilt ramdisk
    761 To download the prebuilt root file system and incorporate the needed overlay files manually, follow these steps:
     766==== Option1: Downloading a prebuilt ramdisk and modifying
     767To download the prebuilt root file system and incorporate the needed extra files manually, follow these steps:
    762768
    763769Note: 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
     775We 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
    769777Additionally, 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.
    770778{{{#!bash
    771 #download the ramdisk
     779# download prebuilt ramdisk
    772780wget https://dev.gateworks.com/buildroot/venice/minimal/rootfs.cpio.xz
    773781# extract files from an existing gzipped cpio:
    774782mkdir initrd
    775783(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
     785cp 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:
     787for 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)
     789mkdir -p initrd/lib/firmware/imx/sdma/
     790wget 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
    790791# re-create initrd
    791792(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
     794cp rootfs.cpio.xz $BLOBS
    797795}}}
    798796
     
    821819 - Buildroot's make command generates multiple artifacts, however, our focus is solely on the rootfs.cpio.xz file it produces
    822820{{{#!bash
    823 # make the custom filesystem
     821# beging with the example venice defconfig
    824822make venice_example_defconfig
    825823make
    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
     825cp output/images/rootfs.cpio.xz $BLOBS
    831826}}}
    832827
     
    880875 - copy the kernel Image, your dtb, and your rootfs.cpio.xz ramdisk to your tftp server venice directory
    881876{{{#!bash
    882 cp blobs/imx8mm-venice-gw73xx-0x.dtb blobs/Image blobs/rootfs.cpio.xz /tftpboot/venice/
     877cp $BLOBS/boot/imx8mm-venice-gw73xx-0x.dtb $BLOBS/boot/Image $BLOBS/rootfs.cpio.xz /tftpboot/venice/
    883878}}}
    884879 - target; boot them via tftp
     
    953948To create a new public/private 2048 bit key pair:
    954949{{{#!bash
    955 # on host machine
     950# on host machine create fit.key (or copy one here)
    956951openssl 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
    958953openssl req -batch -new -x509 -key fit.key -out fit.crt
    959954# you can see the public key:
     
    973968                kernel {
    974969                        description = "Linux Kernel";
    975                         data = /incbin/("blobs/Image.gz");
     970                        data = /incbin/("$BLOBS/boot/Image.gz");
    976971                        type = "kernel";
    977972                        arch = "arm64";
     
    986981                ramdisk {
    987982                        description = "ramdisk";
    988                         data = /incbin/("blobs/rootfs.cpio.xz");
     983                        data = /incbin/("$BLOBS/rootfs.cpio.xz");
    989984                        type = "ramdisk";
    990985                        arch = "arm64";
     
    998993                fdt {
    999994                        description = "fdt";
    1000                         data = /incbin/("blobs/imx8mm-venice-gw73xx-0x.dtb");
     995                        data = /incbin/("$BLOBS/boot/imx8mm-venice-gw73xx-0x.dtb");
    1001996                        type = "flat_dt";
    1002997                        arch = "arm64";
     
    10281023At 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.
    10291024
    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
     1025Now 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
     1029Procedure:
     1030{{{#!bash
     1031# create a signature.dtb for 'mkimage -K <dtb>' to modify
     1032printf "/dts-v1/;\n/ {\n};\n" > signature.dts && dtc -I dts -O dtb signature.dts > signature.dtb
    10421033# 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
     1034mkimage -f fit.its -k . -K signature.dtb -r fit.itb
    10461035# now we have a signed fit.itb you can put on your board or tftp
    10471036cp 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
     1038dtc -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
     1040cat 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.
    10501043
    10511044Before 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.
     
    10561049
    10571050==== 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.dtb in the previous step by using ‘mkimage -K’ to ‘inject’ a node into our signature.dtb.
     1051In 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.
    10591052
    10601053Now we need to modify U-Boot to allow it to verify FIT images against that key:
     
    10631056 - disable CONFIG_LEGACY_IMAGE_FORMAT so that unsigned (or signed images that failed verification!) are not allowed to boot
    10641057
    1065 Procedure:
     1058Procedure: (Note that we require some files from the Venice BSP with an env directory VENICE_BSP pointing to it)
    10661059 1. Checkout U-Boot (or use your existing U-Boot that you have been working with):
    10671060{{{#!bash
     
    10721065cp $VENICE_BSP/atf/build/imx8mm/release/bl31.bin . # ATF
    10731066}}}
     1067 - Note that if you needed to modify the ATF in some way, for example adding OPTEE, copy it from there instead
    10741068 2. Make sure your environment is configured for cross-compiling:
    10751069{{{#!bash
    1076 (cd $VENICE_BSP; . ./setup-environment)
     1070pushd .; cd $VENICE_BSP; . ./setup-environment; popd # do not do this in a subshell or the env vars will not be retained
    10771071make imx8mm_venice_defconfig
    10781072}}}
    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.
    10801074 4. Use 'make menuconfig' to make the following changes:
    10811075 - CONFIG_FIT_SIGNATURE=y - enable signature verification of FIT uImages using a hash signed and verified using RSA.
    1082  - RSA=y
     1076 - CONFIG_RSA=y
    10831077 - CONFIG_LEGACY_IMAGE_FORMAT is undefined - otherwise this allows booting unsigned images or any image if you lack a signature node
    10841078{{{#!bash
     
    10901084When complete your differences should look like this:
    10911085{{{#!bash
    1092 $ git diff
     1086$ diff configs/imx8mm_venice_defconfig configs/imx8mm_venice_signed_fit_defconfig
    10931087diff --git a/arch/arm/dts/imx8mm-venice-u-boot.dtsi b/arch/arm/dts/imx8mm-venice-u-boot.dtsi
    10941088index 6f786b9467..1dd642284f 100644
     
    11281122 CONFIG_SPL_LOAD_FIT_ADDRESS=0x44000000
    11291123 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
     1127Now 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
     1129make && cp flash.bin /tftpboot/venice/venice-imx8mm-flash.bin
     1130}}}
     1131
     1132When you boot your updated firmware verify that the signature node is in the new controlling fdt:
    11361133{{{#!bash
    11371134u=boot-> fdt addr $fdtcontroladdr && fdt print /signature
     
    12311228U-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.
    12321229{{{#!bash
    1233 mkimage -A arm64 -T ramdisk -C none -d blobs/rootfs.cpio.xz blobs/uramdisk
     1230mkimage -A arm64 -T ramdisk -C none -d $BLOBS/rootfs.cpio.xz $BLOBS/uramdisk
    12341231}}}
    12351232 1. Modify the U-Boot device tree source per SoC (ie arch/arm/dts/imx8mm-u-boot.dtsi) and:
     
    12441241
    12451242                                        uboot-blob {
    1246                                                 filename = "blobs/Image";
     1243                                                filename = "$BLOBS/boot/Image";
    12471244                                                type = "blob-ext";
    12481245                                        };
     
    12571254
    12581255                                        uboot-blob {
    1259                                                 filename = "blobs/imx8mm-venice-gw73xx-0x.dtb";
     1256                                                filename = "$BLOBS/boot/imx8mm-venice-gw73xx-0x.dtb";
    12601257                                                type = "blob-ext";
    12611258                                        };
     
    12701267
    12711268                                        uboot-blob {
    1272                                                 filename = "blobs/uramdisk";
     1269                                                filename = "$BLOBS/uramdisk";
    12731270                                                type = "blob-ext";
    12741271                                        };
     
    12781275 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.
    12791276{{{#!bash
    1280 mkimage -A arm64 -T ramdisk -C none -d ../blobs/rootfs.cpio.xz ../blobs/uramdisk
     1277mkimage -A arm64 -T ramdisk -C none -d $BLOBS/rootfs.cpio.xz  $BLOBS/uramdisk
    12811278}}}
    12821279
     
    13001297+
    13011298+                                       uboot-blob {
    1302 +                                               filename = "../blobs/Image";
     1299+                                               filename = "$BLOBS/Image";
    13031300+                                               type = "blob-ext";
    13041301+                                       };
     
    13131310+
    13141311+                                       uboot-blob {
    1315 +                                               filename = "../blobs/imx8mm-venice-gw73xx-0x.dtb";
     1312+                                               filename = "$BLOBS/imx8mm-venice-gw73xx-0x.dtb";
    13161313+                                               type = "blob-ext";
    13171314+                                       };
     
    13261323+
    13271324+                                       uboot-blob {
    1328 +                                               filename = "../blobs/uramdisk";
     1325+                                               filename = "$BLOBS/uramdisk";
    13291326+                                               type = "blob-ext";
    13301327+                                       };
     
    14841481Similarly 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:
    14851482
    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 {{{#!bash
    1488 mkdir blobs
    1489 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 kernel
    1493 gzip -fk blobs/Image
    1494 }}}
    1495 
    14961483Once 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).
    14971484