trusted gptboot preview [patch]

Stefan Grundmann sg2342 at
Wed Mar 25 09:04:39 UTC 2015

hi, the promised minimal howto got a bit longer than planed.

best regards

Stefan Grundmann


SRTM (Static Root Of Trust) FreeBSD boot

* Motivation

 Anti Evil Maid

* Existing SRTM solutions

** TrustedGRUB
 - ported by BSSSD
 - GNU GRUB 1.* based
 - no GPT support
 - insufficient UFS support
 - no easy way to decrypt disk keys with secrets from TPM

 - same limitations as TrustedGRUB plus never ported to FreeBSD

* Deliverables

The attached patch should work on any FreeBSD-10 or FreeBSD-11 amd64 or x86
TPM 1.2 is required.

** sys/boot/i386/tpmbr
 - this is sys/boot/i386/pmbr plus TCG (Trusted Computing Group) support
 - had to sacrifice most of the error messages to make space for
   the TCG_CompactHashLogExtendEvent code
 - the entire 'freebsd-boot' partition is measured (up to 545k)

** sys/boot/i386/tgptboot
 - gptboot(8) extended with parts of loader(8) and TCG support
 - get Key and config data path from TPM
 - read and decrypt the config data from UFS
 - use config data to set kernel environment, load disk keys,
   verify and load kernel + modules (from UFS)
 - boot the kernel

** sbin/tgptbootdata
 - create tgptboot config_data files

* Use Case

For a system that has TPM 1.2 enabled and configured to have a KEY in TPM NVRAM.
The system performs a (legacy) BIOS boot from a GTP disk that has tpmbr as
 bootcode and tgptboot as partcode in the 'freebsd-boot' partition.

 boot sequence, see [TCG] section 3.2:

 1. S-CRTM (Static Core Root of Trust)
   - TPM Startup
   - load and measure BIOS
   - execute BIOS
 2. BIOS
   - measure configuration
   - load and measure PMBR (Protective Master Boot Record)
   - execute PMBR
 3. PMBR
   - locate 'freebsd-boot' partition
   - load and measure 'freebsd-boot' partition (extend PCR9)
   - transfer control to tgptboot
 4. tgptboot
   - select UFS partition (take gptboot(8) attributes into account)
   - get KEY from TPM NVRAM
   - get DATA_PATH from TPM NVRAM
   - read and decrypt DATA at DATA_PATH using KEY
   - set kernel environment (if specified in DATA)
   - load and checksum kernel and modules (path, size and hash in DATA)
   - load disk keys (if specified in DATA)
   - execute kernel

Since each measurement modifies TPM PCRs (Platform Configuration Registers),
the TPM NVRAM index that contains the KEY can not be read if the current PCRs
do not match the PCRs at write time (for the set of PCRs the TPM NVRAM index
 write was sealed under).

If tgptboot can not contiune because of an error, the next GPT UFS partion is
selected (gptboot(8) behaviour).

kernel tpm(4) support is only needed for provisioning.

changes to anything measured into the PCRs included in the TPM NVRAM index write
for the KEY (BIOS update, changes to tpmbr or tgptboot, ...) require

kernel update does not require tpm interaction.

[TCG] TCG PC Client Specific Implementaion Specification
      for Conventional BIOS
      Specification Version 1.21 Errata Revision 1.00
      February 24th, 2012
      For TPM Family 1.2; Level 2

* Setup (step by step tutorial)

SRTM on an ThinkPad X60

** preparations
*** buildsystem
 - FreeBSD-10.1-p8 amd64
 - r280275 in /usr/src
 - results of successfull buildworld and buildkernel (GENERIC) for r280275 in
*** tpm-tools 1.3.8
 - the security/tpm-tools in the ports tree is too old
   (missing nvram write support)
 - get the tpm-tools 1.3.8 port from
 - build packages for tpm-tools and its runtime dependencies

** build deliverables
*** apply 0001-trusted-gptboot-preview.patch to /usr/src

 # cd /usr/src && patch -p0 < path_to/0001_trusted-gptboot-preview.patch

*** build tpmbr

 # make -C sys/boot/i386/tpmbr clean obj
 # make -C sys/boot/i386/tpmbr depend all

*** build tgptboot

 # make -C sys/boot/i386/tgptboot clean obj
 # make -C sys/boot/i386/tgptboot depend all

*** build tgptbootdata

 # make -C sbin/tgptbootdata clean obj
 # make -C sbin/tgptbootdata depend all

** create provisioning USB stick

 - usb stick is da0 in the buildsystem
 - usb stick size is at least 2GB

*** create GPT schema and partitions

 # gpart destroy -F da0
 # gpart create -s GPT da0
 # gpart bootcode -b /usr/obj/usr/src/sys/boot/i386/tpmbr/tpmbr da0
 # gpart add -b 40 -s 384 -t freebsd-boot -l tgptboot -i 1 da0
 # dd if=/dev/zero of=/dev/da0p1
 # gpart bootcode -p /usr/obj/usr/src/sys/boot/i386/tgptboot/tgptboot -i 1 da0
 # gpart add -a 4k -s 131072 -t freebsd-ufs -l bootA -i 2 da0
 # gpart add -a 4k -s 131072 -t freebsd-ufs -l bootB -i 3 da0
 # gpart add -a 4k -s 1G -t freebsd-ufs -l toolRoot -i 4 da0

*** newfs

 # newfs -m 0 -L bootA /dev/gpt/bootA
 # newfs -m 0 -L bootB /dev/gpt/bootB
 # newfs -m 0 -L toolRoot /dev/gpt/toolRoot

*** installworld and kernel in toolRoot

 # mkdir -p /tmp/toolRoot && mount -o noatime /dev/ufs/toolRoot /tmp/toolRoot
 # cd /usr/src
 # make installworld DESTDIR=/tmp/toolRoot
 # make distribution DESTDIR=/tmp/toolRoot
 # make installkernel DESTDIR=/tmp/toolRoot

*** install tpm-tools in toolRoot

 # mkdir -p /tmp/toolRoot/tmp/pkg
 # mount_nullfs -o ro path_to_package_directory /tmp/toolRoot/tmp/pkg
 # pkg -c /tmp/toolRoot add /tmp/pkg/All/tpm-tools-1.3.8.txz
 # umount /tmp/toolRoot/tmp/pkg

 install a the tgptbootdata tool as well
 # cp /usr/obj/usr/src/sbin/tgptbootdata/tgptbootdata /tmp/toolRoot/sbin/

*** fix fstab in toolRoot

 # printf "/dev/ufs/toolRoot\t/\tufs\trw\t1 1\n" > /tmp/toolRoot/etc/fstab

*** install kernel in bootA

 # mkdir -p /tmp/bootA && mount -o noatime /dev/ufs/bootA /tmp/bootA
 # mkdir -p /tmp/bootA/boot/kernel
 # cp /tmp/toolRoot/boot/kernel/kernel /tmp/bootA/boot/kernel

*** create tgptbootdata file in bootA

 there is no key and data_path in the TPM NVRAM yet, we force tgptboot
 to use key and data_file from well known override locations

 # mkdir -p /tmp/bootA/boot/magic

 - existence of /boot/magic/key on UFS boot partition will make
   tgptboot to use the (all zero in this case) key to decrypt the data file
 # dd if=/dev/zero of=/tmp/bootA/boot/magic/key bs=32 count=1

 - existence of /boot/magic/data_force will make tgptboot to use the
   tgptboot data_file at /boot/magic/data
 # touch /tmp/bootA/boot/magic/data_force

 - create minimal tgptbootdata config file:
 # cat >> /tmp/magic_toolRoot.conf << EOF
  {load, [{"/tmp/bootA/boot/kernel/kernel", "/boot/kernel/kernel",""}]},
  {key, []}]}.

 - create the data_file
 # /usr/obj/10.1/usr/src/10.1/sbin/tgptbootdata/tgptbootdata \
   -f /tmp/magic_toolRoot.conf -k /tmp/bootA/boot/magic/key \
   -o /tmp/bootA/boot/magic/data

*** set bootme on bootA

 # gpart set -a bootme -i 2 da0

*** umount file systems, eject usb stic

 # umount /tmp/toolRoot
 # umount /tmp/bootA
 # camcontrol eject da0

** test the provisioning USB stick

 - the USB stick should boot the target system regardless of TPM configuration
   in the ThinkPad BIOS
 - actually the USB stick should boot anything amd64 system that supports
   BIOS legacy boot with GENERIC kernel and empty kernel environment

** setup target system TPM in BIOS

  - poweroff the ThinkPad X66
  - press power button while holding F1 (TPM physical presence indicator in
    Thinkpad BIOS, required to clear TPM) until the BIOS Setup Utility is shown
  - in > Security > Security Chip
    - set 'Security Chip' to 'Active'
    - clear security chip
  - in > Security > Security Chip > Security Reporting Options
    several Reporting Options can be set which will together with the choice
    of PCR set used to seal the KEY determine which changes to BIOS options and
    system configuration will require TPM reprovisioning. selection of
    the right PCR selection is out of scope, we will use only PCR9 in this

** provision target system TPM

  - boot ThinkPad with the provisioning USB stick
  - log in as root

  - start tcsd
  # kldload tpm
  # service tcsd onestart

  - take tpm ownership
  # tpm_takeownership -y -z

  - define NVRAM area for the AES key, read selection PCR 9
  - 0x020002323 is the index tgptboot will use when looking for the KEY
  - the READ_STCLEAR permission will make this nvram index unreadable
    after size 0 read (which is done by tgptboot right before executing the
  # tpm_nvdefine -i 0x020002323 -s 32 -y -r 9 -p "OWNERWRITE|READ_STCLEAR"

  - create AES key and write NV RAM
  # tpm_nvwrite -i 0x020002323 -z -s 32 -d "012345678901234567890123456789012345"

  - define NV RAM area for the tgptboot data file path
  - 0x020004242 is the index tgptboot will use when looking for the data file
  # tpm_nvdefine -i 0x020004242 -s 128 -y -p OWNERWRITE

  - fill the NV RAM area for the tgptboot data file path with zeros
  # tpm_nvwrite -i 0x020004242 -z -s 128 -m 0x00

  - write the path "/boot/x60"
  # tpm_nvwrite -i 0x020004242 -z -d "/boot/x60"

** install kernel, and one modules and tgptboot data file to /dev/gpt/bootB

  # mkdir -p /tmp/bootB
  # mount -o noatime /dev/ufs/bootB /tmp/bootB
  # mkdir -p /tmp/bootB/boot/kernel
  # cp /boot/kernel/kernel /tmp/bootB/boot/kernel/
  # cp /boot/kernel/tpm.ko /tmp/bootB/boot/kernel/

  - create tgptbootdata config file, kern + one module, no disk key, only
     vsf.root.mountfrom in env:
 # cat >> /tmp/tgptbootdata.conf << EOF
  {load, [{"/tmp/bootB/boot/kernel/kernel", "/boot/kernel/kernel",""},
          {"/tmp/bootB/boot/kernel/tmp.ko", "/boot/kernel/tpm.ko",undefined}]}
  {key, []}]}.

 - create the data_file
 # echo -n "012345678901234567890123456789012345" > /tmp/aes.key
 # tgptbootdata/tgptbootdata \
   -f /tmp/tgptbootdata.conf -k /tpm/aes.key \
   -o /tmp/bootB/boot/x60

 - set gptboot(8) attribute bootme to bootB remove it from bootA
 # gpart set -a bootme -i 3 da0
 # gpart unset -a bootme -i 2 da0

** reboot
  target system will now boot using key and path from TPM nvram

-------------- next part --------------
A non-text attachment was scrubbed...
Name: 0001-trusted-gptboot-preview.patch
Type: text/x-diff
Size: 87959 bytes
Desc: not available
URL: <>

More information about the freebsd-hackers mailing list