46 | | [=#measuredboot] |
47 | | == Measured Boot |
48 | | The concept of measured boot utilizes a TPM to used measured values of boot stages to extend PCR's that are used to lock a secret. The secret can not be revealed unless the PCR values match what was used when the secret was stored and the only way that can happen is if the measurements are the same. So if the measurements used in the PCR's cover each boot phase your secret is secure and can never be pulled from the TPM if access to your device is obtained. |
49 | | |
50 | | For example consider the following: |
51 | | * boot firmware is loaded by an SoC BOOT_ROM and authenticated by fuses and signature (the BOOT_ROM would be the root of trust here) |
52 | | * boot firmware code is measured into a PCR; a hash algorithm can be run on the code itself and the PCR extended with that hash |
53 | | * a key used to unlock/decrypt the root filesystem is locked by that PCR. Once the key is read and used the PCR is extended again which effectively 'seals' the key from being read further down the chain |
54 | | |
55 | | |
56 | | [=#key] |
57 | | == TPM Key Flow |
| 50 | [=#keys] |
| 51 | == TPM Keys |
| 52 | A TPM can securely store cryptographic keys that are specific to the host system and provide restricted access to the stored keys and secrets. |
| 53 | |
| 54 | You can never read out private keys from the TPM once stored but you can sign something and verify a signed object with the private key and verify that against the public key using the TPM. This way your private keys remain secure in the TPM even if the host system is compromised. |
| 55 | |
| 56 | There are two categories of keys in a TPM: |
| 57 | 1. Non-migratable keys; unique keys bound to a specific TPM that can not be migrated outside of the TPM. |
| 58 | 2. Migratable keys; keys that are not specific to a TPM and can be migrated outside with he right owner authorization. |
| 59 | |
| 60 | === Migratable keys |
| 61 | Migratable keys are keys that are not specific to a TPM and can be migrated outside (public and private portion) with the right owner authorization. Primary keys for restricted storage, encryption and signing can be generated from the storage primary seed and can be used to encrypt other non-root keys. |
| 62 | |
| 63 | The {{{tpm2 createprimary}}} command is used to derive primary keys from the seed of corresponding hierarchy and the {{{tpm2 evictcontrol}}} command can make the key persistent. |
| 64 | |
| 65 | NVM is the general pupose memory in a TPM that can be used to store user credentials, user data and certificates. Each area in NVRAM is addressed by a handle/index. There are a few reserved handles as defined in the [https://trustedcomputinggroup.org/wp-content/uploads/RegistryOfReservedTPM2HandlesAndLocalities_v1p1_pub.pdf TCG specification] for accessing the TPM manufacture-installed Endorsement Key (EK) certificates: |
| 66 | * handle 0x1c00002 stores the RSA EK certificate |
| 67 | * handle 0x1c0000a stores the ECC EK certificate |
| 68 | |
| 69 | To see a list of available persistent handles use {{{tpm2_getcap handles-persistent}}} |
| 70 | |
| 82 | [=#measuredboot] |
| 83 | == Measured Boot |
| 84 | The concept of measured boot utilizes a TPM to used measured values of boot stages to extend PCR's that are used to lock a secret. The secret can not be revealed unless the PCR values match what was used when the secret was stored and the only way that can happen is if the measurements are the same. So if the measurements used in the PCR's cover each boot phase your secret is secure and can never be pulled from the TPM if access to your device is obtained. |
| 85 | |
| 86 | For example consider the following: |
| 87 | * boot firmware is loaded by an SoC BOOT_ROM and authenticated by fuses and signature (the BOOT_ROM would be the root of trust here) |
| 88 | * boot firmware code is measured into a PCR; a hash algorithm can be run on the code itself and the PCR extended with that hash |
| 89 | * a key used to unlock/decrypt the root filesystem is locked by that PCR. Once the key is read and used the PCR is extended again which effectively 'seals' the key from being read further down the chain |
| 90 | |
| 91 | Examples: |
| 92 | * using a Venice board with a TPM |
| 93 | * Hide a 128byte secret key in the TPM based on hash of boot firmware and first 64MB of user partition (which could be your partition table and FIT image containing a kernel+dtb+ramdisk used to decrypt a filesystem that starts at 64MB) |
| 94 | - via Linux: |
| 95 | - store the key |
| 96 | {{{#!bash |
| 97 | # |
| 98 | # config |
| 99 | # |
| 100 | DEV=/dev/mmcblk2 # emmc on Venice |
| 101 | KEY_HANDLE=0x81234567 # TPM2 Owner Persistent Handle Range: 0x81000000 - 0x81800000 |
| 102 | KEY=fs.key # a 128 byte key secrect (ie dd if=/dev/urandom of=fs.key bs=1 count=128) |
| 103 | |
| 104 | # |
| 105 | # extend PCRs (measure the boot artifacts) |
| 106 | # |
| 107 | # PCR0: extend with sha1 hash of emmc boot0:0MB-4MB (boot firmware including env) |
| 108 | dd if=${DEV}boot0 of=data bs=1M count=4 |
| 109 | tpm2 pcrextend 0:sha1=$(sha1sum data | cut -d" " -f1) |
| 110 | # PCR8: extend with sha1 hash of emmc user:0MB-16M (ie partition table and FIT image) |
| 111 | dd if=$DEV of=data bs=1M count=16 |
| 112 | tpm2 pcrextend 8:sha1=$(sha1sum data | cut -d" " -f1) |
| 113 | # show current PCR's |
| 114 | tpm2 pcrread |
| 115 | |
| 116 | # |
| 117 | # store key |
| 118 | # |
| 119 | # evict any existing persistent object at $KEY_HANDLE |
| 120 | tpm2 evictcontrol -C o -c $KEY_HANDLE |
| 121 | # create a policy that depends on PCR0 and PCR8 |
| 122 | tpm2 createpolicy --policy-pcr -l sha1:0,8 -L policy.digest |
| 123 | tpm2 createprimary -g sha256 -G rsa -c primary.context |
| 124 | # create an object containing the key |
| 125 | hexdump -C $KEY # for debugging |
| 126 | tpm2 create -g sha256 -u obj.pub -r obj.priv -C primary.context -L policy.digest -a "noda|adminwithpolicy|fixedparent|fixedtpm" -i $KEY |
| 127 | # load it |
| 128 | tpm2 load -C primary.context -u obj.pub -r obj.priv -c load.context |
| 129 | # make it it persistent at $KEY_HANDLE |
| 130 | tpm2 evictcontrol -C o -c load.context $KEY_HANDLE |
| 131 | # clean up our temporary files |
| 132 | rm -f policy.digest primary.context obj.pub obj.priv load.context fs.key |
| 133 | }}} |
| 134 | - retrieve the key (after a power cycle) |
| 135 | {{{#!bash |
| 136 | # |
| 137 | # config |
| 138 | # |
| 139 | DEV=/dev/mmcblk2 # emmc on Venice |
| 140 | KEY_HANDLE=0x81234567 # TPM2 Owner Persistent Handle Range: 0x81000000 - 0x81800000 |
| 141 | KEY=fs.key # the key we will read from the TPM |
| 142 | |
| 143 | # |
| 144 | # extend PCRs (measure the boot artifacts) |
| 145 | # |
| 146 | # PCR0: extend with sha1 hash of emmc boot0:0MB-4MB (boot firmware including env) |
| 147 | dd if=${DEV}boot0 of=data bs=1M count=4 |
| 148 | tpm2 pcrextend 0:sha1=$(sha1sum data | cut -d" " -f1) |
| 149 | # PCR8: extend with sha1 hash of emmc user:0MB-16M (ie partition table and FIT image) |
| 150 | dd if=$DEV of=data bs=1M count=16 |
| 151 | tpm2 pcrextend 8:sha1=$(sha1sum data | cut -d" " -f1) |
| 152 | # show current PCR's (which should equal the values when the key was stored as long as the hashes the PCR's were extended with remain the same) |
| 153 | tpm2 pcrread |
| 154 | |
| 155 | # |
| 156 | # get key |
| 157 | # |
| 158 | # unseal key at $KEY_HANDLE |
| 159 | tpm2 unseal -c $KEY_HANDLE -p pcr:sha1:0,8 -o $KEY |
| 160 | hexdump -C $KEY # for debugging; should equal the key that was stored |
| 161 | # reseal it after use by extending the PCR's so that it can't be stolen if system is later compromised |
| 162 | rm -f $KEY |
| 163 | tpm2 pcrextend 0:sha1=0000000000000000000000000000000000000000 |
| 164 | tpm2 pcrextend 8:sha1=0000000000000000000000000000000000000000 |
| 165 | }}} |
| 166 | |
| 167 | Note that while U-Boot's TPM support is not as full featured as Linux you can still read and extend PCR's in U-Boot thus perform some measurement and verification there as well: |
| 168 | {{{#!bash |
| 169 | # initialize the tpm |
| 170 | tpm2 init && tpm2 startup TPM2_SU_CLEAR && tpm2 self_test full && tpm2 self_test continue |
| 171 | |
| 172 | # |
| 173 | # extend PCRs (measure the boot artifacts) |
| 174 | # |
| 175 | # PCR0: extend with sha1 hash of emmc boot0:0MB-4MB (boot firmware including env) |
| 176 | mmc dev 2 1 && mmc read $loadaddr 0 0x2000 && hash sha1 $loadaddr $filesize *0x40200000 |
| 177 | tpm2 pcr_extend 0 0x40200000 sha1 |
| 178 | # PCR8: extend with sha1 hash of emmc user:0MB-16M (ie partition table and FIT image) |
| 179 | mmc dev 2 0 && mmc read $loadaddr 0x0 0x8000 && hash sha1 $loadaddr $filesize *0x40200000 |
| 180 | tpm2 pcr_extend 8 0x40200000 sha1 |
| 181 | # show current PCR's (which should equal the values when the key was stored as long as the hashes the PCR's were extended with remain the same) |
| 182 | tpm2 pcr_read 0 0x40200000 sha1 |
| 183 | tpm2 pcr_read 8 0x40200000 sha1 |
| 184 | }}} |
| 185 | |
| 186 | note the firmware hashes and thus PCR's will be different (which will keep the key inaccessible) if there are any changes to the hash values used to extend the PCR (meaning any changes to flash/memory areas you hash over) |
| 187 | |
| 188 | |