summaryrefslogtreecommitdiffstats
path: root/src/shared
diff options
context:
space:
mode:
authorDan Streetman <ddstreet@ieee.org>2023-07-12 23:35:54 +0200
committerDan Streetman <ddstreet@ieee.org>2023-08-04 17:20:22 +0200
commit9e4379945b74ee7920fe375be0bcb04d8ef53873 (patch)
tree478508e67c611cefebd184e82f0262362d61bcc4 /src/shared
parenttpm2: add functions to convert TPM2B_PUBLIC to/from openssl pkey or PEM (diff)
downloadsystemd-9e4379945b74ee7920fe375be0bcb04d8ef53873.tar.xz
systemd-9e4379945b74ee7920fe375be0bcb04d8ef53873.zip
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().
Diffstat (limited to 'src/shared')
-rw-r--r--src/shared/creds-util.c51
-rw-r--r--src/shared/tpm2-util.c104
-rw-r--r--src/shared/tpm2-util.h6
3 files changed, 73 insertions, 88 deletions
diff --git a/src/shared/creds-util.c b/src/shared/creds-util.c
index 16df01b9ca..8a5240e5f1 100644
--- a/src/shared/creds-util.c
+++ b/src/shared/creds-util.c
@@ -825,18 +825,49 @@ int encrypt_credential_and_warn(
if (!pubkey)
tpm2_pubkey_pcr_mask = 0;
- r = tpm2_seal(tpm2_device,
- tpm2_hash_pcr_mask,
- pubkey, pubkey_size,
- tpm2_pubkey_pcr_mask,
+ _cleanup_(tpm2_context_unrefp) Tpm2Context *tpm2_context = NULL;
+ r = tpm2_context_new(tpm2_device, &tpm2_context);
+ if (r < 0)
+ return r;
+
+ r = tpm2_get_best_pcr_bank(tpm2_context, tpm2_hash_pcr_mask | tpm2_pubkey_pcr_mask, &tpm2_pcr_bank);
+ if (r < 0)
+ return r;
+
+ TPML_PCR_SELECTION tpm2_hash_pcr_selection;
+ tpm2_tpml_pcr_selection_from_mask(tpm2_hash_pcr_mask, tpm2_pcr_bank, &tpm2_hash_pcr_selection);
+
+ _cleanup_free_ Tpm2PCRValue *tpm2_hash_pcr_values = NULL;
+ size_t tpm2_n_hash_pcr_values;
+ r = tpm2_pcr_read(tpm2_context, &tpm2_hash_pcr_selection, &tpm2_hash_pcr_values, &tpm2_n_hash_pcr_values);
+ if (r < 0)
+ return r;
+
+ 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 tpm2_policy = TPM2B_DIGEST_MAKE(NULL, TPM2_SHA256_DIGEST_SIZE);
+ r = tpm2_calculate_sealing_policy(
+ tpm2_hash_pcr_values,
+ tpm2_n_hash_pcr_values,
+ pubkey ? &public : NULL,
+ /* use_pin= */ false,
+ &tpm2_policy);
+ if (r < 0)
+ return r;
+
+ r = tpm2_seal(tpm2_context,
+ &tpm2_policy,
/* pin= */ NULL,
&tpm2_key, &tpm2_key_size,
&tpm2_blob, &tpm2_blob_size,
- &tpm2_policy_hash, &tpm2_policy_hash_size,
- &tpm2_pcr_bank,
&tpm2_primary_alg,
/* ret_srk_buf= */ NULL,
- /* ret_srk_buf_size= */ 0);
+ /* ret_srk_buf_size= */ NULL);
if (r < 0) {
if (sd_id128_equal(with_key, _CRED_AUTO_INITRD))
log_warning("TPM2 present and used, but we didn't manage to talk to it. Credential will be refused if SecureBoot is enabled.");
@@ -846,6 +877,12 @@ int encrypt_credential_and_warn(
log_notice_errno(r, "TPM2 sealing didn't work, continuing without TPM2: %m");
}
+ tpm2_policy_hash_size = tpm2_policy.size;
+ tpm2_policy_hash = malloc(tpm2_policy_hash_size);
+ if (!tpm2_policy_hash)
+ return log_oom();
+ memcpy(tpm2_policy_hash, tpm2_policy.buffer, tpm2_policy_hash_size);
+
assert(tpm2_blob_size <= CREDENTIAL_FIELD_SIZE_MAX);
assert(tpm2_policy_hash_size <= CREDENTIAL_FIELD_SIZE_MAX);
}
diff --git a/src/shared/tpm2-util.c b/src/shared/tpm2-util.c
index 6b995fd272..21ee4dc8e0 100644
--- a/src/shared/tpm2-util.c
+++ b/src/shared/tpm2-util.c
@@ -3425,7 +3425,7 @@ static int tpm2_policy_authorize(
}
/* Extend 'digest' with the calculated policy hash. */
-static int tpm2_calculate_sealing_policy(
+int tpm2_calculate_sealing_policy(
const Tpm2PCRValue *pcr_values,
size_t n_pcr_values,
const TPM2B_PUBLIC *public,
@@ -3722,38 +3722,25 @@ int tpm2_tpm2b_public_from_pem(const void *pem, size_t pem_size, TPM2B_PUBLIC *r
#endif
}
-int tpm2_seal(const char *device,
- uint32_t hash_pcr_mask,
- const void *pubkey,
- const size_t pubkey_size,
- uint32_t pubkey_pcr_mask,
+int tpm2_seal(Tpm2Context *c,
+ const TPM2B_DIGEST *policy,
const char *pin,
void **ret_secret,
size_t *ret_secret_size,
void **ret_blob,
size_t *ret_blob_size,
- void **ret_pcr_hash,
- size_t *ret_pcr_hash_size,
- uint16_t *ret_pcr_bank,
uint16_t *ret_primary_alg,
void **ret_srk_buf,
size_t *ret_srk_buf_size) {
+ uint16_t primary_alg = 0;
TSS2_RC rc;
int r;
- assert(pubkey || pubkey_size == 0);
-
assert(ret_secret);
assert(ret_secret_size);
assert(ret_blob);
assert(ret_blob_size);
- assert(ret_pcr_hash);
- assert(ret_pcr_hash_size);
- assert(ret_pcr_bank);
-
- assert(TPM2_PCR_MASK_VALID(hash_pcr_mask));
- assert(TPM2_PCR_MASK_VALID(pubkey_pcr_mask));
/* So here's what we do here: we connect to the TPM2 chip. It persistently contains a "seed" key that
* is randomized when the TPM2 is first initialized or reset and remains stable across boots. We
@@ -3773,53 +3760,6 @@ int tpm2_seal(const char *device,
usec_t start = now(CLOCK_MONOTONIC);
- _cleanup_(tpm2_context_unrefp) Tpm2Context *c = NULL;
- r = tpm2_context_new(device, &c);
- if (r < 0)
- return r;
-
- TPMI_ALG_HASH pcr_bank = 0;
- if (hash_pcr_mask | pubkey_pcr_mask) {
- /* Some TPM2 devices only can do SHA1. Prefer SHA256 but allow SHA1. */
- r = tpm2_get_best_pcr_bank(c, hash_pcr_mask|pubkey_pcr_mask, &pcr_bank);
- if (r < 0)
- return r;
- }
-
- _cleanup_free_ Tpm2PCRValue *hash_pcr_values = NULL;
- size_t n_hash_pcr_values;
- if (hash_pcr_mask) {
- /* For now, we just read the current values from the system; we need to be able to specify
- * expected values, eventually. */
- TPML_PCR_SELECTION hash_pcr_selection;
- tpm2_tpml_pcr_selection_from_mask(hash_pcr_mask, pcr_bank, &hash_pcr_selection);
-
- r = tpm2_pcr_read(c, &hash_pcr_selection, &hash_pcr_values, &n_hash_pcr_values);
- if (r < 0)
- return r;
- }
-
- TPM2B_PUBLIC pubkey_tpm2b;
- if (pubkey) {
- r = tpm2_tpm2b_public_from_pem(pubkey, pubkey_size, &pubkey_tpm2b);
- if (r < 0)
- return log_error_errno(r, "Could not create TPMT_PUBLIC: %m");
- }
-
- TPM2B_DIGEST policy_digest;
- r = tpm2_digest_init(TPM2_ALG_SHA256, &policy_digest);
- if (r < 0)
- return r;
-
- r = tpm2_calculate_sealing_policy(
- hash_pcr_values,
- n_hash_pcr_values,
- pubkey ? &pubkey_tpm2b : NULL,
- !!pin,
- &policy_digest);
- if (r < 0)
- return r;
-
/* We use a keyed hash object (i.e. HMAC) to store the secret key we want to use for unlocking the
* LUKS2 volume with. We don't ever use for HMAC/keyed hash operations however, we just use it
* because it's a key type that is universally supported and suitable for symmetric binary blobs. */
@@ -3829,7 +3769,7 @@ int tpm2_seal(const char *device,
.objectAttributes = TPMA_OBJECT_FIXEDTPM | TPMA_OBJECT_FIXEDPARENT,
.parameters.keyedHashDetail.scheme.scheme = TPM2_ALG_NULL,
.unique.keyedHash.size = SHA256_DIGEST_SIZE,
- .authPolicy = policy_digest,
+ .authPolicy = policy ? *policy : TPM2B_DIGEST_MAKE(NULL, TPM2_SHA256_DIGEST_SIZE),
};
TPMS_SENSITIVE_CREATE hmac_sensitive = {
@@ -3854,21 +3794,33 @@ int tpm2_seal(const char *device,
if (r < 0)
return log_error_errno(r, "Failed to generate secret key: %m");
- _cleanup_(Esys_Freep) TPM2B_PUBLIC *primary_public = NULL;
_cleanup_(tpm2_handle_freep) Tpm2Handle *primary_handle = NULL;
if (ret_srk_buf) {
- r = tpm2_get_or_create_srk(c, NULL, &primary_public, NULL, NULL, &primary_handle);
+ _cleanup_(Esys_Freep) TPM2B_PUBLIC *primary_public = NULL;
+ r = tpm2_get_or_create_srk(
+ c,
+ /* session= */ NULL,
+ &primary_public,
+ /* ret_name= */ NULL,
+ /* ret_qname= */ NULL,
+ &primary_handle);
if (r < 0)
return r;
+
+ primary_alg = primary_public->publicArea.type;
} else {
/* TODO: force all callers to provide ret_srk_buf, so we can stop sealing with the legacy templates. */
+ primary_alg = TPM2_ALG_ECC;
+
TPM2B_PUBLIC template = { .size = sizeof(TPMT_PUBLIC), };
- r = tpm2_get_legacy_template(TPM2_ALG_ECC, &template.publicArea);
+ r = tpm2_get_legacy_template(primary_alg, &template.publicArea);
if (r < 0)
return log_error_errno(r, "Could not get legacy ECC template: %m");
if (!tpm2_supports_tpmt_public(c, &template.publicArea)) {
- r = tpm2_get_legacy_template(TPM2_ALG_RSA, &template.publicArea);
+ primary_alg = TPM2_ALG_RSA;
+
+ r = tpm2_get_legacy_template(primary_alg, &template.publicArea);
if (r < 0)
return log_error_errno(r, "Could not get legacy RSA template: %m");
@@ -3882,7 +3834,7 @@ int tpm2_seal(const char *device,
/* session= */ NULL,
&template,
/* sensitive= */ NULL,
- &primary_public,
+ /* ret_public= */ NULL,
&primary_handle);
if (r < 0)
return r;
@@ -3923,11 +3875,6 @@ int tpm2_seal(const char *device,
return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
"Failed to marshal public key: %s", sym_Tss2_RC_Decode(rc));
- _cleanup_free_ void *hash = NULL;
- hash = memdup(policy_digest.buffer, policy_digest.size);
- if (!hash)
- return log_oom();
-
/* serialize the key for storage in the LUKS header. A deserialized ESYS_TR provides both
* the raw TPM handle as well as the object name. The object name is used to verify that
* the key we use later is the key we expect to establish the session with.
@@ -3963,10 +3910,9 @@ int tpm2_seal(const char *device,
*ret_secret_size = hmac_sensitive.data.size;
*ret_blob = TAKE_PTR(blob);
*ret_blob_size = blob_size;
- *ret_pcr_hash = TAKE_PTR(hash);
- *ret_pcr_hash_size = policy_digest.size;
- *ret_pcr_bank = pcr_bank;
- *ret_primary_alg = primary_public->publicArea.type;
+
+ if (ret_primary_alg)
+ *ret_primary_alg = primary_alg;
return 0;
}
diff --git a/src/shared/tpm2-util.h b/src/shared/tpm2-util.h
index c3bc35172a..32da247c37 100644
--- a/src/shared/tpm2-util.h
+++ b/src/shared/tpm2-util.h
@@ -154,8 +154,9 @@ int tpm2_calculate_name(const TPMT_PUBLIC *public, TPM2B_NAME *ret_name);
int tpm2_calculate_policy_auth_value(TPM2B_DIGEST *digest);
int tpm2_calculate_policy_authorize(const TPM2B_PUBLIC *public, const TPM2B_DIGEST *policy_ref, TPM2B_DIGEST *digest);
int tpm2_calculate_policy_pcr(const Tpm2PCRValue *pcr_values, size_t n_pcr_values, TPM2B_DIGEST *digest);
+int tpm2_calculate_sealing_policy(const Tpm2PCRValue *pcr_values, size_t n_pcr_values, const TPM2B_PUBLIC *public, bool use_pin, TPM2B_DIGEST *digest);
-int tpm2_seal(const char *device, uint32_t hash_pcr_mask, const void *pubkey, size_t pubkey_size, uint32_t pubkey_pcr_mask, const char *pin, void **ret_secret, size_t *ret_secret_size, void **ret_blob, size_t *ret_blob_size, void **ret_pcr_hash, size_t *ret_pcr_hash_size, uint16_t *ret_pcr_bank, uint16_t *ret_primary_alg, void **ret_srk_buf, size_t *ret_srk_buf_size);
+int tpm2_seal(Tpm2Context *c, const TPM2B_DIGEST *policy, const char *pin, void **ret_secret, size_t *ret_secret_size, void **ret_blob, size_t *ret_blob_size, uint16_t *ret_primary_alg, void **ret_srk_buf, size_t *ret_srk_buf_size);
int tpm2_unseal(const char *device, uint32_t hash_pcr_mask, uint16_t pcr_bank, const void *pubkey, size_t pubkey_size, uint32_t pubkey_pcr_mask, JsonVariant *signature, const char *pin, uint16_t primary_alg, const void *blob, size_t blob_size, const void *policy_hash, size_t policy_hash_size, const void *srk_buf, size_t srk_buf_size, void **ret_secret, size_t *ret_secret_size);
#if HAVE_OPENSSL
@@ -240,7 +241,8 @@ int tpm2_make_luks2_json(int keyslot, uint32_t hash_pcr_mask, uint16_t pcr_bank,
int tpm2_parse_luks2_json(JsonVariant *v, int *ret_keyslot, uint32_t *ret_hash_pcr_mask, uint16_t *ret_pcr_bank, void **ret_pubkey, size_t *ret_pubkey_size, uint32_t *ret_pubkey_pcr_mask, uint16_t *ret_primary_alg, void **ret_blob, size_t *ret_blob_size, void **ret_policy_hash, size_t *ret_policy_hash_size, void **ret_salt, size_t *ret_salt_size, void **ret_srk_buf, size_t *ret_srk_buf_size, TPM2Flags *ret_flags);
/* Default to PCR 7 only */
-#define TPM2_PCR_MASK_DEFAULT (UINT32_C(1) << 7)
+#define TPM2_PCR_INDEX_DEFAULT (7)
+#define TPM2_PCR_MASK_DEFAULT INDEX_TO_MASK(uint32_t, TPM2_PCR_INDEX_DEFAULT)
/* We want the helpers below to work also if TPM2 libs are not available, hence define these four defines if
* they are missing. */