From bd860983a6f884e37e88915f545d5520f92890ec Mon Sep 17 00:00:00 2001 From: Dan Streetman Date: Mon, 23 Jan 2023 19:52:56 -0500 Subject: [PATCH 1/4] tpm2: rename struct tpm2_context to Tpm2Context This aligns with systemd coding guidelines for struct naming --- src/boot/measure.c | 2 +- src/boot/pcrphase.c | 4 ++-- src/cryptsetup/cryptsetup.c | 2 +- src/shared/tpm2-util.c | 10 +++++----- src/shared/tpm2-util.h | 14 +++++++------- 5 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/boot/measure.c b/src/boot/measure.c index b0bcfe0f98..0d1737200b 100644 --- a/src/boot/measure.c +++ b/src/boot/measure.c @@ -726,7 +726,7 @@ static int verb_sign(int argc, char *argv[], void *userdata) { _cleanup_(json_variant_unrefp) JsonVariant *v = NULL; _cleanup_(pcr_state_free_all) PcrState *pcr_states = NULL; _cleanup_(EVP_PKEY_freep) EVP_PKEY *privkey = NULL, *pubkey = NULL; - _cleanup_(tpm2_context_destroy) struct tpm2_context c = {}; + _cleanup_(tpm2_context_destroy) Tpm2Context c = {}; _cleanup_fclose_ FILE *privkeyf = NULL; ESYS_TR session_handle = ESYS_TR_NONE; TSS2_RC rc; diff --git a/src/boot/pcrphase.c b/src/boot/pcrphase.c index 2add7f1f89..057b9f495c 100644 --- a/src/boot/pcrphase.c +++ b/src/boot/pcrphase.c @@ -155,7 +155,7 @@ static int parse_argv(int argc, char *argv[]) { return 1; } -static int determine_banks(struct tpm2_context *c, unsigned target_pcr_nr) { +static int determine_banks(Tpm2Context *c, unsigned target_pcr_nr) { _cleanup_strv_free_ char **l = NULL; int r; @@ -240,7 +240,7 @@ static int get_file_system_word( } static int run(int argc, char *argv[]) { - _cleanup_(tpm2_context_destroy) struct tpm2_context c = {}; + _cleanup_(tpm2_context_destroy) Tpm2Context c = {}; _cleanup_free_ char *joined = NULL, *word = NULL; unsigned target_pcr_nr; size_t length; diff --git a/src/cryptsetup/cryptsetup.c b/src/cryptsetup/cryptsetup.c index 819d5bbb97..27d7c2769a 100644 --- a/src/cryptsetup/cryptsetup.c +++ b/src/cryptsetup/cryptsetup.c @@ -841,7 +841,7 @@ static int measure_volume_key( if (r < 0) return log_error_errno(r, "Failed to load TPM2 libraries: %m"); - _cleanup_(tpm2_context_destroy) struct tpm2_context c = {}; + _cleanup_(tpm2_context_destroy) Tpm2Context c = {}; r = tpm2_context_init(arg_tpm2_device, &c); if (r < 0) return r; diff --git a/src/shared/tpm2-util.c b/src/shared/tpm2-util.c index 363e8df5cc..9bbf1bba44 100644 --- a/src/shared/tpm2-util.c +++ b/src/shared/tpm2-util.c @@ -104,7 +104,7 @@ int dlopen_tpm2(void) { DLSYM_ARG(Tss2_MU_TPM2B_PUBLIC_Unmarshal)); } -void tpm2_context_destroy(struct tpm2_context *c) { +void tpm2_context_destroy(Tpm2Context *c) { assert(c); if (c->esys_context) @@ -138,7 +138,7 @@ ESYS_TR tpm2_flush_context_verbose(ESYS_CONTEXT *c, ESYS_TR handle) { return ESYS_TR_NONE; } -int tpm2_context_init(const char *device, struct tpm2_context *ret) { +int tpm2_context_init(const char *device, Tpm2Context *ret) { _cleanup_(Esys_Finalize_wrapper) ESYS_CONTEXT *c = NULL; _cleanup_free_ TSS2_TCTI_CONTEXT *tcti = NULL; _cleanup_(dlclosep) void *dl = NULL; @@ -238,7 +238,7 @@ int tpm2_context_init(const char *device, struct tpm2_context *ret) { return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Failed to start up TPM: %s", sym_Tss2_RC_Decode(rc)); - *ret = (struct tpm2_context) { + *ret = (Tpm2Context) { .esys_context = TAKE_PTR(c), .tcti_context = TAKE_PTR(tcti), .tcti_dl = TAKE_PTR(dl), @@ -1403,7 +1403,7 @@ int tpm2_seal(const char *device, uint16_t *ret_pcr_bank, uint16_t *ret_primary_alg) { - _cleanup_(tpm2_context_destroy) struct tpm2_context c = {}; + _cleanup_(tpm2_context_destroy) Tpm2Context c = {}; _cleanup_(Esys_Freep) TPM2B_DIGEST *policy_digest = NULL; _cleanup_(Esys_Freep) TPM2B_PRIVATE *private = NULL; _cleanup_(Esys_Freep) TPM2B_PUBLIC *public = NULL; @@ -1624,7 +1624,7 @@ int tpm2_unseal(const char *device, void **ret_secret, size_t *ret_secret_size) { - _cleanup_(tpm2_context_destroy) struct tpm2_context c = {}; + _cleanup_(tpm2_context_destroy) Tpm2Context c = {}; ESYS_TR primary = ESYS_TR_NONE, session = ESYS_TR_NONE, hmac_session = ESYS_TR_NONE, hmac_key = ESYS_TR_NONE; _cleanup_(Esys_Freep) TPM2B_SENSITIVE_DATA* unsealed = NULL; diff --git a/src/shared/tpm2-util.h b/src/shared/tpm2-util.h index 99b258c290..d48cbecd42 100644 --- a/src/shared/tpm2-util.h +++ b/src/shared/tpm2-util.h @@ -53,11 +53,11 @@ int dlopen_tpm2(void); 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); 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, void **ret_secret, size_t *ret_secret_size); -struct tpm2_context { +typedef struct { void *tcti_dl; TSS2_TCTI_CONTEXT *tcti_context; ESYS_CONTEXT *esys_context; -}; +} Tpm2Context; ESYS_TR tpm2_flush_context_verbose(ESYS_CONTEXT *c, ESYS_TR handle); @@ -73,12 +73,12 @@ int tpm2_get_good_pcr_banks_strv(ESYS_CONTEXT *c, uint32_t pcr_mask, char ***ret int tpm2_extend_bytes(ESYS_CONTEXT *c, char **banks, unsigned pcr_index, const void *data, size_t data_size, const void *secret, size_t secret_size); -#else -struct tpm2_context; -#endif +#else /* HAVE_TPM2 */ +typedef struct {} Tpm2Context; +#endif /* HAVE_TPM2 */ -int tpm2_context_init(const char *device, struct tpm2_context *ret); -void tpm2_context_destroy(struct tpm2_context *c); +int tpm2_context_init(const char *device, Tpm2Context *ret); +void tpm2_context_destroy(Tpm2Context *c); int tpm2_list_devices(void); int tpm2_find_device_auto(int log_level, char **ret); From 68d084cee56e2686fb840106de20e267482183be Mon Sep 17 00:00:00 2001 From: Dan Streetman Date: Mon, 23 Jan 2023 19:52:56 -0500 Subject: [PATCH 2/4] tpm2: use ref counter for Tpm2Context This will be used by Tpm2Handle instances, which is added in later patches. The refcounting allows the context to be retained until all Tpm2Handles have been cleaned up, and the initial ref is released, before cleaning the context. --- src/boot/measure.c | 14 +++--- src/boot/pcrphase.c | 8 ++-- src/cryptsetup/cryptsetup.c | 8 ++-- src/shared/tpm2-util.c | 91 ++++++++++++++++++------------------- src/shared/tpm2-util.h | 11 +++-- 5 files changed, 68 insertions(+), 64 deletions(-) diff --git a/src/boot/measure.c b/src/boot/measure.c index 0d1737200b..7b1aca18a1 100644 --- a/src/boot/measure.c +++ b/src/boot/measure.c @@ -726,7 +726,6 @@ static int verb_sign(int argc, char *argv[], void *userdata) { _cleanup_(json_variant_unrefp) JsonVariant *v = NULL; _cleanup_(pcr_state_free_all) PcrState *pcr_states = NULL; _cleanup_(EVP_PKEY_freep) EVP_PKEY *privkey = NULL, *pubkey = NULL; - _cleanup_(tpm2_context_destroy) Tpm2Context c = {}; _cleanup_fclose_ FILE *privkeyf = NULL; ESYS_TR session_handle = ESYS_TR_NONE; TSS2_RC rc; @@ -811,7 +810,8 @@ static int verb_sign(int argc, char *argv[], void *userdata) { if (r < 0) return r; - r = tpm2_context_init(arg_tpm2_device, &c); + _cleanup_tpm2_context_ Tpm2Context *c = NULL; + r = tpm2_context_new(arg_tpm2_device, &c); if (r < 0) return r; @@ -830,7 +830,7 @@ static int verb_sign(int argc, char *argv[], void *userdata) { PcrState *p = pcr_states + i; rc = sym_Esys_StartAuthSession( - c.esys_context, + c->esys_context, ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE, @@ -865,7 +865,7 @@ static int verb_sign(int argc, char *argv[], void *userdata) { tpm2_pcr_mask_to_selection(1 << TPM_PCR_INDEX_KERNEL_IMAGE, tpmalg, &pcr_selection); rc = sym_Esys_PolicyPCR( - c.esys_context, + c->esys_context, session_handle, ESYS_TR_NONE, ESYS_TR_NONE, @@ -880,7 +880,7 @@ static int verb_sign(int argc, char *argv[], void *userdata) { _cleanup_(Esys_Freep) TPM2B_DIGEST *pcr_policy_digest = NULL; rc = sym_Esys_PolicyGetDigest( - c.esys_context, + c->esys_context, session_handle, ESYS_TR_NONE, ESYS_TR_NONE, @@ -892,7 +892,7 @@ static int verb_sign(int argc, char *argv[], void *userdata) { goto finish; } - session_handle = tpm2_flush_context_verbose(c.esys_context, session_handle); + session_handle = tpm2_flush_context_verbose(c->esys_context, session_handle); _cleanup_(EVP_MD_CTX_freep) EVP_MD_CTX* mdctx = NULL; mdctx = EVP_MD_CTX_new(); @@ -983,7 +983,7 @@ static int verb_sign(int argc, char *argv[], void *userdata) { r = 0; finish: - session_handle = tpm2_flush_context_verbose(c.esys_context, session_handle); + session_handle = tpm2_flush_context_verbose(c->esys_context, session_handle); return r; } diff --git a/src/boot/pcrphase.c b/src/boot/pcrphase.c index 057b9f495c..dc5604a33c 100644 --- a/src/boot/pcrphase.c +++ b/src/boot/pcrphase.c @@ -240,7 +240,6 @@ static int get_file_system_word( } static int run(int argc, char *argv[]) { - _cleanup_(tpm2_context_destroy) Tpm2Context c = {}; _cleanup_free_ char *joined = NULL, *word = NULL; unsigned target_pcr_nr; size_t length; @@ -346,11 +345,12 @@ static int run(int argc, char *argv[]) { if (r < 0) return log_error_errno(r, "Failed to load TPM2 libraries: %m"); - r = tpm2_context_init(arg_tpm2_device, &c); + _cleanup_tpm2_context_ Tpm2Context *c = NULL; + r = tpm2_context_new(arg_tpm2_device, &c); if (r < 0) return r; - r = determine_banks(&c, target_pcr_nr); + r = determine_banks(c, target_pcr_nr); if (r < 0) return r; if (strv_isempty(arg_banks)) /* Still none? */ @@ -362,7 +362,7 @@ static int run(int argc, char *argv[]) { log_debug("Measuring '%s' into PCR index %u, banks %s.", word, target_pcr_nr, joined); - r = tpm2_extend_bytes(c.esys_context, arg_banks, target_pcr_nr, word, length, NULL, 0); + r = tpm2_extend_bytes(c->esys_context, arg_banks, target_pcr_nr, word, length, NULL, 0); if (r < 0) return r; diff --git a/src/cryptsetup/cryptsetup.c b/src/cryptsetup/cryptsetup.c index 27d7c2769a..845667eabe 100644 --- a/src/cryptsetup/cryptsetup.c +++ b/src/cryptsetup/cryptsetup.c @@ -841,14 +841,14 @@ static int measure_volume_key( if (r < 0) return log_error_errno(r, "Failed to load TPM2 libraries: %m"); - _cleanup_(tpm2_context_destroy) Tpm2Context c = {}; - r = tpm2_context_init(arg_tpm2_device, &c); + _cleanup_tpm2_context_ Tpm2Context *c = NULL; + r = tpm2_context_new(arg_tpm2_device, &c); if (r < 0) return r; _cleanup_strv_free_ char **l = NULL; if (strv_isempty(arg_tpm2_measure_banks)) { - r = tpm2_get_good_pcr_banks_strv(c.esys_context, UINT32_C(1) << arg_tpm2_measure_pcr, &l); + r = tpm2_get_good_pcr_banks_strv(c->esys_context, UINT32_C(1) << arg_tpm2_measure_pcr, &l); if (r < 0) return r; } @@ -871,7 +871,7 @@ static int measure_volume_key( if (!s) return log_oom(); - r = tpm2_extend_bytes(c.esys_context, l ?: arg_tpm2_measure_banks, arg_tpm2_measure_pcr, s, SIZE_MAX, volume_key, volume_key_size); + r = tpm2_extend_bytes(c->esys_context, l ?: arg_tpm2_measure_banks, arg_tpm2_measure_pcr, s, SIZE_MAX, volume_key, volume_key_size); if (r < 0) return r; diff --git a/src/shared/tpm2-util.c b/src/shared/tpm2-util.c index 9bbf1bba44..0b02d7978c 100644 --- a/src/shared/tpm2-util.c +++ b/src/shared/tpm2-util.c @@ -104,22 +104,20 @@ int dlopen_tpm2(void) { DLSYM_ARG(Tss2_MU_TPM2B_PUBLIC_Unmarshal)); } -void tpm2_context_destroy(Tpm2Context *c) { - assert(c); +static Tpm2Context *tpm2_context_free(Tpm2Context *c) { + if (!c) + return NULL; if (c->esys_context) sym_Esys_Finalize(&c->esys_context); c->tcti_context = mfree(c->tcti_context); c->tcti_dl = safe_dlclose(c->tcti_dl); + + return mfree(c); } -static inline void Esys_Finalize_wrapper(ESYS_CONTEXT **c) { - /* A wrapper around Esys_Finalize() for use with _cleanup_(). Only reasons we need this wrapper is - * because the function itself warn logs if we'd pass a pointer to NULL, and we don't want that. */ - if (*c) - sym_Esys_Finalize(c); -} +DEFINE_TRIVIAL_REF_UNREF_FUNC(Tpm2Context, tpm2_context, tpm2_context_free); ESYS_TR tpm2_flush_context_verbose(ESYS_CONTEXT *c, ESYS_TR handle) { TSS2_RC rc; @@ -138,13 +136,19 @@ ESYS_TR tpm2_flush_context_verbose(ESYS_CONTEXT *c, ESYS_TR handle) { return ESYS_TR_NONE; } -int tpm2_context_init(const char *device, Tpm2Context *ret) { - _cleanup_(Esys_Finalize_wrapper) ESYS_CONTEXT *c = NULL; - _cleanup_free_ TSS2_TCTI_CONTEXT *tcti = NULL; - _cleanup_(dlclosep) void *dl = NULL; +int tpm2_context_new(const char *device, Tpm2Context **ret_context) { + _cleanup_tpm2_context_ Tpm2Context *context = NULL; TSS2_RC rc; int r; + assert(ret_context); + + context = new0(Tpm2Context, 1); + if (!context) + return log_oom(); + + context->n_ref = 1; + r = dlopen_tpm2(); if (r < 0) return log_error_errno(r, "TPM2 support not installed: %m"); @@ -192,11 +196,11 @@ int tpm2_context_init(const char *device, Tpm2Context *ret) { if (!filename_is_valid(fn)) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "TPM2 driver name '%s' not valid, refusing.", driver); - dl = dlopen(fn, RTLD_NOW); - if (!dl) + context->tcti_dl = dlopen(fn, RTLD_NOW); + if (!context->tcti_dl) return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Failed to load %s: %s", fn, dlerror()); - func = dlsym(dl, TSS2_TCTI_INFO_SYMBOL); + func = dlsym(context->tcti_dl, TSS2_TCTI_INFO_SYMBOL); if (!func) return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Failed to find TCTI info symbol " TSS2_TCTI_INFO_SYMBOL ": %s", @@ -206,7 +210,6 @@ int tpm2_context_init(const char *device, Tpm2Context *ret) { if (!info) return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Unable to get TCTI info data."); - log_debug("Loaded TCTI module '%s' (%s) [Version %" PRIu32 "]", info->name, info->description, info->version); rc = info->init(NULL, &sz, NULL); @@ -214,22 +217,22 @@ int tpm2_context_init(const char *device, Tpm2Context *ret) { return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Failed to initialize TCTI context: %s", sym_Tss2_RC_Decode(rc)); - tcti = malloc0(sz); - if (!tcti) + context->tcti_context = malloc0(sz); + if (!context->tcti_context) return log_oom(); - rc = info->init(tcti, &sz, param); + rc = info->init(context->tcti_context, &sz, param); if (rc != TPM2_RC_SUCCESS) return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Failed to initialize TCTI context: %s", sym_Tss2_RC_Decode(rc)); } - rc = sym_Esys_Initialize(&c, tcti, NULL); + rc = sym_Esys_Initialize(&context->esys_context, context->tcti_context, NULL); if (rc != TSS2_RC_SUCCESS) return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Failed to initialize TPM context: %s", sym_Tss2_RC_Decode(rc)); - rc = sym_Esys_Startup(c, TPM2_SU_CLEAR); + rc = sym_Esys_Startup(context->esys_context, TPM2_SU_CLEAR); if (rc == TPM2_RC_INITIALIZE) log_debug("TPM already started up."); else if (rc == TSS2_RC_SUCCESS) @@ -238,11 +241,7 @@ int tpm2_context_init(const char *device, Tpm2Context *ret) { return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Failed to start up TPM: %s", sym_Tss2_RC_Decode(rc)); - *ret = (Tpm2Context) { - .esys_context = TAKE_PTR(c), - .tcti_context = TAKE_PTR(tcti), - .tcti_dl = TAKE_PTR(dl), - }; + *ret_context = TAKE_PTR(context); return 0; } @@ -1403,7 +1402,6 @@ int tpm2_seal(const char *device, uint16_t *ret_pcr_bank, uint16_t *ret_primary_alg) { - _cleanup_(tpm2_context_destroy) Tpm2Context c = {}; _cleanup_(Esys_Freep) TPM2B_DIGEST *policy_digest = NULL; _cleanup_(Esys_Freep) TPM2B_PRIVATE *private = NULL; _cleanup_(Esys_Freep) TPM2B_PUBLIC *public = NULL; @@ -1453,21 +1451,22 @@ int tpm2_seal(const char *device, CLEANUP_ERASE(hmac_sensitive); - r = tpm2_context_init(device, &c); + _cleanup_tpm2_context_ Tpm2Context *c = NULL; + r = tpm2_context_new(device, &c); if (r < 0) return r; - r = tpm2_make_primary(c.esys_context, &primary, 0, &primary_alg); + r = tpm2_make_primary(c->esys_context, &primary, 0, &primary_alg); if (r < 0) return r; /* we cannot use the bind key before its created */ - r = tpm2_make_encryption_session(c.esys_context, primary, ESYS_TR_NONE, NULL, &session); + r = tpm2_make_encryption_session(c->esys_context, primary, ESYS_TR_NONE, NULL, &session); if (r < 0) goto finish; r = tpm2_make_policy_session( - c.esys_context, + c->esys_context, primary, session, TPM2_SE_TRIAL, @@ -1507,7 +1506,7 @@ int tpm2_seal(const char *device, assert(sizeof(hmac_sensitive.sensitive.data.buffer) >= hmac_sensitive.sensitive.data.size); - (void) tpm2_credit_random(c.esys_context); + (void) tpm2_credit_random(c->esys_context); log_debug("Generating secret key data."); @@ -1520,7 +1519,7 @@ int tpm2_seal(const char *device, log_debug("Creating HMAC key."); rc = sym_Esys_Create( - c.esys_context, + c->esys_context, primary, session, /* use HMAC session to enable parameter encryption */ ESYS_TR_NONE, @@ -1601,8 +1600,8 @@ int tpm2_seal(const char *device, r = 0; finish: - primary = tpm2_flush_context_verbose(c.esys_context, primary); - session = tpm2_flush_context_verbose(c.esys_context, session); + primary = tpm2_flush_context_verbose(c->esys_context, primary); + session = tpm2_flush_context_verbose(c->esys_context, session); return r; } @@ -1624,7 +1623,6 @@ int tpm2_unseal(const char *device, void **ret_secret, size_t *ret_secret_size) { - _cleanup_(tpm2_context_destroy) Tpm2Context c = {}; ESYS_TR primary = ESYS_TR_NONE, session = ESYS_TR_NONE, hmac_session = ESYS_TR_NONE, hmac_key = ESYS_TR_NONE; _cleanup_(Esys_Freep) TPM2B_SENSITIVE_DATA* unsealed = NULL; @@ -1675,11 +1673,12 @@ int tpm2_unseal(const char *device, return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Failed to unmarshal public key: %s", sym_Tss2_RC_Decode(rc)); - r = tpm2_context_init(device, &c); + _cleanup_tpm2_context_ Tpm2Context *c = NULL; + r = tpm2_context_new(device, &c); if (r < 0) return r; - r = tpm2_make_primary(c.esys_context, &primary, primary_alg, NULL); + r = tpm2_make_primary(c->esys_context, &primary, primary_alg, NULL); if (r < 0) return r; @@ -1692,7 +1691,7 @@ int tpm2_unseal(const char *device, * primary key is not verified and they could attack there as well. */ rc = sym_Esys_Load( - c.esys_context, + c->esys_context, primary, ESYS_TR_PASSWORD, ESYS_TR_NONE, @@ -1715,13 +1714,13 @@ int tpm2_unseal(const char *device, goto finish; } - r = tpm2_make_encryption_session(c.esys_context, primary, hmac_key, pin, &hmac_session); + r = tpm2_make_encryption_session(c->esys_context, primary, hmac_key, pin, &hmac_session); if (r < 0) goto finish; for (unsigned i = RETRY_UNSEAL_MAX;; i--) { r = tpm2_make_policy_session( - c.esys_context, + c->esys_context, primary, hmac_session, TPM2_SE_POLICY, @@ -1748,7 +1747,7 @@ int tpm2_unseal(const char *device, log_debug("Unsealing HMAC key."); rc = sym_Esys_Unseal( - c.esys_context, + c->esys_context, hmac_key, session, hmac_session, /* use HMAC session to enable parameter encryption */ @@ -1756,7 +1755,7 @@ int tpm2_unseal(const char *device, &unsealed); if (rc == TPM2_RC_PCR_CHANGED && i > 0) { log_debug("A PCR value changed during the TPM2 policy session, restarting HMAC key unsealing (%u tries left).", i); - session = tpm2_flush_context_verbose(c.esys_context, session); + session = tpm2_flush_context_verbose(c->esys_context, session); continue; } if (rc != TSS2_RC_SUCCESS) { @@ -1784,9 +1783,9 @@ int tpm2_unseal(const char *device, r = 0; finish: - primary = tpm2_flush_context_verbose(c.esys_context, primary); - session = tpm2_flush_context_verbose(c.esys_context, session); - hmac_key = tpm2_flush_context_verbose(c.esys_context, hmac_key); + primary = tpm2_flush_context_verbose(c->esys_context, primary); + session = tpm2_flush_context_verbose(c->esys_context, session); + hmac_key = tpm2_flush_context_verbose(c->esys_context, hmac_key); return r; } diff --git a/src/shared/tpm2-util.h b/src/shared/tpm2-util.h index d48cbecd42..bb89931913 100644 --- a/src/shared/tpm2-util.h +++ b/src/shared/tpm2-util.h @@ -54,11 +54,19 @@ int tpm2_seal(const char *device, uint32_t hash_pcr_mask, const void *pubkey, si 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, void **ret_secret, size_t *ret_secret_size); typedef struct { + unsigned n_ref; + void *tcti_dl; TSS2_TCTI_CONTEXT *tcti_context; ESYS_CONTEXT *esys_context; } Tpm2Context; +int tpm2_context_new(const char *device, Tpm2Context **ret_context); +Tpm2Context *tpm2_context_ref(Tpm2Context *context); +Tpm2Context *tpm2_context_unref(Tpm2Context *context); +DEFINE_TRIVIAL_CLEANUP_FUNC(Tpm2Context*, tpm2_context_unref); +#define _cleanup_tpm2_context_ _cleanup_(tpm2_context_unrefp) + ESYS_TR tpm2_flush_context_verbose(ESYS_CONTEXT *c, ESYS_TR handle); void tpm2_pcr_mask_to_selection(uint32_t mask, uint16_t bank, TPML_PCR_SELECTION *ret); @@ -77,9 +85,6 @@ int tpm2_extend_bytes(ESYS_CONTEXT *c, char **banks, unsigned pcr_index, const v typedef struct {} Tpm2Context; #endif /* HAVE_TPM2 */ -int tpm2_context_init(const char *device, Tpm2Context *ret); -void tpm2_context_destroy(Tpm2Context *c); - int tpm2_list_devices(void); int tpm2_find_device_auto(int log_level, char **ret); From 23e9ccc24ae0e7d3f3f609c69dbde171f1c55302 Mon Sep 17 00:00:00 2001 From: Dan Streetman Date: Tue, 6 Dec 2022 13:07:34 -0500 Subject: [PATCH 3/4] tpm2: use Tpm2Context* instead of ESYS_CONTEXT* This is needed for later patches that use Tpm2Handle, which requires access to the Tpm2Context. --- src/boot/measure.c | 4 +- src/boot/pcrphase.c | 4 +- src/cryptsetup/cryptsetup.c | 4 +- src/shared/tpm2-util.c | 90 ++++++++++++++++++------------------- src/shared/tpm2-util.h | 8 ++-- 5 files changed, 55 insertions(+), 55 deletions(-) diff --git a/src/boot/measure.c b/src/boot/measure.c index 7b1aca18a1..8bb319189e 100644 --- a/src/boot/measure.c +++ b/src/boot/measure.c @@ -892,7 +892,7 @@ static int verb_sign(int argc, char *argv[], void *userdata) { goto finish; } - session_handle = tpm2_flush_context_verbose(c->esys_context, session_handle); + session_handle = tpm2_flush_context_verbose(c, session_handle); _cleanup_(EVP_MD_CTX_freep) EVP_MD_CTX* mdctx = NULL; mdctx = EVP_MD_CTX_new(); @@ -983,7 +983,7 @@ static int verb_sign(int argc, char *argv[], void *userdata) { r = 0; finish: - session_handle = tpm2_flush_context_verbose(c->esys_context, session_handle); + session_handle = tpm2_flush_context_verbose(c, session_handle); return r; } diff --git a/src/boot/pcrphase.c b/src/boot/pcrphase.c index dc5604a33c..05e9645de9 100644 --- a/src/boot/pcrphase.c +++ b/src/boot/pcrphase.c @@ -164,7 +164,7 @@ static int determine_banks(Tpm2Context *c, unsigned target_pcr_nr) { if (!strv_isempty(arg_banks)) /* Explicitly configured? Then use that */ return 0; - r = tpm2_get_good_pcr_banks_strv(c->esys_context, UINT32_C(1) << target_pcr_nr, &l); + r = tpm2_get_good_pcr_banks_strv(c, UINT32_C(1) << target_pcr_nr, &l); if (r < 0) return r; @@ -362,7 +362,7 @@ static int run(int argc, char *argv[]) { log_debug("Measuring '%s' into PCR index %u, banks %s.", word, target_pcr_nr, joined); - r = tpm2_extend_bytes(c->esys_context, arg_banks, target_pcr_nr, word, length, NULL, 0); + r = tpm2_extend_bytes(c, arg_banks, target_pcr_nr, word, length, NULL, 0); if (r < 0) return r; diff --git a/src/cryptsetup/cryptsetup.c b/src/cryptsetup/cryptsetup.c index 845667eabe..e776605501 100644 --- a/src/cryptsetup/cryptsetup.c +++ b/src/cryptsetup/cryptsetup.c @@ -848,7 +848,7 @@ static int measure_volume_key( _cleanup_strv_free_ char **l = NULL; if (strv_isempty(arg_tpm2_measure_banks)) { - r = tpm2_get_good_pcr_banks_strv(c->esys_context, UINT32_C(1) << arg_tpm2_measure_pcr, &l); + r = tpm2_get_good_pcr_banks_strv(c, UINT32_C(1) << arg_tpm2_measure_pcr, &l); if (r < 0) return r; } @@ -871,7 +871,7 @@ static int measure_volume_key( if (!s) return log_oom(); - r = tpm2_extend_bytes(c->esys_context, l ?: arg_tpm2_measure_banks, arg_tpm2_measure_pcr, s, SIZE_MAX, volume_key, volume_key_size); + r = tpm2_extend_bytes(c, l ?: arg_tpm2_measure_banks, arg_tpm2_measure_pcr, s, SIZE_MAX, volume_key, volume_key_size); if (r < 0) return r; diff --git a/src/shared/tpm2-util.c b/src/shared/tpm2-util.c index 0b02d7978c..43c760576c 100644 --- a/src/shared/tpm2-util.c +++ b/src/shared/tpm2-util.c @@ -119,13 +119,13 @@ static Tpm2Context *tpm2_context_free(Tpm2Context *c) { DEFINE_TRIVIAL_REF_UNREF_FUNC(Tpm2Context, tpm2_context, tpm2_context_free); -ESYS_TR tpm2_flush_context_verbose(ESYS_CONTEXT *c, ESYS_TR handle) { +ESYS_TR tpm2_flush_context_verbose(Tpm2Context *c, ESYS_TR handle) { TSS2_RC rc; - if (!c || handle == ESYS_TR_NONE) + if (!c || !c->esys_context || handle == ESYS_TR_NONE) return ESYS_TR_NONE; - rc = sym_Esys_FlushContext(c, handle); + rc = sym_Esys_FlushContext(c->esys_context, handle); if (rc != TSS2_RC_SUCCESS) /* We ignore failures here (besides debug logging), since this is called * in error paths, where we cannot do anything about failures anymore. And * when it is called in successful codepaths by this time we already did @@ -248,7 +248,7 @@ int tpm2_context_new(const char *device, Tpm2Context **ret_context) { #define TPM2_CREDIT_RANDOM_FLAG_PATH "/run/systemd/tpm-rng-credited" -static int tpm2_credit_random(ESYS_CONTEXT *c) { +static int tpm2_credit_random(Tpm2Context *c) { size_t rps, done = 0; TSS2_RC rc; usec_t t; @@ -275,7 +275,7 @@ static int tpm2_credit_random(ESYS_CONTEXT *c) { _cleanup_(Esys_Freep) TPM2B_DIGEST *buffer = NULL; rc = sym_Esys_GetRandom( - c, + c->esys_context, ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE, @@ -307,7 +307,7 @@ static int tpm2_credit_random(ESYS_CONTEXT *c) { } static int tpm2_make_primary( - ESYS_CONTEXT *c, + Tpm2Context *c, ESYS_TR *ret_primary, TPMI_ALG_PUBLIC alg, TPMI_ALG_PUBLIC *ret_alg) { @@ -364,7 +364,7 @@ static int tpm2_make_primary( if (IN_SET(alg, 0, TPM2_ALG_ECC)) { rc = sym_Esys_CreatePrimary( - c, + c->esys_context, ESYS_TR_RH_OWNER, ESYS_TR_PASSWORD, ESYS_TR_NONE, @@ -393,7 +393,7 @@ static int tpm2_make_primary( if (IN_SET(alg, 0, TPM2_ALG_RSA)) { rc = sym_Esys_CreatePrimary( - c, + c->esys_context, ESYS_TR_RH_OWNER, ESYS_TR_PASSWORD, ESYS_TR_NONE, @@ -469,7 +469,7 @@ static unsigned find_nth_bit(uint32_t mask, unsigned n) { } static int tpm2_pcr_mask_good( - ESYS_CONTEXT *c, + Tpm2Context *c, TPMI_ALG_HASH bank, uint32_t mask) { @@ -487,7 +487,7 @@ static int tpm2_pcr_mask_good( tpm2_pcr_mask_to_selection(mask, bank, &selection); rc = sym_Esys_PCR_Read( - c, + c->esys_context, ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE, @@ -551,7 +551,7 @@ static int tpm2_bank_has24(const TPMS_PCR_SELECTION *selection) { } static int tpm2_get_best_pcr_bank( - ESYS_CONTEXT *c, + Tpm2Context *c, uint32_t pcr_mask, TPMI_ALG_HASH *ret) { @@ -564,7 +564,7 @@ static int tpm2_get_best_pcr_bank( assert(c); rc = sym_Esys_GetCapability( - c, + c->esys_context, ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE, @@ -648,7 +648,7 @@ static int tpm2_get_best_pcr_bank( } int tpm2_get_good_pcr_banks( - ESYS_CONTEXT *c, + Tpm2Context *c, uint32_t pcr_mask, TPMI_ALG_HASH **ret) { @@ -663,7 +663,7 @@ int tpm2_get_good_pcr_banks( assert(ret); rc = sym_Esys_GetCapability( - c, + c->esys_context, ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE, @@ -727,7 +727,7 @@ int tpm2_get_good_pcr_banks( } int tpm2_get_good_pcr_banks_strv( - ESYS_CONTEXT *c, + Tpm2Context *c, uint32_t pcr_mask, char ***ret) { @@ -785,7 +785,7 @@ static void hash_pin(const char *pin, size_t len, TPM2B_AUTH *auth) { } static int tpm2_make_encryption_session( - ESYS_CONTEXT *c, + Tpm2Context *c, ESYS_TR primary, ESYS_TR bind_key, const char *pin, @@ -817,7 +817,7 @@ static int tpm2_make_encryption_session( hash_pin(pin, strlen(pin), &auth); - rc = sym_Esys_TR_SetAuth(c, bind_key, &auth); + rc = sym_Esys_TR_SetAuth(c->esys_context, bind_key, &auth); if (rc != TSS2_RC_SUCCESS) return log_error_errno( SYNTHETIC_ERRNO(ENOTRECOVERABLE), @@ -831,7 +831,7 @@ static int tpm2_make_encryption_session( * means that the random salt will be encrypted with the well-known key. That way, only the TPM can * recover the salt, which is then used for key derivation. */ rc = sym_Esys_StartAuthSession( - c, + c->esys_context, primary, bind_key, ESYS_TR_NONE, @@ -849,7 +849,7 @@ static int tpm2_make_encryption_session( /* Enable parameter encryption/decryption with AES in CFB mode. Together with HMAC digests (which are * always used for sessions), this provides confidentiality, integrity and replay protection for * operations that use this session. */ - rc = sym_Esys_TRSess_SetAttributes(c, session, sessionAttributes, 0xff); + rc = sym_Esys_TRSess_SetAttributes(c->esys_context, session, sessionAttributes, 0xff); if (rc != TSS2_RC_SUCCESS) return log_error_errno( SYNTHETIC_ERRNO(ENOTRECOVERABLE), @@ -1048,7 +1048,7 @@ static int find_signature( #endif static int tpm2_make_policy_session( - ESYS_CONTEXT *c, + Tpm2Context *c, ESYS_TR primary, ESYS_TR parent_session, TPM2_SE session_type, @@ -1125,7 +1125,7 @@ static int tpm2_make_policy_session( #endif rc = sym_Esys_StartAuthSession( - c, + c->esys_context, primary, ESYS_TR_NONE, parent_session, @@ -1151,7 +1151,7 @@ static int tpm2_make_policy_session( goto finish; rc = sym_Esys_LoadExternal( - c, + c->esys_context, ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE, @@ -1174,7 +1174,7 @@ static int tpm2_make_policy_session( /* Acquire the "name" of what we just loaded */ _cleanup_(Esys_Freep) TPM2B_NAME *pubkey_name = NULL; rc = sym_Esys_TR_GetName( - c, + c->esys_context, pubkey_handle, &pubkey_name); if (rc != TSS2_RC_SUCCESS) { @@ -1187,7 +1187,7 @@ static int tpm2_make_policy_session( TPML_PCR_SELECTION pcr_selection; tpm2_pcr_mask_to_selection(pubkey_pcr_mask, pcr_bank, &pcr_selection); rc = sym_Esys_PolicyPCR( - c, + c->esys_context, session, ESYS_TR_NONE, ESYS_TR_NONE, @@ -1203,7 +1203,7 @@ static int tpm2_make_policy_session( /* Get the policy hash of the PCR policy */ _cleanup_(Esys_Freep) TPM2B_DIGEST *approved_policy = NULL; rc = sym_Esys_PolicyGetDigest( - c, + c->esys_context, session, ESYS_TR_NONE, ESYS_TR_NONE, @@ -1256,7 +1256,7 @@ static int tpm2_make_policy_session( memcpy(policy_signature.signature.rsassa.sig.buffer, signature_raw, signature_size); rc = sym_Esys_VerifySignature( - c, + c->esys_context, pubkey_handle, ESYS_TR_NONE, ESYS_TR_NONE, @@ -1282,7 +1282,7 @@ static int tpm2_make_policy_session( } rc = sym_Esys_PolicyAuthorize( - c, + c->esys_context, session, ESYS_TR_NONE, ESYS_TR_NONE, @@ -1307,7 +1307,7 @@ static int tpm2_make_policy_session( TPML_PCR_SELECTION pcr_selection; tpm2_pcr_mask_to_selection(hash_pcr_mask, pcr_bank, &pcr_selection); rc = sym_Esys_PolicyPCR( - c, + c->esys_context, session, ESYS_TR_NONE, ESYS_TR_NONE, @@ -1325,7 +1325,7 @@ static int tpm2_make_policy_session( log_debug("Configuring PIN policy."); rc = sym_Esys_PolicyAuthValue( - c, + c->esys_context, session, ESYS_TR_NONE, ESYS_TR_NONE, @@ -1342,7 +1342,7 @@ static int tpm2_make_policy_session( log_debug("Acquiring policy digest."); rc = sym_Esys_PolicyGetDigest( - c, + c->esys_context, session, ESYS_TR_NONE, ESYS_TR_NONE, @@ -1456,17 +1456,17 @@ int tpm2_seal(const char *device, if (r < 0) return r; - r = tpm2_make_primary(c->esys_context, &primary, 0, &primary_alg); + r = tpm2_make_primary(c, &primary, 0, &primary_alg); if (r < 0) return r; /* we cannot use the bind key before its created */ - r = tpm2_make_encryption_session(c->esys_context, primary, ESYS_TR_NONE, NULL, &session); + r = tpm2_make_encryption_session(c, primary, ESYS_TR_NONE, NULL, &session); if (r < 0) goto finish; r = tpm2_make_policy_session( - c->esys_context, + c, primary, session, TPM2_SE_TRIAL, @@ -1506,7 +1506,7 @@ int tpm2_seal(const char *device, assert(sizeof(hmac_sensitive.sensitive.data.buffer) >= hmac_sensitive.sensitive.data.size); - (void) tpm2_credit_random(c->esys_context); + (void) tpm2_credit_random(c); log_debug("Generating secret key data."); @@ -1600,8 +1600,8 @@ int tpm2_seal(const char *device, r = 0; finish: - primary = tpm2_flush_context_verbose(c->esys_context, primary); - session = tpm2_flush_context_verbose(c->esys_context, session); + primary = tpm2_flush_context_verbose(c, primary); + session = tpm2_flush_context_verbose(c, session); return r; } @@ -1678,7 +1678,7 @@ int tpm2_unseal(const char *device, if (r < 0) return r; - r = tpm2_make_primary(c->esys_context, &primary, primary_alg, NULL); + r = tpm2_make_primary(c, &primary, primary_alg, NULL); if (r < 0) return r; @@ -1714,13 +1714,13 @@ int tpm2_unseal(const char *device, goto finish; } - r = tpm2_make_encryption_session(c->esys_context, primary, hmac_key, pin, &hmac_session); + r = tpm2_make_encryption_session(c, primary, hmac_key, pin, &hmac_session); if (r < 0) goto finish; for (unsigned i = RETRY_UNSEAL_MAX;; i--) { r = tpm2_make_policy_session( - c->esys_context, + c, primary, hmac_session, TPM2_SE_POLICY, @@ -1755,7 +1755,7 @@ int tpm2_unseal(const char *device, &unsealed); if (rc == TPM2_RC_PCR_CHANGED && i > 0) { log_debug("A PCR value changed during the TPM2 policy session, restarting HMAC key unsealing (%u tries left).", i); - session = tpm2_flush_context_verbose(c->esys_context, session); + session = tpm2_flush_context_verbose(c, session); continue; } if (rc != TSS2_RC_SUCCESS) { @@ -1783,9 +1783,9 @@ int tpm2_unseal(const char *device, r = 0; finish: - primary = tpm2_flush_context_verbose(c->esys_context, primary); - session = tpm2_flush_context_verbose(c->esys_context, session); - hmac_key = tpm2_flush_context_verbose(c->esys_context, hmac_key); + primary = tpm2_flush_context_verbose(c, primary); + session = tpm2_flush_context_verbose(c, session); + hmac_key = tpm2_flush_context_verbose(c, hmac_key); return r; } @@ -1917,7 +1917,7 @@ int tpm2_find_device_auto( #if HAVE_TPM2 int tpm2_extend_bytes( - ESYS_CONTEXT *c, + Tpm2Context *c, char **banks, unsigned pcr_index, const void *data, @@ -1978,7 +1978,7 @@ int tpm2_extend_bytes( } rc = sym_Esys_PCR_Extend( - c, + c->esys_context, ESYS_TR_PCR0 + pcr_index, ESYS_TR_PASSWORD, ESYS_TR_NONE, diff --git a/src/shared/tpm2-util.h b/src/shared/tpm2-util.h index bb89931913..9dc55d4a19 100644 --- a/src/shared/tpm2-util.h +++ b/src/shared/tpm2-util.h @@ -67,7 +67,7 @@ Tpm2Context *tpm2_context_unref(Tpm2Context *context); DEFINE_TRIVIAL_CLEANUP_FUNC(Tpm2Context*, tpm2_context_unref); #define _cleanup_tpm2_context_ _cleanup_(tpm2_context_unrefp) -ESYS_TR tpm2_flush_context_verbose(ESYS_CONTEXT *c, ESYS_TR handle); +ESYS_TR tpm2_flush_context_verbose(Tpm2Context *c, ESYS_TR handle); void tpm2_pcr_mask_to_selection(uint32_t mask, uint16_t bank, TPML_PCR_SELECTION *ret); @@ -76,10 +76,10 @@ static inline void Esys_Freep(void *p) { sym_Esys_Free(*(void**) p); } -int tpm2_get_good_pcr_banks(ESYS_CONTEXT *c, uint32_t pcr_mask, TPMI_ALG_HASH **ret_banks); -int tpm2_get_good_pcr_banks_strv(ESYS_CONTEXT *c, uint32_t pcr_mask, char ***ret); +int tpm2_get_good_pcr_banks(Tpm2Context *c, uint32_t pcr_mask, TPMI_ALG_HASH **ret_banks); +int tpm2_get_good_pcr_banks_strv(Tpm2Context *c, uint32_t pcr_mask, char ***ret); -int tpm2_extend_bytes(ESYS_CONTEXT *c, char **banks, unsigned pcr_index, const void *data, size_t data_size, const void *secret, size_t secret_size); +int tpm2_extend_bytes(Tpm2Context *c, char **banks, unsigned pcr_index, const void *data, size_t data_size, const void *secret, size_t secret_size); #else /* HAVE_TPM2 */ typedef struct {} Tpm2Context; From 16e16b8c7b1621f3db96bfc357e5bba727c9dded Mon Sep 17 00:00:00 2001 From: Dan Streetman Date: Tue, 24 Jan 2023 10:19:03 -0500 Subject: [PATCH 4/4] tpm2: add Tpm2Handle with automatic cleanup This allows using _cleanup_ with the handles, which then allows removing the use of goto in all functions that use the handles. --- src/boot/measure.c | 119 +++++-------- src/shared/tpm2-util.c | 371 ++++++++++++++++++++--------------------- src/shared/tpm2-util.h | 14 +- 3 files changed, 237 insertions(+), 267 deletions(-) diff --git a/src/boot/measure.c b/src/boot/measure.c index 8bb319189e..f2fbd9d2c1 100644 --- a/src/boot/measure.c +++ b/src/boot/measure.c @@ -727,7 +727,6 @@ static int verb_sign(int argc, char *argv[], void *userdata) { _cleanup_(pcr_state_free_all) PcrState *pcr_states = NULL; _cleanup_(EVP_PKEY_freep) EVP_PKEY *privkey = NULL, *pubkey = NULL; _cleanup_fclose_ FILE *privkeyf = NULL; - ESYS_TR session_handle = ESYS_TR_NONE; TSS2_RC rc; size_t n; int r; @@ -829,6 +828,11 @@ static int verb_sign(int argc, char *argv[], void *userdata) { }; PcrState *p = pcr_states + i; + _cleanup_tpm2_handle_ Tpm2Handle *session = NULL; + r = tpm2_handle_new(c, &session); + if (r < 0) + return r; + rc = sym_Esys_StartAuthSession( c->esys_context, ESYS_TR_NONE, @@ -840,12 +844,10 @@ static int verb_sign(int argc, char *argv[], void *userdata) { TPM2_SE_TRIAL, &symmetric, TPM2_ALG_SHA256, - &session_handle); - if (rc != TSS2_RC_SUCCESS) { - r = log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), - "Failed to open session in TPM: %s", sym_Tss2_RC_Decode(rc)); - goto finish; - } + &session->esys_handle); + if (rc != TSS2_RC_SUCCESS) + return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), + "Failed to open session in TPM: %s", sym_Tss2_RC_Decode(rc)); /* Generate a single hash value from the PCRs included in our policy. Given that that's * exactly one, the calculation is trivial. */ @@ -856,94 +858,72 @@ static int verb_sign(int argc, char *argv[], void *userdata) { sha256_direct(p->value, p->value_size, intermediate_digest.buffer); int tpmalg = tpm2_hash_alg_from_string(EVP_MD_name(p->md)); - if (tpmalg < 0) { - log_error_errno(tpmalg, "Unsupported PCR bank"); - goto finish; - } + if (tpmalg < 0) + return log_error_errno(tpmalg, "Unsupported PCR bank"); TPML_PCR_SELECTION pcr_selection; tpm2_pcr_mask_to_selection(1 << TPM_PCR_INDEX_KERNEL_IMAGE, tpmalg, &pcr_selection); rc = sym_Esys_PolicyPCR( c->esys_context, - session_handle, + session->esys_handle, ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE, &intermediate_digest, &pcr_selection); - if (rc != TSS2_RC_SUCCESS) { - r = log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), - "Failed to push PCR policy into TPM: %s", sym_Tss2_RC_Decode(rc)); - goto finish; - } + if (rc != TSS2_RC_SUCCESS) + return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), + "Failed to push PCR policy into TPM: %s", sym_Tss2_RC_Decode(rc)); _cleanup_(Esys_Freep) TPM2B_DIGEST *pcr_policy_digest = NULL; rc = sym_Esys_PolicyGetDigest( c->esys_context, - session_handle, + session->esys_handle, ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE, &pcr_policy_digest); - if (rc != TSS2_RC_SUCCESS) { - r = log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), - "Failed to get policy digest from TPM: %s", sym_Tss2_RC_Decode(rc)); - goto finish; - } - - session_handle = tpm2_flush_context_verbose(c, session_handle); + if (rc != TSS2_RC_SUCCESS) + return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), + "Failed to get policy digest from TPM: %s", sym_Tss2_RC_Decode(rc)); _cleanup_(EVP_MD_CTX_freep) EVP_MD_CTX* mdctx = NULL; mdctx = EVP_MD_CTX_new(); - if (!mdctx) { - r = log_oom(); - goto finish; - } + if (!mdctx) + return log_oom(); - if (EVP_DigestSignInit(mdctx, NULL, p->md, NULL, privkey) != 1) { - r = log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), - "Failed to initialize signature context."); - goto finish; - } + if (EVP_DigestSignInit(mdctx, NULL, p->md, NULL, privkey) != 1) + return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), + "Failed to initialize signature context."); - if (EVP_DigestSignUpdate(mdctx, pcr_policy_digest->buffer, pcr_policy_digest->size) != 1) { - r = log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), - "Failed to sign data."); - goto finish; - } + if (EVP_DigestSignUpdate(mdctx, pcr_policy_digest->buffer, pcr_policy_digest->size) != 1) + return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), + "Failed to sign data."); size_t ss; - if (EVP_DigestSignFinal(mdctx, NULL, &ss) != 1) { - r = log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), - "Failed to finalize signature"); - goto finish; - } + if (EVP_DigestSignFinal(mdctx, NULL, &ss) != 1) + return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), + "Failed to finalize signature"); _cleanup_free_ void *sig = malloc(ss); - if (!sig) { - r = log_oom(); - goto finish; - } + if (!sig) + return log_oom(); - if (EVP_DigestSignFinal(mdctx, sig, &ss) != 1) { - r = log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), - "Failed to acquire signature data"); - goto finish; - } + if (EVP_DigestSignFinal(mdctx, sig, &ss) != 1) + return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), + "Failed to acquire signature data"); _cleanup_free_ void *pubkey_fp = NULL; size_t pubkey_fp_size = 0; r = pubkey_fingerprint(pubkey, EVP_sha256(), &pubkey_fp, &pubkey_fp_size); if (r < 0) - goto finish; + return r; _cleanup_(json_variant_unrefp) JsonVariant *a = NULL; r = tpm2_make_pcr_json_array(UINT64_C(1) << TPM_PCR_INDEX_KERNEL_IMAGE, &a); - if (r < 0) { - log_error_errno(r, "Failed to build JSON PCR mask array: %m"); - goto finish; - } + if (r < 0) + return log_error_errno(r, "Failed to build JSON PCR mask array: %m"); _cleanup_(json_variant_unrefp) JsonVariant *bv = NULL; r = json_build(&bv, JSON_BUILD_OBJECT( @@ -951,25 +931,19 @@ static int verb_sign(int argc, char *argv[], void *userdata) { JSON_BUILD_PAIR("pkfp", JSON_BUILD_HEX(pubkey_fp, pubkey_fp_size)), /* SHA256 fingerprint of public key (DER) used for the signature */ JSON_BUILD_PAIR("pol", JSON_BUILD_HEX(pcr_policy_digest->buffer, pcr_policy_digest->size)), /* TPM2 policy hash that is signed */ JSON_BUILD_PAIR("sig", JSON_BUILD_BASE64(sig, ss)))); /* signature data */ - if (r < 0) { - log_error_errno(r, "Failed to build JSON object: %m"); - goto finish; - } + if (r < 0) + return log_error_errno(r, "Failed to build JSON object: %m"); _cleanup_(json_variant_unrefp) JsonVariant *av = NULL; av = json_variant_ref(json_variant_by_key(v, p->bank)); r = json_variant_append_array_nodup(&av, bv); - if (r < 0) { - log_error_errno(r, "Failed to append JSON object: %m"); - goto finish; - } + if (r < 0) + return log_error_errno(r, "Failed to append JSON object: %m"); r = json_variant_set_field(&v, p->bank, av); - if (r < 0) { - log_error_errno(r, "Failed to add JSON field: %m"); - goto finish; - } + if (r < 0) + return log_error_errno(r, "Failed to add JSON field: %m"); } /* Return to the original kernel measurement for the next phase calculation */ @@ -980,11 +954,8 @@ static int verb_sign(int argc, char *argv[], void *userdata) { pager_open(arg_pager_flags); json_variant_dump(v, arg_json_format_flags, stdout, NULL); - r = 0; -finish: - session_handle = tpm2_flush_context_verbose(c, session_handle); - return r; + return 0; } static int compare_reported_pcr_nr(uint32_t pcr, const char *varname, const char *description) { diff --git a/src/shared/tpm2-util.c b/src/shared/tpm2-util.c index 43c760576c..6552e66bf4 100644 --- a/src/shared/tpm2-util.c +++ b/src/shared/tpm2-util.c @@ -119,23 +119,6 @@ static Tpm2Context *tpm2_context_free(Tpm2Context *c) { DEFINE_TRIVIAL_REF_UNREF_FUNC(Tpm2Context, tpm2_context, tpm2_context_free); -ESYS_TR tpm2_flush_context_verbose(Tpm2Context *c, ESYS_TR handle) { - TSS2_RC rc; - - if (!c || !c->esys_context || handle == ESYS_TR_NONE) - return ESYS_TR_NONE; - - rc = sym_Esys_FlushContext(c->esys_context, handle); - if (rc != TSS2_RC_SUCCESS) /* We ignore failures here (besides debug logging), since this is called - * in error paths, where we cannot do anything about failures anymore. And - * when it is called in successful codepaths by this time we already did - * what we wanted to do, and got the results we wanted so there's no - * reason to make this fail more loudly than necessary. */ - log_debug("Failed to get flush context of TPM, ignoring: %s", sym_Tss2_RC_Decode(rc)); - - return ESYS_TR_NONE; -} - int tpm2_context_new(const char *device, Tpm2Context **ret_context) { _cleanup_tpm2_context_ Tpm2Context *context = NULL; TSS2_RC rc; @@ -246,6 +229,47 @@ int tpm2_context_new(const char *device, Tpm2Context **ret_context) { return 0; } +static void tpm2_handle_flush(ESYS_CONTEXT *esys_context, ESYS_TR esys_handle) { + if (!esys_context || esys_handle == ESYS_TR_NONE) + return; + + TSS2_RC rc = sym_Esys_FlushContext(esys_context, esys_handle); + if (rc != TSS2_RC_SUCCESS) /* We ignore failures here (besides debug logging), since this is called + * in error paths, where we cannot do anything about failures anymore. And + * when it is called in successful codepaths by this time we already did + * what we wanted to do, and got the results we wanted so there's no + * reason to make this fail more loudly than necessary. */ + log_debug("Failed to flush TPM handle, ignoring: %s", sym_Tss2_RC_Decode(rc)); +} + +Tpm2Handle *tpm2_handle_free(Tpm2Handle *handle) { + if (!handle) + return NULL; + + _cleanup_tpm2_context_ Tpm2Context *context = (Tpm2Context*)handle->tpm2_context; + if (context) + tpm2_handle_flush(context->esys_context, handle->esys_handle); + + return mfree(handle); +} + +int tpm2_handle_new(Tpm2Context *context, Tpm2Handle **ret_handle) { + _cleanup_tpm2_handle_ Tpm2Handle *handle = NULL; + + assert(ret_handle); + + handle = new0(Tpm2Handle, 1); + if (!handle) + return log_oom(); + + handle->tpm2_context = tpm2_context_ref(context); + handle->esys_handle = ESYS_TR_NONE; + + *ret_handle = TAKE_PTR(handle); + + return 0; +} + #define TPM2_CREDIT_RANDOM_FLAG_PATH "/run/systemd/tpm-rng-credited" static int tpm2_credit_random(Tpm2Context *c) { @@ -308,7 +332,7 @@ static int tpm2_credit_random(Tpm2Context *c) { static int tpm2_make_primary( Tpm2Context *c, - ESYS_TR *ret_primary, + Tpm2Handle **ret_primary, TPMI_ALG_PUBLIC alg, TPMI_ALG_PUBLIC *ret_alg) { @@ -350,9 +374,9 @@ static int tpm2_make_primary( }; static const TPML_PCR_SELECTION creation_pcr = {}; - ESYS_TR primary = ESYS_TR_NONE; TSS2_RC rc; usec_t ts; + int r; log_debug("Creating primary key on TPM."); @@ -362,6 +386,11 @@ static int tpm2_make_primary( ts = now(CLOCK_MONOTONIC); + _cleanup_tpm2_handle_ Tpm2Handle *primary = NULL; + r = tpm2_handle_new(c, &primary); + if (r < 0) + return r; + if (IN_SET(alg, 0, TPM2_ALG_ECC)) { rc = sym_Esys_CreatePrimary( c->esys_context, @@ -373,7 +402,7 @@ static int tpm2_make_primary( &primary_template_ecc, NULL, &creation_pcr, - &primary, + &primary->esys_handle, NULL, NULL, NULL, @@ -402,7 +431,7 @@ static int tpm2_make_primary( &primary_template_rsa, NULL, &creation_pcr, - &primary, + &primary->esys_handle, NULL, NULL, NULL, @@ -421,7 +450,8 @@ static int tpm2_make_primary( log_debug("Generating primary key on TPM2 took %s.", FORMAT_TIMESPAN(now(CLOCK_MONOTONIC) - ts, USEC_PER_MSEC)); - *ret_primary = primary; + if (ret_primary) + *ret_primary = TAKE_PTR(primary); if (ret_alg) *ret_alg = alg; @@ -786,10 +816,10 @@ static void hash_pin(const char *pin, size_t len, TPM2B_AUTH *auth) { static int tpm2_make_encryption_session( Tpm2Context *c, - ESYS_TR primary, - ESYS_TR bind_key, + const Tpm2Handle *primary, + const Tpm2Handle *bind_key, const char *pin, - ESYS_TR *ret_session) { + Tpm2Handle **ret_session) { static const TPMT_SYM_DEF symmetric = { .algorithm = TPM2_ALG_AES, @@ -798,10 +828,11 @@ static int tpm2_make_encryption_session( }; const TPMA_SESSION sessionAttributes = TPMA_SESSION_DECRYPT | TPMA_SESSION_ENCRYPT | TPMA_SESSION_CONTINUESESSION; - ESYS_TR session = ESYS_TR_NONE; TSS2_RC rc; + int r; assert(c); + assert(ret_session); /* * if a pin is set for the seal object, use it to bind the session @@ -817,7 +848,7 @@ static int tpm2_make_encryption_session( hash_pin(pin, strlen(pin), &auth); - rc = sym_Esys_TR_SetAuth(c->esys_context, bind_key, &auth); + rc = sym_Esys_TR_SetAuth(c->esys_context, bind_key->esys_handle, &auth); if (rc != TSS2_RC_SUCCESS) return log_error_errno( SYNTHETIC_ERRNO(ENOTRECOVERABLE), @@ -830,10 +861,15 @@ static int tpm2_make_encryption_session( /* Start a salted, unbound HMAC session with a well-known key (e.g. primary key) as tpmKey, which * means that the random salt will be encrypted with the well-known key. That way, only the TPM can * recover the salt, which is then used for key derivation. */ + _cleanup_tpm2_handle_ Tpm2Handle *session = NULL; + r = tpm2_handle_new(c, &session); + if (r < 0) + return r; + rc = sym_Esys_StartAuthSession( c->esys_context, - primary, - bind_key, + primary->esys_handle, + bind_key->esys_handle, ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE, @@ -841,7 +877,7 @@ static int tpm2_make_encryption_session( TPM2_SE_HMAC, &symmetric, TPM2_ALG_SHA256, - &session); + &session->esys_handle); if (rc != TSS2_RC_SUCCESS) return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Failed to open session in TPM: %s", sym_Tss2_RC_Decode(rc)); @@ -849,19 +885,15 @@ static int tpm2_make_encryption_session( /* Enable parameter encryption/decryption with AES in CFB mode. Together with HMAC digests (which are * always used for sessions), this provides confidentiality, integrity and replay protection for * operations that use this session. */ - rc = sym_Esys_TRSess_SetAttributes(c->esys_context, session, sessionAttributes, 0xff); + rc = sym_Esys_TRSess_SetAttributes(c->esys_context, session->esys_handle, sessionAttributes, 0xff); if (rc != TSS2_RC_SUCCESS) return log_error_errno( SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Failed to configure TPM session: %s", sym_Tss2_RC_Decode(rc)); - if (ret_session) { - *ret_session = session; - session = ESYS_TR_NONE; - } + *ret_session = TAKE_PTR(session); - session = tpm2_flush_context_verbose(c, session); return 0; } @@ -1049,8 +1081,8 @@ static int find_signature( static int tpm2_make_policy_session( Tpm2Context *c, - ESYS_TR primary, - ESYS_TR parent_session, + const Tpm2Handle *primary, + const Tpm2Handle *parent_session, TPM2_SE session_type, uint32_t hash_pcr_mask, uint16_t pcr_bank, /* If UINT16_MAX, pick best bank automatically, otherwise specify bank explicitly. */ @@ -1059,7 +1091,7 @@ static int tpm2_make_policy_session( uint32_t pubkey_pcr_mask, JsonVariant *signature_json, bool use_pin, - ESYS_TR *ret_session, + Tpm2Handle **ret_session, TPM2B_DIGEST **ret_policy_digest, TPMI_ALG_HASH *ret_pcr_bank) { @@ -1069,7 +1101,6 @@ static int tpm2_make_policy_session( .mode.aes = TPM2_ALG_CFB, }; _cleanup_(Esys_Freep) TPM2B_DIGEST *policy_digest = NULL; - ESYS_TR session = ESYS_TR_NONE, pubkey_handle = ESYS_TR_NONE; TSS2_RC rc; int r; @@ -1124,18 +1155,23 @@ static int tpm2_make_policy_session( } #endif + _cleanup_tpm2_handle_ Tpm2Handle *session = NULL; + r = tpm2_handle_new(c, &session); + if (r < 0) + return r; + rc = sym_Esys_StartAuthSession( c->esys_context, - primary, + primary->esys_handle, ESYS_TR_NONE, - parent_session, + parent_session->esys_handle, ESYS_TR_NONE, ESYS_TR_NONE, NULL, session_type, &symmetric, TPM2_ALG_SHA256, - &session); + &session->esys_handle); if (rc != TSS2_RC_SUCCESS) return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Failed to open session in TPM: %s", sym_Tss2_RC_Decode(rc)); @@ -1148,7 +1184,12 @@ static int tpm2_make_policy_session( TPM2B_PUBLIC pubkey_tpm2; r = openssl_pubkey_to_tpm2_pubkey(pk, &pubkey_tpm2); if (r < 0) - goto finish; + return r; + + _cleanup_tpm2_handle_ Tpm2Handle *pubkey_handle = NULL; + r = tpm2_handle_new(c, &pubkey_handle); + if (r < 0) + return r; rc = sym_Esys_LoadExternal( c->esys_context, @@ -1164,56 +1205,48 @@ static int tpm2_make_policy_session( #else TPM2_RH_OWNER, #endif - &pubkey_handle); - if (rc != TSS2_RC_SUCCESS) { - r = log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), - "Failed to load public key into TPM: %s", sym_Tss2_RC_Decode(rc)); - goto finish; - } + &pubkey_handle->esys_handle); + if (rc != TSS2_RC_SUCCESS) + return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), + "Failed to load public key into TPM: %s", sym_Tss2_RC_Decode(rc)); /* Acquire the "name" of what we just loaded */ _cleanup_(Esys_Freep) TPM2B_NAME *pubkey_name = NULL; rc = sym_Esys_TR_GetName( c->esys_context, - pubkey_handle, + pubkey_handle->esys_handle, &pubkey_name); - if (rc != TSS2_RC_SUCCESS) { - r = log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), - "Failed to get name of public key from TPM: %s", sym_Tss2_RC_Decode(rc)); - goto finish; - } + if (rc != TSS2_RC_SUCCESS) + return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), + "Failed to get name of public key from TPM: %s", sym_Tss2_RC_Decode(rc)); /* Put together the PCR policy we want to use */ TPML_PCR_SELECTION pcr_selection; tpm2_pcr_mask_to_selection(pubkey_pcr_mask, pcr_bank, &pcr_selection); rc = sym_Esys_PolicyPCR( c->esys_context, - session, + session->esys_handle, ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE, NULL, &pcr_selection); - if (rc != TSS2_RC_SUCCESS) { - r = log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), - "Failed to add PCR policy to TPM: %s", sym_Tss2_RC_Decode(rc)); - goto finish; - } + if (rc != TSS2_RC_SUCCESS) + return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), + "Failed to add PCR policy to TPM: %s", sym_Tss2_RC_Decode(rc)); /* Get the policy hash of the PCR policy */ _cleanup_(Esys_Freep) TPM2B_DIGEST *approved_policy = NULL; rc = sym_Esys_PolicyGetDigest( c->esys_context, - session, + session->esys_handle, ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE, &approved_policy); - if (rc != TSS2_RC_SUCCESS) { - r = log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), - "Failed to get policy digest from TPM: %s", sym_Tss2_RC_Decode(rc)); - goto finish; - } + if (rc != TSS2_RC_SUCCESS) + return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), + "Failed to get policy digest from TPM: %s", sym_Tss2_RC_Decode(rc)); /* When we are unlocking and have a signature, let's pass it to the TPM */ _cleanup_(Esys_Freep) TPMT_TK_VERIFIED *check_ticket_buffer = NULL; @@ -1232,7 +1265,7 @@ static int tpm2_make_policy_session( &signature_raw, &signature_size); if (r < 0) - goto finish; + return r; /* TPM2_VerifySignature() will only verify the RSA part of the RSA+SHA256 signature, * hence we need to do the SHA256 part ourselves, first */ @@ -1249,26 +1282,22 @@ static int tpm2_make_policy_session( .sig.size = signature_size, }, }; - if (signature_size > sizeof(policy_signature.signature.rsassa.sig.buffer)) { - r = log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Signature larger than buffer."); - goto finish; - } + if (signature_size > sizeof(policy_signature.signature.rsassa.sig.buffer)) + return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Signature larger than buffer."); memcpy(policy_signature.signature.rsassa.sig.buffer, signature_raw, signature_size); rc = sym_Esys_VerifySignature( c->esys_context, - pubkey_handle, + pubkey_handle->esys_handle, ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE, &signature_hash, &policy_signature, &check_ticket_buffer); - if (rc != TSS2_RC_SUCCESS) { - r = log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), - "Failed to validate signature in TPM: %s", sym_Tss2_RC_Decode(rc)); - goto finish; - } + if (rc != TSS2_RC_SUCCESS) + return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), + "Failed to validate signature in TPM: %s", sym_Tss2_RC_Decode(rc)); check_ticket = check_ticket_buffer; } else { @@ -1283,7 +1312,7 @@ static int tpm2_make_policy_session( rc = sym_Esys_PolicyAuthorize( c->esys_context, - session, + session->esys_handle, ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE, @@ -1291,11 +1320,9 @@ static int tpm2_make_policy_session( /* policyRef= */ &(const TPM2B_NONCE) {}, pubkey_name, check_ticket); - if (rc != TSS2_RC_SUCCESS) { - r = log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), - "Failed to push Authorize policy into TPM: %s", sym_Tss2_RC_Decode(rc)); - goto finish; - } + if (rc != TSS2_RC_SUCCESS) + return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), + "Failed to push Authorize policy into TPM: %s", sym_Tss2_RC_Decode(rc)); #else return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "OpenSSL support is disabled."); #endif @@ -1308,17 +1335,15 @@ static int tpm2_make_policy_session( tpm2_pcr_mask_to_selection(hash_pcr_mask, pcr_bank, &pcr_selection); rc = sym_Esys_PolicyPCR( c->esys_context, - session, + session->esys_handle, ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE, NULL, &pcr_selection); - if (rc != TSS2_RC_SUCCESS) { - r = log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), - "Failed to add PCR policy to TPM: %s", sym_Tss2_RC_Decode(rc)); - goto finish; - } + if (rc != TSS2_RC_SUCCESS) + return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), + "Failed to add PCR policy to TPM: %s", sym_Tss2_RC_Decode(rc)); } if (use_pin) { @@ -1326,16 +1351,14 @@ static int tpm2_make_policy_session( rc = sym_Esys_PolicyAuthValue( c->esys_context, - session, + session->esys_handle, ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE); - if (rc != TSS2_RC_SUCCESS) { - r = log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), - "Failed to add authValue policy to TPM: %s", - sym_Tss2_RC_Decode(rc)); - goto finish; - } + if (rc != TSS2_RC_SUCCESS) + return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), + "Failed to add authValue policy to TPM: %s", + sym_Tss2_RC_Decode(rc)); } if (DEBUG_LOGGING || ret_policy_digest) { @@ -1343,35 +1366,29 @@ static int tpm2_make_policy_session( rc = sym_Esys_PolicyGetDigest( c->esys_context, - session, + session->esys_handle, ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE, &policy_digest); - if (rc != TSS2_RC_SUCCESS) { - r = log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), - "Failed to get policy digest from TPM: %s", sym_Tss2_RC_Decode(rc)); - goto finish; - } + if (rc != TSS2_RC_SUCCESS) + return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), + "Failed to get policy digest from TPM: %s", sym_Tss2_RC_Decode(rc)); if (DEBUG_LOGGING) { _cleanup_free_ char *h = NULL; h = hexmem(policy_digest->buffer, policy_digest->size); - if (!h) { - r = log_oom(); - goto finish; - } + if (!h) + return log_oom(); log_debug("Session policy digest: %s", h); } } - if (ret_session) { - *ret_session = session; - session = ESYS_TR_NONE; - } + if (ret_session) + *ret_session = TAKE_PTR(session); if (ret_policy_digest) *ret_policy_digest = TAKE_PTR(policy_digest); @@ -1379,12 +1396,7 @@ static int tpm2_make_policy_session( if (ret_pcr_bank) *ret_pcr_bank = pcr_bank; - r = 0; - -finish: - session = tpm2_flush_context_verbose(c, session); - pubkey_handle = tpm2_flush_context_verbose(c, pubkey_handle); - return r; + return 0; } int tpm2_seal(const char *device, @@ -1408,7 +1420,6 @@ int tpm2_seal(const char *device, static const TPML_PCR_SELECTION creation_pcr = {}; _cleanup_(erase_and_freep) void *secret = NULL; _cleanup_free_ void *blob = NULL, *hash = NULL; - ESYS_TR primary = ESYS_TR_NONE, session = ESYS_TR_NONE; TPM2B_SENSITIVE_CREATE hmac_sensitive; TPMI_ALG_PUBLIC primary_alg; TPM2B_PUBLIC hmac_template; @@ -1456,14 +1467,16 @@ int tpm2_seal(const char *device, if (r < 0) return r; + _cleanup_tpm2_handle_ Tpm2Handle *primary = NULL; r = tpm2_make_primary(c, &primary, 0, &primary_alg); if (r < 0) return r; /* we cannot use the bind key before its created */ - r = tpm2_make_encryption_session(c, primary, ESYS_TR_NONE, NULL, &session); + _cleanup_tpm2_handle_ Tpm2Handle *session = NULL; + r = tpm2_make_encryption_session(c, primary, &TPM2_HANDLE_NONE, NULL, &session); if (r < 0) - goto finish; + return r; r = tpm2_make_policy_session( c, @@ -1480,7 +1493,7 @@ int tpm2_seal(const char *device, &policy_digest, &pcr_bank); if (r < 0) - goto finish; + 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 @@ -1511,17 +1524,15 @@ int tpm2_seal(const char *device, log_debug("Generating secret key data."); r = crypto_random_bytes(hmac_sensitive.sensitive.data.buffer, hmac_sensitive.sensitive.data.size); - if (r < 0) { - log_error_errno(r, "Failed to generate secret key: %m"); - goto finish; - } + if (r < 0) + return log_error_errno(r, "Failed to generate secret key: %m"); log_debug("Creating HMAC key."); rc = sym_Esys_Create( c->esys_context, - primary, - session, /* use HMAC session to enable parameter encryption */ + primary->esys_handle, + session->esys_handle, /* use HMAC session to enable parameter encryption */ ESYS_TR_NONE, ESYS_TR_NONE, &hmac_sensitive, @@ -1533,17 +1544,13 @@ int tpm2_seal(const char *device, NULL, NULL, NULL); - if (rc != TSS2_RC_SUCCESS) { - r = log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), - "Failed to generate HMAC key in TPM: %s", sym_Tss2_RC_Decode(rc)); - goto finish; - } + if (rc != TSS2_RC_SUCCESS) + return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), + "Failed to generate HMAC key in TPM: %s", sym_Tss2_RC_Decode(rc)); secret = memdup(hmac_sensitive.sensitive.data.buffer, hmac_sensitive.sensitive.data.size); - if (!secret) { - r = log_oom(); - goto finish; - } + if (!secret) + return log_oom(); log_debug("Marshalling private and public part of HMAC key."); @@ -1553,10 +1560,8 @@ int tpm2_seal(const char *device, size_t offset = 0; buf = malloc(k); - if (!buf) { - r = log_oom(); - goto finish; - } + if (!buf) + return log_oom(); rc = sym_Tss2_MU_TPM2B_PRIVATE_Marshal(private, buf, k, &offset); if (rc == TSS2_RC_SUCCESS) { @@ -1567,16 +1572,12 @@ int tpm2_seal(const char *device, break; } } - if (rc != TSS2_MU_RC_INSUFFICIENT_BUFFER) { - r = log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), - "Failed to marshal private/public key: %s", sym_Tss2_RC_Decode(rc)); - goto finish; - } + if (rc != TSS2_MU_RC_INSUFFICIENT_BUFFER) + return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), + "Failed to marshal private/public key: %s", sym_Tss2_RC_Decode(rc)); - if (k > SIZE_MAX / 2) { - r = log_oom(); - goto finish; - } + if (k > SIZE_MAX / 2) + return log_oom(); k *= 2; } @@ -1597,12 +1598,7 @@ int tpm2_seal(const char *device, *ret_pcr_bank = pcr_bank; *ret_primary_alg = primary_alg; - r = 0; - -finish: - primary = tpm2_flush_context_verbose(c, primary); - session = tpm2_flush_context_verbose(c, session); - return r; + return 0; } #define RETRY_UNSEAL_MAX 30u @@ -1623,8 +1619,6 @@ int tpm2_unseal(const char *device, void **ret_secret, size_t *ret_secret_size) { - ESYS_TR primary = ESYS_TR_NONE, session = ESYS_TR_NONE, hmac_session = ESYS_TR_NONE, - hmac_key = ESYS_TR_NONE; _cleanup_(Esys_Freep) TPM2B_SENSITIVE_DATA* unsealed = NULL; _cleanup_(Esys_Freep) TPM2B_DIGEST *policy_digest = NULL; _cleanup_(erase_and_freep) char *secret = NULL; @@ -1678,6 +1672,7 @@ int tpm2_unseal(const char *device, if (r < 0) return r; + _cleanup_tpm2_handle_ Tpm2Handle *primary = NULL; r = tpm2_make_primary(c, &primary, primary_alg, NULL); if (r < 0) return r; @@ -1690,35 +1685,41 @@ int tpm2_unseal(const char *device, * is provided. If an attacker gives back a bad key, we already lost since * primary key is not verified and they could attack there as well. */ + _cleanup_tpm2_handle_ Tpm2Handle *hmac_key = NULL; + r = tpm2_handle_new(c, &hmac_key); + if (r < 0) + return r; + rc = sym_Esys_Load( c->esys_context, - primary, + primary->esys_handle, ESYS_TR_PASSWORD, ESYS_TR_NONE, ESYS_TR_NONE, &private, &public, - &hmac_key); + &hmac_key->esys_handle); if (rc != TSS2_RC_SUCCESS) { /* If we're in dictionary attack lockout mode, we should see a lockout error here, which we * need to translate for the caller. */ if (rc == TPM2_RC_LOCKOUT) - r = log_error_errno( + return log_error_errno( SYNTHETIC_ERRNO(ENOLCK), "TPM2 device is in dictionary attack lockout mode."); else - r = log_error_errno( + return log_error_errno( SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Failed to load HMAC key in TPM: %s", sym_Tss2_RC_Decode(rc)); - goto finish; } + _cleanup_tpm2_handle_ Tpm2Handle *hmac_session = NULL; r = tpm2_make_encryption_session(c, primary, hmac_key, pin, &hmac_session); if (r < 0) - goto finish; + return r; for (unsigned i = RETRY_UNSEAL_MAX;; i--) { + _cleanup_tpm2_handle_ Tpm2Handle *policy_session = NULL; r = tpm2_make_policy_session( c, primary, @@ -1730,11 +1731,11 @@ int tpm2_unseal(const char *device, pubkey_pcr_mask, signature, !!pin, - &session, + &policy_session, &policy_digest, /* ret_pcr_bank= */ NULL); if (r < 0) - goto finish; + return r; /* If we know the policy hash to expect, and it doesn't match, we can shortcut things here, and not * wait until the TPM2 tells us to go away. */ @@ -1748,31 +1749,23 @@ int tpm2_unseal(const char *device, rc = sym_Esys_Unseal( c->esys_context, - hmac_key, - session, - hmac_session, /* use HMAC session to enable parameter encryption */ + hmac_key->esys_handle, + policy_session->esys_handle, + hmac_session->esys_handle, /* use HMAC session to enable parameter encryption */ ESYS_TR_NONE, &unsealed); - if (rc == TPM2_RC_PCR_CHANGED && i > 0) { - log_debug("A PCR value changed during the TPM2 policy session, restarting HMAC key unsealing (%u tries left).", i); - session = tpm2_flush_context_verbose(c, session); - continue; - } - if (rc != TSS2_RC_SUCCESS) { - r = log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), - "Failed to unseal HMAC key in TPM: %s", sym_Tss2_RC_Decode(rc)); - goto finish; - } - - break; + if (rc == TSS2_RC_SUCCESS) + break; + if (rc != TPM2_RC_PCR_CHANGED || i == 0) + return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), + "Failed to unseal HMAC key in TPM: %s", sym_Tss2_RC_Decode(rc)); + log_debug("A PCR value changed during the TPM2 policy session, restarting HMAC key unsealing (%u tries left).", i); } secret = memdup(unsealed->buffer, unsealed->size); explicit_bzero_safe(unsealed->buffer, unsealed->size); - if (!secret) { - r = log_oom(); - goto finish; - } + if (!secret) + return log_oom(); if (DEBUG_LOGGING) log_debug("Completed TPM2 key unsealing in %s.", FORMAT_TIMESPAN(now(CLOCK_MONOTONIC) - start, 1)); @@ -1780,13 +1773,7 @@ int tpm2_unseal(const char *device, *ret_secret = TAKE_PTR(secret); *ret_secret_size = unsealed->size; - r = 0; - -finish: - primary = tpm2_flush_context_verbose(c, primary); - session = tpm2_flush_context_verbose(c, session); - hmac_key = tpm2_flush_context_verbose(c, hmac_key); - return r; + return 0; } #endif diff --git a/src/shared/tpm2-util.h b/src/shared/tpm2-util.h index 9dc55d4a19..d26a945a90 100644 --- a/src/shared/tpm2-util.h +++ b/src/shared/tpm2-util.h @@ -67,7 +67,18 @@ Tpm2Context *tpm2_context_unref(Tpm2Context *context); DEFINE_TRIVIAL_CLEANUP_FUNC(Tpm2Context*, tpm2_context_unref); #define _cleanup_tpm2_context_ _cleanup_(tpm2_context_unrefp) -ESYS_TR tpm2_flush_context_verbose(Tpm2Context *c, ESYS_TR handle); +typedef struct { + Tpm2Context *tpm2_context; + ESYS_TR esys_handle; +} Tpm2Handle; + +#define _tpm2_handle(c, h) { .tpm2_context = (c), .esys_handle = (h), } +static const Tpm2Handle TPM2_HANDLE_NONE = _tpm2_handle(NULL, ESYS_TR_NONE); + +int tpm2_handle_new(Tpm2Context *context, Tpm2Handle **ret_handle); +Tpm2Handle *tpm2_handle_free(Tpm2Handle *handle); +DEFINE_TRIVIAL_CLEANUP_FUNC(Tpm2Handle*, tpm2_handle_free); +#define _cleanup_tpm2_handle_ _cleanup_(tpm2_handle_freep) void tpm2_pcr_mask_to_selection(uint32_t mask, uint16_t bank, TPML_PCR_SELECTION *ret); @@ -83,6 +94,7 @@ int tpm2_extend_bytes(Tpm2Context *c, char **banks, unsigned pcr_index, const vo #else /* HAVE_TPM2 */ typedef struct {} Tpm2Context; +typedef struct {} Tpm2Handle; #endif /* HAVE_TPM2 */ int tpm2_list_devices(void);