You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
209 lines
8.7 KiB
209 lines
8.7 KiB
From 3047d3fed460b6df83cb0713d5ef25169fdebb4e Mon Sep 17 00:00:00 2001
|
|
From: Dan Streetman <ddstreet@ieee.org>
|
|
Date: Thu, 15 Dec 2022 12:56:35 -0500
|
|
Subject: [PATCH] tpm2: add tpm2_calculate_sealing_policy()
|
|
|
|
This adds a function to fully calculate the authPolicy needed to seal a secret,
|
|
and updates tpm2_seal() to use the new function instead of a trial policy.
|
|
|
|
(cherry picked from commit d9a1f1a724a08defb70dbc6f44aa578983a66ac8)
|
|
|
|
Related: RHEL-16182
|
|
---
|
|
src/shared/tpm2-util.c | 118 ++++++++++++++++++++++++-----------------
|
|
1 file changed, 70 insertions(+), 48 deletions(-)
|
|
|
|
diff --git a/src/shared/tpm2-util.c b/src/shared/tpm2-util.c
|
|
index 2747cf0b53..f638c18223 100644
|
|
--- a/src/shared/tpm2-util.c
|
|
+++ b/src/shared/tpm2-util.c
|
|
@@ -2263,6 +2263,40 @@ static int tpm2_policy_authorize(
|
|
return tpm2_get_policy_digest(c, session, ret_policy_digest);
|
|
}
|
|
|
|
+/* Extend 'digest' with the calculated policy hash. */
|
|
+static int tpm2_calculate_sealing_policy(
|
|
+ const TPML_PCR_SELECTION *hash_pcr_selection,
|
|
+ const TPM2B_DIGEST *hash_pcr_values,
|
|
+ size_t n_hash_pcr_values,
|
|
+ const TPM2B_PUBLIC *public,
|
|
+ const char *pin,
|
|
+ TPM2B_DIGEST *digest) {
|
|
+
|
|
+ int r;
|
|
+
|
|
+ assert(digest);
|
|
+
|
|
+ if (public) {
|
|
+ r = tpm2_calculate_policy_authorize(public, NULL, digest);
|
|
+ if (r < 0)
|
|
+ return r;
|
|
+ }
|
|
+
|
|
+ if (hash_pcr_selection && !tpm2_tpml_pcr_selection_is_empty(hash_pcr_selection)) {
|
|
+ r = tpm2_calculate_policy_pcr(hash_pcr_selection, hash_pcr_values, n_hash_pcr_values, digest);
|
|
+ if (r < 0)
|
|
+ return r;
|
|
+ }
|
|
+
|
|
+ if (pin) {
|
|
+ r = tpm2_calculate_policy_auth_value(digest);
|
|
+ if (r < 0)
|
|
+ return r;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
static int tpm2_build_sealing_policy(
|
|
Tpm2Context *c,
|
|
const Tpm2Handle *session,
|
|
@@ -2345,7 +2379,6 @@ int tpm2_seal(const char *device,
|
|
_cleanup_(erase_and_freep) void *secret = NULL;
|
|
_cleanup_free_ void *hash = NULL;
|
|
TPM2B_SENSITIVE_CREATE hmac_sensitive;
|
|
- TPMI_ALG_PUBLIC primary_alg;
|
|
TPM2B_PUBLIC hmac_template;
|
|
usec_t start;
|
|
TSS2_RC rc;
|
|
@@ -2398,59 +2431,37 @@ int tpm2_seal(const char *device,
|
|
return r;
|
|
}
|
|
|
|
+ TPML_PCR_SELECTION hash_pcr_selection = {};
|
|
+ _cleanup_free_ TPM2B_DIGEST *hash_pcr_values = NULL;
|
|
+ size_t n_hash_pcr_values = 0;
|
|
+ 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. */
|
|
+ tpm2_tpml_pcr_selection_from_mask(hash_pcr_mask, pcr_bank, &hash_pcr_selection);
|
|
+ r = tpm2_pcr_read(c, &hash_pcr_selection, &hash_pcr_selection, &hash_pcr_values, &n_hash_pcr_values);
|
|
+ if (r < 0)
|
|
+ return r;
|
|
+ }
|
|
+
|
|
TPM2B_PUBLIC pubkey_tpm2, *authorize_key = NULL;
|
|
- _cleanup_free_ void *fp = NULL;
|
|
- size_t fp_size = 0;
|
|
if (pubkey) {
|
|
- r = openssl_pubkey_to_tpm2_pubkey(pubkey, pubkey_size, &pubkey_tpm2, &fp, &fp_size);
|
|
+ r = openssl_pubkey_to_tpm2_pubkey(pubkey, pubkey_size, &pubkey_tpm2, NULL, NULL);
|
|
if (r < 0)
|
|
return r;
|
|
authorize_key = &pubkey_tpm2;
|
|
}
|
|
|
|
- _cleanup_tpm2_handle_ Tpm2Handle *primary = NULL;
|
|
- r = tpm2_make_primary(c, /* alg = */0, !!ret_srk_buf, &primary_alg, &primary);
|
|
+ TPM2B_DIGEST policy_digest;
|
|
+ r = tpm2_digest_init(TPM2_ALG_SHA256, &policy_digest);
|
|
if (r < 0)
|
|
return r;
|
|
|
|
- /* we cannot use the bind key before its created */
|
|
- _cleanup_tpm2_handle_ Tpm2Handle *encryption_session = NULL;
|
|
- r = tpm2_make_encryption_session(c, primary, &TPM2_HANDLE_NONE, &encryption_session);
|
|
- if (r < 0)
|
|
- return r;
|
|
-
|
|
- /* So apparently some TPM implementations don't implement trial mode correctly. To avoid issues let's
|
|
- * avoid it when it is easy to. At the moment we only really need trial mode for the signed PCR
|
|
- * policies (since only then we need to shove PCR values into the policy that don't match current
|
|
- * state anyway), hence if we have none of those we don't need to bother. Hence, let's patch in
|
|
- * TPM2_SE_POLICY even if trial mode is requested unless a pubkey PCR mask is specified that is
|
|
- * non-zero, i.e. signed PCR policy is requested.
|
|
- *
|
|
- * One day we should switch to calculating policy hashes client side when trial mode is requested, to
|
|
- * avoid this mess. */
|
|
- bool trial = (pubkey_pcr_mask != 0);
|
|
-
|
|
- _cleanup_tpm2_handle_ Tpm2Handle *policy_session = NULL;
|
|
- r = tpm2_make_policy_session(
|
|
- c,
|
|
- primary,
|
|
- encryption_session,
|
|
- trial,
|
|
- &policy_session);
|
|
- if (r < 0)
|
|
- return r;
|
|
-
|
|
- _cleanup_(Esys_Freep) TPM2B_DIGEST *policy_digest = NULL;
|
|
- r = tpm2_build_sealing_policy(
|
|
- c,
|
|
- policy_session,
|
|
- hash_pcr_mask,
|
|
- pcr_bank,
|
|
+ r = tpm2_calculate_sealing_policy(
|
|
+ &hash_pcr_selection,
|
|
+ hash_pcr_values,
|
|
+ n_hash_pcr_values,
|
|
authorize_key,
|
|
- fp, fp_size,
|
|
- pubkey_pcr_mask,
|
|
- /* signature_json= */ NULL,
|
|
- !!pin,
|
|
+ pin,
|
|
&policy_digest);
|
|
if (r < 0)
|
|
return r;
|
|
@@ -2466,7 +2477,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_digest,
|
|
},
|
|
};
|
|
|
|
@@ -2490,11 +2501,22 @@ int tpm2_seal(const char *device,
|
|
if (r < 0)
|
|
return log_error_errno(r, "Failed to generate secret key: %m");
|
|
|
|
+ _cleanup_tpm2_handle_ Tpm2Handle *primary_handle = NULL;
|
|
+ TPMI_ALG_PUBLIC primary_alg;
|
|
+ r = tpm2_make_primary(c, /* alg = */0, !!ret_srk_buf, &primary_alg, &primary_handle);
|
|
+ if (r < 0)
|
|
+ return r;
|
|
+
|
|
+ _cleanup_tpm2_handle_ Tpm2Handle *encryption_session = NULL;
|
|
+ r = tpm2_make_encryption_session(c, primary_handle, &TPM2_HANDLE_NONE, &encryption_session);
|
|
+ if (r < 0)
|
|
+ return r;
|
|
+
|
|
log_debug("Creating HMAC key.");
|
|
|
|
rc = sym_Esys_Create(
|
|
c->esys_context,
|
|
- primary->esys_handle,
|
|
+ primary_handle->esys_handle,
|
|
encryption_session->esys_handle, /* use HMAC session to enable parameter encryption */
|
|
ESYS_TR_NONE,
|
|
ESYS_TR_NONE,
|
|
@@ -2534,7 +2556,7 @@ int tpm2_seal(const char *device,
|
|
return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
|
|
"Failed to marshal public key: %s", sym_Tss2_RC_Decode(rc));
|
|
|
|
- hash = memdup(policy_digest->buffer, policy_digest->size);
|
|
+ hash = memdup(policy_digest.buffer, policy_digest.size);
|
|
if (!hash)
|
|
return log_oom();
|
|
|
|
@@ -2544,7 +2566,7 @@ int tpm2_seal(const char *device,
|
|
*/
|
|
if (ret_srk_buf) {
|
|
log_debug("Serializing SRK ESYS_TR reference");
|
|
- rc = sym_Esys_TR_Serialize(c->esys_context, primary->esys_handle, &srk_buf, &srk_buf_size);
|
|
+ rc = sym_Esys_TR_Serialize(c->esys_context, primary_handle->esys_handle, &srk_buf, &srk_buf_size);
|
|
if (rc != TSS2_RC_SUCCESS)
|
|
return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
|
|
"Failed to serialize primary key: %s", sym_Tss2_RC_Decode(rc));
|
|
@@ -2572,7 +2594,7 @@ int tpm2_seal(const char *device,
|
|
*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_hash_size = policy_digest.size;
|
|
*ret_pcr_bank = pcr_bank;
|
|
*ret_primary_alg = primary_alg;
|
|
|