SYSTEMD-CRYPTENROLL(1)
๐ NAME ๐
okay so bestie, welcome to systemd-cryptenroll (it lives in the systemd-cryptenroll corner of the man pages, section 1, and it is iconic) โ this is the tool that enrolls PKCS#11, FIDO2, and TPM2 tokens/devices into LUKS2 encrypted volumes. โจ
๐ฆ SYNOPSIS ๐ฆ
systemd-cryptenroll [OPTIONS...] [DEVICE]
๐ธ DESCRIPTION ๐ธ
So like, systemd-cryptenroll is the girl whose whole job is enrolling hardware security tokens and devices into a LUKS2 encrypted volume, which you can then use to unlock that volume while booting. no cap, that's the gig. ๐
Specifically, she supports these kinds of tokens and credentials to be enrolled:
- PKCS#11 security tokens and smartcards that may carry an RSA or EC key pair (e.g. various YubiKeys) ๐
- FIDO2 security tokens that implement the
"hmac-secret"extension (most FIDO2 keys, including YubiKeys) ๐๏ธ - TPM2 security devices ๐ง
- Regular passphrases ๐ฌ
- Recovery keys. These are similar to regular passphrases, however are randomly generated on the computer and thus generally have higher entropy than user-chosen passphrases. Their character set has been designed to ensure they are easy to type in, while having high entropy. They may also be scanned off screen using QR codes. Recovery keys may be used for unlocking LUKS2 volumes wherever passphrases are accepted. They are intended to be used in combination with an enrolled hardware security token, as a recovery option when the token is lost. ๐ญ๐
Plus โ plot twist โ the tool may also be used to enumerate currently enrolled security tokens and wipe a subset of them. And the wipe can be combined with the enrollment operation of a new security token, so you can update or replace enrollments in one go. ate that. ๐
IMPORTANT: this tool supports only LUKS2 volumes, because it stores token meta-information in the LUKS2 JSON token area, which is not available in other encryption formats. so don't come at her with LUKS1, she will not. ๐
Also, systemd-cryptsetup operates on the device backing /var/ if no device is specified explicitly, and no wipe operation is requested. (Note that in the typical case where /var/ is on the same file system as the root file system, this hence enrolls a key into the backing device of the root file system.) ๐ซถ
๐ TPM2 PCRs and policies ๐
PCRs allow binding of the encryption of secrets to specific software versions and system state, so that the enrolled key is only accessible (may be "unsealed") if specific trusted software and/or configuration is used. Such bindings may be created with the option --tpm2-pcrs= described below. โจ
Secrets may also be bound indirectly: a signed policy for a state of some combination of PCR values is provided, and the secret is bound to the public part of the key used to sign this policy. This means that the owner of a key can generate a sequence of signed policies, for specific software versions and system states, and the secret can be decrypted as long as the machine state matches one of those policies. For example, a vendor may provide such a policy for each kernel+initrd update, allowing users to encrypt secrets so that they can be decrypted when running any kernel+initrd signed by the vendor. Such bindings may be created with the options --tpm2-public-key=, --tpm2-public-key-pcrs=, --tpm2-signature= described below. ๐
See UAPI.7 Linux TPM PCR Registry[1] for an authoritative list of PCRs and how they are updated. The table below contains a quick reference, describing in particular the PCRs modified by systemd. ๐
๐ Table 1. Well-known PCR Definitions ๐
okay so here's the tea on which PCR does what, bestie โ bookmark this, it's giving cheat sheet ๐
0โplatform-code: core system firmware executable code; changes on firmware updates โจ1โplatform-config: core system firmware data/host platform configuration; typically contains serial and model numbers, changes on basic hardware/CPU/RAM replacements2โexternal-code: extended or pluggable executable code; includes option ROMs on pluggable hardware3โexternal-config: extended or pluggable firmware data; includes information about pluggable hardware4โboot-loader-code: boot loader and additional drivers, PE binaries invoked by the boot loader; changes on boot loader updates.sd-stub(7)measures system extension images read from the ESP here too (seesystemd-sysext(8)). ๐ฆ5โboot-loader-config: GPT/Partition table; changes when the partitions are added, modified, or removed7โsecure-boot-policy: Secure Boot state; changes when UEFI SecureBoot mode is enabled/disabled, or firmware certificates (PK, KEK, db, dbx, ...) changes. ๐9โkernel-initrd: the Linux kernel measures all initrds it receives into this PCR.10โima: the IMA project measures its runtime state into this PCR.11โkernel-boot:systemd-stub(7)measures the ELF kernel image, embedded initrd and other payload of the PE image it is placed in into this PCR.systemd-pcrphase.service(8)measures boot phase strings into this PCR at various milestones of the boot process. ๐12โkernel-config:systemd-boot(7)measures the kernel command line into this PCR.systemd-stub(7)measures any manually specified kernel command line (i.e. a kernel command line that overrides the one embedded in the unified PE image) and loaded credentials into this PCR.13โsysexts:systemd-stub(7)measures anysystemd-sysext(8)images it passes to the booted kernel into this PCR.14โshim-policy: the shim project measures its "MOK" certificates and hashes into this PCR. ๐15โsystem-identity:systemd-cryptsetup(8)optionally measures the volume key of activated LUKS volumes into this PCR.systemd-pcrmachine.service(8)measures themachine-id(5)into this PCR.systemd-pcrfs@.service(8)measures mount points, file system UUIDs, labels, partition UUIDs of the root and/var/filesystems into this PCR.16โdebug: Debug23โapplication-support: Application Support
so, like, in general, encrypted volumes would be bound to some combination of PCRs 7, 11, and 14 (if shim/MOK is used). and the way that updates work?? ๐ in order to allow firmware and OS version updates, it is typically not advisable to use PCRs such as 0 and 2, since the program code they cover should already be covered indirectly through the certificates measured into PCR 7. validation through certificates hashes is typically preferable over validation through direct measurements as it is less brittle in context of OS/firmware updates: the measurements will change on every update, but signatures should remain unchanged. iykyk ๐
fr fr tho, go read the UAPI.7 Linux TPM PCR Registry[1] for more discussion โ it's literally the deep dive you want. ๐ซถ
๐ LIMITATIONS (the fine print bestie, read it fr fr)
Okay so first thing's first, and I need you to hear me on this one: right now, when you enroll a new key of one of the five supported types listed above, you have to first provide a passphrase, a recovery key, a FIDO2 token, or a TPM2 key. That's the vibe. No getting around it.
And here's the kicker โ it's currently not supported to unlock a device with a PKCS#11 key in order to enroll a new PKCS#11 key. Like, the door won't open with the very key you're trying to duplicate. So if you're thinking about future key roll-over (which, lowkey, you should be), the general recommendation is to make sure a passphrase, a recovery key, a FIDO2 token, or a TPM2 key is always enrolled. Keep one of those in your back pocket, always. ๐ซถ
Also, heads up: support for enrolling multiple FIDO2 tokens is currently limited. When multiple FIDO2 tokens are enrolled, systemd-cryptsetup will perform pre-flight requests to attempt to identify which of the enrolled tokens are currently plugged in. Cute, right? But it's not possible for FIDO2 tokens with user verification (UV, usually via biometrics), in which case it will fall back to attempting each enrolled token one by one. Which meansโฆ multiple prompts for PIN and user verification. ๐ญ Yeah. A whole parade of prompts.
Good news though: this limitation does not apply to PKCS#11 tokens. They ate and left no crumbs. ๐
๐ COMPATIBILITY (aka the "will my old stuff still work" section)
Security technology both in systemd and in the general industry constantly evolves. Like, constantly. In order to provide best security guarantees, the way TPM2, FIDO2, PKCS#11 devices are enrolled is regularly updated in newer versions of systemd. And whenever this happens, here are the compatibility guarantees you get:
- Old enrollments continue to be supported and may be unlocked with newer versions of
systemd-cryptsetup@.service(8). - The opposite is not guaranteed however: it might not be possible to unlock volumes with enrollments done with a newer version of
systemd-cryptenrollwith an older version ofsystemd-cryptsetup.
That said, it is generally recommended to use matching versions of systemd-cryptenroll and systemd-cryptsetup, since this is best tested and supported. Matching sets, besties. Matching sets. ๐
It might be advisable to re-enroll existing enrollments to take benefit of newer security features, as they are added to systemd. Glow-up your keys, periodt. โจ
๐ UNLOCKING (how we get the volume open before we do the thing)
The following options are understood that may be used to unlock the device in preparation of the enrollment operations:
--unlock-emptyโ Use an empty password/passphrase to unlock the volume, instead of reading one from stdin. This is useful to unlock volumes that are currently protected by an empty password, in order to enroll a different, stronger unlock mechanism. Glow-up arc activated. ๐ฑ
Added in version 262.
- *
--unlock-key-file=PATH* โ Use a file instead of a password/passphrase read from stdin to unlock the volume. Expects the PATH to the file containing your key to unlock the volume. Currently there is nothing like--key-file-offset=or--key-file-size=so this file has to only contain the full key. Like, the whole key, nothing else, no extras. ๐
Added in version 252.
- *
--unlock-fido2-device=PATH* โ Use a FIDO2 device instead of a password/passphrase read from stdin to unlock the volume. Expects ahidrawdevice referring to the FIDO2 device (e.g./dev/hidraw1). Alternatively the special value"auto"may be specified, in order to automatically determine the device node of a currently plugged in security token (of which there must be exactly one). This automatic discovery is unsupported if--fido2-device=option is also specified. Note that currently FIDO2 devices enrolled without an accompanying LUKS2 token (i.e.--fido2-parameters-in-header=no) cannot be used for unlocking. ๐ซ
Added in version 253.
- *
--unlock-tpm2-device=PATH* โ Use a TPM2 device instead of a password/passphrase read from stdin to unlock the volume. Expects a device node path referring to the TPM2 chip (e.g./dev/tpmrm0). Alternatively the special value"auto"may be specified, in order to automatically determine the device node of a currently discovered TPM2 device (of which there must be exactly one). One and only one, bestie, don't make it choose. ๐
Added in version 256.
--unlock-headlessโ Try the unlock mechanisms suitable for headless operation in turn, without requiring any interactive input. If a TPM2 device is available the volume is unlocked via TPM2, and otherwise (or if TPM2 unlocking fails) an empty password is attempted. This is primarily useful in automated provisioning scenarios where a volume is first set up with a TPM2 enrollment or an empty password and a stronger unlock mechanism shall be enrolled subsequently. Hands-free, no vibes required. ๐ค
Added in version 262.
๐ SIMPLE ENROLLMENT (the classics, the OGs)
The following options are understood that may be used to enroll simple user input based unlocking:
--passwordโ Enroll a regular password/passphrase. This command is mostly equivalent tocryptsetup luksAddKey, however may be combined with--wipe-slot=in one call, see below. Two birds, one slay. ๐ฆ
Added in version 248.
--recovery-keyโ Enroll a recovery key. Recovery keys are mostly identical to passphrases, but are computer-generated instead of being chosen by a human, and thus have a guaranteed high entropy. The key uses a character set that is easy to type in, and may be scanned off screen via a QR code. It's giving "written by the algorithm, typed by you." ๐ฑโจ
Added in version 248.
๐ง INTERACTIVE ENROLLMENT (the wizard!! it's giving first boot energy)
The following options are understood that drive an interactive enrollment wizard, intended to be run on first boot (similar in spirit to systemd-firstboot(1)):
--firstbootโ Run an interactive wizard that lets the user enroll a passphrase, a recovery key, or a FIDO2 security token (one menu entry per suitable token currently plugged in). If credentials of any of these types are already enrolled, the wizard additionally offers to wipe them. Pressing enter at the top-level menu leaves the volume unchanged. This option may not be combined with an explicit enrollment type or with--wipe-slot=. As with the other commands, the volume to operate on is the one backing/var/if none is specified. Honours thesystemd.firstboot=kernel command line option.
Added in version 262.
- *
--prompt-suppress=TYPE*... โ Takes a comma-separated list of slot types, out of"password","recovery","pkcs11","fido2"and"tpm2". Only useful together with--firstboot: if a slot of any of the listed types is already enrolled on the volume, the wizard does nothing and exits successfully. This is useful to hook the wizard into the boot process while ensuring it stays quiet once suitable credentials have been set up. Silent mode: engaged. ๐คซ
Added in version 262.
- *
--chrome=BOOL* โ Takes a boolean argument, defaults toon. Only useful together with--firstboot: if enabled the interactive wizard draws a coloured bar across the top and bottom of the terminal to visually frame the prompt. Pass--chrome=noto disable this decoration, for example when running on a terminal that does not render it well. Aesthetic framing, immaculate. ๐จ
Added in version 262.
- *
--mute-console=BOOL* โ Takes a boolean argument, defaults tooff. Only useful together with--firstboot: if enabled the kernel and PID 1 are asked to refrain from writing log messages to the console while the interactive wizard is shown, so that such output does not interfere with the prompt. The console is unmuted again once the wizard exits. Shhh, the wizard is speaking. ๐ค
Added in version 262.
๐ณ PKCS#11 ENROLLMENT (smartcard girlies rise up)
The following option is understood that may be used to enroll PKCS#11 tokens:
- *
--pkcs11-token-uri=URI* โ Enroll a PKCS#11 security token or smartcard (e.g. a YubiKey). Expects a PKCS#11 URI that allows finding an X.509 certificate or a public key on the token. The URI must also be suitable to find a related private key after changing the type of object in it. Alternatively the special value"auto"may be specified, in order to automatically determine the suitable URI if a single security token containing a single key pair is plugged in. The special value"list"may be used to enumerate all suitable PKCS#11 tokens currently plugged in. Window shopping for tokens, we love to see it. ๐๏ธ
The PKCS#11 token must contain an RSA or EC key pair which will be used to unlock a LUKS2 volume. For RSA, a randomly generated volume key is encrypted with a public key in the token, and stored in the LUKS2 JSON token header area. To unlock a volume, the stored encrypted volume key will be decrypted with a private key in the token. For ECC, ECDH algorithm is used: we generate a pair of EC keys in the same EC group, then derive a shared secret using the generated private key and the public key in the token. The derived shared secret is used as a volume key. The generated public key is stored in the LUKS2 JSON token header area. The generated private key is erased. To unlock a volume, we derive the shared secret with the stored public key and a private key in the token. Crypto math, but make it fashion. ๐งฎ๐
In order to unlock a LUKS2 volume with an enrolled PKCS#11 security token, specify the pkcs11-uri= option in the respective /etc/crypttab line:
myvolume /dev/sda1 none pkcs11-uri=auto
See crypttab(5) for a more comprehensive example of a systemd-cryptenroll invocation and its matching /etc/crypttab line.
Added in version 248.
๐ FIDO2 ENROLLMENT โจ
okay bestie so these are the options you're gonna use when you wanna enroll a FIDO2 token. they're giving "tiny key that lives on your keychain but is lowkey a whole security system" ๐
--fido2-device=PATHโ this one enrolls a FIDO2 security token that implements the"hmac-secret"extension (hi, YubiKey ๐). You pass it a hidraw device that points at the FIDO2 device, like/dev/hidraw1. OR โ and this is the slay part โ you can pass the special value"auto"and it'll go find the device node of the currently plugged-in security token all by itself (there has to be exactly one tho, no sharing). ngl this auto-discovery does not work if you also specify--unlock-fido2-device=. There's also a special value"list"that enumerates every suitable FIDO2 token that's currently plugged in, like a little roster. โจ Note that lots of hardware security tokens that do FIDO2 also do the older PKCS#11 thing โ and typically FIDO2 is the move, since it's simpler to use and more modern. periodt.
So to unlock a LUKS2 volume with an enrolled FIDO2 security token, you specify the fido2-device= option in the matching /etc/crypttab line, like:
myvolume /dev/sda1 none fido2-device=auto
Wanna see a more comprehensive example of a systemd-cryptenroll invocation and its matching /etc/crypttab line? That's in crypttab(5). ๐ซถ
Added in version 248.
--fido2-credential-algorithm=STRINGโ picks the COSE algorithm used when generating the credential. Default is"es256". Supported values are"es256","rs256"and"eddsa". Let's break it down fr fr:"es256"= ECDSA over NIST P-256 with SHA-256."rs256"= 2048-bit RSA with PKCS#1.5 padding and SHA-256."eddsa"= EDDSA over Curve25519 with SHA-512.
Heads up tho: your authenticator might just be like "no ๐" and not support some of these algorithms.
Added in version 251.
--fido2-salt-file=PATHโ when you're enrolling a FIDO2 security token, this gives the path to a file (or anAF_UNIXsocket ๐) that we read the salt value from โ the salt gets used in the HMAC operation that the FIDO2 security token performs. If you don't specify this option at all, the salt just gets randomly generated for you. cute, effortless.
Added in version 257.
--fido2-parameters-in-header=BOOLโ when enrolling a FIDO2 security token, this controls whether the FIDO2 parameters get stored in a token in the LUKS2 superblock. Defaults to"yes". If you set it to"no", then you have to specify thefido2-cid=option manually in the respective/etc/crypttabline, along with a key file. Details are incrypttab(5). iykyk.
Added in version 257.
--fido2-with-client-pin=BOOLโ when enrolling a FIDO2 security token, controls whether the user has to enter a PIN when unlocking the volume (that's the FIDO2"clientPin"feature). Defaults to"yes". But bestie, note that this setting does literally nothing if the security token doesn't support the"clientPin"feature, or if it doesn't let the client PIN requirement be enabled/disabled for the requested operation. it's giving "the token decides" ๐
Added in version 249.
--fido2-with-user-presence=BOOLโ when enrolling a FIDO2 security token, controls whether the user has to verify presence by tapping the token (the FIDO2"up"feature) when unlocking the volume. Defaults to"yes". Same vibe check as before: this setting has no effect if the security token doesn't support the"up"feature, or doesn't allow the user presence requirement to be enabled or disabled for the requested operation.
Added in version 249.
--fido2-with-user-verification=BOOLโ when enrolling a FIDO2 security token, controls whether user verification is required when unlocking the volume (the FIDO2"uv"feature). Defaults to"no". And yep, same disclaimer: no effect if the security token doesn't support the"uv"feature, or doesn't allow the user verification requirement to be enabled or disabled for the requested operation. ๐คท
Added in version 249.
๐ก๏ธ TPM2 ENROLLMENT ๐
now for the other main character: TPM2 devices. these options are what you use to enroll them. ngl this section is a whole meal, so hydrate first ๐
--tpm2-device=PATHโ enrolls a TPM2 security chip. Expects a device node path referring to the TPM2 chip, like/dev/tpmrm0. OR you can pass the special value"auto"and it'll automatically figure out the device node of a currently discovered TPM2 device (and again โ there must be exactly one, no polyamory for TPMs). The special value"list"enumerates all suitable TPM2 devices that are currently discovered. ๐
So to unlock a LUKS2 volume with an enrolled TPM2 security chip, you specify the tpm2-device= option in the respective /etc/crypttab line:
myvolume /dev/sda1 none tpm2-device=auto
Again, crypttab(5) has a more comprehensive example of a systemd-cryptenroll invocation and its matching /etc/crypttab line. โจ
And use --tpm2-pcrs= (peep below ๐) to configure which TPM2 PCR indexes the enrollment gets bound to.
Added in version 248.
--tpm2-device-key=PATHโ enrolls a TPM2 security chip using its public key. Expects a path referring to the TPM2 public key inTPM2B_PUBLICformat. This cannot be used together with--tpm2-device=, because it does the exact same operation โ but without connecting to the TPM2 security chip. Instead, the enrollment gets calculated using the TPM2 key you provided. This is highkey useful when the TPM2 security chip just isn't available at the time of enrollment. iconic for that exact scenario. ๐
The key, in most cases, should be the Storage Root Key (SRK) from a local TPM2 security chip. But if you use a key from a different handle (not the SRK), then you must specify its handle index using --tpm2-seal-key-handle=.
Good news: the systemd-tpm2-setup.service(8) service writes the SRK to /run/systemd/tpm2-srk-public-key.tpm2b_public automatically during boot, in the correct format. so it's just... there. ๐
Alternatively, you can use systemd-analyze srk to retrieve the SRK from the TPM2 security chip explicitly. See systemd-analyze(1) for details. Example:
systemd-analyze srk > srk.tpm2b_public
Added in version 255.
--tpm2-seal-key-handle=HANDLEโ configures which parent key to use for sealing, using the TPM handle (index) of the key. This is what you use to "seal" (encrypt) a secret, and it must be used later to "unseal" (decrypt) that secret. Expects a hexadecimal 32bit integer, optionally prefixed with"0x". Allowable values are any handle index in the persistent range ("0x81000000"-"0x81ffffff") or the transient range ("0x80000000"-"0x80ffffff"). โ ๏ธ But listen: since transient handles get lost after a TPM reset, and may be flushed during TPM context switching, they should not be used except for very specific use cases, e.g. testing. don't be brave.
The default is the Storage Root Key (SRK) handle index "0x81000001". A value of 0 will use the default. For the SRK handle, a new key will be created and stored in the TPM if one doesn't already exist; but for any other handle, the key must already exist in the TPM at the specified handle index.
bestie. this should not be changed unless you know what you are doing. ๐
Added in version 255.
--tpm2-pcrs=PCR[+PCR...]โ configures the TPM2 PCRs (Platform Configuration Registers) to bind to when enrollment is requested via--tpm2-device=. It takes a list of PCR entries, where each entry starts with a name or a numeric index in the range0...23, optionally followed by":"and a hash algorithm name (which specifies the PCR bank), optionally followed by"="and a hash digest value. Multiple PCR entries get separated by"+". If you specify an empty string, it binds the enrollment to no PCRs at all (and this is also the default if you don't use this option). See the table above for a list of available PCRs. ๐
Example: --tpm2-pcrs=boot-loader-code+platform-config+boot-loader-config specifies that PCR registers 4, 1, and 5 should be used.
Example: --tpm2-pcrs=7:sha256 specifies that PCR register 7 from the SHA256 bank should be used.
Example: --tpm2-pcrs=4:sha1=3a3f780f11a4b49969fcaa80cd6e3957c33b2275 specifies that PCR register 4 from the SHA1 bank should be used, and a hash digest value of 3a3f780f11a4b49969fcaa80cd6e3957c33b2275 will be used instead of reading the current PCR value. cute, custom, obsessed.
Added in version 248.
--tpm2-with-pin=BOOL|directโ when enrolling a TPM2 device, this controls whether the user has to enter a PIN when unlocking the volume, in addition to PCR binding, based on TPM2 policy authentication. Takes a boolean or the special value"direct". Defaults to"no". And yes, despite being called PIN, literally any character can be used โ not just numbers. so go off with your emoji passphrase, it's valid ๐
When enabled ("yes"), the PIN is hardened with Argon2id before it gets passed to the TPM โ which makes the TPM a second factor rather than a single point of failure. Like, a compromised TPM alone doesn't expose the volume key without the PIN. slay. When "direct" is used, the PIN gets hashed with PBKDF2 and used directly (compatible with systemd v253 and later).
โ ๏ธ Note that incorrect PIN entry when unlocking increments the TPM dictionary attack lockout mechanism, and may lock out users for a prolonged time, depending on its configuration. The lockout mechanism is a global property of the TPM โ systemd-cryptenroll does not control or configure it. You may use tpm2-tss tools to inspect or configure the dictionary attack lockout, with the tpm2_getcap(1) and tpm2_dictionarylockout(1) commands, respectively.
Added in version 262.
--tpm2-argon2id-memory=BYTESโ when enrolling a TPM2 with PIN hardening enabled, this sets the Argon2id memory cost, in bytes. By default, the memory cost is auto-detected from available RAM (up to 50% of total physical memory), with a minimum of 64 MiB. When you specify it, the benchmark calibrates only iterations to the target time; the memory cost is used exactly as specified. And to express large values comfortably, use suffixes like"K","M","G"(for kilobytes, megabytes, gigabytes). ๐ง
Added in version 262.
--tpm2-argon2id-iterations=NUMโ when enrolling a TPM2 with PIN hardening enabled, sets the Argon2id iteration count. Defaults to auto-calibrated by a benchmark to reach the target unlock time. When you specify it, the benchmark calibrates only memory cost to the target time; the iteration count is used exactly as specified. ๐
Added in version 262.
--tpm2-argon2id-parallelism=NUMโ when enrolling a TPM2 with PIN hardening enabled, sets the Argon2id parallelism (the lane count). Defaults to the number of online CPUs. ๐ฆ
Added in version 262.
--tpm2-argon2id-iter-time=SECโ okay so if you're enrolling a TPM2 with PIN hardening turned on, this sets the target benchmark time for calibrating the Argon2id parameters, measured in seconds. Defaults to2seconds. The benchmark tweaks the memory cost and/or the iteration count so the actual derivation time lands inside a tolerance window around the target time you picked. ๐ฏ
Added in version 262.
--tpm2-public-key=PATH,--tpm2-public-key-pcrs=PCR[+PCR...],--tpm2-signature=PATHโ this trio configures a TPM2 signed PCR policy to bind your encryption to, bestie. Let's go one by one:--tpm2-public-key=takes a path to a PEM encoded RSA public key, and that's what the encryption gets bound to. If you don't specify it explicitly but a filetpm2-pcr-public-key.pemexists in one of/etc/systemd/,/run/systemd/,/usr/lib/systemd/(searched in exactly that order, no skipping โจ), it just gets used automatically.--tpm2-public-key-pcrs=takes a list of TPM2 PCR indexes to bind to (same syntax as--tpm2-pcrs=described above, iykyk). If you don't specify it, it defaults to11โ which basically binds the policy to any unified kernel image that a PCR signature can be provided for.--tpm2-signature=takes a path to a TPM2 PCR signature file as generated by thesystemd-measure(1)tool. If you don't specify it explicitly, a suitable signature filetpm2-pcr-signature.jsongets searched for in/etc/systemd/,/run/systemd/,/usr/lib/systemd/(in this order) and used. If a signature file is specified or found, it's used to verify whether the volume can actually be unlocked with it given the current PCR state, before the new slot is written to disk. This is a safety net, periodt โ it's there so you don't lose access to a volume because you enrolled a public key that has no valid signature for the current PCR state. If the supplied signature doesn't unlock the current PCR state + public key combo, no slot is enrolled and the whole operation fails. If no signature file is specified or found, no such safety verification happens. ๐
Now the important difference between --tpm2-pcrs= and --tpm2-public-key-pcrs=: the first one binds decryption to the current, specific PCR values. The second one binds decryption to any set of PCR values for which a signature by the specified public key can be provided. That makes the latter way more useful when you want software updates to be possible without losing access to all your previously encrypted LUKS2 volumes. And just like with --tpm2-pcrs=, the names defined in the table above can be used to specify the registers too, for instance --tpm2-public-key-pcrs=boot-loader-code+system-identity.
Added in version 252.
--tpm2-public-key-policyref=STRINGโ sets the policy reference to use together with the signed PCR policy you enrolled via--tpm2-public-key=. The policy reference is an opaque string that gets incorporated into the resulting authorization policy (via theTPM2_PolicyAuthorizeassertion), so the slot can only be unlocked by a signed policy that was generated with the same policy reference. This must match the policy reference you passed to the--policyref=option ofsystemd-measure(1)when the signature was generated. It's how you bind a slot to signatures for a specific boot phase, even when a single signing key produces signatures for multiple phases. ๐
You can use this to select a policy reference that's only bound to a signature for the initrd phase, so you get a slot that can only be unlocked from the initrd. For example, if such a signature is created by supplying --phase=enter-initrd and --policyref=initrd to systemd-measure(1):
systemd-cryptenroll --tpm2-device=auto --tpm2-public-key-policyref=initrd /dev/sda1
Added in version 262.
--tpm2-pcrlock=PATHโ configures a TPM2 pcrlock policy to bind encryption to. It expects a path to a pcrlock policy file as generated by thesystemd-pcrlock(8)tool. If a TPM2 device is enrolled and you don't use this option, but a filepcrlock.jsonis found in/run/systemd/or/var/lib/systemd/, it gets used automatically. Assign an empty string to turn this behaviour off. ๐
Added in version 255.
โจ OTHER OPTIONS โจ
These extra options are understood too, bestie:
--wipe-slot=SLOT[,SLOT...]โ wipes one or more LUKS2 key slots. It takes a comma separated list of numeric slot indexes, or these special strings:allโ for wiping all key slotsemptyโ for wiping all key slots that are unlocked by an empty passphrasepasswordโ for wiping all key slots that are unlocked by a traditional passphraserecoveryโ for wiping all key slots that are unlocked by a recovery keypkcs11โ for wiping all key slots that are unlocked by a PKCS#11 tokenfido2โ for wiping all key slots that are unlocked by a FIDO2 tokentpm2โ for wiping all key slots that are unlocked by a TPM2 chip
Or any combination of these strings or numeric indexes, in which case all slots matching either get wiped. And as a safety precaution, an operation that wipes all slots without exception (so the volume can't be unlocked at all anymore, unless the volume key is known) is refused. ๐ซ
This switch can be used alone, and then only the requested wipe operation is executed. It can also be combined with any of the enrollment options listed above, and then the enrollment is completed first, and only when it succeeds does the wipe operation execute โ and the newly added slot is always excluded from the wiping. So combining enrollment and slot wiping is how you update existing enrollments:
systemd-cryptenroll /dev/sda1 --wipe-slot=tpm2 --tpm2-device=auto --unlock-tpm2-device=auto
The above command enrolls the TPM2 chip, then wipes all previously created TPM2 enrollments on the LUKS2 volume, leaving only the brand new one. ๐
Combining wiping and enrollment can also replace enrollments of different types โ say, changing from a PKCS#11 enrollment to a FIDO2 one:
systemd-cryptenroll /dev/sda1 --wipe-slot=pkcs11 --fido2-device=auto
Or replacing an enrolled empty password with TPM2:
systemd-cryptenroll /dev/sda1 --wipe-slot=empty --tpm2-device=auto
Added in version 248.
--list-devicesโ shows a list of candidate block devices this command may operate on. Specifically, it enumerates the block devices currently present that contain a LUKS superblock, and shows their device node paths along with any of their symlinks. The devices must implement thehmac-secretextension to be usable. ๐ฆ
Added in version 257.
-h,--helpโ prints a short help text and exits.--versionโ prints a short version string and exits.--no-pagerโ doesn't pipe output into a pager.
๐ CREDENTIALS ๐
systemd-cryptenroll supports the service credentials logic as implemented by ImportCredential=, LoadCredential=, SetCredential= (peep systemd.exec(5) for the deets). These credentials are used when passed in:
cryptenroll.passphrase,cryptenroll.new-passphraseโ may contain the passphrase to unlock the volume with, and/or to newly enroll. ๐
Added in version 256.
cryptenroll.tpm2-pin,cryptenroll.new-tpm2-pinโ may contain the TPM2 PIN to unlock the volume with, and/or to newly enroll.
Added in version 256.
cryptenroll.fido2-pinโ if a FIDO2 token is enrolled, this may contain the PIN of the token.
Added in version 256.
cryptenroll.pkcs11-pinโ if a PKCS#11 token is enrolled, this may contain the PIN of the token.
Added in version 256.
๐ฆ EXIT STATUS ๐ฆ
On success, 0 is returned. A non-zero failure code otherwise. That's it, that's the whole vibe check. โจ
๐ EXAMPLES ๐
crypttab(5) and systemd-measure(1) contain various examples employing systemd-cryptenroll. Go look, bestie, they're cute. ๐
๐ SEE ALSO ๐
systemd(1), systemd-cryptsetup@.service(8), crypttab(5), cryptsetup(8), systemd-measure(1)
๐ NOTES ๐
- UAPI.7 Linux TPM PCR Registry โ
https://uapi-group.org/specifications/specs/linux_tpm_pcr_registry/
aaaand that's a wrap on the whole page, babe! ๐
this was systemd 262.1's take on SYSTEMD-CRYPTENROLL(1), and honestly? she ate. now go enroll something responsibly, keep your recovery keys safe, and don't wipe all your slots without the volume key. love u, bye!! ๐ซถโจ๐ธ
๐ฆ where this page comes from
- arch rolling: systemd 262.1-1 ยท LGPL-2.1-or-later AND CC0-1.0 AND GPL-2.0-or-later AND MIT-0
- ๐ girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms