Skip to content

Instantly share code, notes, and snippets.

@kmille
Last active March 16, 2025 08:05
Show Gist options
  • Save kmille/1bc2e4b84adac13f4cc529e9f0b6391a to your computer and use it in GitHub Desktop.
Save kmille/1bc2e4b84adac13f4cc529e9f0b6391a to your computer and use it in GitHub Desktop.
How to use a TPM on Linux

How to use a TPM on Linux

Prerequisites

  • I use it on Arch Linux (systemd 257.3-1)
  • Install dependency: yay tpm2-tools (5.7-1)

Do I have a TPM 2.0?

kmille@linbox:~ journalctl --boot --dmesg --grep=tpm_tis
Mar 05 12:14:27 linbox kernel: tpm_tis MSFT0101:00: 2.0 TPM (device-id 0x0, rev-id 78)

kmille@linbox:~ systemd-analyze has-tpm2
yes
+firmware
+driver
+system
+subsystem
+libraries
  +libtss2-esys.so.0
  +libtss2-rc.so.0
  +libtss2-mu.so.0

kmille@linbox:~ systemd-cryptenroll --tpm2-device=list
PATH        DEVICE      DRIVER 
/dev/tpmrm0 MSFT0101:00 tpm_tis

Show PCR values

  • you can also use the tool tpm2_pcrread
kmille@linbox:~ systemd-analyze pcrs
NR NAME                SHA256                                                          
 0 platform-code       e24699d6713720c6f6b912ed53c24ed8d3b921ab132a4e7ef8599c79935cfdff
 1 platform-config     0bbaeb2077143a79b1e011839528b383b78b6168f9efe680a08d468fa4dc6582
 2 external-code       3d458cfe55cc03ea1f443f1562beec8df51c75e14a9fcf9a7234a13f198e7969
 3 external-config     3d458cfe55cc03ea1f443f1562beec8df51c75e14a9fcf9a7234a13f198e7969
 4 boot-loader-code    6ea1add10c66122467134b64a502208bcc4e9e841dc2455a6cc3e105548965ed
 5 boot-loader-config  610da8f089771da655d219ed30c204a061477e4e153e58569759ca9101d7924a
 6 host-platform       3d458cfe55cc03ea1f443f1562beec8df51c75e14a9fcf9a7234a13f198e7969
 7 secure-boot-policy  915f1e9f770dcb1bbff7c25293be747805f9fddf607310827f2396582267902b
 8 -                   f15076071efe7176235c8c1d4c1c44d1dac19c2878f80d4fd1b4b043678f9e5b
 9 kernel-initrd       70ab0d5401f7275b9280a8fa0e487112f2e2f3cc257cbf8ec41acde854298efa
10 ima                 0000000000000000000000000000000000000000000000000000000000000000
11 kernel-boot         0000000000000000000000000000000000000000000000000000000000000000
12 kernel-config       0000000000000000000000000000000000000000000000000000000000000000
13 sysexts             0000000000000000000000000000000000000000000000000000000000000000
14 shim-policy         0000000000000000000000000000000000000000000000000000000000000000
15 system-identity     0000000000000000000000000000000000000000000000000000000000000000
16 debug               0000000000000000000000000000000000000000000000000000000000000000
17 -                   ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
18 -                   ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
19 -                   ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
20 -                   ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
21 -                   ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
22 -                   ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
23 application-support 0000000000000000000000000000000000000000000000000000000000000000

Create a disk

kmille@linbox:~ fallocate -l 100m disk.raw
kmille@linbox:~ 

Encrypt disk (use an empty password here, it can be removed later)

kmille@linbox:~ sudo cryptsetup luksFormat disk.raw 

WARNING!
========
This will overwrite data on disk.raw irrevocably.

Are you sure? (Type 'yes' in capital letters): YES
Enter passphrase for disk.raw: 
Verify passphrase:


kmille@linbox:~ sudo systemd-cryptenroll disk.raw                                                         
SLOT TYPE    
   0 password

Add TPM

  • --tpm2-device=auto automatically uses the right TPM device (most of the time there is just one)
  • --tpm2-with-pin requires a pin to unlock the device
  • --tpm2-pcrs=1+2+3+4 sets the PCR registers
  • --wipe-slot=empty automatically removes key slot 0 (the one with the empty password)
kmille@linbox:~ sudo systemd-cryptenroll --tpm2-device=auto --tpm2-with-pin=yes --tpm2-pcrs=1+2+3+4 --wipe-slot=empty disk.raw
πŸ” Please enter current passphrase for disk /home/kmille/disk.raw:                         
πŸ” Please enter TPM2 PIN: β€’β€’β€’β€’                    
πŸ” Please enter TPM2 PIN (repeat): β€’β€’β€’β€’                    
New TPM2 token enrolled as key slot 1.
Wiped slot 0.

kmille@linbox:~ sudo systemd-cryptenroll disk.raw                                                                             
SLOT TYPE
   1 tpm2

Add recovery key

kmille@linbox:~ sudo systemd-cryptenroll --unlock-tpm2-device=auto --recovery-key disk.raw 
Automatically discovered security TPM2 token unlocks volume.
πŸ” Please enter TPM2 PIN: β€’β€’β€’β€’                    
A secret recovery key has been generated for this volume:

    πŸ” rhdhclnt-chjudccv-hhtunvnj-cceutteg-cnvdlnlg-njdbrnkv-rlugknnj-nfldvrie

Please save this secret recovery key at a secure location. It may be used to
regain access to the volume if the other configured access credentials have
been lost or forgotten. The recovery key may be entered in place of a password
whenever authentication is requested.

Optionally scan the recovery key for safekeeping:

β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ
β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ
β–ˆβ–ˆβ–ˆβ–ˆ β–„β–„β–„β–„β–„ β–ˆβ–€β–ˆ β–ˆβ–„ β–€β–€ β–€β–„β–„β–„β–„β–ˆβ–„β–ˆβ–ˆ β–„β–„β–„β–„β–„ β–ˆβ–ˆβ–ˆβ–ˆ
β–ˆβ–ˆβ–ˆβ–ˆ β–ˆ   β–ˆ β–ˆβ–€β–€β–€β–ˆ β–€β–€β–ˆβ–ˆβ–€β–€β–€β–„β–„ β–€β–€β–ˆ β–ˆ   β–ˆ β–ˆβ–ˆβ–ˆβ–ˆ
β–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–„β–„β–„β–ˆ β–ˆβ–€ β–ˆβ–€β–€ β–€β–€ β–„β–„β–„β–„β–„β–ˆβ–„ β–ˆ β–ˆβ–„β–„β–„β–ˆ β–ˆβ–ˆβ–ˆβ–ˆ
β–ˆβ–ˆβ–ˆβ–ˆβ–„β–„β–„β–„β–„β–„β–„β–ˆβ–„β–€ β–€β–„β–ˆβ–„β–ˆ β–ˆβ–„β–€ β–€ β–€ β–ˆβ–„β–„β–„β–„β–„β–„β–„β–ˆβ–ˆβ–ˆβ–ˆ
β–ˆβ–ˆβ–ˆβ–ˆ  β–„ β–„β–ˆβ–„ β–„β–„β–€β–„β–€ β–„β–„β–€ β–€ β–€β–€β–„ β–„β–„β–€β–„β–ˆβ–„β–€β–„β–€β–ˆβ–ˆβ–ˆβ–ˆ
β–ˆβ–ˆβ–ˆβ–ˆβ–„β–€ β–„ β–ˆβ–„  β–ˆβ–„β–ˆβ–€β–„β–ˆ  β–„β–€β–ˆβ–€  β–€β–„β–€β–€β–€β–„ β–€β–„β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ
β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–€β–€β–„β–„β–€ β–„β–„β–ˆβ–„ β–ˆβ–„  β–€ β–€β–€  β–„ β–€β–„β–„β–€β–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆ
β–ˆβ–ˆβ–ˆβ–ˆ  β–€β–ˆ β–€β–„ β–ˆβ–ˆβ–€ β–„β–ˆ  β–€β–„ β–ˆβ–€  β–€β–„β–„β–€β–„β–ˆβ–€ β–„β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ
β–ˆβ–ˆβ–ˆβ–ˆβ–„ β–ˆβ–€ β–€β–„β–€β–ˆβ–€β–ˆβ–„  β–„β–ˆβ–€β–„β–€β–€β–€β–€ β–€β–ˆβ–ˆβ–€β–„β–„β–€β–ˆβ–„β–€β–ˆβ–ˆβ–ˆβ–ˆ
β–ˆβ–ˆβ–ˆβ–ˆβ–€β–„  β–ˆβ–€β–„ β–ˆβ–ˆβ–€β–ˆβ–ˆβ–„β–„β–„β–ˆβ–ˆβ–€β–€β–€ β–„β–€β–„ β–„β–ˆβ–ˆβ–€β–€β–„β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ
β–ˆβ–ˆβ–ˆβ–ˆβ–€β–„β–ˆ β–ˆβ–€β–„ β–€β–ˆ β–€β–„β–„β–„β–„ β–„β–€β–€ β–€  β–„β–„β–€β–ˆβ–„ β–€β–ˆ β–ˆβ–ˆβ–ˆβ–ˆ
β–ˆβ–ˆβ–ˆβ–ˆ β–ˆ  β–ˆβ–ˆβ–„β–„β–„β–€β–„β–ˆβ–€β–„β–„  β–„ β–€β–€ β–„β–ˆβ–ˆβ–ˆβ–„  β–ˆ β–„β–€β–ˆβ–ˆβ–ˆβ–ˆ
β–ˆβ–ˆβ–ˆβ–ˆβ–„β–ˆβ–ˆβ–„β–ˆβ–„β–„β–ˆβ–€β–ˆβ–€ β–„ β–„β–ˆβ–ˆβ–„β–ˆ β–€β–€β–„β–€ β–„β–„β–„ β–€β–ˆβ–€β–€β–ˆβ–ˆβ–ˆβ–ˆ
β–ˆβ–ˆβ–ˆβ–ˆ β–„β–„β–„β–„β–„ β–ˆβ–„β–ˆβ–ˆβ–€ β–ˆβ–„β–„β–€β–„ β–€β–„    β–ˆβ–„β–ˆ    β–€β–ˆβ–ˆβ–ˆβ–ˆ
β–ˆβ–ˆβ–ˆβ–ˆ β–ˆ   β–ˆ β–ˆ β–„β–€β–€β–ˆβ–„β–„β–„  β–€β–€β–€β–€β–„β–ˆ  β–„  β–ˆβ–€β–„β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ
β–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–„β–„β–„β–ˆ β–ˆ β–„β–„β–€β–„β–ˆβ–„β–„β–„β–„β–€β–ˆ β–€  β–„β–ˆ β–€β–ˆ β–€β–„β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ
β–ˆβ–ˆβ–ˆβ–ˆβ–„β–„β–„β–„β–„β–„β–„β–ˆβ–„β–„β–ˆβ–ˆβ–ˆβ–„β–„β–ˆβ–ˆβ–„β–ˆβ–„β–ˆβ–ˆβ–ˆβ–„β–„β–ˆβ–ˆβ–„β–„β–ˆβ–ˆβ–„β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ
β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ
β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ

New recovery key enrolled as key slot 0.

kmille@linbox:~ sudo systemd-cryptenroll disk.raw 
SLOT TYPE    
   0 recovery
   1 tpm2

Open the device with TPM, create a file system, mount it

kmille@linbox:~ sudo systemd-cryptsetup attach tpm2-test disk.raw none tpm2-device=auto
πŸ” Please enter LUKS2 token PIN: β€’β€’β€’β€’               

kmille@linbox:~ sudo mkfs.ext4 /dev/mapper/tpm2-test 
mke2fs 1.47.2 (1-Jan-2025)
Creating filesystem with 21504 4k blocks and 21504 inodes

Allocating group tables: done                            
Writing inode tables: done                            
Creating journal (1024 blocks): done
Writing superblocks and filesystem accounting information: done


sudo mount /dev/mapper/tpm2-test /mnt 
kmille@linbox:~

kmille@linbox:~ sudo systemd-cryptsetup detach tpm2-test
kmille@linbox:~ 

Open device with recovery key

kmille@linbox:~ sudo cryptsetup open disk.raw tpm2-test
Enter passphrase for disk.raw: 
kmille@linbox:~ sudo cryptsetup close tpm2-test 
kmille@linbox:~ 

See dm-crypt/System configuration#crypttab and dm-crypt/System configuration#Trusted Platform Module and FIDO2 keys in order to unlock the volume at boot time.

Show luks header

kmille@linbox:~ sudo cryptsetup luksDump disk.raw
LUKS header information
Version:        2         
Epoch:          8        
Metadata area:  16384 [bytes]                                       
Keyslots area:  16744448 [bytes]                                    
UUID:           f8cc1e8b-66fc-427e-9da8-04042325af72                
Label:          (no label)                                          
Subsystem:      (no subsystem)
Flags:          (no flags)

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

Keyslots:
  0: luks2
        Key:        512 bits
        Priority:   normal
        Cipher:     aes-xts-plain64
        Cipher key: 512 bits
        PBKDF:      pbkdf2
        Hash:       sha512
        Iterations: 1000
        Salt:       ac aa 7d 68 c4 cf cb 2d 70 da 3b de 9d 13 7c 32 
                    86 d4 ef 51 16 3e 8e ca 41 34 7e 2e 83 6c e9 9a 
        AF stripes: 4000
        AF hash:    sha512
        Area offset:32768 [bytes]
        Area length:258048 [bytes]
        Digest ID:  0
  1: luks2
        Key:        512 bits
        Priority:   normal
        Cipher:     aes-xts-plain64
        Cipher key: 512 bits
        PBKDF:      pbkdf2
        Hash:       sha512
        Iterations: 1000
        Salt:       88 a0 d0 47 52 03 47 0a a7 39 7a e8 90 b6 25 b5 
                    96 3b b1 de f0 11 1e 35 93 21 8c 37 f1 2d 96 a7 
        AF stripes: 4000
        AF hash:    sha512
        Area offset:290816 [bytes]
        Area length:258048 [bytes]
        Digest ID:  0
Tokens:
  0: systemd-tpm2
        tpm2-hash-pcrs:   1+2+3+4
        tpm2-pcr-bank:    sha256
        tpm2-pubkey:
                    (null)
        tpm2-pubkey-pcrs: 
        tpm2-primary-alg: ecc
        tpm2-pin:         true
        tpm2-pcrlock:     false
        tpm2-salt:        true
        tpm2-srk:         true
        tpm2-pcrlock-nv:  false
        tpm2-policy-hash:
                    aa 37 1c 54 18 7c 54 61 3e 1f f3 41 1f 20 a7 e7
                    3d db 17 ec a5 ed ca 0c 00 91 af 6d 98 a5 f3 7d
        tpm2-blob:        00 9e 00 20 b2 72 5d c0 e1 48 3b 8f e2 0f 13 9b
                    53 05 f5 79 bf 8d 55 c8 63 9a 35 2f 27 c9 ed 68
                    93 8f 5a ce 00 10 b3 86 85 12 3b cd a7 ef 97 5e
                    e9 9a 44 b0 17 96 2a d6 49 dd 5a 9d 6d 6c 90 fa
                    24 2f 40 18 62 a4 89 aa ec be a6 ec 52 c2 24 d9
                    8b 22 7b 6d 96 d0 e4 91 52 77 34 9e 74 a9 71 cb
                    73 db 8e 7e 7a a0 44 60 a6 94 1b a4 5c 72 17 f5
                    85 d5 1c 23 7f ed 07 01 04 39 37 43 c5 53 b5 c6
                    d4 eb 6c 3e 00 57 d0 37 52 e2 ff a7 90 2f 69 f4
                    ff 82 9e 3f d1 16 61 85 26 34 37 b1 c6 f6 a0 dd
                    00 4e 00 08 00 0b 00 00 00 12 00 20 aa 37 1c 54
                    18 7c 54 61 3e 1f f3 41 1f 20 a7 e7 3d db 17 ec
                    a5 ed ca 0c 00 91 af 6d 98 a5 f3 7d 00 10 00 20
                    22 ce 78 91 3a 57 45 2f 11 79 72 24 32 47 20 54
                    2e 4f 00 b6 ba 44 fe e6 d1 cf 07 8c e1 49 2d 78
        Keyslot:    1
  1: systemd-recovery
        Keyslot:    0
Digests:
  0: pbkdf2
        Hash:       sha256
        Iterations: 89775
        Salt:       44 c8 01 e3 76 ef e1 9e f7 ce df a9 eb 66 a6 7c 
                    65 58 83 1e 1f d4 94 56 3b d4 b2 62 3b e9 5c 13 
        Digest:     07 9d e3 44 0e 94 8b 8a 39 70 48 5f 9e 3b 00 f0 
                    4d d6 15 3e 26 3c 5f 88 1d 04 96 51 71 2f 8a 7f 

Encrypt data with TPM

kmille@linbox:~ sudo clevis encrypt tpm2 '{"pcr_ids":"4,7"}' <<< 'hello, world' > data.enc
kmille@linbox:~ cat data.enc | base64 -d | jq
base64: invalid input
{
  "alg": "dir",
  "clevis": {
    "pin": "tpm2",
    "tpm2": {
      "hash": "sha256",
      "jwk_priv": "AM4AIFgjlp67Tzinzb4102kdiFijWPZgBDxAiWU_hh1nykK7ABBcZ6bN5XIQABK5KAfnWNTcA2QMsYi6FOmAsKnv1pdfKG9TOdhOJZjuyT7dt-hU_WVwwxkCPjdsAGiAet6O_gEcoM9JDUsy06JEMd-qcssOJwhOqdHjuic0Kcq0F6c2VnZ9N2t8YUyFqJkCvUxakkopQy0ComDImgXV1YRZPsBZkqRiWpRaG9xH4gVzzz1Ase20Q6nSPADANCw-RCtnOc656Wf-fu7W6BaYOg",
      "jwk_pub": "AE4ACAALAAAEkgAgh3hIYBvJ6HtIVysdzo2qEPTLta4NGyiLluBJnBfXw3oAEAAgztpOb1cDUCqfkZCpW5Yd15mPNWClGdJaVr1Lb4At3Wo",
      "key": "ecc",
      "pcr_bank": "sha1",
      "pcr_ids": "4,7"
    }
  },
  "enc": "A256GCM"
}
kmille@linbox:~ cat data.enc|  sudo clevis decrypt tpm2 '{"pcr_ids":"4,7"}' 
hello, world
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment