Commit Graph
37 Commits
Author SHA1 Message Date
Daan De Meyer 94d745c42c cryptsetup: dlopen libcryptsetup in tokens
This avoids having to subpackage the tokens separately. If they link directly
against libcryptsetup, package manager will automatically add a dependency on
libcryptsetup to the package containing the tokens. With this change, the tokens
can ship in the main systemd package without necessarily pulling in libcryptsetup.

It also makes things more consistent. Once we also do the same for pam, any direct
linking will be limited to just libc, which for example simplifies writing tests for
ensuring we don't link unnecessarily as we don't have to add exceptions for the
cryptsetup tokens.

This actually drops the dependency on cryptsetup-libs for the fedora/centos/opensuse
systemd-udev package so install it explicitly in the initrd now to keep the tests
working.
2026-05-18 21:17:38 +00:00
Lennart Poettering 2c74a91cb8 sd-json: when parsing optionally insist top-level variant is object or array
Typically, the top-level JSON object has to be an object, in any json
document we parse, hence let's add a simple way to enforce that.

Make use of this in various places.

(Note, various other JSON parsers insist on this logic right from the
beginning, but I actually thinking making this insisting optional like
this patch does it is the cleaner approach)
2026-03-20 15:34:56 +01:00
Vitaly Kuznetsov 4883ef8aae cryptsetup-tokens: Print tpm2-primary-alg: only when it is known
When 'tpm2-primary-alg' is missing in LUKS JSON token, the output of
'cryptsetup luksDump' is always:

	tpm2-primary-alg: ecc

because tpm2_parse_luks2_json() returns the default (TPM2_ALG_ECC). This can be
misleading and wrong. Make tpm2_parse_luks2_json() return the reality and move
the default to tpm2_unseal().
2026-02-27 14:22:22 +01:00
Daan De Meyer 96fafb925c cryptsetup: Clean up includes
Split out of #37344.
2025-05-22 01:40:01 +09:00
Daan De Meyer e53d4f343d iovec-util: Reduce transitive includes 2025-05-07 22:04:46 +09:00
Aaron Rogers 08633ea902 cryptsetup: align tpm2-blob 2025-03-05 11:41:30 +01:00
Lennart Poettering 8e6587679b cryptenroll/cryptsetup: allow combined signed TPM2 PCR policy + pcrlock policy
So far you had to pick:

1. Use a signed PCR TPM2 policy to lock your disk to (i.e. UKI vendor
   blesses your setup via signature)
or
2. Use a pcrlock policy (i.e. local system blesses your setup via
   dynamic local policy stored in NV index)

It was not possible combine these two, because TPM2 access policies do
not allow the combination of PolicyAuthorize (used to implement #1
above) and PolicyAuthorizeNV (used to implement #2) in a single policy,
unless one is "further upstream" (and can simply remove the other from
the policy freely).

This is quite limiting of course, since we actually do want to enforce
on each TPM object that both the OS vendor policy and the local policy
must be fulfilled, without the chance for the vendor or the local system
to disable the other.

This patch addresses this: instead of trying to find a way to come up
with some adventurous scheme to combine both policy into one TPM2
policy, we simply shard the symmetric LUKS decryption key: one half we
protect via the signed PCR policy, and the other we protect via the
pcrlock policy. Only if both halves can be acquired the disk can be
decrypted.

This means:

1. we simply double the unlock key in length in case both policies shall
   be used.
2. We store two resulting TPM policy hashes in the LUKS token JSON, one
   for each policy
3. We store two sealed TPM policy key blobs in the LUKS token JSON, for
   both halves of the LUKS unlock key.

This patch keeps the "sharding" logic relatively generic (i.e. the low
level logic is actually fine with more than 2 shards), because I figure
sooner or later we might have to encode more shards, for example if we
add further TPM2-based access policies, for example when combining FIDO2
with TPM2, or implementing TOTP for this.
2024-09-06 15:55:28 +02:00
Lennart Poettering 9407fe6c3d treewide: use sd_json_variant_un{hex|base64}() pervasively
Use these helpers whenever appropriate. Drop separate string checks,
since these helpers already do them anyway.

No actual code change, just a rework to make use of a nice helper we
have already.
2024-08-30 10:35:44 +02:00
Kamil Szczęk 0828c6a2bf cryptsetup: improve TPM2 blob display
Just a tiny change to fix an eyesore in cryptsetup luksDump display :)
2024-06-26 20:52:31 +02:00
Lennart Poettering 309a747fa6 libsystemd: turn json.[ch] into a public API
This is preparation for making our Varlink API a public API. Since our
Varlink API is built on top of our JSON API we need to make that public
first (it's a nice API, but JSON APIs there are already enough, this is
purely about the Varlink angle).

I made most of the json.h APIs public, and just placed them in
sd-json.h. Sometimes I wasn't so sure however, since the underlying data
structures would have to be made public too. If in doubt I didn#t risk
it, and moved the relevant API to src/libsystemd/sd-json/json-util.h
instead (without any sd_* symbol prefixes).

This is mostly a giant search/replace patch.
2024-06-12 18:42:22 +02:00
Antonio Alvarez Feijoo 5cef6b5393 cryptsetup-tokens: fix pin asserts
If a user only presses ENTER when the PIN is requested (without actually typing
the PIN), an assertion is reached and no other unlock method is requested.

```
sh-5.2# systemctl status systemd-cryptsetup@cr_root
× systemd-cryptsetup@cr_root.service - Cryptography Setup for cr_root
     Loaded: loaded (/etc/crypttab; generated)
    Drop-In: /etc/systemd/system/systemd-cryptsetup@.service.d
             └─pcr-signature.conf
     Active: failed (Result: core-dump) since Thu 2024-04-25 08:44:30 UTC; 10min ago
       Docs: man:crypttab(5)
             man:systemd-cryptsetup-generator(8)
             man:systemd-cryptsetup@.service(8)
    Process: 559 ExecStartPre=/usr/bin/pcr-signature.sh (code=exited, status=0/SUCCESS)
    Process: 604 ExecStart=/usr/bin/systemd-cryptsetup attach cr_root /dev/disk/by-uuid/a8cbd937-6975-4e61-9120-ce5c03138700 none x-initrd.attach,tpm2-device=auto (code=dumped, signal=ABRT)
   Main PID: 604 (code=dumped, signal=ABRT)
        CPU: 19ms

Apr 25 08:44:29 localhost systemd[1]: Starting Cryptography Setup for cr_root...
Apr 25 08:44:30 localhost systemd-cryptsetup[604]: Assertion '!pin || pin_size > 0' failed at src/cryptsetup/cryptsetup-tokens/cryptsetup-token-systemd-tpm2.c:60, function cryptsetup_token_open_pin(). Aborting.
Apr 25 08:44:30 localhost systemd[1]: systemd-cryptsetup@cr_root.service: Main process exited, code=dumped, status=6/ABRT
Apr 25 08:44:30 localhost systemd[1]: systemd-cryptsetup@cr_root.service: Failed with result 'core-dump'.
Apr 25 08:44:30 localhost systemd[1]: Failed to start Cryptography Setup for cr_root.
```

In this case, `cryptsetup_token_open_pin()` receives an empty (non-NULL) `pin`
with `pin_size` equals to 0.

```
🔐 Please enter LUKS2 token PIN:

Breakpoint 3, cryptsetup_token_open_pin (cd=0x5555555744c0, token=0, pin=0x5555555b3cc0 "", pin_size=0, ret_password=0x7fffffffd380,
    ret_password_len=0x7fffffffd378, usrptr=0x0) at ../src/cryptsetup/cryptsetup-tokens/cryptsetup-token-systemd-tpm2.c:42
42	                void *usrptr /* plugin defined parameter passed to crypt_activate_by_token*() API */) {
(gdb) continue
Assertion '!pin || pin_size > 0' failed at src/cryptsetup/cryptsetup-tokens/cryptsetup-token-systemd-tpm2.c:60, function cryptsetup_token_open_pin(). Aborting.
```
2024-04-25 17:07:11 +02:00
Daan De Meyer ea2a57bee3 meson: Start adding devel and rc suffixes to the project version
Let's make sure that versions generated by meson-vcs-tag.sh always
sort higher than official and stable releases. We achieve this by
immediately updating the meson version in meson.build after a new
release. To make sure this version always sorts lower than future
rcs, we suffix it with "~devel" which will sort lower than "~rcX".

The new release workflow is to update the version in meson.build
for each rc and the official release and to also update the version
number after a new release to the next development version.

The full version is exposed as PROJECT_VERSION_FULL and used where
it makes sense over PROJECT_VERSION.

We also switch to reading the version from a meson.version file in
the repo instead of hardcoding it in meson.build. This makes it
easier to access both inside and outside of the project.

The meson-vcs-tag.sh script is rewritten to query the version from
meson.version instead of passing it in via the command line. This
makes it easier to use outside of systemd since users don't have to
query the version themselves first.
2024-02-14 15:36:34 +01:00
Lennart Poettering d37c312b87 pcrlock: when unlocking try to pick up pcrlock policy from system credentials 2024-01-22 15:20:22 +01:00
Mike Yuan bdd2036e81 hexdecoct: make unbase64mem and unhexmem always use SIZE_MAX 2024-01-09 03:59:15 +09:00
Lennart Poettering 8d042bc40a tpm2-util: more iovec'ification
Let's move more code to using struct iovec for passing around binary
chunks of data.

No real changes in behaviour, just refactoring.
2024-01-05 11:34:46 +01:00
Zbigniew Jędrzejewski-Szmek cee60fc36f tree-wide: use the usual spelling of "cannot"
(There's a bunch more in src/basic/linux/, but those files are copied from the
kernel and should not be modified.)
2023-11-13 13:27:36 +01:00
Lennart Poettering 404aea7815 tree-wide: hook everything up with pcrlock policy
Make sure cryptenroll and repart can enroll TPM2 policies with pcrlock
logic.

Make sure cryptsetup can unlock TPM2 policies with pcrlock in effect.
2023-11-03 11:24:24 +01:00
Dan Streetman 323eb4803a tpm2: add Tpm2PCRValue struct and associated functions
Add a new struct that can represent a PCR index, hash, and value all
together. This replaces code (e.g. the tpm2_pcr_read() parameters) that
required using both a TPML_PCR_SELECTION as well as array of TPM2B_DIGEST
entries, which was difficult to correlate the selection hash/index to each
digest.
2023-08-04 10:57:05 -04:00
William Roberts acbb504eaf tpm2: add support for a trusted SRK
Prevent attackers from spoofing the tpmKey portion of the AuthSession by
adding a trusted key to the LUKS header metadata. Also, use a persistent
object rather than a transient object.

This provides the following benifits:
1. No way to MITM the tpmKey portion of the session, see [1] for
details.

2. Strengthens the encrypted sessions, note that the bindKey could be
   dropped now.

3. Speed, once it's created we just use it.

4. Owner Auth is needed to call create primary, so using the SRK
   creates a scratch space for normal users.

This is a "first to set" model, in where the first person to set the key
in the LUKS header wins. Thus, setup should be done in a known good
state. If an SRK, which is a primary key at a special persistent
address, is found, it will use whatever is there. If not, it creates an
SRK. The SRK follows the convetions used through the tpm2-software
organization code on GitHub [2], however, a split has occured between
Windows and Linux with respect to SRK templates. The Linux SRK is
generated with the unique field size set to 0, in Windows, it properly
sets the size to key size in bytes and the unique data to all 0's of that
size. Note the proper templates for SRKs is covered in spec [3].
However, the most important thing, is that both SRKs are passwordless,
and thus they should be interchangable. If Windows is the first to make
the SRK, systemd will gladly accept it and vice-versa.

1. Without the bindKey being utilized, an attacker was able to intercept
this and fake a key, thus being able to decrypt and encrypt traffic as
needed. Introduction of the bindKey strengthened this, but allows for
the attacker to brute force AES128CFB using pin guesses. Introduction of
the salt increases the difficulty of this attack as well as DA attacks
on the TPM objects itself.

2. https://github.com/tpm2-software

3. https://trustedcomputinggroup.org/wp-content/uploads/TCG-TPM-v2.0-Provisioning-Guidance-Published-v1r1.pdf

Fixes: #20668
Fixes: #22637

Signed-off-by: William Roberts <william.c.roberts@intel.com>
2023-04-03 13:10:49 +02:00
Dan Streetman c69bd0abdb tpm2: add/rename functions to manage pcr selections
This renames some functions to match other to/from_string() naming,
and allows better management of TPML_PCR_SELECTION and TPMS_PCR_SELECTION
structs.
2023-03-09 10:46:19 -05:00
Dan Streetman aa07a4fa35 tpm2: add TPM2_PCR_VALID() 2023-03-09 10:46:19 -05:00
Dan Streetman 7bfe0a48d9 tpm2: rename tpm2 alg id<->string functions
The 'pcr_bank' functions operate on hash algs, and are not specific to the PCR
banks, while the 'primary_alg' functions operate on asymmetric algs, and are
not specific to primary keys.
2023-02-01 18:13:48 +01:00
William Roberts aae6eb9611 tpm2: add salt to pin
Add a salt to the pin and store it in the TPM2 LUKS header for future
this. This adds entropy to user supplied pins and helps brute forcing
the passphrase on the key residing in the TPM or brute forcing bind key
encrypted sessions with low entropy passphrases.

Signed-off-by: malikabhi05 <abhishek.malik@intel.com>
Signed-off-by: William Roberts <william.c.roberts@intel.com>
2023-01-18 21:58:33 +00:00
Lennart Poettering 5e476b8512 tree-wide: fix return value handling of base64mem()
This returns an ssize_t, not an int. On populare archs that's the
difference between 64bit and 32bit. hence, let's be more careful here,
and not silently drop half the bits on the ground by assigning the
return value to "int".

As noticed by @malikabhi05:

https://github.com/systemd/systemd/pull/24754#discussion_r1062903159
2023-01-11 10:46:08 +01:00
Lennart Poettering b6fd88a511 cryptsetup: use errno-flavoured logging where we have an errno 2022-10-17 08:02:03 +02:00
Lennart Poettering 75a9681ec0 cryptsetup: hook up TPM2 token code with policies based on PCR signatures, too 2022-09-08 16:34:27 +02:00
Jonas Witschel 35ba2b4f01 cryptsetup: implement cryptsetup_token_open_pin for systemd-tpm2 LUKS2 token
This finishes the implementation started in commit
1f895adac2 ("cryptsetup: add libcryptsetup TPM2
PIN support").

Note that the previous implementation took a shortcut by returning EOPNOTSUPP
instead of the correct ENOANO as per the cryptsetup documentation. This meant
that systemd-cryptsetup fell back to the non-plugin implementation in order to
ask for the PIN. Since this does not happen any more when returning ENOANO, we
need to ask for the PIN in attach_luks2_by_tpm2_via_plugin() instead like
attach_luks2_by_fido2_via_plugin() does.
2022-08-05 12:19:57 +02:00
Grigori Goronzy 1f895adac2 cryptsetup: add libcryptsetup TPM2 PIN support
This is unfinished: we don't have any way to actually query for PINs
interactively this way. It is similar to FIDO2 and PKCS#11 in this
regard.

Nonetheless, this code is capable of validating and dumping tokens, so
it is already useful as-is.
2022-03-15 21:17:00 +01:00
Zbigniew Jędrzejewski-Szmek 718ca77232 shared/json: use int64_t instead of intmax_t
We were already asserting that the intmax_t and uintmax_t types
are the same as int64_t and uint64_t. Pretty much everywhere in
the code base we use the latter types. In principle intmax_t could
be something different on some new architecture, and then the code would
fail to compile or behave differently. We actually do not want the code
to behave differently on those architectures, because that'd break
interoperability. So let's just use int64_t/uint64_t since that's what
we indend to use.
2021-11-18 01:34:31 +01:00
Lennart Poettering 2b92a67261 tpm2: support RSA primary keys as fallback if TPM2 devices don't support ECC
Previously, we hardcoded use of ECC as primary keys, since they are much
faster (i.e. saving multiple seconds) to do TPM2 operations with. Alas,
not all TPM2 chips appear to support ECC. Bummer.

Let's hence add a fallback logic: if we can't create an ECC primary key,
use an RSA key, and store that fact away.

AFIU the security guarantees should be roughly the same, it's just that
RSA primary keys is so much slower to work with than ECC.

The primary key algorithm is used is stored in the JSON header of LUKS
disks, in a new field. If the field is absent we assume to use ECC, to
provide full compatibility with old systemd versions.

The primary key algorithm is stored in a new field in the credentials
file format (in fact, a previously unused zero space is used), too.

Hopefully, this should ensure that TPM2 support will "just work" on more
systems.

Fixes: #20361
2021-09-13 14:48:23 +02:00
Anssi Hannula dfba45185c cryptsetup-tokens: fix typo in tpm2 token dump output
cryptsetup_token_dump() gets called when the user calls
"cryptsetup luksDump"  for a volume and it prints the token-specific
data.

The tpm2 cryptsetup_token_dump() function misspells tpm2 as tmp2 on two
lines of its output.

Fix that.
2021-09-09 17:54:41 +01:00
Yu Watanabe bdbb61f69f tree-wide: fix typo 2021-08-18 13:36:14 +02:00
Luca Boccassi e908236e05 Merge pull request #20384 from keszybz/udev-code-modernization
Various minor refactorings (basic/log, udev, cryptsetup-tokens)
2021-08-07 12:06:00 +01:00
Zbigniew Jędrzejewski-Szmek 700ea50482 cryptsetup-tokens: inline one interator variable declaration 2021-08-07 08:50:18 +02:00
Ondrej Kozina 38a0aec61e cryptsetup: validate optional tpm2 pcr bank field in token. 2021-08-06 13:33:50 +01:00
Lennart Poettering b98855d90b cryptsetup: unbreak CI build
PR #20176 broke building of the cryptsetup token logic. This wasn't
noticed before the PR was merged, because the only CIs new enough to be
able to build the token logic (the Fedora Rawhide ones) didn't actually
run at all on the PR.

Let's add the missing hookup for the TPM2 PCR bank logic also to the
token module, to make the CI pass again.
2021-08-01 10:43:36 +02:00
Ondrej Kozina d1ae38d85a Add support for systemd-tpm2 libcryptsetup plugin.
Add support for systemd-tpm2 based LUKS2 device activation
via libcryptsetup plugin. This make the feature (tpm2 sealed
LUKS2 keyslot passphrase) usable from both systemd utilities
and cryptsetup cli.

The feature is configured via -Dlibcryptsetup-plugins combo
with default value set to 'auto'. It get's enabled automatically
when cryptsetup 2.4.0 or later is installed in build system.
2021-07-26 15:15:16 +02:00