]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
pcrlock: when unlocking try to pick up pcrlock policy from system credentials
authorLennart Poettering <lennart@poettering.net>
Tue, 21 Nov 2023 10:44:34 +0000 (11:44 +0100)
committerLennart Poettering <lennart@poettering.net>
Mon, 22 Jan 2024 14:20:22 +0000 (15:20 +0100)
src/cryptenroll/cryptenroll-tpm2.c
src/cryptsetup/cryptsetup-tokens/cryptsetup-token-systemd-tpm2.c
src/cryptsetup/cryptsetup-tokens/luks2-tpm2.c
src/cryptsetup/cryptsetup-tokens/luks2-tpm2.h
src/cryptsetup/cryptsetup-tpm2.c
src/cryptsetup/cryptsetup-tpm2.h
src/cryptsetup/cryptsetup.c
src/partition/repart.c
src/shared/tpm2-util.c
src/shared/tpm2-util.h

index 87e19814db4a16f430c5ee65eafc227bd87f6dd5..b556c70931f5fadb5964a0407b6d75964bd3fa79 100644 (file)
@@ -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)
index 14b98abc060728dc6214faf93dea322ec3ce34bd..b65229992cfc43474dbcf8e493ae31f9bf804faf 100644 (file)
@@ -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)));
 }
 
 /*
index e2e4d0dc049b7aec121b6cc737b35748c92059ac..d902c591dffc1c333594ca51f024d6b2766bbd32 100644 (file)
@@ -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;
index 20151d6ca9f89b037491b1dfc40d6b8165567c5c..4900cd536284d7ec6f694ba70fea1d2c494ceae0 100644 (file)
@@ -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);
index fc0ec443a512a9e486d867131b3c358971b9742c..297ef6fe4a3f370cb4cefded3b33a2f855c2f12f 100644 (file)
@@ -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;
                 }
index a593e043749ab1d83cab678d028cfdd827220576..0eaf9280ef41ec7709c74daa76d23fd9ee5fe1f4 100644 (file)
@@ -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) {
index a8be8052370dbfa262f0f106c6a8239c696ed7c1..0840a71548b73739a149cea93b42ea7a2122cec1 100644 (file)
@@ -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,
index 9b6b8a5a14cfde6b57204589c775b2cca33933d3..958af799e4e401dca8b6ef8321baeb64b098f7c8 100644 (file)
@@ -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)
index 770a1e2b1429322566620a22c40e8d4ccc0dc838..713ea2a49567f29c953c5f8249d64dd97f95f7bf 100644 (file)
@@ -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;
 }
 
index e94b345de7647223649295f85da757a76b163740..f9f29e310d9c0f0e85d04c02433a7b3e90060a18 100644 (file)
@@ -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)