From: Lennart Poettering Date: Tue, 21 Nov 2023 10:44:34 +0000 (+0100) Subject: pcrlock: when unlocking try to pick up pcrlock policy from system credentials X-Git-Tag: v256-rc1~1060^2~2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d37c312b87aeba4a470ad720eda56cdbc9ea2290;p=thirdparty%2Fsystemd.git pcrlock: when unlocking try to pick up pcrlock policy from system credentials --- diff --git a/src/cryptenroll/cryptenroll-tpm2.c b/src/cryptenroll/cryptenroll-tpm2.c index 87e19814db4..b556c70931f 100644 --- a/src/cryptenroll/cryptenroll-tpm2.c +++ b/src/cryptenroll/cryptenroll-tpm2.c @@ -365,6 +365,7 @@ int enroll_tpm2(struct crypt_device *cd, &IOVEC_MAKE(policy.buffer, policy.size), use_pin ? &IOVEC_MAKE(binary_salt, sizeof(binary_salt)) : NULL, &srk, + pcrlock_path ? &pcrlock_policy.nv_handle : NULL, flags, &v); if (r < 0) diff --git a/src/cryptsetup/cryptsetup-tokens/cryptsetup-token-systemd-tpm2.c b/src/cryptsetup/cryptsetup-tokens/cryptsetup-token-systemd-tpm2.c index 14b98abc060..b65229992cf 100644 --- a/src/cryptsetup/cryptsetup-tokens/cryptsetup-token-systemd-tpm2.c +++ b/src/cryptsetup/cryptsetup-tokens/cryptsetup-token-systemd-tpm2.c @@ -42,7 +42,7 @@ _public_ int cryptsetup_token_open_pin( void *usrptr /* plugin defined parameter passed to crypt_activate_by_token*() API */) { _cleanup_(erase_and_freep) char *base64_encoded = NULL, *pin_string = NULL; - _cleanup_(iovec_done) struct iovec blob = {}, pubkey = {}, policy_hash = {}, salt = {}, srk = {}; + _cleanup_(iovec_done) struct iovec blob = {}, pubkey = {}, policy_hash = {}, salt = {}, srk = {}, pcrlock_nv = {}; _cleanup_(iovec_done_erase) struct iovec decrypted_key = {}; _cleanup_(json_variant_unrefp) JsonVariant *v = NULL; uint32_t hash_pcr_mask, pubkey_pcr_mask; @@ -88,6 +88,7 @@ _public_ int cryptsetup_token_open_pin( &policy_hash, &salt, &srk, + &pcrlock_nv, &flags); if (r < 0) return log_debug_open_error(cd, r); @@ -109,6 +110,7 @@ _public_ int cryptsetup_token_open_pin( &policy_hash, &salt, &srk, + &pcrlock_nv, flags, &decrypted_key); if (r < 0) @@ -166,7 +168,7 @@ _public_ void cryptsetup_token_dump( const char *json /* validated 'systemd-tpm2' token if cryptsetup_token_validate is defined */) { _cleanup_free_ char *hash_pcrs_str = NULL, *pubkey_pcrs_str = NULL, *blob_str = NULL, *policy_hash_str = NULL, *pubkey_str = NULL; - _cleanup_(iovec_done) struct iovec blob = {}, pubkey = {}, policy_hash = {}, salt = {}, srk = {}; + _cleanup_(iovec_done) struct iovec blob = {}, pubkey = {}, policy_hash = {}, salt = {}, srk = {}, pcrlock_nv = {}; _cleanup_(json_variant_unrefp) JsonVariant *v = NULL; uint32_t hash_pcr_mask, pubkey_pcr_mask; uint16_t pcr_bank, primary_alg; @@ -191,6 +193,7 @@ _public_ void cryptsetup_token_dump( &policy_hash, &salt, &srk, + &pcrlock_nv, &flags); if (r < 0) return (void) crypt_log_debug_errno(cd, r, "Failed to parse " TOKEN_NAME " JSON fields: %m"); @@ -226,6 +229,7 @@ _public_ void cryptsetup_token_dump( crypt_log(cd, "\ttpm2-pcrlock: %s\n", true_false(flags & TPM2_FLAGS_USE_PCRLOCK)); crypt_log(cd, "\ttpm2-salt: %s\n", true_false(iovec_is_set(&salt))); crypt_log(cd, "\ttpm2-srk: %s\n", true_false(iovec_is_set(&srk))); + crypt_log(cd, "\ttpm2-pcrlock-nv: %s\n", true_false(iovec_is_set(&pcrlock_nv))); } /* diff --git a/src/cryptsetup/cryptsetup-tokens/luks2-tpm2.c b/src/cryptsetup/cryptsetup-tokens/luks2-tpm2.c index e2e4d0dc049..d902c591dff 100644 --- a/src/cryptsetup/cryptsetup-tokens/luks2-tpm2.c +++ b/src/cryptsetup/cryptsetup-tokens/luks2-tpm2.c @@ -27,6 +27,7 @@ int acquire_luks2_key( const struct iovec *policy_hash, const struct iovec *salt, const struct iovec *srk, + const struct iovec *pcrlock_nv, TPM2Flags flags, struct iovec *ret_decrypted_key) { @@ -75,6 +76,14 @@ int acquire_luks2_key( r = tpm2_pcrlock_policy_load(pcrlock_path, &pcrlock_policy); if (r < 0) return r; + if (r == 0) { + /* Not found? Then search among passed credentials */ + r = tpm2_pcrlock_policy_from_credentials(srk, pcrlock_nv, &pcrlock_policy); + if (r < 0) + return r; + if (r == 0) + return log_error_errno(SYNTHETIC_ERRNO(EREMOTE), "Couldn't find pcrlock policy for volume."); + } } _cleanup_(tpm2_context_unrefp) Tpm2Context *tpm2_context = NULL; diff --git a/src/cryptsetup/cryptsetup-tokens/luks2-tpm2.h b/src/cryptsetup/cryptsetup-tokens/luks2-tpm2.h index 20151d6ca9f..4900cd53628 100644 --- a/src/cryptsetup/cryptsetup-tokens/luks2-tpm2.h +++ b/src/cryptsetup/cryptsetup-tokens/luks2-tpm2.h @@ -20,5 +20,6 @@ int acquire_luks2_key( const struct iovec *policy_hash, const struct iovec *salt, const struct iovec *srk, + const struct iovec *pcrlock_nv, TPM2Flags flags, struct iovec *decrypted_key); diff --git a/src/cryptsetup/cryptsetup-tpm2.c b/src/cryptsetup/cryptsetup-tpm2.c index fc0ec443a51..297ef6fe4a3 100644 --- a/src/cryptsetup/cryptsetup-tpm2.c +++ b/src/cryptsetup/cryptsetup-tpm2.c @@ -70,6 +70,7 @@ int acquire_tpm2_key( const struct iovec *policy_hash, const struct iovec *salt, const struct iovec *srk, + const struct iovec *pcrlock_nv, TPM2Flags flags, usec_t until, bool headless, @@ -128,6 +129,14 @@ int acquire_tpm2_key( r = tpm2_pcrlock_policy_load(pcrlock_path, &pcrlock_policy); if (r < 0) return r; + if (r == 0) { + /* Not found? Then search among passed credentials */ + r = tpm2_pcrlock_policy_from_credentials(srk, pcrlock_nv, &pcrlock_policy); + if (r < 0) + return r; + if (r == 0) + return log_error_errno(SYNTHETIC_ERRNO(EREMOTE), "Couldn't find pcrlock policy for volume."); + } } _cleanup_(tpm2_context_unrefp) Tpm2Context *tpm2_context = NULL; @@ -219,6 +228,7 @@ int find_tpm2_auto_data( struct iovec *ret_policy_hash, struct iovec *ret_salt, struct iovec *ret_srk, + struct iovec *ret_pcrlock_nv, TPM2Flags *ret_flags, int *ret_keyslot, int *ret_token) { @@ -228,7 +238,7 @@ int find_tpm2_auto_data( assert(cd); for (token = start_token; token < sym_crypt_token_max(CRYPT_LUKS2); token++) { - _cleanup_(iovec_done) struct iovec blob = {}, policy_hash = {}, pubkey = {}, salt = {}, srk = {}; + _cleanup_(iovec_done) struct iovec blob = {}, policy_hash = {}, pubkey = {}, salt = {}, srk = {}, pcrlock_nv = {}; _cleanup_(json_variant_unrefp) JsonVariant *v = NULL; uint32_t hash_pcr_mask, pubkey_pcr_mask; uint16_t pcr_bank, primary_alg; @@ -253,6 +263,7 @@ int find_tpm2_auto_data( &policy_hash, &salt, &srk, + &pcrlock_nv, &flags); if (r == -EUCLEAN) /* Gracefully handle issues in JSON fields not owned by us */ continue; @@ -276,6 +287,7 @@ int find_tpm2_auto_data( *ret_keyslot = keyslot; *ret_token = token; *ret_srk = TAKE_STRUCT(srk); + *ret_pcrlock_nv = TAKE_STRUCT(pcrlock_nv); *ret_flags = flags; return 0; } diff --git a/src/cryptsetup/cryptsetup-tpm2.h b/src/cryptsetup/cryptsetup-tpm2.h index a593e043749..0eaf9280ef4 100644 --- a/src/cryptsetup/cryptsetup-tpm2.h +++ b/src/cryptsetup/cryptsetup-tpm2.h @@ -28,6 +28,7 @@ int acquire_tpm2_key( const struct iovec *policy_hash, const struct iovec *salt, const struct iovec *srk, + const struct iovec *pcrlock_nv, TPM2Flags flags, usec_t until, bool headless, @@ -47,6 +48,7 @@ int find_tpm2_auto_data( struct iovec *ret_policy_hash, struct iovec *ret_salt, struct iovec *ret_srk, + struct iovec *ret_pcrlock_nv, TPM2Flags *ret_flags, int *ret_keyslot, int *ret_token); @@ -70,6 +72,7 @@ static inline int acquire_tpm2_key( const struct iovec *policy_hash, const struct iovec *salt, const struct iovec *srk, + const struct iovec *pcrlock_nv, TPM2Flags flags, usec_t until, bool headless, @@ -93,6 +96,7 @@ static inline int find_tpm2_auto_data( struct iovec *ret_policy_hash, struct iovec *ret_salt, struct iovec *ret_srk, + struct iovec *ret_pcrlock_nv, TPM2Flags *ret_flags, int *ret_keyslot, int *ret_token) { diff --git a/src/cryptsetup/cryptsetup.c b/src/cryptsetup/cryptsetup.c index a8be8052370..0840a71548b 100644 --- a/src/cryptsetup/cryptsetup.c +++ b/src/cryptsetup/cryptsetup.c @@ -1688,6 +1688,7 @@ static int attach_luks_or_plain_or_bitlk_by_tpm2( /* policy_hash= */ NULL, /* we don't know the policy hash */ /* salt= */ NULL, /* srk= */ NULL, + /* pcrlock_nv= */ NULL, arg_tpm2_pin ? TPM2_FLAGS_USE_PIN : 0, until, arg_headless, @@ -1732,7 +1733,7 @@ static int attach_luks_or_plain_or_bitlk_by_tpm2( * works. */ for (;;) { - _cleanup_(iovec_done) struct iovec pubkey = {}, salt = {}, srk = {}; + _cleanup_(iovec_done) struct iovec pubkey = {}, salt = {}, srk = {}, pcrlock_nv = {}; uint32_t hash_pcr_mask, pubkey_pcr_mask; uint16_t pcr_bank, primary_alg; TPM2Flags tpm2_flags; @@ -1750,6 +1751,7 @@ static int attach_luks_or_plain_or_bitlk_by_tpm2( &policy_hash, &salt, &srk, + &pcrlock_nv, &tpm2_flags, &keyslot, &token); @@ -1784,6 +1786,7 @@ static int attach_luks_or_plain_or_bitlk_by_tpm2( &policy_hash, &salt, &srk, + &pcrlock_nv, tpm2_flags, until, arg_headless, diff --git a/src/partition/repart.c b/src/partition/repart.c index 9b6b8a5a14c..958af799e4e 100644 --- a/src/partition/repart.c +++ b/src/partition/repart.c @@ -3922,6 +3922,7 @@ static int partition_encrypt(Context *context, Partition *p, PartitionTarget *ta &IOVEC_MAKE(policy.buffer, policy.size), /* salt= */ NULL, /* no salt because tpm2_seal has no pin */ &srk, + &pcrlock_policy.nv_handle, flags, &v); if (r < 0) diff --git a/src/shared/tpm2-util.c b/src/shared/tpm2-util.c index 770a1e2b142..713ea2a4956 100644 --- a/src/shared/tpm2-util.c +++ b/src/shared/tpm2-util.c @@ -4,6 +4,7 @@ #include "alloc-util.h" #include "constants.h" +#include "creds-util.h" #include "cryptsetup-util.h" #include "dirent-util.h" #include "dlfcn-util.h" @@ -25,6 +26,7 @@ #include "nulstr-util.h" #include "parse-util.h" #include "random-util.h" +#include "recurse-dir.h" #include "sha256.h" #include "sort-util.h" #include "stat-util.h" @@ -6800,6 +6802,43 @@ int tpm2_pcrlock_search_file(const char *path, FILE **ret_file, char **ret_path) return 0; } +int tpm2_pcrlock_policy_from_json( + JsonVariant *v, + Tpm2PCRLockPolicy *ret_policy) { + + /* We use a type check of _JSON_VARIANT_TYPE_INVALID for the integer fields to allow + * json_dispatch_uint32() to parse strings as integers to work around the integer type weakness of + * JSON's design. */ + JsonDispatch policy_dispatch[] = { + { "pcrBank", JSON_VARIANT_STRING, json_dispatch_tpm2_algorithm, offsetof(Tpm2PCRLockPolicy, algorithm), JSON_MANDATORY }, + { "pcrValues", JSON_VARIANT_ARRAY, json_dispatch_variant, offsetof(Tpm2PCRLockPolicy, prediction_json), JSON_MANDATORY }, + { "nvIndex", _JSON_VARIANT_TYPE_INVALID, json_dispatch_uint32, offsetof(Tpm2PCRLockPolicy, nv_index), JSON_MANDATORY }, + { "nvHandle", JSON_VARIANT_STRING, json_dispatch_unbase64_iovec, offsetof(Tpm2PCRLockPolicy, nv_handle), JSON_MANDATORY }, + { "nvPublic", JSON_VARIANT_STRING, json_dispatch_unbase64_iovec, offsetof(Tpm2PCRLockPolicy, nv_public), JSON_MANDATORY }, + { "srkHandle", JSON_VARIANT_STRING, json_dispatch_unbase64_iovec, offsetof(Tpm2PCRLockPolicy, srk_handle), JSON_MANDATORY }, + { "pinPublic", JSON_VARIANT_STRING, json_dispatch_unbase64_iovec, offsetof(Tpm2PCRLockPolicy, pin_public), JSON_MANDATORY }, + { "pinPrivate", JSON_VARIANT_STRING, json_dispatch_unbase64_iovec, offsetof(Tpm2PCRLockPolicy, pin_private), JSON_MANDATORY }, + {} + }; + + _cleanup_(tpm2_pcrlock_policy_done) Tpm2PCRLockPolicy policy = {}; + int r; + + assert(v); + assert(ret_policy); + + r = json_dispatch(v, policy_dispatch, JSON_LOG, &policy); + if (r < 0) + return r; + + r = tpm2_pcr_prediction_from_json(&policy.prediction, policy.algorithm, policy.prediction_json); + if (r < 0) + return r; + + *ret_policy = TAKE_STRUCT(policy); + return 1; +} + int tpm2_pcrlock_policy_load( const char *path, Tpm2PCRLockPolicy *ret_policy) { @@ -6816,41 +6855,140 @@ int tpm2_pcrlock_policy_load( if (r < 0) return log_error_errno(r, "Failed to load TPM2 pcrlock policy file: %m"); - _cleanup_(json_variant_unrefp) JsonVariant *configuration_json = NULL; + _cleanup_(json_variant_unrefp) JsonVariant *v = NULL; r = json_parse_file( f, discovered_path, /* flags = */ 0, - &configuration_json, + &v, /* ret_line= */ NULL, /* ret_column= */ NULL); if (r < 0) return log_error_errno(r, "Failed to parse existing pcrlock policy file '%s': %m", discovered_path); - JsonDispatch policy_dispatch[] = { - { "pcrBank", JSON_VARIANT_STRING, json_dispatch_tpm2_algorithm, offsetof(Tpm2PCRLockPolicy, algorithm), JSON_MANDATORY }, - { "pcrValues", JSON_VARIANT_ARRAY, json_dispatch_variant, offsetof(Tpm2PCRLockPolicy, prediction_json), JSON_MANDATORY }, - { "nvIndex", _JSON_VARIANT_TYPE_INVALID, json_dispatch_uint32, offsetof(Tpm2PCRLockPolicy, nv_index), JSON_MANDATORY }, - { "nvHandle", JSON_VARIANT_STRING, json_dispatch_unbase64_iovec, offsetof(Tpm2PCRLockPolicy, nv_handle), JSON_MANDATORY }, - { "nvPublic", JSON_VARIANT_STRING, json_dispatch_unbase64_iovec, offsetof(Tpm2PCRLockPolicy, nv_public), JSON_MANDATORY }, - { "srkHandle", JSON_VARIANT_STRING, json_dispatch_unbase64_iovec, offsetof(Tpm2PCRLockPolicy, srk_handle), JSON_MANDATORY }, - { "pinPublic", JSON_VARIANT_STRING, json_dispatch_unbase64_iovec, offsetof(Tpm2PCRLockPolicy, pin_public), JSON_MANDATORY }, - { "pinPrivate", JSON_VARIANT_STRING, json_dispatch_unbase64_iovec, offsetof(Tpm2PCRLockPolicy, pin_private), JSON_MANDATORY }, - {} - }; + return tpm2_pcrlock_policy_from_json(v, ret_policy); +} - _cleanup_(tpm2_pcrlock_policy_done) Tpm2PCRLockPolicy policy = {}; +static int pcrlock_policy_load_credential( + const char *name, + const struct iovec *data, + Tpm2PCRLockPolicy *ret) { + + _cleanup_free_ char *c = NULL; + int r; + + assert(name); + + c = strdup(name); + if (!c) + return log_oom(); - r = json_dispatch(configuration_json, policy_dispatch, JSON_LOG, &policy); + ascii_strlower(c); /* Lowercase, to match what we did at encryption time */ + + _cleanup_(iovec_done) struct iovec decoded = {}; + r = decrypt_credential_and_warn( + c, + now(CLOCK_REALTIME), + /* tpm2_device= */ NULL, + /* tpm2_signature_path= */ NULL, + data, + CREDENTIAL_ALLOW_NULL, + &decoded); if (r < 0) return r; - r = tpm2_pcr_prediction_from_json(&policy.prediction, policy.algorithm, policy.prediction_json); + if (memchr(decoded.iov_base, 0, decoded.iov_len)) + return log_error_errno(r, "Credential '%s' contains embedded NUL byte, refusing.", name); + + _cleanup_(json_variant_unrefp) JsonVariant *v = NULL; + r = json_parse(decoded.iov_base, + /* flags= */ 0, + &v, + /* ret_line= */ NULL, + /* ret_column= */ NULL); + if (r < 0) + return log_error_errno(r, "Failed to parse pcrlock policy: %m"); + + r = tpm2_pcrlock_policy_from_json(v, ret); if (r < 0) return r; - *ret_policy = TAKE_STRUCT(policy); - return 1; + return 0; +} + +int tpm2_pcrlock_policy_from_credentials( + const struct iovec *srk, + const struct iovec *nv, + Tpm2PCRLockPolicy *ret) { + + _cleanup_close_ int dfd = -EBADF; + int r; + + /* During boot we'll not have access to the pcrlock.json file in /var/. In order to support + * pcrlock-bound root file systems we'll store a copy of the JSON data, wrapped in an (plaintext) + * credential in the ESP or XBOOTLDR partition. There might be multiple of those however (because of + * multi-boot), hence we use the SRK and NV data from the LUKS2 header as search key, and parse all + * such JSON policies until we find a matching one. */ + + const char *cp = secure_getenv("SYSTEMD_ENCRYPTED_SYSTEM_CREDENTIALS_DIRECTORY") ?: ENCRYPTED_SYSTEM_CREDENTIALS_DIRECTORY; + + dfd = open(cp, O_CLOEXEC|O_DIRECTORY); + if (dfd < 0) { + if (errno == ENOENT) { + log_debug("No encrypted system credentials passed."); + return 0; + } + + return log_error_errno(errno, "Faile to open system credentials directory."); + } + + _cleanup_free_ DirectoryEntries *de = NULL; + r = readdir_all(dfd, RECURSE_DIR_IGNORE_DOT, &de); + if (r < 0) + return log_error_errno(r, "Failed to enumerate system credentials: %m"); + + FOREACH_ARRAY(i, de->entries, de->n_entries) { + _cleanup_(iovec_done) struct iovec data = {}; + struct dirent *d = *i; + + if (!startswith_no_case(d->d_name, "pcrlock.")) /* VFAT is case-insensitive, hence don't be too strict here */ + continue; + + r = read_full_file_full( + dfd, d->d_name, + /* offset= */ UINT64_MAX, + /* size= */ CREDENTIAL_ENCRYPTED_SIZE_MAX, + READ_FULL_FILE_UNBASE64|READ_FULL_FILE_FAIL_WHEN_LARGER, + /* bind_name= */ NULL, + (char**) &data.iov_base, + &data.iov_len); + if (r == -ENOENT) + continue; + if (r < 0) { + log_warning_errno(r, "Failed to read credentials file %s/%s, skipping: %m", ENCRYPTED_SYSTEM_CREDENTIALS_DIRECTORY, d->d_name); + continue; + } + + _cleanup_(tpm2_pcrlock_policy_done) Tpm2PCRLockPolicy loaded_policy = {}; + r = pcrlock_policy_load_credential( + d->d_name, + &data, + &loaded_policy); + if (r < 0) { + log_warning_errno(r, "Loading of pcrlock policy from credential '%s/%s' failed, skipping.", ENCRYPTED_SYSTEM_CREDENTIALS_DIRECTORY, d->d_name); + continue; + } + + if ((!srk || iovec_memcmp(srk, &loaded_policy.srk_handle) == 0) && + (!nv || iovec_memcmp(nv, &loaded_policy.nv_handle) == 0)) { + *ret = TAKE_STRUCT(loaded_policy); + return 1; + } + } + + log_info("No pcrlock policy found among system credentials."); + *ret = (Tpm2PCRLockPolicy) {}; + return 0; } int tpm2_load_public_key_file(const char *path, TPM2B_PUBLIC *ret) { @@ -6970,6 +7108,7 @@ int tpm2_make_luks2_json( const struct iovec *policy_hash, const struct iovec *salt, const struct iovec *srk, + const struct iovec *pcrlock_nv, TPM2Flags flags, JsonVariant **ret) { @@ -7012,7 +7151,8 @@ int tpm2_make_luks2_json( JSON_BUILD_PAIR_CONDITION(pubkey_pcr_mask != 0, "tpm2_pubkey_pcrs", JSON_BUILD_VARIANT(pkmj)), JSON_BUILD_PAIR_CONDITION(pubkey_pcr_mask != 0, "tpm2_pubkey", JSON_BUILD_IOVEC_BASE64(pubkey)), JSON_BUILD_PAIR_CONDITION(iovec_is_set(salt), "tpm2_salt", JSON_BUILD_IOVEC_BASE64(salt)), - JSON_BUILD_PAIR_CONDITION(iovec_is_set(srk), "tpm2_srk", JSON_BUILD_IOVEC_BASE64(srk)))); + JSON_BUILD_PAIR_CONDITION(iovec_is_set(srk), "tpm2_srk", JSON_BUILD_IOVEC_BASE64(srk)), + JSON_BUILD_PAIR_CONDITION(iovec_is_set(pcrlock_nv), "tpm2_pcrlock_nv", JSON_BUILD_IOVEC_BASE64(pcrlock_nv)))); if (r < 0) return r; @@ -7034,9 +7174,10 @@ int tpm2_parse_luks2_json( struct iovec *ret_policy_hash, struct iovec *ret_salt, struct iovec *ret_srk, + struct iovec *ret_pcrlock_nv, TPM2Flags *ret_flags) { - _cleanup_(iovec_done) struct iovec blob = {}, policy_hash = {}, pubkey = {}, salt = {}, srk = {}; + _cleanup_(iovec_done) struct iovec blob = {}, policy_hash = {}, pubkey = {}, salt = {}, srk = {}, pcrlock_nv = {}; uint32_t hash_pcr_mask = 0, pubkey_pcr_mask = 0; uint16_t primary_alg = TPM2_ALG_ECC; /* ECC was the only supported algorithm in systemd < 250, use that as implied default, for compatibility */ uint16_t pcr_bank = UINT16_MAX; /* default: pick automatically */ @@ -7158,6 +7299,13 @@ int tpm2_parse_luks2_json( return log_debug_errno(r, "Invalid base64 data in 'tpm2_srk' field."); } + w = json_variant_by_key(v, "tpm2_pcrlock_nv"); + if (w) { + r = json_variant_unbase64_iovec(w, &pcrlock_nv); + if (r < 0) + return log_debug_errno(r, "Invalid base64 data in 'tpm2_pcrlock_nv' field."); + } + if (ret_keyslot) *ret_keyslot = keyslot; if (ret_hash_pcr_mask) @@ -7176,11 +7324,12 @@ int tpm2_parse_luks2_json( *ret_policy_hash = TAKE_STRUCT(policy_hash); if (ret_salt) *ret_salt = TAKE_STRUCT(salt); - if (ret_flags) - *ret_flags = flags; if (ret_srk) *ret_srk = TAKE_STRUCT(srk); - + if (ret_pcrlock_nv) + *ret_pcrlock_nv = TAKE_STRUCT(pcrlock_nv); + if (ret_flags) + *ret_flags = flags; return 0; } diff --git a/src/shared/tpm2-util.h b/src/shared/tpm2-util.h index e94b345de76..f9f29e310d9 100644 --- a/src/shared/tpm2-util.h +++ b/src/shared/tpm2-util.h @@ -245,8 +245,10 @@ typedef struct Tpm2PCRLockPolicy { } Tpm2PCRLockPolicy; void tpm2_pcrlock_policy_done(Tpm2PCRLockPolicy *data); +int tpm2_pcrlock_policy_from_json(JsonVariant *v, Tpm2PCRLockPolicy *ret_policy); int tpm2_pcrlock_search_file(const char *path, FILE **ret_file, char **ret_path); int tpm2_pcrlock_policy_load(const char *path, Tpm2PCRLockPolicy *ret_policy); +int tpm2_pcrlock_policy_from_credentials(const struct iovec *srk, const struct iovec *nv, Tpm2PCRLockPolicy *ret); int tpm2_index_to_handle(Tpm2Context *c, TPM2_HANDLE index, const Tpm2Handle *session, TPM2B_PUBLIC **ret_public, TPM2B_NAME **ret_name, TPM2B_NAME **ret_qname, Tpm2Handle **ret_handle); int tpm2_index_from_handle(Tpm2Context *c, const Tpm2Handle *handle, TPM2_HANDLE *ret_index); @@ -383,8 +385,8 @@ int tpm2_find_device_auto(char **ret); int tpm2_make_pcr_json_array(uint32_t pcr_mask, JsonVariant **ret); int tpm2_parse_pcr_json_array(JsonVariant *v, uint32_t *ret); -int tpm2_make_luks2_json(int keyslot, uint32_t hash_pcr_mask, uint16_t pcr_bank, const struct iovec *pubkey, uint32_t pubkey_pcr_mask, uint16_t primary_alg, const struct iovec *blob, const struct iovec *policy_hash, const struct iovec *salt, const struct iovec *srk, TPM2Flags flags, JsonVariant **ret); -int tpm2_parse_luks2_json(JsonVariant *v, int *ret_keyslot, uint32_t *ret_hash_pcr_mask, uint16_t *ret_pcr_bank, struct iovec *ret_pubkey, uint32_t *ret_pubkey_pcr_mask, uint16_t *ret_primary_alg, struct iovec *ret_blob, struct iovec *ret_policy_hash, struct iovec *ret_salt, struct iovec *ret_srk, TPM2Flags *ret_flags); +int tpm2_make_luks2_json(int keyslot, uint32_t hash_pcr_mask, uint16_t pcr_bank, const struct iovec *pubkey, uint32_t pubkey_pcr_mask, uint16_t primary_alg, const struct iovec *blob, const struct iovec *policy_hash, const struct iovec *salt, const struct iovec *srk, const struct iovec *pcrlock_nv, TPM2Flags flags, JsonVariant **ret); +int tpm2_parse_luks2_json(JsonVariant *v, int *ret_keyslot, uint32_t *ret_hash_pcr_mask, uint16_t *ret_pcr_bank, struct iovec *ret_pubkey, uint32_t *ret_pubkey_pcr_mask, uint16_t *ret_primary_alg, struct iovec *ret_blob, struct iovec *ret_policy_hash, struct iovec *ret_salt, struct iovec *ret_srk, struct iovec *pcrlock_nv, TPM2Flags *ret_flags); /* Default to PCR 7 only */ #define TPM2_PCR_INDEX_DEFAULT UINT32_C(7)