tpm2: move policy calculation out of tpm2_seal()

Move the calculation of the sealed object policy hash out of the tpm2_seal()
function. Instead, callers of tpm2_seal() can directly call
tpm2_calculate_sealing_policy() and then provide the policy hash to
tpm2_seal().
This commit is contained in:
Dan Streetman
2023-08-04 11:20:22 -04:00
parent e3acb4d24c
commit 9e4379945b
7 changed files with 227 additions and 142 deletions
+66 -20
View File
@@ -133,7 +133,8 @@ int enroll_tpm2(struct crypt_device *cd,
const void *volume_key,
size_t volume_key_size,
const char *device,
uint32_t hash_pcr_mask,
Tpm2PCRValue *hash_pcr_values,
size_t n_hash_pcr_values,
const char *pubkey_path,
uint32_t pubkey_pcr_mask,
const char *signature_path,
@@ -143,9 +144,8 @@ int enroll_tpm2(struct crypt_device *cd,
_cleanup_(json_variant_unrefp) JsonVariant *v = NULL, *signature_json = NULL;
_cleanup_(erase_and_freep) char *base64_encoded = NULL;
_cleanup_free_ void *srk_buf = NULL;
size_t secret_size, blob_size, hash_size, pubkey_size = 0, srk_buf_size = 0;
_cleanup_free_ void *blob = NULL, *hash = NULL, *pubkey = NULL;
uint16_t pcr_bank, primary_alg;
size_t secret_size, blob_size, pubkey_size = 0, srk_buf_size = 0;
_cleanup_free_ void *blob = NULL, *pubkey = NULL;
const char *node;
_cleanup_(erase_and_freep) char *pin_str = NULL;
ssize_t base64_encoded_size;
@@ -163,7 +163,7 @@ int enroll_tpm2(struct crypt_device *cd,
assert(cd);
assert(volume_key);
assert(volume_key_size > 0);
assert(TPM2_PCR_MASK_VALID(hash_pcr_mask));
assert(TPM2_PCR_VALUES_VALID(hash_pcr_values, n_hash_pcr_values));
assert(TPM2_PCR_MASK_VALID(pubkey_pcr_mask));
assert_se(node = crypt_get_device_name(cd));
@@ -206,23 +206,69 @@ int enroll_tpm2(struct crypt_device *cd,
return log_debug_errno(r, "Failed to read TPM PCR signature: %m");
}
r = tpm2_seal(device,
hash_pcr_mask,
pubkey, pubkey_size,
pubkey_pcr_mask,
_cleanup_(tpm2_context_unrefp) Tpm2Context *tpm2_context = NULL;
r = tpm2_context_new(device, &tpm2_context);
if (r < 0)
return r;
bool pcr_value_specified = false;
for (size_t i = 0; i < n_hash_pcr_values; i++)
if (hash_pcr_values[i].value.size > 0) {
pcr_value_specified = true;
break;
}
r = tpm2_pcr_read_missing_values(tpm2_context, hash_pcr_values, n_hash_pcr_values);
if (r < 0)
return r;
uint16_t hash_pcr_bank = 0;
uint32_t hash_pcr_mask = 0;
if (n_hash_pcr_values > 0) {
size_t hash_count;
r = tpm2_pcr_values_hash_count(hash_pcr_values, n_hash_pcr_values, &hash_count);
if (r < 0)
return log_error_errno(r, "Could not get hash count: %m");
if (hash_count > 1)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Multiple PCR banks selected.");
hash_pcr_bank = hash_pcr_values[0].hash;
r = tpm2_pcr_values_to_mask(hash_pcr_values, n_hash_pcr_values, hash_pcr_bank, &hash_pcr_mask);
if (r < 0)
return log_error_errno(r, "Could not get hash mask: %m");
}
TPM2B_PUBLIC public;
if (pubkey) {
r = tpm2_tpm2b_public_from_pem(pubkey, pubkey_size, &public);
if (r < 0)
return log_error_errno(r, "Could not convert public key to TPM2B_PUBLIC: %m");
}
TPM2B_DIGEST policy = TPM2B_DIGEST_MAKE(NULL, TPM2_SHA256_DIGEST_SIZE);
r = tpm2_calculate_sealing_policy(
hash_pcr_values,
n_hash_pcr_values,
pubkey ? &public : NULL,
use_pin,
&policy);
if (r < 0)
return r;
r = tpm2_seal(tpm2_context,
&policy,
pin_str,
&secret, &secret_size,
&blob, &blob_size,
&hash, &hash_size,
&pcr_bank,
&primary_alg,
/* ret_primary_alg= */ NULL,
&srk_buf,
&srk_buf_size);
if (r < 0)
return r;
/* Let's see if we already have this specific PCR policy hash enrolled, if so, exit early. */
r = search_policy_hash(cd, hash, hash_size);
r = search_policy_hash(cd, policy.buffer, policy.size);
if (r == -ENOENT)
log_debug_errno(r, "PCR policy hash not yet enrolled, enrolling now.");
else if (r < 0)
@@ -233,21 +279,21 @@ int enroll_tpm2(struct crypt_device *cd,
}
/* Quick verification that everything is in order, we are not in a hurry after all. */
if (!pubkey || signature_json) {
if ((!pubkey || signature_json) && !pcr_value_specified) {
_cleanup_(erase_and_freep) void *secret2 = NULL;
size_t secret2_size;
log_debug("Unsealing for verification...");
r = tpm2_unseal(device,
hash_pcr_mask,
pcr_bank,
hash_pcr_bank,
pubkey, pubkey_size,
pubkey_pcr_mask,
signature_json,
pin_str,
primary_alg,
/* primary_alg= */ 0,
blob, blob_size,
hash, hash_size,
policy.buffer, policy.size,
srk_buf, srk_buf_size,
&secret2, &secret2_size);
if (r < 0)
@@ -279,12 +325,12 @@ int enroll_tpm2(struct crypt_device *cd,
r = tpm2_make_luks2_json(
keyslot,
hash_pcr_mask,
pcr_bank,
hash_pcr_bank,
pubkey, pubkey_size,
pubkey_pcr_mask,
primary_alg,
/* primary_alg= */ 0,
blob, blob_size,
hash, hash_size,
policy.buffer, policy.size,
use_pin ? binary_salt : NULL,
use_pin ? sizeof(binary_salt) : 0,
srk_buf, srk_buf_size,
+3 -2
View File
@@ -5,11 +5,12 @@
#include "cryptsetup-util.h"
#include "log.h"
#include "tpm2-util.h"
#if HAVE_TPM2
int enroll_tpm2(struct crypt_device *cd, const void *volume_key, size_t volume_key_size, const char *device, uint32_t hash_pcr_mask, const char *pubkey_path, uint32_t pubkey_pcr_mask, const char *signature_path, bool use_pin);
int enroll_tpm2(struct crypt_device *cd, const void *volume_key, size_t volume_key_size, const char *device, Tpm2PCRValue *hash_pcrs, size_t n_hash_pcrs, const char *pubkey_path, uint32_t pubkey_pcr_mask, const char *signature_path, bool use_pin);
#else
static inline int enroll_tpm2(struct crypt_device *cd, const void *volume_key, size_t volume_key_size, const char *device, uint32_t hash_pcr_mask, const char *pubkey_path, uint32_t pubkey_pcr_mask, const char *signature_path, bool use_pin) {
static inline int enroll_tpm2(struct crypt_device *cd, const void *volume_key, size_t volume_key_size, const char *device, Tpm2PCRValue *hash_pcrs, size_t n_hash_pcrs, const char *pubkey_path, uint32_t pubkey_pcr_mask, const char *signature_path, bool use_pin) {
return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
"TPM2 key enrollment not supported.");
}
+19 -9
View File
@@ -28,7 +28,6 @@
#include "strv.h"
#include "terminal-util.h"
#include "tpm-pcr.h"
#include "tpm2-util.h"
static EnrollType arg_enroll_type = _ENROLL_TYPE_INVALID;
static char *arg_unlock_keyfile = NULL;
@@ -37,10 +36,13 @@ static char *arg_unlock_fido2_device = NULL;
static char *arg_pkcs11_token_uri = NULL;
static char *arg_fido2_device = NULL;
static char *arg_tpm2_device = NULL;
static uint32_t arg_tpm2_pcr_mask = UINT32_MAX;
static Tpm2PCRValue *arg_tpm2_hash_pcr_values = NULL;
static size_t arg_tpm2_n_hash_pcr_values = 0;
static bool arg_tpm2_hash_pcr_values_use_default = true;
static bool arg_tpm2_pin = false;
static char *arg_tpm2_public_key = NULL;
static uint32_t arg_tpm2_public_key_pcr_mask = UINT32_MAX;
static uint32_t arg_tpm2_public_key_pcr_mask = 0;
static bool arg_tpm2_public_key_pcr_mask_use_default = true;
static char *arg_tpm2_signature = NULL;
static char *arg_node = NULL;
static int *arg_wipe_slots = NULL;
@@ -61,6 +63,7 @@ STATIC_DESTRUCTOR_REGISTER(arg_unlock_fido2_device, freep);
STATIC_DESTRUCTOR_REGISTER(arg_pkcs11_token_uri, freep);
STATIC_DESTRUCTOR_REGISTER(arg_fido2_device, freep);
STATIC_DESTRUCTOR_REGISTER(arg_tpm2_device, freep);
STATIC_DESTRUCTOR_REGISTER(arg_tpm2_hash_pcr_values, freep);
STATIC_DESTRUCTOR_REGISTER(arg_tpm2_public_key, freep);
STATIC_DESTRUCTOR_REGISTER(arg_tpm2_signature, freep);
STATIC_DESTRUCTOR_REGISTER(arg_node, freep);
@@ -356,7 +359,8 @@ static int parse_argv(int argc, char *argv[]) {
}
case ARG_TPM2_PCRS:
r = tpm2_parse_pcr_argument_to_mask(optarg, &arg_tpm2_pcr_mask);
arg_tpm2_hash_pcr_values_use_default = false;
r = tpm2_parse_pcr_argument_append(optarg, &arg_tpm2_hash_pcr_values, &arg_tpm2_n_hash_pcr_values);
if (r < 0)
return r;
@@ -377,6 +381,7 @@ static int parse_argv(int argc, char *argv[]) {
break;
case ARG_TPM2_PUBLIC_KEY_PCRS:
arg_tpm2_public_key_pcr_mask_use_default = false;
r = tpm2_parse_pcr_argument_to_mask(optarg, &arg_tpm2_public_key_pcr_mask);
if (r < 0)
return r;
@@ -476,10 +481,15 @@ static int parse_argv(int argc, char *argv[]) {
if (r < 0)
return r;
if (arg_tpm2_pcr_mask == UINT32_MAX)
arg_tpm2_pcr_mask = TPM2_PCR_MASK_DEFAULT;
if (arg_tpm2_public_key_pcr_mask == UINT32_MAX)
arg_tpm2_public_key_pcr_mask = UINT32_C(1) << TPM_PCR_INDEX_KERNEL_IMAGE;
if (arg_tpm2_public_key_pcr_mask_use_default && arg_tpm2_public_key)
arg_tpm2_public_key_pcr_mask = INDEX_TO_MASK(uint32_t, TPM_PCR_INDEX_KERNEL_IMAGE);
if (arg_tpm2_hash_pcr_values_use_default && !GREEDY_REALLOC_APPEND(
arg_tpm2_hash_pcr_values,
arg_tpm2_n_hash_pcr_values,
&TPM2_PCR_VALUE_MAKE(TPM2_PCR_INDEX_DEFAULT, /* hash= */ 0, /* value= */ {}),
1))
return log_oom();
return 1;
}
@@ -655,7 +665,7 @@ static int run(int argc, char *argv[]) {
break;
case ENROLL_TPM2:
slot = enroll_tpm2(cd, vk, vks, arg_tpm2_device, arg_tpm2_pcr_mask, arg_tpm2_public_key, arg_tpm2_public_key_pcr_mask, arg_tpm2_signature, arg_tpm2_pin);
slot = enroll_tpm2(cd, vk, vks, arg_tpm2_device, arg_tpm2_hash_pcr_values, arg_tpm2_n_hash_pcr_values, arg_tpm2_public_key, arg_tpm2_public_key_pcr_mask, arg_tpm2_signature, arg_tpm2_pin);
break;
case _ENROLL_TYPE_INVALID: