[[PageOutline]] = Trusted Protection Module A Trusted Platform Module (TPM) is a small piece of hardware designed to provide various security functionalities. It offers numerous features, such as storing secrets, ‘measuring’ boot, and may act as an external cryptographic engine. [https://trustedcomputinggroup.org/ The Trusted Computing Group (TCG)] delivers a document called TPM Interface Specifications (TIS) which describes the architecture of such devices and how they are supposed to behave as well as various details around the concepts. Additionally they provide a Library Specification. TPM chips are either compliant with the initial specification or the v2.0+ specification: See [https://en.wikipedia.org/wiki/Trusted_Platform_Module#TPM_1.2_vs_TPM_2.0 TPM v1.2 vs TPM 2.0] for details. Note that the information here is not meant to be a full guide to Trusted Platform Modules - this should be considered a brief overview. See also: - [wiki:venice/secure_boot] - Example showing use of TPM on Venice for secure/measured boot == Microchip ATTPM20P Gateworks has an optional TPM on the Venice and Malibu family SBCs: * Malibu GW8901 * Venice: * GW74xx (revision B+) * GW73xx (revision F+) * GW72xx (revision F+) * GW71xx (revision E+) The TPM used is a Microchip ATTPM20P-H6MA1-10 TPM connected to the SPI bus and is compliant to the Trusted Computing Group (TCG) [https://trustedcomputinggroup.org/ Trusted Platform Module (TPM) Version 2.0] This provides cryptographic support for: - HMAC - AES-128 - SHA-1 - SHA-256 - ECC BN_P256, ECCNIST_P256 - RSA 1024-2048 bit keys - 16KB of user accessible NVM - storage for up to 10x 2048-bit keys [=#pcr] == PCR Values A cryptographic hash (sometimes called a 'digest') is a kind of 'signature' for a set of data. For example the SHA-256 algorithm can be used to generate an almost-unique 256-bit (32-byte) signature (aka 'hash' or 'digest') for a file. Note that this signature/hash/digest is not 'encryption' - it is a one way cryptographic function and is a fixed size for any source of data. Starting from a root of trust (typically the SoC BOOT ROM) each software stage during the boot process is supposed to to some measurements and store them in a safe place. A 'measure' is just a signature/hash/digest of a memory region. This value can be sent to the TPM as a measure which will merge with measurement with the previous ones. The hardware feature used to store and merge these measurements is called Platform Configuration Registers (PCR). At power-up a PCR is set to a known value (typically either 0x00's or 0xff's) and sending a new value to the TPM is called 'extending a PCR' because the chosen register will extend its value with the one received. This way a PCR can only evolve in one direction and never go back unless the platform is reset. Each software stage will be in charge of extending a set of PCRs with digests of the next software stage. Once in Linux for example user software may ask the TPM to deliver its secrects but the only way to get them is having all PCRs matching a known pattern which can only be obtained by extending the PCRs in the right order with the right digets. If the stored PCR values in the TPM do not match the currently booting system PCRs, access will not be granted. For example, someone trying to boot a Ubuntu Live CD would not be able to access the TPM key as the PCRs generated from the original disk and stored in the TPM will not match the newly generated PCRs from the boot CD. PCRs use hashing and thus any new value is concatenated with the old and then hashed. This new hash will replace the old hash. The definition of each specific PCR register can be found online. [=#keys] == TPM Keys A TPM can securely store cryptographic keys that are specific to the host system and provide restricted access to the stored keys and secrets. 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. There are two categories of keys in a TPM: 1. Non-migratable keys; unique keys bound to a specific TPM that can not be migrated outside of the TPM. 2. Migratable keys; keys that are not specific to a TPM and can be migrated outside with he right owner authorization. === Migratable keys 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. 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. 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: * handle 0x1c00002 stores the RSA EK certificate * handle 0x1c0000a stores the ECC EK certificate To see a list of available persistent handles use {{{tpm2_getcap handles-persistent}}} A general flow for loading a key into the TPM: (arguments needed for below commands specific to each application ) {{{#!bash tpm2_createpolicy # Create PCR Policy tpm2_createprimary # Create primary TPM object tpm2_create # Create TPM Object with Secret tpm2_load # Load object into the TPM tpm2_evictcontrol # Make TPM Object Persistant rm files #remove your working files }}} [=#measuredboot] == Measured Boot 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. For example consider the following: * 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) * 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 * 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 Examples: * using a Venice board with a TPM * 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) - via Linux: - store the key {{{#!bash # # config # DEV=/dev/mmcblk2 # emmc on Venice KEY_HANDLE=0x81234567 # TPM2 Owner Persistent Handle Range: 0x81000000 - 0x81800000 KEY=fs.key # a 128 byte key secrect (ie dd if=/dev/urandom of=fs.key bs=1 count=128) # # extend PCRs (measure the boot artifacts) # # PCR0: extend with sha1 hash of emmc boot0:0MB-4MB (boot firmware including env) dd if=${DEV}boot0 of=data bs=1M count=4 tpm2 pcrextend 0:sha1=$(sha1sum data | cut -d" " -f1) # PCR8: extend with sha1 hash of emmc user:0MB-16M (ie partition table and FIT image) dd if=$DEV of=data bs=1M count=16 tpm2 pcrextend 8:sha1=$(sha1sum data | cut -d" " -f1) # show current PCR's tpm2 pcrread # # store key # # evict any existing persistent object at $KEY_HANDLE tpm2 evictcontrol -C o -c $KEY_HANDLE # create a policy that depends on PCR0 and PCR8 tpm2 createpolicy --policy-pcr -l sha1:0,8 -L policy.digest tpm2 createprimary -g sha256 -G rsa -c primary.context # create an object containing the key hexdump -C $KEY # for debugging tpm2 create -g sha256 -u obj.pub -r obj.priv -C primary.context -L policy.digest -a "noda|adminwithpolicy|fixedparent|fixedtpm" -i $KEY # load it tpm2 load -C primary.context -u obj.pub -r obj.priv -c load.context # make it it persistent at $KEY_HANDLE tpm2 evictcontrol -C o -c load.context $KEY_HANDLE # clean up our temporary files rm -f policy.digest primary.context obj.pub obj.priv load.context fs.key }}} - retrieve the key (after a power cycle) {{{#!bash # # config # DEV=/dev/mmcblk2 # emmc on Venice KEY_HANDLE=0x81234567 # TPM2 Owner Persistent Handle Range: 0x81000000 - 0x81800000 KEY=fs.key # the key we will read from the TPM # # extend PCRs (measure the boot artifacts) # # PCR0: extend with sha1 hash of emmc boot0:0MB-4MB (boot firmware including env) dd if=${DEV}boot0 of=data bs=1M count=4 tpm2 pcrextend 0:sha1=$(sha1sum data | cut -d" " -f1) # PCR8: extend with sha1 hash of emmc user:0MB-16M (ie partition table and FIT image) dd if=$DEV of=data bs=1M count=16 tpm2 pcrextend 8:sha1=$(sha1sum data | cut -d" " -f1) # 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) tpm2 pcrread # # get key # # unseal key at $KEY_HANDLE tpm2 unseal -c $KEY_HANDLE -p pcr:sha1:0,8 -o $KEY hexdump -C $KEY # for debugging; should equal the key that was stored # reseal it after use by extending the PCR's so that it can't be stolen if system is later compromised rm -f $KEY tpm2 pcrextend 0:sha1=0000000000000000000000000000000000000000 tpm2 pcrextend 8:sha1=0000000000000000000000000000000000000000 }}} 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: {{{#!bash # initialize the tpm tpm2 init && tpm2 startup TPM2_SU_CLEAR && tpm2 self_test full && tpm2 self_test continue # # extend PCRs (measure the boot artifacts) # # PCR0: extend with sha1 hash of emmc boot0:0MB-4MB (boot firmware including env) mmc dev 2 1 && mmc read $loadaddr 0 0x2000 && hash sha1 $loadaddr $filesize *0x40200000 tpm2 pcr_extend 0 0x40200000 sha1 # PCR8: extend with sha1 hash of emmc user:0MB-16M (ie partition table and FIT image) mmc dev 2 0 && mmc read $loadaddr 0x0 0x8000 && hash sha1 $loadaddr $filesize *0x40200000 tpm2 pcr_extend 8 0x40200000 sha1 # 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) tpm2 pcr_read 0 0x40200000 sha1 tpm2 pcr_read 8 0x40200000 sha1 }}} 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) [=#linux] == Linux === Driver The TIS compliant TPM devices are supported by the TCG SPI Linux driver: * drivers/char/tpm/ (CONFIG_TCG_TIS_CORE, CONFIG_TCG_TIS, CONFIG_TCG_TIS_SPI) This driver provides access via: - /dev/tpm0 - /dev/tpmrm0 === Software Stack A solid [https://github.com/tpm2-software TPM 2.0 software stack is available for Linux]: - [https://github.com/tpm2-software/tpm2-tss tpm2-tss] TPM Software Stack (tss) - [https://github.com/tpm2-software/tpm2-tools tpm2-tools] TPM2 tools based on the tpm2-tss stack - [https://github.com/tpm2-software/tpm2-abrmd tpm2-abrmd] TPM2 Access Broker and Resource Manager Examples: - Install packages {{{#!bash apt install tpm2-tools tpm2-abrmd }}} - Show tpm capabilities/properties: {{{#!bash root@jammy-malibu:~# tpm2_getcap properties-fixed TPM2_PT_FAMILY_INDICATOR: raw: 0x322E3000 value: "2.0" TPM2_PT_LEVEL: raw: 0 TPM2_PT_REVISION: raw: 0x77 value: 1.19 TPM2_PT_DAY_OF_YEAR: raw: 0x42 TPM2_PT_YEAR: raw: 0x7DE TPM2_PT_MANUFACTURER: raw: 0x4D434850 value: "MCHP" TPM2_PT_VENDOR_STRING_1: raw: 0x0 value: "" ..... }}} - Read the PCR Values: {{{#!bash root@jammy-venice:~# tpm2_pcrread sha1: 0 : 0x0000000000000000000000000000000000000000 1 : 0x0000000000000000000000000000000000000000 2 : 0x0000000000000000000000000000000000000000 3 : 0x0000000000000000000000000000000000000000 4 : 0x0000000000000000000000000000000000000000 5 : 0x0000000000000000000000000000000000000000 6 : 0x0000000000000000000000000000000000000000 7 : 0x0000000000000000000000000000000000000000 8 : 0x0000000000000000000000000000000000000000 9 : 0x0000000000000000000000000000000000000000 10: 0x0000000000000000000000000000000000000000 11: 0x0000000000000000000000000000000000000000 12: 0x0000000000000000000000000000000000000000 13: 0x0000000000000000000000000000000000000000 14: 0x0000000000000000000000000000000000000000 15: 0x0000000000000000000000000000000000000000 16: 0x0000000000000000000000000000000000000000 17: 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF 18: 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF 19: 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF 20: 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF 21: 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF 22: 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF 23: 0x0000000000000000000000000000000000000000 sha256: }}} - Clearing the TPM {{{#!bash tpm2_clear }}} - Generate Random Number {{{#!bash tpm2_getrandom --hex 8 }}} Please also read: [wiki:venice/secure_boot Gateworks TPM Wiki when used with Secure Boot] [=#uboot] == U-Boot U-Boot has TPM support as well: * drivers/tpm/tpm2_tis_spi.c (CONFIG_TPM,CONFIG_TPM2_TIS_SPI) Usage Example: {{{#!bash u-boot=> tpm device device 0: tpm@0 v2.0: VendorID 0x1114, DeviceID 0x3205, RevisionID 0x01 [open] u-boot=> tpm info tpm@0 v2.0: VendorID 0x1114, DeviceID 0x3205, RevisionID 0x01 [open] u-boot=> tpm init u-boot=> tpm startup TPM2_SU_CLEAR u-boot=> tpm self_test full u-boot=> tpm self_test continue }}} At this point you can pursue [https://bootlin.com/blog/measured-boot-with-a-tpm-2-0-in-u-boot/ measured boot] byt extending the PCR as needed: {{{#!bash u-boot=> tpm extend 0 $loadaddr # extend PCR 0 using digest loaded to $loadaddr }}} See also: * [https://github.com/Infineon/optiga-tpm-cheatsheet] * [wiki:venice/secure_boot Gateworks TPM Wiki when used with Secure Boot] Seee also: - [https://lwn.net/Articles/571031/ Verified U-Boot] - [https://bootlin.com/blog/measured-boot-with-a-tpm-2-0-in-u-boot/ Measured boot with a TPM 2.0 in U-Boot] == Additional Resources * Gateworks Venice Secure Boot Wiki: [wiki:venice/secure_boot Gateworks TPM Wiki when used with Secure Boot] * Security Considerations for Embedded Designs: https://www.gateworks.com/security-considerations-for-embedded-designs-single-board-computers/ * TPM Specification: https://trustedcomputinggroup.org/resource/pc-client-platform-tpm-profile-ptp-specification/ * Microchip TPM Product Page: https://www.microchip.com/en-us/product/attpm20p * The Web - A lot of examples and information about TPMs are available by searching the web