Introduce 'fixate-volume-key' option to repart/cryptsetup to pin the exact LUKS volume key hash (#40343)

Add an option to generate the expected volume key hash for LUKS volumes
by systemd-repart
and put it to crypttab, make systemd-cryptsetup check it upon attaching.
The format of the hash
matches what's currently being measured to TPM2 PCR with
tpm2-measure-pcr=.

Closes #40123
This commit is contained in:
Lennart Poettering
2026-01-19 21:59:47 +01:00
committed by GitHub
8 changed files with 270 additions and 28 deletions
+61
View File
@@ -7,6 +7,9 @@
#include "alloc-util.h"
#include "cryptsetup-util.h"
#include "dlfcn-util.h"
#include "escape.h"
#include "hexdecoct.h"
#include "hmac.h"
#include "log.h"
#include "parse-util.h"
#include "string-util.h"
@@ -198,6 +201,64 @@ int cryptsetup_add_token_json(struct crypt_device *cd, sd_json_variant *v) {
return 0;
}
int cryptsetup_get_volume_key_prefix(
struct crypt_device *cd,
const char *volume_name,
char **ret) {
_cleanup_free_ char *volume = NULL;
const char *uuid;
char *s;
uuid = sym_crypt_get_uuid(cd);
if (!uuid)
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to get LUKS UUID.");
if (volume_name)
/* avoid ambiguity around ":" once we join things below */
volume = xescape(volume_name, ":");
else
volume = strjoin("luks-", uuid);
if (!volume)
return log_oom_debug();
s = strjoin("cryptsetup:", volume, ":", uuid);
if (!s)
return log_oom_debug();
*ret = s;
return 0;
}
/* The hash must match what measure_volume_key() extends to the SHA256 bank of the TPM2. */
int cryptsetup_get_volume_key_id(
struct crypt_device *cd,
const char *volume_name,
const void *volume_key,
size_t volume_key_size,
char **ret) {
_cleanup_free_ char *prefix = NULL;
uint8_t digest[SHA256_DIGEST_SIZE];
char *hex;
int r;
r = cryptsetup_get_volume_key_prefix(cd, volume_name, &prefix);
if (r < 0)
return log_debug_errno(r, "Failed to get LUKS volume key prefix.");
hmac_sha256(volume_key, volume_key_size, prefix, strlen(prefix), digest);
hex = hexmem(digest, sizeof(digest));
if (!hex)
return log_oom_debug();
*ret = hex;
return 0;
}
#endif
int dlopen_cryptsetup(void) {
+3
View File
@@ -66,6 +66,9 @@ int cryptsetup_set_minimal_pbkdf(struct crypt_device *cd);
int cryptsetup_get_token_as_json(struct crypt_device *cd, int idx, const char *verify_type, sd_json_variant **ret);
int cryptsetup_add_token_json(struct crypt_device *cd, sd_json_variant *v);
int cryptsetup_get_volume_key_prefix(struct crypt_device *cd, const char *volume_name, char **ret);
int cryptsetup_get_volume_key_id(struct crypt_device *cd, const char *volume_name, const void *volume_key,
size_t volume_key_size, char **ret);
#endif
int dlopen_cryptsetup(void);
+1 -1
View File
@@ -151,7 +151,7 @@ typedef enum Tpm2UserspaceEventType {
DECLARE_STRING_TABLE_LOOKUP(tpm2_userspace_event_type, Tpm2UserspaceEventType);
int tpm2_pcr_extend_bytes(Tpm2Context *c, char **banks, unsigned pcr_index, const struct iovec *data, const struct iovec *secret, Tpm2UserspaceEventType event, const char *description);
int tpm2_pcr_extend_bytes(Tpm2Context *c, char **banks, unsigned pcr_index, const struct iovec *data, const struct iovec *secret, Tpm2UserspaceEventType event_type, const char *description);
int tpm2_nvpcr_get_index(const char *name, uint32_t *ret);
int tpm2_nvpcr_extend_bytes(Tpm2Context *c, const Tpm2Handle *session, const char *name, const struct iovec *data, const struct iovec *secret, Tpm2UserspaceEventType event_type, const char *description);
int tpm2_nvpcr_acquire_anchor_secret(struct iovec *ret, bool sync_secondary);