Commit Graph
80 Commits
Author SHA1 Message Date
lzwind 02b2eb9ede man: clarify that --fido2-with-user-presence= may not be supported (#43266)
Reword the note for --fido2-with-user-presence= to make it clear that the
setting has no effect if the token does not support the up feature, or does
not allow the user presence requirement to be enabled or disabled for the
requested operation. Drop the surrounding parentheses and the spurious
"in other contexts" qualifier.

Apply the same rewording to the sibling --fido2-with-client-pin= and
--fido2-with-user-verification= options so the three parallel FIDO2
entries stay consistent.

Fixes #23632.
2026-08-05 16:59:47 +09:00
fuldeka f3fe668cdf cryptsetup: add Argon2id-based PIN mode for TPM2 enrollment
The current TPM2 PIN mode is flawed as a compromised TPM directly exposes
the sealed secret which is the LUKS volume key itself (#27502 and #37386).

Goal: add Argon2id-based PIN hardening to TPM2 enrollment, making
the TPM a second factor rather than a single point of failure:

1. Password + salt -> Argon2id -> 512-bit key split into Key1 + Key2
2. Key2 (base64-encoded) is used as the PIN to seal a random secret
in the TPM
3. Key1 + unsealed secret -> HKDF-SHA256 -> final LUKS volume key

This implementation ensures that if the TPM is compromised, an attacker
still needs the password to derive Key1 and combine it with the unsealed
secret.

The --tpm2-with-pin= option now accepts three values:
- false (no PIN used)
- true (PIN hardened with Argon2id - default)
- "direct" (legacy PIN without Argon2id for backward compatibility)

Argon2id parameters are customizable via:

--tpm2-argon2id-memory=
--tpm2-argon2id-iterations=
--tpm2-argon2id-parallelism=
--tpm2-argon2id-iter-time=

These default to a function of available CPUs and physical memory, with
a benchmark that scales iterations to the target time (default: 2s) and
falls back to ARGON2ID_PARAMETERS_DEFAULT (64 MiB, 8 iter, 4 lanes) when
auto detection fails.
Also if the runtime OpenSSL lacks Argon2id support (< 3.2), the feature
silently falls back to direct PIN mode with a warning.

Added includes:
- src/cryptenroll/cryptenroll.c: cpu-set-util.h, limits-util.h, time-util.h
  for Argon2id benchmark auto-tuning (cpus_online, physical_memory_scale,
  now/usec_t)
- src/cryptenroll/cryptenroll-tpm2.c: crypto-util.h for Argon2IdParameters
  struct in load_volume_key_tpm2()
- src/shared/tpm2-util.h: crypto-util.h for Argon2IdParameters in
  tpm2_make_luks2_json() API
- src/shared/tpm2-util.c: limits-util.h, tpm2-util.h for physical_memory() validation
  of Argon2id memory cost and function prototypes
- src/cryptsetup/cryptsetup-tokens/luks2-tpm2.c: crypto-util.h for
  kdf_argon2id_derive()/kdf_hkdf_sha256() on the token unlock path
2026-07-12 23:31:29 +02:00
Chris Coulson 2348941b5d measure: Support binding signed policies to individual phases
systemd-measure can produce multiple signed policies for different
phases. However, a policy for a TPM resource that includes these signed
policies can currently be satisfied by any policy that is signed
with the same key.

It can be desirable to bind a resource's policy to one or more
specific phases. One way to do this could be to sign policies for
different phases or phase combinations with different keys. Another
approach is to limit the scope of signed policies using a policy
reference.

Using a policy reference works because:
- The reference is included along with the approved policy digest in the
  digest that is signed.
- The reference argument is included in the authorization policy for a
  resource via the TPM2_PolicyAuthorize assertion.
- During execution of the TPM2_PolicyAuthorize assertion, the TPM checks
  that the session's current policy digest is the approved policy digest,
  computes a digest from the approved policy digest and the supplied policy
  reference, and checks that the resulting digest is the one that was
  verified by TPM2_VerifySignature (via the returned ticket).

This adds a new --policyref argument to systemd-measure which binds all
of the signed policies to the specified policy reference. I did consider
making this more intelligent by auto-generating policy references for each
phase, but this approach provides the most flexibility for now. By making
use of the existing --append argument, a signer can produce multiple
signed policies with the same key that are bound to any individual phases
or combinations of phases.

The policy reference is a string without the NULL terminator. It is
supplied to the TPM via the TPM2B_NONCE type, which has a maximum size
equivalent to the size of the largest digest supported by the TPM. As
the signer doesn't know the capabilities of the target TPM,
systemd-measure limits the size of the policy reference to 32 bytes, to
fit within the size of a SHA256 digest.

This also includes the corresponding changes to systemd-cryptenroll and
systemd-repart (to add an equivalent --tpm2-public-key-policyref argument
so that the policy can be bound to the desired corresponding phase, and to
ensure that the policy reference is included in the LUKS2 token metadata),
and systemd-cryptsetup (to handle the policy reference stored in the LUKS2
token metadata).

This doesn't include policy reference support for credentials yet
because it requires a change to the credential headers.
2026-07-02 21:28:42 +02:00
Lennart Poettering 0089a46b6b cryptenroll: add interactive --firstboot enrollment wizard
Add a --firstboot mode that interactively walks the user through enrolling a
passphrase, a recovery key, or a FIDO2 token, with one menu entry per suitable
token currently plugged in (driven by a new fido2_enumerate_devices() helper).
Pressing enter at the top-level menu leaves the volume unchanged; for each
already-enrolled credential type the wizard offers to wipe it as part of the
operation. It populates the same EnrollContext the command line and Varlink
paths use, so the actual enrollment goes through the shared enroll_now() path.

A companion --prompt-suppress= option takes a list of slot types: if a slot of
any listed type already exists, the wizard does nothing and exits successfully.
This lets it be hooked into the boot process while staying quiet once the
system has been set up.

The accompanying systemd-cryptenroll-firstboot.service runs this from the
initrd, after systemd-repart has created the encrypted volume but before we
transition to the host, suppressing itself once a password, recovery key or
FIDO2 token is enrolled. To make that work, determine_default_node() now looks
below /sysroot/ when running in the initrd, since the host file systems aren't
at their final location yet.

While the wizard is active it draws the same installer-style chrome (blue bars
at the top and bottom of the terminal) as systemd-sysinstall, using the shared
prompt_loop_yes_no() helper for its wipe confirmations.

Honours the systemd.firstboot= kernel command line option.

Fixes: #36298
2026-06-27 17:28:39 +02:00
Lennart Poettering e298331876 cryptenroll: add --unlock-headless as a new pseudo-unlock mechanism
THis simply tries TPM2 if available, and falls back to empty password.
2026-06-27 17:28:39 +02:00
Lennart Poettering 5f2d4fb623 cryptenroll: add --unlock-empty to unlock via an empty password 2026-06-27 17:28:39 +02:00
Yu Watanabe 9bad7610f8 man: fix typo 2026-01-06 08:48:05 +09:00
Lennart Poettering fc3adbbbcb man: always prefix links to uapi specs with their UAPI.XY spec number
Let's try to establish the spec numbers, by mentioning them in most doc
links.

Follow-up for: https://github.com/uapi-group/specifications/pull/187
2025-11-23 18:09:11 +01:00
Lennart Poettering c91f1a3db8 man: suggest using --unlock-tpm2-device=auto in cryptenroll example
When refreshing a tpm2 enrollment, it makes sense to use tpm2 to unlock
the device.

Fixes: #35279
2025-06-05 14:10:32 +01:00
Lennart Poettering 4b840414be cryptenroll/repart/creds: no longer default to binding against literal PCR 7
PCR 7 covers the SecureBoot policy, in particular "dbx", i.e. the
denylist of bad actors. That list is pretty much as frequently updated
as firmware these days (as fwupd took over automatic updating). This
means literal PCR 7 policies are problematic: they likely break soon,
and are as brittle as any other literal PCR policies.

hence, pick safer defaults, i.e. exclude PCR 7 from the default mask.
This means the mask is now empty.

Generally, people should really switch to signed PCR policies covering
PCR 11, in combination with systemd-pcrlock for the other PCRs.
2025-01-30 10:32:26 +01:00
nl6720 a153d7cbd2 man: replace "-" with "none" in cryptsetup commands and crypttab
`none` is more explicit and harder to overlook than `-` which in certain
contexts could be misunderstood to mean standard input.
2025-01-19 04:37:14 +09:00
Jan Engelhardt c592ebdf4f man: grammar fixes for introductory adverbs/phrases 2024-12-25 17:24:38 +01:00
Jan Engelhardt 44855c77a1 man: expand word contractions
For written text, contractions are not normally used.
2024-12-25 17:00:31 +01:00
Carlo Teubner dfbd4d8bc5 systemd-cryptenroll.xml: fix typo 2024-12-11 23:10:59 +00:00
Antonio Alvarez Feijoo 62b7b70bb7 man/systemd-cryptenroll: sort --fido2-credential-algorithm after --fido2-device
And also fix a typo.
2024-12-11 07:32:04 +01:00
Zbigniew Jędrzejewski-Szmek 7b2ebd7040 cryptenroll: show which devices support "hmac secret"
We'd silently skip devices which don't have the feature in the list.
This looked wrong esp. if no devices were suitable. Instead, list them
and show which ones are usable.

$ build/systemd-cryptenroll --fido2-device=list
PATH          MANUFACTURER PRODUCT                HMAC SECRET
/dev/hidraw7  Yubico       YubiKey OTP+FIDO+CCID  ✓
/dev/hidraw10 Yubico       Security Key by Yubico ✗
/dev/hidraw5  Yubico       Security Key by Yubico ✗
/dev/hidraw9  Yubico       Yubikey 4 OTP+U2F+CCID ✗
2024-12-10 10:58:58 +01:00
Zbigniew Jędrzejewski-Szmek 4b034cc128 systemd-cryptenroll: use pager for --help, add --no-pager option 2024-12-09 16:04:25 +01:00
Yu Watanabe 4ebbb5bfe8 man: asorted fixes
Closes #35307.
2024-11-24 01:11:42 +09:00
Lennart Poettering 3ae48d071c man: add enrollment type sections to cryptenroll man page
We have the same sections in the --help text, hence we even more so
should have them in the man page.
2024-11-22 10:42:37 +01:00
Štěpán Němec 597c6cc119 man: fix incorrect volume numbers in internal man page references
Some ambiguity (e.g., same-named man pages in multiple volumes)
makes it impossible to fully automate this, but the following
Python snippet (run inside the man/ directory of the systemd repo)
helped to generate the sed command lines (which were subsequently
manually reviewed, run and the false positives reverted):

from pathlib import Path

import lxml
from lxml import etree as ET

man2vol: dict[str, str] = {}
man2citerefs: dict[str, list] = {}

for file in Path(".").glob("*.xml"):
    tree = ET.parse(file, lxml.etree.XMLParser(recover=True))
    meta = tree.find("refmeta")
    if meta is not None:
        title = meta.findtext("refentrytitle")
        if title is not None:
            vol = meta.findtext("manvolnum")
            if vol is not None:
                man2vol[title] = vol
            citerefs = list(tree.iter("citerefentry"))
            if citerefs:
                man2citerefs[title] = citerefs

for man, refs in man2citerefs.items():
    for ref in refs:
        title = ref.findtext("refentrytitle")
        if title is not None:
            has = ref.findtext("manvolnum")
            try:
                should_have = man2vol[title]
            except KeyError:  # Non-systemd man page reference?  Ignore.
                continue
            if has != should_have:
                print(
                    f"sed -i '\\|<citerefentry><refentrytitle>{title}"
                    f"</refentrytitle><manvolnum>{has}</manvolnum>"
                    f"</citerefentry>|s|<manvolnum>{has}</manvolnum>|"
                    f"<manvolnum>{should_have}</manvolnum>|' {man}.xml"
                )
2024-11-11 20:31:08 +01:00
Lennart Poettering e742c99999 cryptenroll: add --list-devices switch that shows candidate block devices 2024-07-01 16:39:40 +02:00
Kamil Szczęk e262205eb7 cryptenroll: support for enrolling FIDO2 tokens in manual mode
systemd-cryptsetup supports a FIDO2 mode with manual parameters, where
the user provides all the information necessary for recreating the
secret, such as: credential ID, relaying party ID and the salt. This
feature works great for implementing 2FA schemes, where the salt file
is for example a secret unsealed from the TPM or some other source.
While the unlocking part is quite straightforward to set up, enrolling
such a keyslot - not so easy. There is no clearly documented
way on how to set this up and online resources are scarce on this topic
too. By implementing a straightforward way to enroll such a keyslot
directly from systemd-cryptenroll we streamline the enrollment process
and reduce chances for user error when doing such things manually.
2024-06-20 14:26:24 +02:00
Luca Boccassi 93df5217b9 tree-wide: 'allows to' -> 'allows one to'
As flagged by Lintian
2024-05-14 18:33:27 +02:00
Colin Watson 566491c971 docs,man: Avoid some ambiguous uses of "may not"
Like much English text, the systemd documentation uses "may not" in the
sense of both "will possibly not" and "is forbidden to".  In many cases
this is OK because the context makes it clear, but in others I felt it
was possible to read the "is forbidden to" sense by mistake: in
particular, I tripped over "the target file may not exist" in
systemd.unit(5) before realizing the correct interpretation.

Use "might not" or "may choose not to" in these cases to make it clear
which sense we mean.
2024-05-08 17:14:32 +02:00
Lennart Poettering 8518f4a814 cryptenroll: default to block device backing /var/ rather than /
With 1df4b21abd we started to default to
enrolling into the LUKS device backing the root fs if none was specified
(and no wipe operation is used). This changes to look for /var/ instead.

On most systems /var/ is going to be on the root fs, hence this change
is with little effect.

However, on systems where / and /var/ is separate it makes more sense to
default to /var/ because that's where the persistent and variable data
is placed (i.e.  where LUKS should be used) while / doesn't really have
to be variable, could as well be immutable, or ephemeral. Hence /var/
should be a safer default.

Or to say this differently: I think it makes sense to support systems
with /var/ being on / well. I also think it makes sense to support
systems with them being separate, and /var/ being variable and
persistent. But any other kind of system I find much less interesting to
support, and in that case people should just specify the device name.

Also, while we are at it, tighten the checks a bit, insist on a dm-crypt
+ LUKS superblock before continuing.

And finally, let's print a short message indicating the device we
operate on.
2024-04-23 15:23:44 +02:00
Ludwig Nussel 1df4b21abd cryptenroll: use root device by default 2024-04-23 12:29:32 +02:00
Sam Leonard 9bfabe14e5 man: fix incorrect XML in man page 2024-04-15 10:40:11 +02:00
Lennart Poettering 0fceb5539d man: now that the crdentials used by systemd-cryptenroll are in order, document them
Replaces: #31370
2024-02-20 16:50:00 +01:00
Yu Watanabe d2eb27eb7b man: fix typo
Follow-up for 631cf7f004.
2024-02-09 17:49:48 +09:00
Lennart Poettering 9d99f1686a Merge pull request #30766 from polarina/cryptenroll-tpm2-unlock
cryptenroll: Add support for unlocking through TPM2 enrollments
2024-02-08 17:41:03 +01:00
Vladimir Stoiakin 85686b37b0 cryptenroll: allow to use a public key on a token
This patch allows systemd-cryptenroll to enroll directly with a public key if a certificate is missing on a token.

Fixes: #30675
2024-02-03 03:00:51 +09:00
Gabríel Arthúr Pétursson 631cf7f004 cryptenroll: Add support for unlocking through TPM2 enrollments 2024-02-01 12:37:12 +00:00
Lennart Poettering 8ef31e1f13 Merge pull request #29692 from H5117/fix_pkcs11_uri
cryptenroll: change class in provided PKCS#11 URI if necessary
2024-01-05 12:14:26 +01:00
Vladimir Stoiakin 85828ef920 cryptenroll: change class in provided PKCS#11 URI if necessary
cryptenroll accepts only PKCS#11 URIs that match both a certificate and a private key in a token.
This patch allows users to provide a PKCS#11 URI that points to a certificate only, and makes possible to use output of some PKCS#11 tools directly.
Internally the patch changes 'type=cert' in the provided PKCS#11 URI to 'type=private' before storing in a LUKS2 header.

Fixes: #23479
2024-01-05 12:32:36 +03:00
David Tardon 932abebf4d man: fix markup
<arg> is not allowed inside <term>.
2023-12-26 13:10:35 +01:00
David Tardon eea10b26f7 man: use same version in public and system ident. 2023-12-25 15:51:47 +01:00
David Tardon 13a69c120b man: use <simplelist> for 'See also' sections
This is just a slight markup improvement; there should be no difference
in rendering.
2023-12-23 08:28:57 +01:00
Vladimir StoiakinandMkfsSion 3d05c05873 cryptsetup: Add support for EC keys in PKCS#11 tokens
Since EC keys doesn't support encryption directly, we use ECDH protocol.
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.

Co-authored-by: MkfsSion <mkfssion@mkfssion.com>
2023-12-19 13:14:16 +03:00
Lennart Poettering 342c70da7c man: update --tpm2-device-key= docs to reference the new ways to get the SRK 2023-11-09 12:49:29 +01:00
Lennart Poettering 244101876c man: explicitly document compat guarantees of cryptenroll vs. cryptsetup
Fixes: #29743
2023-11-08 14:28:10 +01:00
Dan Streetman c3a2a681be cryptenroll: add support for calculated TPM2 enrollment
Instead of enrolling the local TPM to a luks volume, use the public key from a
TPM to enroll it into the luks volume. This is useful when enrolling a TPM that
is not currently accessible, for example if the TPM is located on a different
system.
2023-11-07 12:20:54 -05:00
Lennart Poettering e206210909 man: document pcrlock 2023-11-03 11:24:58 +01:00
Dan Streetman 382bfd90c3 cryptenroll: allow specifying handle index of key to use for sealing
This defaults to the SRK index.
2023-10-10 05:40:27 -04:00
Zbigniew Jędrzejewski-Szmek 38e3c61dbb man/cryptenroll: link to crypttab(5) for examples
I was missing an example of how to use cryptenroll. We have that, but in
another page. Instead of repeating, let's just direct the user to the right
place.

Also, reformat synopsis to the "official" non-nested syntax.
2023-09-26 15:35:06 +02:00
Abderrahim Kitouni ec07c3c80b man: add version info
This tries to add information about when each option was added. It goes
back to version 183.

The version info is included from a separate file to allow generating it,
which would allow more control on the formatting of the final output.
2023-08-29 14:07:24 +01:00
Dan Streetman a11a2e059c cryptenroll: change man page example to remove leading 0x and lowercase hex 2023-08-24 12:35:58 -04:00
Dan Streetman 1782b0b88c man: update systemd-cryptenroll man page with details on --tpm2-pcrs format change
The previous commit extended the accepted format of --tpm2-pcrs to allow
specifying the hash algorithm (i.e. PCR bank) and hash digest value, this
updates the man page with those changes.
2023-08-04 11:20:31 -04:00
Frantisek Sumsal 94d82b5980 tree-wide: code spelling fixes
As reported by Fossies.
2023-04-20 21:54:59 +02:00
Zbigniew Jędrzejewski-Szmek 10fa7251c0 man/systemd-cryptenroll: update list of PCRs, link to uapi docs
Entia non sunt multiplicanda praeter necessitatem. We had a list of PCRs in the
man page which was already half out-of-date. Instead, link to web page with the
"authoritative" list. Here, drop the descriptions of what shim and grub do. Instead,
just give some short descriptions and mention what systemd components do.
systemd-pcrmachine.service and systemd-pcrfs@.service are now mentioned too.

https://github.com/uapi-group/specifications/commit/d0e590b1e2648e76ece66157ceade3f45b165b14
extended the table in the specs repo.
https://github.com/uapi-group/specifications/pull/59 adds some more text there
too.

Also, rework the recommendation: hint that PCR 11 is useful, and recommend
binding to policy signatures instead of direct PCR values. This new text is
intentionally vague: doing this correctly is hard, but let's at least not imply
that just binding to PCR 7 is useful in any way.

Also, change "string alias" to "name" in discussion of PCR names.

Inspired by https://discussion.fedoraproject.org/t/future-of-encryption-in-fedora/80397/17
2023-04-14 20:01:22 +01:00
OMOJOLA JOSHUA DAMILOLA 96ead603b8 systemd-cryptenroll: add string aliases for tpm2 PCRs
Fixes #26697. RFE.
2023-04-13 12:08:32 +01:00