From 3047d3fed460b6df83cb0713d5ef25169fdebb4e Mon Sep 17 00:00:00 2001 From: Dan Streetman 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;