Trusted Platform Module

From Gentoo Wiki
Jump to:navigation Jump to:search
Resources

The Trusted Platform Module, or TPM for short, is a secure cryptoprocessor that is available on most modern computers. Its purpose is to securely store decryption keys outside of RAM to prevent attackers from reading the keys from the RAM itself.

The two most common versions of the TPM are 1.2 and 2.0. Both versions are supported on Linux, but this article covers TPM 2.0. There are a few ways to use TPM under Linux: storing SSH and GPG keys in the TPM, generating random numbers and/or decrypting LUKS-encrypted drives.

Installation

Kernel

KERNEL Enable support for TPM
Device Drivers --->
    Character devices --->
    [*] TPM Hardware Support --->
        <*/M> TPM HW Random Number Generator support
        <*/M> TPM Interface Specification 1.2 Interface / TPM 2.0 FIFO Interface
        <*/M> TPM 2.0 CRB Interface

USE flags

USE flags for app-crypt/tpm2-tss TCG Trusted Platform Module 2.0 Software Stack

doc Add extra documentation (API, Javadoc, etc). It is recommended to enable per package instead of globally
fapi Enable feature API (requires openssl as crypto backend)
mbedtls Use net-libs/mbedtls as crypto engine
openssl Use dev-libs/openssl as crypto engine
policy Enable policy library (requires openssl as crypto backend)
static-libs Build static versions of dynamic libraries as well
test Enable dependencies and/or preparations necessary to run tests (usually controlled by FEATURES=test but can be toggled independently)

Emerge

root #emerge --ask app-crypt/tpm2-tss

Usage

SSH Private Key

Using a TPM for a private key makes it much harder for an attacker to steal a SSH private key. Filesystem permissions typically protect private keys. Unfortunately, this still means any malicious program running as a user can read related SSH private keys. A TPM stores keys in isolated hardware, in order to use it but not read or copy it.

Emerge

root #emerge --ask app-crypt/tpm2-pkcs11

Configuration

Add the user to the tss group (example uses larry as the user):

root #gpasswd -a larry tss

Then, as the user, create a new primary, token & private key. There is debate about whether it is better to create the private key in software and import it (easier to audit and trust the creation). Or create the private key on the TPM so it never touches the disk. For this example, create the private key via the TPM.

user $tpm2_ptool init
user $tpm2_ptool addtoken --pid=1 --label=ssh --userpin=PasswordRequiredToUsekey --sopin=AdminPasswordForUncommonModifications
user $tpm2_ptool addkey --label=ssh --userpin=PasswordrequiredToUseKey --algorithm=ecc256

RSA and different key sizes are available. Find a complete list in the source.

--userpin can be set to an empty string to mimic the behavior of an SSH key that doesn't have password protection. But leaving it empty means the physical theft of the computer can allow an attacker to use the SSH private key through possession of the TPM alone. Setting a password achieves two factors of authentication, something you have (TPM) and something you know (password).

Reading a public key

To retrieve the public key from the TPM, run:

user $ssh-keygen -D /usr/lib64/pkcs11/libtpm2_pkcs11.so

Next, copy the public key to the authorized_keys file on a remote machine. At this time, ssh-copy-id does not work for this type of key.

Using a key

To use the TPM key for a single SSH connection:

user $ssh -I /usr/lib64/pkcs11/libtpm2_pkcs11.so user@remote.host.tld

To use the TPM key for all SSH connections, add this to a the ssh config:

FILE ~/.ssh/config
PKCS11Provider /usr/lib64/pkcs11/libtpm2_pkcs11.so

For ssh-agent to remember the password for an active session bypassing the need to type it for each connection, run:

user $ssh-add -s /usr/lib64/pkcs11/libtpm2_pkcs11.so

This command is necessary every time the system reboots or the ssh-agent session expires if configured to do so.

Random Number Generation

Using a hardware random number generator gives more entropy to the system and can therefore give faster random numbers. When the TPM drivers compiled in the kernel, there will be a new device named /dev/hwrng. This is the TPM random number generator.

To use it, first, emerge the package sys-apps/rng-tools which will be used to redirect /dev/hwrng into /dev/random.

root #emerge --ask sys-apps/rng-tools

Then, simply start the service. By default, rng-tools looks for /dev/hwrng so it does not need any configuration to work.

root #rc-service rngd start
rngd                 | * Caching service dependencies ...    [ ok ]
rngd                 | * Starting rngd ...                   [ ok ]
root #rc-update add rngd default

Decrypting Root

The TPM can be used to decrypt LUKS drives using programs like Clevis. Clevis supports many methods to encrypt and decrypt data, but this guide will focus on using TPM to decrypt LUKS-encrypted drives.

Warning
Using this method to unlock a root partition means that if the conditions mentioned below are met, the system's root partition will automatically decrypt itself on boot! Without having a secure login/lock screen, or if this does not fit the required threat model, then proceed no further.

When app-crypt/tpm2-tss is installed, tpm2_pcrread will list the PCR values of the TPM. Each number at the beginning of the rows represents a different parameter that is calculated by the TPM chip to check the integrity of the system. If the system's configuration changes (for instance, if secure boot is disabled, if CMOS is reset, or if any UEFI settings are changed), then these values will be different.

root #tpm2_pcrread
  sha1:
  sha256:
    0 : 0x181210f8f9c779c26da1d9b2075bde0127302ee0e3fca38c9a83f5b1dd8e5d3b
    1 : 0xfc68f3b1c9b809ce39d3142d79d18a22df73914008f0378eb23a487f12c895de
    2 : 0x0c47cda934d53d7ca29d822a59531dcf6d36cbd9740a4fd0b867a0343910a715
    3 : 0xcdfba543ee8ef7fdb3d8b587648cc22dd792bbd6272cc5447307c7c106c2374c
    4 : 0x5834860c74b368a6922b8064b557a48518455990c94e56993f04de1ff4803ac9
    5 : 0x121ec7fc388e3fd084f8d46536adc3b2077d866839b5f5dc6248e6790bb3488e
    6 : 0xd928266e89b1da2263838e86df3a430548ca1768bedbc9d4b20f9e370d5518df
    7 : 0xb2caf463818e33587218f354ad3cf0e75a34a6e6124c4e3fddd1c4ef255b7b1f
    8 : 0x0000000000000000000000000000000000000000000000000000000000000000
    9 : 0x0000000000000000000000000000000000000000000000000000000000000000
    10: 0x0000000000000000000000000000000000000000000000000000000000000000
    11: 0x0000000000000000000000000000000000000000000000000000000000000000
    12: 0x0000000000000000000000000000000000000000000000000000000000000000
    13: 0x0000000000000000000000000000000000000000000000000000000000000000
    14: 0x0000000000000000000000000000000000000000000000000000000000000000
    15: 0x0000000000000000000000000000000000000000000000000000000000000000
    16: 0x0000000000000000000000000000000000000000000000000000000000000000
    17: 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
    18: 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
    19: 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
    20: 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
    21: 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
    22: 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
    23: 0x0000000000000000000000000000000000000000000000000000000000000000

This functionally means that TPM can be used to check the integrity of the system at boot, and if it hasn't been tampered with, then it unlocks the root partition without any user input. If on the other hand, the PCR values are different, then the root partition will not be unlocked and will require the passphrase to be entered.

The numbers 0 through 7 are parameters fetched from various parameters of the UEFI:

PCR IDs Definition
PCR Index PCR Usage
0 SRTM, BIOS, Host Platform Extensions, Embedded Options ROMs and PI Drivers
1 Host Platform Configuration
2 UEFI driver and application code
3 UEFI driver and application configuration and data
4 UEFI Boot Manager Code and boot attempts
5 Boot Manager Code configuration and data and GPT partition table
6 Host Platform Manufacturer Specific
7 Secure Boot Policy

For more information on the PCR IDs and their usage, refer to the official Trusted Computing Group's documentation, specifically section 2.3.4, table 1, on page 26.

app-crypt/clevis is available in the GURU repository which can be added with Eselect/Repository.

root #eselect repository enable guru

Then app-crypt/clevis can be emerged:

root #emerge --ask app-crypt/clevis

Adding a TPM LUKS key

First, this guide assumes that a LUKS-encrypted drive already exists and is in a usable state. For more information on this topic, refer to dm-crypt.

Use the cryptsetup luksDump command to list the keys associated to a drive. Keep at least one passphrase in the LUKS header, otherwise if the system configuration changes, access to all data will be lost.

root #cryptsetup luksDump /dev/nvme0n1p3
LUKS header information
Version:       	2
Epoch:         	3
Metadata area: 	16384 [bytes]
Keyslots area: 	16744448 [bytes]
UUID:          	aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee
Label:         	(no label)
Subsystem:     	(no subsystem)
Flags:       	(no flags)

Data segments:
  0: crypt
	offset: 16777216 [bytes]
	length: (whole device)
	cipher: aes-xts-plain64
	sector: 512 [bytes]

Keyslots:
  0: luks2
	Key:        512 bits
	Priority:   normal
	Cipher:     aes-xts-plain64
	Cipher key: 512 bits
	PBKDF:      argon2id
	Time cost:  15
	Memory:     1048576
	Threads:    4
	Salt:       00 11 22 33 44 55 66 77 88 99 00 aa bb cc dd ee 
	           00 11 22 33 44 55 66 77 88 99 00 aa bb cc dd ee
	AF stripes: 4000
	AF hash:    sha256
	Area offset:111111 [bytes]
	Area length:111111 [bytes]
	Digest ID:  0
Tokens:
Digests:
  0: pbkdf2
	Hash:       sha256
	Iterations: 111111
	Salt:       00 11 22 33 44 55 66 77 88 99 00 aa bb cc dd ee
	           00 11 22 33 44 55 66 77 88 99 00 aa bb cc dd ee
	Digest:     00 11 22 33 44 55 66 77 88 99 00 aa bb cc dd ee
	           00 11 22 33 44 55 66 77 88 99 00 aa bb cc dd ee

Now, using clevis, add a key to our LUKS header that will be stored in the TPM:

root #clevis luks bind -d /dev/nvme0n1p3 tpm2 '{"pcr_bank":"sha256","pcr_ids":"0,2,3,5,6,7"}'
Enter existing LUKS password: 
Warning: Value 512 is outside of the allowed entropy range, adjusting it.
Note
Adding too many PCR IDs in the clevis command might do more harm than good : some parameters change often, depending on the system's UEFI, resulting in a system that won't boot without user intervention. 0,2,3,5,6,7 seem to be a good configuration.

Finally, run cryptsetup luksDump again to confirm that the new key has been added to the LUKS header:

root #cryptsetup luksDump /dev/nvme0n1p3
LUKS header information
Version:       	2
Epoch:         	5
Metadata area: 	16384 [bytes]
Keyslots area: 	16744448 [bytes]
UUID:          	af9789b4-39fc-4e3c-aeba-4b9542a5d4e7
Label:         	(no label)
Subsystem:     	(no subsystem)
Flags:       	(no flags)

Data segments:
  0: crypt
	offset: 16777216 [bytes]
	length: (whole device)
	cipher: aes-xts-plain64
	sector: 512 [bytes]

Keyslots:
  0: luks2
	Key:        512 bits
	Priority:   normal
	Cipher:     aes-xts-plain64
	Cipher key: 512 bits
	PBKDF:      argon2id
	Time cost:  15
	Memory:     1048576
	Threads:    4
	Salt:       00 11 22 33 44 55 66 77 88 99 00 aa bb cc dd ee
	           00 11 22 33 44 55 66 77 88 99 00 aa bb cc dd ee
	AF stripes: 4000
	AF hash:    sha256
	Area offset:111111 [bytes]
	Area length:111111 [bytes]
	Digest ID:  0
  1: luks2
	Key:        512 bits
	Priority:   normal
	Cipher:     aes-xts-plain64
	Cipher key: 512 bits
	PBKDF:      argon2id
	Time cost:  16
	Memory:     1048576
	Threads:    4
	Salt:       00 11 22 33 44 55 66 77 88 99 00 aa bb cc dd ee
	           00 11 22 33 44 55 66 77 88 99 00 aa bb cc dd ee
	AF stripes: 4000
	AF hash:    sha256
	Area offset:111111 [bytes]
	Area length:111111 [bytes]
	Digest ID:  0
Tokens:
  0: clevis
	Keyslot:    1
Digests:
  0: pbkdf2
	Hash:       sha256
	Iterations: 111111
	Salt:       00 11 22 33 44 55 66 77 88 99 00 aa bb cc dd ee
	           00 11 22 33 44 55 66 77 88 99 00 aa bb cc dd ee
	Digest:     00 11 22 33 44 55 66 77 88 99 00 aa bb cc dd ee
	           00 11 22 33 44 55 66 77 88 99 00 aa bb cc dd ee

Now, a second keyslot is shown : the one that's been created by clevis.

Rebuilding the initramfs

Dracut

Dracut natively supports clevis. When it's installed, dracut will detected it and automatically add the clevis module to the initramfs. Therefore, this is as simple as running the usual dracut command. You can check the output to confirm it added the clevis module:

root #dracut
...
dracut: *** Including module: clevis ***
dracut: *** Including module: clevis-pin-sss ***
dracut: *** Including module: clevis-pin-tpm2 ***
dracut: *** Including module: crypt ***
dracut: *** Including module: dm ***
...

Once the initramfs is built and deployed, the system is ready to reboot and automatically decrypt the root partition, as long as the system has not been tampered with.

Troubleshooting

pcr-input-file filesize does not match pcr set-list

If the TPM has multiple banks, such as SHA1 and SHA256, clevis will fail to encrypt data when given only the pcr_ids:

root #echo "Super Secret Password" | clevis encrypt tpm2 '{"pcr_ids":"1,7"}' > pass.jwe
ERROR: pcr-input-file filesize does not match pcr set-list
ERROR: Could not build pcr policy
ERROR: Unable to run tpm2_createpolicy

To remedy to this, specify which bank to read the pcr_ids from. For example :

root #echo "Super Secret Password" | clevis encrypt tpm2 '{"pcr_bank":"sha256","pcr_ids":"1,7"}' > pass.jwe

TPM is in DA lockout mode

If the TPM fails to boot and dracut repeatedly logs some errors about being unable to unseal:

WARNING:esys:src/tss2-esys/api/Esys_Unseal.c:295:Esys_Unseal_Finish() Received TPM Error
ERROR:esys:src/tss2-esys/api/Esys_Unreal.c:98:Esys_Unseal_Finish() Received TPM Error
ERROR: Esys_Unseal(0x99D) - tpm:session(1):a policy check failed
ERROR: Unable to run tpm2_unseal
Unsealing jwk from TPM failed!
/dev/nvme0n1p3 could not be opened.
Unable to unlock /dev/nvme0n1p3 (UUID=...)

This means dracut failed to unseal the key for one reason or another (most likely, the PCR IDs returned different values), and the TPM locked itself to prevent tampering. The easiest way to recover from this error is to power off the computer and wait for 10 minutes until the TPM unlocks itself. Another alternative is to reboot on a live CD and rebuild the initramfs without the clevis module, though that may very well take more than 10 minutes.

To avoid this error reoccurring in the future, try to figure out which PCR ID has changed, remove the TPM LUKS key, then add a new one without that ID.

See also

External resources