From 5db840e4bc7b86f7870c153d540ef0f6eddf64c2 Mon Sep 17 00:00:00 2001 From: Dan Streetman Date: Sun, 1 Jan 2023 23:42:09 -0500 Subject: [PATCH] tpm2: add tpm2_persist_handle() Add function to convert a transient handle in the TPM into a persistent handle in the TPM. (cherry picked from commit d2d29c3be2ff9557d74c7bf852c1423ea6cfa25a) Related: RHEL-16182 --- src/shared/tpm2-util.c | 83 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 74 insertions(+), 9 deletions(-) diff --git a/src/shared/tpm2-util.c b/src/shared/tpm2-util.c index c05c636745..0c5f3393dd 100644 --- a/src/shared/tpm2-util.c +++ b/src/shared/tpm2-util.c @@ -769,6 +769,75 @@ static int tpm2_esys_handle_from_tpm_handle( return 1; } +/* Copy an object in the TPM at a transient location to a persistent location. + * + * The provided transient handle must exist in the TPM in the transient range. The persistent location may be + * 0 or any location in the persistent range. If 0, this will try each handle in the persistent range, in + * ascending order, until an available one is found. If non-zero, only the requested persistent location will + * be used. + * + * Returns 1 if the object was successfully persisted, or 0 if there is already a key at the requested + * location(s), or < 0 on error. The persistent handle is only provided when returning 1. */ +static int tpm2_persist_handle( + Tpm2Context *c, + const Tpm2Handle *transient_handle, + const Tpm2Handle *session, + TPMI_DH_PERSISTENT persistent_location, + Tpm2Handle **ret_persistent_handle) { + + /* We don't use TPM2_PERSISTENT_FIRST and TPM2_PERSISTENT_LAST here due to: + * https://github.com/systemd/systemd/pull/27713#issuecomment-1591864753 */ + TPMI_DH_PERSISTENT first = UINT32_C(0x81000000), last = UINT32_C(0x81ffffff); + TSS2_RC rc; + int r; + + assert(c); + assert(transient_handle); + + /* If persistent location specified, only try that. */ + if (persistent_location != 0) { + if (TPM2_HANDLE_TYPE(persistent_location) != TPM2_HT_PERSISTENT) + return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), + "Handle not in persistent range: 0x%x", persistent_location); + + first = last = persistent_location; + } + + for (TPMI_DH_PERSISTENT requested = first; requested <= last; requested++) { + _cleanup_(tpm2_handle_freep) Tpm2Handle *persistent_handle = NULL; + r = tpm2_handle_new(c, &persistent_handle); + if (r < 0) + return r; + + /* Since this is a persistent handle, don't flush it. */ + persistent_handle->flush = false; + + rc = sym_Esys_EvictControl( + c->esys_context, + ESYS_TR_RH_OWNER, + transient_handle->esys_handle, + session ? session->esys_handle : ESYS_TR_PASSWORD, + ESYS_TR_NONE, + ESYS_TR_NONE, + requested, + &persistent_handle->esys_handle); + if (rc == TSS2_RC_SUCCESS) { + if (ret_persistent_handle) + *ret_persistent_handle = TAKE_PTR(persistent_handle); + + return 1; + } + if (rc != TPM2_RC_NV_DEFINED) + return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), + "Failed to persist handle: %s", sym_Tss2_RC_Decode(rc)); + } + + if (ret_persistent_handle) + *ret_persistent_handle = NULL; + + return 0; +} + #define TPM2_CREDIT_RANDOM_FLAG_PATH "/run/systemd/tpm-rng-credited" static int tpm2_credit_random(Tpm2Context *c) { @@ -1203,16 +1272,12 @@ static int tpm2_make_primary( FORMAT_TIMESPAN(now(CLOCK_MONOTONIC) - ts, USEC_PER_MSEC)); if (use_srk_model) { - rc = sym_Esys_EvictControl(c->esys_context, ESYS_TR_RH_OWNER, primary->esys_handle, - ESYS_TR_PASSWORD, ESYS_TR_NONE, ESYS_TR_NONE, TPM2_SRK_HANDLE, &primary->esys_handle); - if (rc != TSS2_RC_SUCCESS) - return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), - "Failed to persist SRK within TPM: %s", sym_Tss2_RC_Decode(rc)); - primary->flush = false; - } - - if (ret_primary) + r = tpm2_persist_handle(c, primary, /* session= */ NULL, TPM2_SRK_HANDLE, ret_primary); + if (r < 0) + return r; + } else if (ret_primary) *ret_primary = TAKE_PTR(primary); + if (ret_alg) *ret_alg = alg;