Changes between Version 31 and Version 32 of venice/secure_boot


Ignore:
Timestamp:
05/03/2024 12:09:55 AM (2 weeks ago)
Author:
Tim Harvey
Comment:

update FDE init script: add support for imx8mn/imx8mp, remove specialized error handling, force partprobe between partitining and using partitions to avoid race conditions, make tpm commands consistent, fix keyphrase in luksFormat, moved tpm init from uboot to linux for clarity

Legend:

Unmodified
Added
Removed
Modified
  • venice/secure_boot

    v31 v32  
    471471#!/bin/sh
    472472
     473set -x # script debugging; show commands
     474set -e # exit on error
     475
    473476# This is to be used by a buildroot minimal rootfs on the target board
    474477# as an init script to:
     
    487490NIC=eth0
    488491INIT=/sbin/init # init of final OS
    489 SERVERIP=<YOUR_SERVER_IP> # serverip for tftp server
     492SERVERIP=172.24.21.238
    490493# Boot firmware support
    491 BOOT_FIRMWARE=http://$SERVERIP/tftpboot/venice/flash.bin
     494BOOT_FIRMWARE=http://$SERVERIP/tftpboot/venice/signed-flash.bin
    492495FIT_IMAGE=http://$SERVERIP/tftpboot/venice/fit.itb
    493496# TPM support
     
    514517done
    515518
    516 error() {
    517         printf "\n\nErro: $@"
    518         while [ 1 ]; do sleep 1; done
    519 }
    520 
    521519user_data() {
    522520        echo "Applying user changes..."
     
    526524                GW74*)
    527525                        mkdir -p /mnt/etc/udev/rules.d
    528                         echo 'SUBSYSTEM=="net", ACTION=="add", DEVPATH=="/devices/platform/soc@0/30800000.bus/30bf0000.ethernet/net/eth*", NAME="en0"' > /mnt/etc/udev/rules.d/70-persistent-net.rules
    529                         echo 'SUBSYSTEM=="net", ACTION=="add", DEVPATH=="/devices/platform/soc@0/30800000.bus/30be0000.ethernet/net/eth*", NAME="en1"' >> /mnt/etc/udev/rules.d/70-persistent-net.rules
     526                        echo 'SUBSYSTEM=="net", ACTION=="add", DEVPATH=="/devices/platform/soc@0/30800000.bus/30bf0000.ethernet/net/e
     527th*", NAME="en0"' > /mnt/etc/udev/rules.d/70-persistent-net.rules
     528                        echo 'SUBSYSTEM=="net", ACTION=="add", DEVPATH=="/devices/platform/soc@0/30800000.bus/30be0000.ethernet/net/e
     529th*", NAME="en1"' >> /mnt/etc/udev/rules.d/70-persistent-net.rules
    530530                        sed -i 's/eth0/en0/' /mnt/etc/network/interfaces
    531531                        ;;
     
    542542        # Create an ext4 file system on the opened LUKS device
    543543        echo "Creating filesystem..."
    544         mkfs.ext4 -q -F -L rootfs /dev/mapper/$NAME || error "mkfs.ext4 failed"
     544        mkfs.ext4 -q -F -L rootfs /dev/mapper/$NAME
    545545
    546546        # Mount the LUKS device to /mnt
    547         mount /dev/mapper/$NAME /mnt || error "mount failed"
     547        mount /dev/mapper/$NAME /mnt
    548548
    549549        for url in $ROOTFS_TARS; do
    550550                echo "Downloading $url..."
    551                 wget -q --show-progress --no-check-certificate -O data $url || error "wget failed"
     551                wget -q --show-progress --no-check-certificate -O data $url
    552552                echo "Extracting..."
    553                 pv data | tar -C /mnt -mxJ --keep-directory-symlink || error "tar extract failed"
     553                pv data | tar -C /mnt -mxJ --keep-directory-symlink
    554554        done
    555555
     
    558558        # Unmount the LUKS device
    559559        echo "Unmounting LUKS device..."
    560         umount /dev/mapper/$NAME || error "umount failed"
     560        umount /dev/mapper/$NAME
    561561}
    562562
     
    569569        # it to the LUKS device.
    570570        echo "Downloading $FILESYSTEM..."
    571         wget -q --show-progress --no-check-certificate -O data $FILESYSTEM || exit 1
     571        wget -q --show-progress --no-check-certificate -O data $FILESYSTEM
    572572        # Extract the MBR
    573573        zcat data | dd of=mbr count=1
     
    579579
    580580        # apply user data
    581         mount /dev/mapper/$NAME /mnt || error "mount failed"
     581        mount /dev/mapper/$NAME /mnt
    582582        user_data
    583         umount /dev/mapper/$NAME || error "umount failed"
     583        umount /dev/mapper/$NAME
    584584}
    585585
     
    587587rootfs3() {
    588588        FILESYSTEM=https://dev.gateworks.com/buildroot/venice/minimal/rootfs.ext2.xz
     589        #FILESYSTEM=https://$SERVERIP/tftpboot/venice/rootfs.ext2.xz
    589590        echo "Downloading $FILESYSTEM..."
    590         wget -q --show-progress --no-check-certificate -O data $FILESYSTEM || exit 1
     591        wget -q --show-progress --no-check-certificate -O data $FILESYSTEM
    591592        # copy the filesystem in P1 to the LUKS device
    592593        echo "Copying..."
     
    594595
    595596        # apply user data
    596         mount /dev/mapper/$NAME /mnt || error "mount failed"
     597        mount /dev/mapper/$NAME /mnt
    597598        user_data
    598         umount /dev/mapper/$NAME || error "umount failed"
     599        umount /dev/mapper/$NAME
    599600}
    600601
     602# provision the flash with secure boot firmware and encrypted rootfs
    601603provision() {
    602         rootfs=${1:-rootfs1}
     604        rootfs=${1:-rootfs1}
    603605
    604606        echo "Provision $DEV via $rootfs..."
     
    609611        esac
    610612
     613        # soc specific customizations
     614        case "$(cat /proc/device-tree/soc@0/compatible | tr \0 \n)" in
     615                *imx8mm*)
     616                        boot0_offset_kb=33
     617                        user_offset_kb=33
     618                        ;;
     619                *imx8mn*|*imx8mp*)
     620                        boot0_offset_kb=0
     621                        user_offset_kb=32
     622                        ;;
     623        esac
     624
    611625        # Mount the /tmp directory as a tmpfs with 75% of the available memory
    612626        mount -t tmpfs /tmp -o size=75%
     
    619633        udhcpc -i $NIC
    620634
    621         [ "$BOOT_FIRMWARE" ] && {
    622                 echo "Writing locked down U-Boot to memory..."
    623                 wget -q --show-progress --no-check-certificate -O data $BOOT_FIRMWARE || exit 1
    624                 # create 4MB boot0 image and flash it
    625                 truncate -s 4M boot-firmware
    626                 dd if=data of=boot-firmware bs=1K seek=33 conv=notrunc # note this seek=0 for imx8mm/imx8mp for boot0/boot1
    627                 # BOOT partitions by default are read-only as they are typically used for sensitive boot firmware. To write to them you must disable force_ro in sysfs
    628                 echo 0 > /sys/class/block/${DEVICE}boot0/force_ro
    629                 # write the flash.bin with proper offset to unlocked BOOTpart
    630                 dd if=boot-firmware of=/dev/${DEVICE}boot0
    631         }
    632 
    633         [ "$FIT_IMAGE" ] && {
     635        [ "$BOOT_FIRMWARE" ] && {
     636                echo "Writing locked down U-Boot to memory..."
     637                wget -q --show-progress --no-check-certificate -O data $BOOT_FIRMWARE
     638                # disable boot0 readonly
     639                echo 0 > /sys/class/block/${DEVICE}boot0/force_ro
     640                # write boot firmware to proper offset
     641                dd if=data of=${DEV}boot0 bs=1K seek=$boot0_offset_kb oflag=sync
     642        }
     643
     644        [ "$FIT_IMAGE" ] && {
    634645                echo "Flashing FIT Image to memory..."
    635                 wget -q --show-progress --no-check-certificate -O data $FIT_IMAGE || exit 1
    636                 # sanity check its not too big for P1_OFFSETMB
    637                 #  - we don't want to automatically choose P1_OFFSETMB as you may want to support
    638                 #    firmware updates and you should allow it to grow and thus choose your slack space
    639                 FIT_SIZEMB=$(($(stat -c '%s' data) / 1024 / 1024))
    640                 [ $FIT_SIZEMB -lt $(($P1_OFFSETMB + 1)) ] || {
    641                         echo "Error: $FIT_IMAGE is too large; adjust P1_OFFSETMB"
    642                         exit 1
    643                 }
     646                wget -q --show-progress --no-check-certificate -O data $FIT_IMAGE
     647                # sanity check its not too big for P1_OFFSETMB
     648                #  - we don't want to automatically choose P1_OFFSETMB as you may want to support
     649                #    firmware updates and you should allow it to grow and thus choose your slack space
     650                FIT_SIZEMB=$(($(stat -c '%s' data) / 1024 / 1024))
     651                [ $FIT_SIZEMB -lt $(($P1_OFFSETMB + 1)) ] || { echo "Error: $FIT_IMAGE is too large; adjust P1_OFFSETMB"; exit 1; }
    644652                # Write fit Image to memory
    645                 dd if=data of=$DEV bs=1M seek=1
    646         }
     653                dd if=data of=$DEV bs=1M seek=1 oflag=sync
     654        }
    647655
    648656        echo "Creating partition table..."
     
    651659        #   - ensure that you do not start your partition data until after your boot firmware
    652660        # Create MBR with a single partition taking up the entire device
    653         printf "$((P1_OFFSETMB*1024*1024/512)),,L,*" | sfdisk -u S $DEV || exit 1
     661        printf "$((P1_OFFSETMB*1024*1024/512)),,L,*" | sfdisk -u S $DEV
     662        # force re-read of partition table now
     663        partprobe $DEV
    654664       
    655665        [ "$TPM" ] && {
     
    657667                echo "Retrieving initial PCR measurement values..."
    658668                # PCR0: boot-firmware
    659                 tpm2 pcrextend 0:sha1=$(sha1sum boot-firmware | cut -d" " -f1)
    660                 # PCR8: partition table and FIT image (kernel, dtb, ramdisk)
     669                dd if=${DEV}boot0 of=data bs=1M count=4
     670                tpm2 pcrextend 0:sha1=$(sha1sum data | cut -d" " -f1)
     671                # PCR8: partition table and FIT image (kernel, dtb, ramdisk)
    661672                dd if=$DEV of=data bs=1M count=$P1_OFFSETMB
    662673                tpm2 pcrextend 8:sha1=$(sha1sum data | cut -d" " -f1)
     674                # show PCR's
     675                tpm2 pcrread
    663676
    664677                echo "Creating Key from TPM2.0..."
    665                 tpm2_evictcontrol -C o -c $KEY_HANDLE # delete any existing key
    666                 tpm2_createpolicy --policy-pcr -l sha1:0,8 -L policy.digest #only sha1 works for our current TPM's PCRs
    667                 tpm2_createprimary -g sha256 -G rsa -c primary.context
    668                 tpm2_create -g sha256 -u obj.pub -r obj.priv -C primary.context -L policy.digest -a "noda|adminwithpolicy|fixedparent|fixedtpm" -i $KEY
    669                 tpm2_load -C primary.context -u obj.pub -r obj.priv -c load.context
    670                 tpm2_evictcontrol -C o -c load.context $KEY_HANDLE # save key to TPM handle
    671                 rm -rf policy.digest primary.context obj.pub obj.priv load.context
     678                hexdump -C $KEY # if debugging
     679                # delete any existing key
     680                tpm2 evictcontrol -C o -c $KEY_HANDLE
     681                # create a policy that depends on PCR0 and PCR8
     682                tpm2 createpolicy --policy-pcr -l sha1:0,8 -L policy.digest
     683                tpm2 createprimary -g sha256 -G rsa -c primary.context
     684                # create an object containing the key
     685                tpm2 create -g sha256 -u obj.pub -r obj.priv -C primary.context -L policy.digest -a "noda|adminwithpolicy|fixedparent
     686|fixedtpm" -i $KEY
     687                # load it
     688                tpm2 load -C primary.context -u obj.pub -r obj.priv -c load.context
     689                # save it to TPM handle
     690                tpm2 evictcontrol -C o -c load.context $KEY_HANDLE
     691                rm -f policy.digest primary.context obj.pub obj.priv load.context
    672692        }
    673693
    674694        # Format the partition as a LUKS encrypted file system using the encryption key
    675695        echo "Formating LUKS device..."
    676         echo "YES" | cryptsetup luksFormat ${DEV}${PART} $KEY - || exit 1
     696        cryptsetup --batch-mode luksFormat ${DEV}${PART} --key-file=$KEY
    677697
    678698        # Open the LUKS encrypted partition and map it to the specified name ($NAME)
    679699        echo "Opening LUKS device..."
    680         cryptsetup luksOpen ${DEV}${PART} $NAME --key-file=$KEY || exit 1
     700        cryptsetup luksOpen ${DEV}${PART} $NAME --key-file=$KEY
    681701
    682702        # call rootfs option
     
    685705        # Close the LUKS device and remove the mapping
    686706        echo "Closing LUKS device..."
    687         cryptsetup luksClose $NAME || exit 1
     707        cryptsetup luksClose $NAME
    688708
    689709        echo "Provisioning complete"
     710        sleep 2
    690711
    691712        # Wait forever
     
    696717}
    697718
     719# boot to encrypted fs
     720boot() {
     721        echo "Using $DEV..."
     722
     723        # Wait for device to exist
     724        echo "Waiting for $DEV..."
     725        while [ ! -b "$DEV" ]; do
     726                sleep 1
     727                echo -n .
     728        done
     729
     730        # Open the LUKS encrypted partition and map it to the specified name ($NAME)
     731        [ "$TPM" ] && {
     732                echo "Fetching Key from TPM..."   
     733                KEY=fs.keyphrase_decrypted
     734                # PCR0: boot-firmware
     735                dd if=${DEV}boot0 of=data bs=1M count=4
     736                tpm2 pcrextend 0:sha1=$(sha1sum data | cut -d" " -f1)
     737                # PCR8: partition table and FIT image (kernel, dtb, ramdisk)
     738                dd if=$DEV of=data bs=1M count=$P1_OFFSETMB
     739                tpm2 pcrextend 8:sha1=$(sha1sum data | cut -d" " -f1)
     740                # show PCR's
     741                tpm2 pcrread
     742                # unseal our key
     743                tpm2 unseal -c $KEY_HANDLE -p pcr:sha1:0,8 -o $KEY
     744                hexdump -C $KEY # if debugging
     745        }
     746
     747        DEV=${DEV}${PART}
     748        echo "Opening $DEV..."
     749        cryptsetup luksOpen $DEV $NAME --key-file=$KEY
     750
     751        [ "$TPM" ] && {
     752                # reseal the key by extending the PCR's
     753                rm -f $KEY
     754                tpm2 pcrextend 0:sha1=0000000000000000000000000000000000000000
     755                tpm2 pcrextend 8:sha1=0000000000000000000000000000000000000000
     756        }
     757
     758        # Mount the LUKS device to /mnt
     759        echo "Mounting $DEV..."
     760        mount /dev/mapper/$NAME /mnt
     761
     762        # Switch to the new root and execute init
     763        echo "Switching to new root and running $INIT $@..."
     764        cd /mnt
     765        [ -c dev/console ] || mknod -m 600 dev/console c 5 1
     766        exec switch_root . "$INIT" "$@"
     767
     768        # This will only be run if the above line failed
     769        echo "Failed to switch_root"
     770}
     771
     772# boot straight to ramdisk (no disk encryption)
     773bypass() {
     774        echo "Booting straight to ramdisk..."
     775        umount /proc
     776        umount /sys
     777        umount /run
     778        if (exec 0</dev/console) 2>/dev/null; then
     779                exec 0</dev/console
     780                exec 1>/dev/console
     781                exec 2>/dev/console
     782        fi
     783        exec /sbin/init "$@"
     784}
     785
    698786for x in $(cat /proc/cmdline); do
    699787        case "$x" in
    700                 bypass)
    701 echo "Booting straight to ramdisk..."
    702 umount /proc
    703 umount /sys
    704 umount /run
    705 if (exec 0</dev/console) 2>/dev/null; then
    706     exec 0</dev/console
    707     exec 1>/dev/console
    708     exec 2>/dev/console
    709 fi
    710 exec /sbin/init "$@"
    711                         ;;
     788                bypass) bypass;;
    712789                provision=*) provision ${x//provision=};;
    713790        esac
    714791done
    715792
    716 echo "Using $DEV..."
    717 
    718 # Wait for device to exist
    719 echo "Waiting for $DEV..."
    720 while [ ! -b "$DEV" ]; do
    721         sleep 1
    722         echo -n .
    723 done
    724 
    725 # Open the LUKS encrypted partition and map it to the specified name ($NAME)
    726 [ "$TPM" ] && {
    727         echo "Fetching Key from TPM..."   
    728         tpm2_unseal -c $KEY_HANDLE -p pcr:sha1:0,8 -o fs.keyphrase_decrypted
    729         KEY=fs.keyphrase_decrypted
    730 }
    731 
    732 DEV=${DEV}${PART}
    733 echo "Opening $DEV..."
    734 cryptsetup luksOpen $DEV $NAME --key-file=$KEY || exit 1
    735 
    736 [ "$TPM" ] && {
    737         # reseal the key by extending the PCR's
    738         rm -rf fs.keyphrase_decrypted
    739         tpm2_pcrextend 0:sha1=0000000000000000000000000000000000000000
    740         tpm2_pcrextend 8:sha1=0000000000000000000000000000000000000000
    741 }
    742 
    743 # Mount the LUKS device to /mnt
    744 echo "Mounting $DEV..."
    745 mount /dev/mapper/$NAME /mnt || exit 1
    746 
    747 # Switch to the new root and execute init
    748 echo "Switching to new root and running $INIT $@..."
    749 cd /mnt
    750 [ -c dev/console ] || mknod -m 600 dev/console c 5 1
    751 exec switch_root . "$INIT" "$@"
    752 
    753 # This will only be run if the above line failed
    754 echo "Failed to switch_root"
     793boot
    755794EOF
    756795}}}
     796 - Make sure you set BOOT_FIRMWARE and FIT_IMAGE URL's at the beginning of the script to where your board can get them on your network
    757797
    758798This init script has the following features:
     
    15141554 - CONFIG_ENV_IS_IN_MMC=n
    15151555* '''''Choose BOOTCOMMAND CONFIG OPTION depending on if you want to use a TPM or not'''''
    1516  - CONFIG_BOOTCOMMAND="tpm2 init && tpm2 startup TPM2_SU_CLEAR && tpm2 self_test full && tpm2 self_test continue && mmc dev 2 1 && mmc read $loadaddr 0 0x2000 && hash sha1 $loadaddr 0x400000 *0x40200000 && md.b 0x40200000 0x20 && tpm2 pcr_extend 0 0x40200000 sha1 && tpm2 pcr_read 0 0x40200000 sha1 && mmc dev 2 0 && mmc read $loadaddr 0x0 0x20000 && hash sha1 $loadaddr 0x4000000 *0x40200000 && md.b 0x40200000 0x20 && tpm2 pcr_extend 8 0x40200000 sha1 && tpm2 pcr_read 8 0x40200000 sha1 && setenv bootargs tpm && mmc dev 2 0 && mmc read 0x40200000 0x800 0x1f800 && bootm 0x40200000" #If you are using a TPM
     1556 - CONFIG_BOOTCOMMAND="setenv bootargs tpm && mmc dev 2 0 && mmc read 0x40200000 0x800 0x1f800 && bootm 0x40200000" # If you are using a TPM
    15171557 - CONFIG_BOOTCOMMAND="setenv bootargs; mmc dev 2 0 && mmc read 0x40200000 0x800 0x1f800 && bootm 0x40200000" # If you are not using the TPM
    15181558