diff --git a/src/boot/measure.c b/src/boot/measure.c index b0bcfe0f98..f2fbd9d2c1 100644 --- a/src/boot/measure.c +++ b/src/boot/measure.c @@ -726,9 +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_fclose_ FILE *privkeyf = NULL; - ESYS_TR session_handle = ESYS_TR_NONE; TSS2_RC rc; size_t n; int r; @@ -811,7 +809,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; @@ -829,8 +828,13 @@ 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, + c->esys_context, ESYS_TR_NONE, ESYS_TR_NONE, 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, + c->esys_context, + 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, + c->esys_context, + 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.esys_context, 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.esys_context, 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/boot/pcrphase.c b/src/boot/pcrphase.c index 2add7f1f89..05e9645de9 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; @@ -164,7 +164,7 @@ static int determine_banks(struct tpm2_context *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; @@ -240,7 +240,6 @@ static int get_file_system_word( } static int run(int argc, char *argv[]) { - _cleanup_(tpm2_context_destroy) struct tpm2_context 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, 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 819d5bbb97..e776605501 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) struct tpm2_context 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, 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 363e8df5cc..6552e66bf4 100644 --- a/src/shared/tpm2-util.c +++ b/src/shared/tpm2-util.c @@ -104,47 +104,34 @@ int dlopen_tpm2(void) { DLSYM_ARG(Tss2_MU_TPM2B_PUBLIC_Unmarshal)); } -void tpm2_context_destroy(struct tpm2_context *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; - - if (!c || handle == ESYS_TR_NONE) - return ESYS_TR_NONE; - - rc = sym_Esys_FlushContext(c, 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_init(const char *device, struct tpm2_context *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 +179,11 @@ int tpm2_context_init(const char *device, struct tpm2_context *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 +193,6 @@ int tpm2_context_init(const char *device, struct tpm2_context *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 +200,22 @@ int tpm2_context_init(const char *device, struct tpm2_context *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,18 +224,55 @@ 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) { - .esys_context = TAKE_PTR(c), - .tcti_context = TAKE_PTR(tcti), - .tcti_dl = TAKE_PTR(dl), - }; + *ret_context = TAKE_PTR(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(ESYS_CONTEXT *c) { +static int tpm2_credit_random(Tpm2Context *c) { size_t rps, done = 0; TSS2_RC rc; usec_t t; @@ -276,7 +299,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, @@ -308,8 +331,8 @@ static int tpm2_credit_random(ESYS_CONTEXT *c) { } static int tpm2_make_primary( - ESYS_CONTEXT *c, - ESYS_TR *ret_primary, + Tpm2Context *c, + Tpm2Handle **ret_primary, TPMI_ALG_PUBLIC alg, TPMI_ALG_PUBLIC *ret_alg) { @@ -351,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."); @@ -363,9 +386,14 @@ 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, + c->esys_context, ESYS_TR_RH_OWNER, ESYS_TR_PASSWORD, ESYS_TR_NONE, @@ -374,7 +402,7 @@ static int tpm2_make_primary( &primary_template_ecc, NULL, &creation_pcr, - &primary, + &primary->esys_handle, NULL, NULL, NULL, @@ -394,7 +422,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, @@ -403,7 +431,7 @@ static int tpm2_make_primary( &primary_template_rsa, NULL, &creation_pcr, - &primary, + &primary->esys_handle, NULL, NULL, NULL, @@ -422,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; @@ -470,7 +499,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) { @@ -488,7 +517,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, @@ -552,7 +581,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) { @@ -565,7 +594,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, @@ -649,7 +678,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) { @@ -664,7 +693,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, @@ -728,7 +757,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) { @@ -786,11 +815,11 @@ static void hash_pin(const char *pin, size_t len, TPM2B_AUTH *auth) { } static int tpm2_make_encryption_session( - ESYS_CONTEXT *c, - ESYS_TR primary, - ESYS_TR bind_key, + Tpm2Context *c, + 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, @@ -799,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 @@ -818,7 +848,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->esys_handle, &auth); if (rc != TSS2_RC_SUCCESS) return log_error_errno( SYNTHETIC_ERRNO(ENOTRECOVERABLE), @@ -831,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, - primary, - bind_key, + c->esys_context, + primary->esys_handle, + bind_key->esys_handle, ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE, @@ -842,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)); @@ -850,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, 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,9 +1080,9 @@ static int find_signature( #endif static int tpm2_make_policy_session( - ESYS_CONTEXT *c, - ESYS_TR primary, - ESYS_TR parent_session, + Tpm2Context *c, + 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. */ @@ -1060,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) { @@ -1070,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; @@ -1125,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, - primary, + c->esys_context, + 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)); @@ -1149,10 +1184,15 @@ 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, + c->esys_context, ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE, @@ -1165,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, - pubkey_handle, + c->esys_context, + 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, - session, + c->esys_context, + 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, - session, + c->esys_context, + 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; @@ -1233,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 */ @@ -1250,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, - pubkey_handle, + c->esys_context, + 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,8 +1311,8 @@ static int tpm2_make_policy_session( } rc = sym_Esys_PolicyAuthorize( - c, - session, + c->esys_context, + session->esys_handle, ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE, @@ -1292,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,71 +1334,61 @@ 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, - session, + c->esys_context, + 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) { log_debug("Configuring PIN policy."); rc = sym_Esys_PolicyAuthValue( - c, - session, + c->esys_context, + 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) { log_debug("Acquiring policy digest."); rc = sym_Esys_PolicyGetDigest( - c, - session, + c->esys_context, + 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); @@ -1380,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, @@ -1403,14 +1414,12 @@ 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_(Esys_Freep) TPM2B_DIGEST *policy_digest = NULL; _cleanup_(Esys_Freep) TPM2B_PRIVATE *private = NULL; _cleanup_(Esys_Freep) TPM2B_PUBLIC *public = NULL; 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; @@ -1453,21 +1462,24 @@ 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); + _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.esys_context, 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.esys_context, + c, primary, session, TPM2_SE_TRIAL, @@ -1481,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 @@ -1507,22 +1519,20 @@ 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."); 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 */ + c->esys_context, + primary->esys_handle, + session->esys_handle, /* use HMAC session to enable parameter encryption */ ESYS_TR_NONE, ESYS_TR_NONE, &hmac_sensitive, @@ -1534,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."); @@ -1554,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) { @@ -1568,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; } @@ -1598,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.esys_context, primary); - session = tpm2_flush_context_verbose(c.esys_context, session); - return r; + return 0; } #define RETRY_UNSEAL_MAX 30u @@ -1624,9 +1619,6 @@ int tpm2_unseal(const char *device, void **ret_secret, size_t *ret_secret_size) { - _cleanup_(tpm2_context_destroy) struct tpm2_context 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; _cleanup_(Esys_Freep) TPM2B_DIGEST *policy_digest = NULL; _cleanup_(erase_and_freep) char *secret = NULL; @@ -1675,11 +1667,13 @@ 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); + _cleanup_tpm2_handle_ Tpm2Handle *primary = NULL; + r = tpm2_make_primary(c, &primary, primary_alg, NULL); if (r < 0) return r; @@ -1691,37 +1685,43 @@ 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, + c->esys_context, + 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; } - r = tpm2_make_encryption_session(c.esys_context, primary, hmac_key, pin, &hmac_session); + _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.esys_context, + c, primary, hmac_session, TPM2_SE_POLICY, @@ -1731,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,32 +1748,24 @@ int tpm2_unseal(const char *device, log_debug("Unsealing HMAC key."); rc = sym_Esys_Unseal( - c.esys_context, - hmac_key, - session, - hmac_session, /* use HMAC session to enable parameter encryption */ + c->esys_context, + 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.esys_context, 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)); @@ -1781,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.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; + return 0; } #endif @@ -1918,7 +1904,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, @@ -1979,7 +1965,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 99b258c290..d26a945a90 100644 --- a/src/shared/tpm2-util.h +++ b/src/shared/tpm2-util.h @@ -53,13 +53,32 @@ 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 { + unsigned n_ref; + 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); +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) + +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); @@ -68,17 +87,15 @@ 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 -struct tpm2_context; -#endif - -int tpm2_context_init(const char *device, struct tpm2_context *ret); -void tpm2_context_destroy(struct tpm2_context *c); +#else /* HAVE_TPM2 */ +typedef struct {} Tpm2Context; +typedef struct {} Tpm2Handle; +#endif /* HAVE_TPM2 */ int tpm2_list_devices(void); int tpm2_find_device_auto(int log_level, char **ret);