From 30ae31aeabeecd86a9836eec04bbb44c14d65db8 Mon Sep 17 00:00:00 2001 From: Juergen Repp Date: Wed, 27 Sep 2023 21:43:47 +0200 Subject: [PATCH] Save Context: Add the possibility for autoflush. If the environment variable TPM2TOOLS_AUTOFLUSH exists transient objects will be removed after they were saved and stored to disk. Also a transient parent will be removed if a context file for this parent was used by this command. For the commands which will check the autoflush also an option -R is added to enable the autoflush independent from the environment variable. -R was added to several commands in one integration test. Addresses: #1511 Signed-off-by: Juergen Repp --- lib/files.c | 8 ++++---- lib/files.h | 8 ++++++-- lib/tpm2.c | 18 +++++++++++++++++- lib/tpm2.h | 2 +- lib/tpm2_options.h | 2 +- lib/tpm2_session.c | 2 +- lib/tpm2_util.c | 8 ++++++++ lib/tpm2_util.h | 2 ++ man/common/options.md | 5 +++++ test/integration/tests/load.sh | 6 +++--- test/unit/test_tpm2_session.c | 3 ++- tools/fapi/tss2_gettpm2object.c | 2 +- tools/misc/tpm2_encodeobject.c | 22 ++++++++++++++++++---- tools/tpm2_changeauth.c | 26 ++++++++++++++++++++++++-- tools/tpm2_create.c | 23 +++++++++++++++++++---- tools/tpm2_createak.c | 10 ++++++++-- tools/tpm2_createek.c | 13 ++++++++++--- tools/tpm2_createprimary.c | 10 ++++++++-- tools/tpm2_import.c | 24 ++++++++++++++++++++++-- tools/tpm2_load.c | 27 ++++++++++++++++++++++++--- tools/tpm2_loadexternal.c | 10 ++++++++-- 21 files changed, 192 insertions(+), 39 deletions(-) diff --git a/lib/files.c b/lib/files.c index 26a82a3af..6828770c9 100644 --- a/lib/files.c +++ b/lib/files.c @@ -273,11 +273,11 @@ bool files_save_context(TPMS_CONTEXT *context, FILE *stream) { } tool_rc files_save_tpm_context_to_file(ESYS_CONTEXT *ectx, ESYS_TR handle, - FILE *stream) { + FILE *stream, bool autoflush) { TPMS_CONTEXT *context = NULL; - tool_rc rc = tpm2_context_save(ectx, handle, &context); + tool_rc rc = tpm2_context_save(ectx, handle, autoflush, &context); if (rc != tool_rc_success) { return rc; } @@ -288,7 +288,7 @@ tool_rc files_save_tpm_context_to_file(ESYS_CONTEXT *ectx, ESYS_TR handle, } tool_rc files_save_tpm_context_to_path(ESYS_CONTEXT *context, ESYS_TR handle, - const char *path) { + const char *path, bool autoflush) { FILE *f = fopen(path, "w+b"); if (!f) { @@ -297,7 +297,7 @@ tool_rc files_save_tpm_context_to_path(ESYS_CONTEXT *context, ESYS_TR handle, return tool_rc_general_error; } - tool_rc rc = files_save_tpm_context_to_file(context, handle, f); + tool_rc rc = files_save_tpm_context_to_file(context, handle, f, autoflush); fclose(f); return rc; } diff --git a/lib/files.h b/lib/files.h index c164c6398..3ade0f6e4 100644 --- a/lib/files.h +++ b/lib/files.h @@ -84,12 +84,14 @@ bool files_save_bytes_to_file(const char *path, UINT8 *buf, UINT16 size); * The object handle for the object to save. * @param path * The output path of the file. + * @param autoflush + * Flush the tpm object after context save. * * @return * tool_rc indicating status. */ tool_rc files_save_tpm_context_to_path(ESYS_CONTEXT *context, ESYS_TR handle, - const char *path); + const char *pathm, bool autoflush); /** * Like files_save_tpm_context_to_path() but saves a tpm session to a FILE stream. @@ -99,11 +101,13 @@ tool_rc files_save_tpm_context_to_path(ESYS_CONTEXT *context, ESYS_TR handle, * The object handle for the object to save. * @param stream * The FILE stream to save too. + * @param autoflush + * Flush the tpm object after context save. * @return * tool_rc indicating status. */ tool_rc files_save_tpm_context_to_file(ESYS_CONTEXT *context, ESYS_TR handle, - FILE *stream); + FILE *stream, bool autoflush); /** * Loads a ESAPI TPM object context from disk or an ESAPI serialized ESYS_TR object. diff --git a/lib/tpm2.c b/lib/tpm2.c index fb1f0e9a9..6098f7a9e 100644 --- a/lib/tpm2.c +++ b/lib/tpm2.c @@ -313,14 +313,30 @@ tool_rc tpm2_nv_read(ESYS_CONTEXT *esys_context, } tool_rc tpm2_context_save(ESYS_CONTEXT *esys_context, ESYS_TR save_handle, - TPMS_CONTEXT **context) { + bool autoflush, TPMS_CONTEXT **context) { TSS2_RC rval = Esys_ContextSave(esys_context, save_handle, context); + TPM2_HANDLE tpm_handle; if (rval != TSS2_RC_SUCCESS) { LOG_PERR(Esys_ContextSave, rval); return tool_rc_from_tpm(rval); } + if (autoflush || tpm2_util_env_yes(TPM2TOOLS_ENV_AUTOFLUSH)) { + rval = Esys_TR_GetTpmHandle(esys_context, save_handle, &tpm_handle); + if (rval != TSS2_RC_SUCCESS) { + LOG_PERR(Esys_TR_GetTpmHandle, rval); + return tool_rc_from_tpm(rval); + } + if ((tpm_handle & TPM2_HR_RANGE_MASK) == TPM2_HR_TRANSIENT) { + TSS2_RC rval = Esys_FlushContext(esys_context, save_handle); + if (rval != TPM2_RC_SUCCESS) { + LOG_PERR(Eys_ContextFlush, rval); + return false; + } + } + } + return tool_rc_success; } diff --git a/lib/tpm2.h b/lib/tpm2.h index 52a89564f..67940c0ed 100644 --- a/lib/tpm2.h +++ b/lib/tpm2.h @@ -41,7 +41,7 @@ tool_rc tpm2_nv_read(ESYS_CONTEXT *esys_context, TPMI_ALG_HASH parameter_hash_algorithm, ESYS_TR shandle2, ESYS_TR shandle3); tool_rc tpm2_context_save(ESYS_CONTEXT *esys_context, ESYS_TR save_handle, - TPMS_CONTEXT **context); + bool autoflush, TPMS_CONTEXT **context); tool_rc tpm2_context_load(ESYS_CONTEXT *esys_context, const TPMS_CONTEXT *context, ESYS_TR *loaded_handle); diff --git a/lib/tpm2_options.h b/lib/tpm2_options.h index f678dc9a8..6909cd36c 100644 --- a/lib/tpm2_options.h +++ b/lib/tpm2_options.h @@ -8,10 +8,10 @@ #include #include - #include #define TPM2TOOLS_ENV_TCTI "TPM2TOOLS_TCTI" +#define TPM2TOOLS_ENV_AUTOFLUSH "TPM2TOOLS_AUTOFLUSH" #define TPM2TOOLS_ENV_ENABLE_ERRATA "TPM2TOOLS_ENABLE_ERRATA" diff --git a/lib/tpm2_session.c b/lib/tpm2_session.c index 38c7df5eb..ff7309e28 100644 --- a/lib/tpm2_session.c +++ b/lib/tpm2_session.c @@ -411,7 +411,7 @@ tool_rc tpm2_session_close(tpm2_session **s) { ESYS_TR handle = tpm2_session_get_handle(session); LOG_INFO("Saved session: ESYS_TR(0x%x)", handle); rc = files_save_tpm_context_to_file(session->internal.ectx, handle, - session_file); + session_file, false); if (rc != tool_rc_success) { LOG_ERR("Could not write session context"); /* done, free session resources and use rc to indicate status */ diff --git a/lib/tpm2_util.c b/lib/tpm2_util.c index 5026848f6..53865b31d 100644 --- a/lib/tpm2_util.c +++ b/lib/tpm2_util.c @@ -632,6 +632,14 @@ char *tpm2_util_getenv(const char *name) { return getenv(name); } +bool tpm2_util_env_yes(const char *name) { + + char *value = getenv(name); + return (value && (strcasecmp(name, "yes") == 0 || + strcasecmp(name, "1") == 0 || + strcasecmp(name, "true") == 0)); +} + /** * Parses a hierarchy value from an option argument. * @param value diff --git a/lib/tpm2_util.h b/lib/tpm2_util.h index fc3f114a2..04f96ad11 100644 --- a/lib/tpm2_util.h +++ b/lib/tpm2_util.h @@ -433,6 +433,8 @@ ESYS_TR tpm2_tpmi_hierarchy_to_esys_tr(TPMI_RH_PROVISION inh); char *tpm2_util_getenv(const char *name); +bool tpm2_util_env_yes(const char *name); + typedef enum tpm2_handle_flags tpm2_handle_flags; enum tpm2_handle_flags { TPM2_HANDLE_FLAGS_NONE = 0, diff --git a/man/common/options.md b/man/common/options.md index 565131716..8da93a4bb 100644 --- a/man/common/options.md +++ b/man/common/options.md @@ -27,3 +27,8 @@ information that many users may expect. Enable the application of errata fixups. Useful if an errata fixup needs to be applied to commands sent to the TPM. Defining the environment TPM2TOOLS\_ENABLE\_ERRATA is equivalent. + * **-R**, **\--autoflush**: + Enable autoflush for transient objects created by the command. If a parent + object is loaded from a context file also the transient parent object will + be flushed. Autoflush can also be activated if the environment variable + TPM2TOOLS\_AUTOFLUSH is is set to yes or true. diff --git a/test/integration/tests/load.sh b/test/integration/tests/load.sh index 7358d610d..a0a41a759 100644 --- a/test/integration/tests/load.sh +++ b/test/integration/tests/load.sh @@ -51,13 +51,13 @@ tpm2 clear #####file test -tpm2 createprimary -Q -C e -g $alg_primary_obj -G $alg_primary_key \ +tpm2 createprimary -R -Q -C e -g $alg_primary_obj -G $alg_primary_key \ -c $file_primary_key_ctx -tpm2 create -Q -g $alg_create_obj -G $alg_create_key -u $file_load_key_pub \ +tpm2 create -R -Q -g $alg_create_obj -G $alg_create_key -u $file_load_key_pub \ -r $file_load_key_priv -C $file_primary_key_ctx -tpm2 load -Q -C $file_primary_key_ctx -u $file_load_key_pub \ +tpm2 load -R -Q -C $file_primary_key_ctx -u $file_load_key_pub \ -r $file_load_key_priv -n $file_load_key_name -c $file_load_key_ctx #####handle test diff --git a/test/unit/test_tpm2_session.c b/test/unit/test_tpm2_session.c index 50977dc9c..dccb87f0a 100644 --- a/test/unit/test_tpm2_session.c +++ b/test/unit/test_tpm2_session.c @@ -24,10 +24,11 @@ static void test_tpm2_create_dummy_context(TPMS_CONTEXT *context) { memset(context->contextBlob.buffer, '\0', context->contextBlob.size); } -tool_rc __wrap_tpm2_context_save(ESYS_CONTEXT *esysContext, ESYS_TR saveHandle, +tool_rc __wrap_tpm2_context_save(ESYS_CONTEXT *esysContext, ESYS_TR saveHandle, bool autoflush, TPMS_CONTEXT **context) { UNUSED(esysContext); + UNUSED(autoflush); // context should be non-null or bool files_save_tpm_context_to_file() // segfaults diff --git a/tools/fapi/tss2_gettpm2object.c b/tools/fapi/tss2_gettpm2object.c index 3579c70ba..07e816b77 100644 --- a/tools/fapi/tss2_gettpm2object.c +++ b/tools/fapi/tss2_gettpm2object.c @@ -127,7 +127,7 @@ static int tss2_tool_onrun (FAPI_CONTEXT *fctx) { LOG_PERR("Esys_ContextLoad", e_rc); goto error; } - t_rc = files_save_tpm_context_to_file(esys_ctx, esys_handle, stream); + t_rc = files_save_tpm_context_to_file(esys_ctx, esys_handle, stream, false); if (t_rc != tool_rc_success) { goto error; } diff --git a/tools/misc/tpm2_encodeobject.c b/tools/misc/tpm2_encodeobject.c index 4fe06ce7c..eee939f82 100644 --- a/tools/misc/tpm2_encodeobject.c +++ b/tools/misc/tpm2_encodeobject.c @@ -39,9 +39,12 @@ struct tpm_encodeobject_ctx { } object; char *output_path; + bool autoflush; }; -static tpm_encodeobject_ctx ctx; +static tpm_encodeobject_ctx ctx = { + .autoflush = false, +}; static bool on_option(char key, char *value) { switch (key) { @@ -76,9 +79,10 @@ static bool tpm2_tool_onstart(tpm2_options **opts) { { "parent-context", required_argument, NULL, 'C' }, { "output", required_argument, NULL, 'o' }, { "key-auth", no_argument, NULL, 'p' }, + { "autoflush", no_argument, NULL, 'R' }, }; - *opts = tpm2_options_new("P:u:r:C:o:p", ARRAY_LEN(topts), topts, on_option, + *opts = tpm2_options_new("P:u:r:C:o:pR", ARRAY_LEN(topts), topts, on_option, NULL, 0); return *opts != NULL; @@ -125,7 +129,7 @@ static tool_rc init(ESYS_CONTEXT *ectx) { TPM2_HANDLE_ALL_W_NV); } -static int encode(void) { +static int encode(ESYS_CONTEXT *ectx) { uint8_t private_buf[sizeof(ctx.object.private)]; size_t private_len = 0; @@ -186,6 +190,16 @@ static int encode(void) { } PEM_write_bio_TSSPRIVKEY_OBJ(bio, tpk); + + if ((ctx.autoflush || tpm2_util_env_yes(TPM2TOOLS_ENV_AUTOFLUSH)) && + ctx.parent.object.path && + (ctx.parent.object.handle & TPM2_HR_RANGE_MASK) == TPM2_HR_TRANSIENT) { + rval = Esys_FlushContext(ectx, ctx.parent.object.tr_handle); + if (rval != TPM2_RC_SUCCESS) { + return tool_rc_general_error; + } + } + rc = tool_rc_success; error: @@ -210,7 +224,7 @@ static tool_rc tpm2_tool_onrun(ESYS_CONTEXT *ectx, tpm2_option_flags flags) { return rc; } - return encode(); + return encode(ectx); } // Register this tool with tpm2_tool.c diff --git a/tools/tpm2_changeauth.c b/tools/tpm2_changeauth.c index 4b65ea9e8..f2ad99fe2 100644 --- a/tools/tpm2_changeauth.c +++ b/tools/tpm2_changeauth.c @@ -21,6 +21,8 @@ struct changeauth_ctx { tpm2_loaded_object obj; } parent; + bool autoflush; + struct { const char *auth_current; const char *auth_new; @@ -59,6 +61,7 @@ static changeauth_ctx ctx = { .parameter_hash_algorithm = TPM2_ALG_ERROR, .aux_session_handle[0] = ESYS_TR_NONE, .aux_session_handle[1] = ESYS_TR_NONE, + .autoflush = false, }; static tool_rc hierarchy_change_auth(ESYS_CONTEXT *ectx) { @@ -77,15 +80,29 @@ static tool_rc nv_change_auth(ESYS_CONTEXT *ectx) { static tool_rc object_change_auth(ESYS_CONTEXT *ectx) { + TSS2_RC rval; + if (!ctx.object.out_path) { LOG_ERR("Require private output file path option -r"); return tool_rc_general_error; } - return tpm2_object_change_auth(ectx, &ctx.parent.obj, &ctx.object.obj, + tool_rc rc = tpm2_object_change_auth(ectx, &ctx.parent.obj, &ctx.object.obj, ctx.new_auth, &ctx.out_private, &ctx.cp_hash, &ctx.rp_hash, ctx.parameter_hash_algorithm, ctx.aux_session_handle[0], ctx.aux_session_handle[1]); + if (rc != tool_rc_success) { + return rc; + } + if ((ctx.autoflush || tpm2_util_env_yes(TPM2TOOLS_ENV_AUTOFLUSH)) && + ctx.parent.obj.path && + (ctx.parent.obj.handle & TPM2_HR_RANGE_MASK) == TPM2_HR_TRANSIENT) { + rval = Esys_FlushContext(ectx, ctx.parent.obj.tr_handle); + if (rval != TPM2_RC_SUCCESS) { + return tool_rc_general_error; + } + } + return tool_rc_success; } static tool_rc change_authorization(ESYS_CONTEXT *ectx) { @@ -317,6 +334,10 @@ static bool on_option(char key, char *value) { return false; } break; + case 'R': + ctx.autoflush = true; + break; + /*no default */ } @@ -333,8 +354,9 @@ static bool tpm2_tool_onstart(tpm2_options **opts) { { "cphash", required_argument, NULL, 0 }, { "rphash", required_argument, NULL, 1 }, { "session", required_argument, NULL, 'S' }, + { "autoflush", no_argument, NULL, 'R' }, }; - *opts = tpm2_options_new("p:c:C:r:S:", ARRAY_LEN(topts), topts, + *opts = tpm2_options_new("p:c:C:r:S:R", ARRAY_LEN(topts), topts, on_option, on_arg, 0); return *opts != NULL; diff --git a/tools/tpm2_create.c b/tools/tpm2_create.c index d230fd77c..5f4918b88 100644 --- a/tools/tpm2_create.c +++ b/tools/tpm2_create.c @@ -61,7 +61,7 @@ struct tpm_create_ctx { } object; bool is_createloaded; - + bool autoflush; /* * Parameter hashes */ @@ -103,6 +103,7 @@ static tpm_create_ctx ctx = { .is_command_dispatch = true, .parameter_hash_algorithm = TPM2_ALG_ERROR, .format = pubkey_format_tss, + .autoflush = false, }; static bool load_outside_info(TPM2B_DATA *outside_info) { @@ -125,6 +126,8 @@ static void print_help_message() { static tool_rc create(ESYS_CONTEXT *ectx) { + TSS2_RC rval; + /* * 1. TPM2_CC_ OR Retrieve cpHash */ @@ -179,6 +182,14 @@ static tool_rc create(ESYS_CONTEXT *ectx) { } } + if ((ctx.autoflush || tpm2_util_env_yes(TPM2TOOLS_ENV_AUTOFLUSH)) && + ctx.parent.object.path && + (ctx.parent.object.handle & TPM2_HR_RANGE_MASK) == TPM2_HR_TRANSIENT) { + rval = Esys_FlushContext(ectx, ctx.parent.object.tr_handle); + if (rval != TPM2_RC_SUCCESS) { + return tool_rc_general_error; + } + } return tool_rc_success; } @@ -311,8 +322,8 @@ static tool_rc process_output(ESYS_CONTEXT *ectx) { if (ctx.object.ctx_path) { rc = files_save_tpm_context_to_path(ectx, ctx.object.object_handle, - ctx.object.ctx_path); - + ctx.object.ctx_path, ctx.autoflush); + if (rc != tool_rc_success) { goto out; } @@ -559,6 +570,9 @@ static bool on_option(char key, char *value) { case 'o': ctx.output_path = value; break; + case 'R': + ctx.autoflush = true; + break; /* no default */ }; @@ -590,9 +604,10 @@ static bool tpm2_tool_onstart(tpm2_options **opts) { { "session", required_argument, NULL, 'S' }, { "format", required_argument, NULL, 'f' }, { "output", required_argument, NULL, 'o' }, + { "autoflush", no_argument, NULL, 'R' }, }; - *opts = tpm2_options_new("P:p:g:G:a:i:L:u:r:C:c:t:d:q:l:S:o:f:", + *opts = tpm2_options_new("P:p:g:G:a:i:L:u:r:C:c:t:d:q:l:S:o:f:R", ARRAY_LEN(topts), topts, on_option, NULL, 0); return *opts != NULL; diff --git a/tools/tpm2_createak.c b/tools/tpm2_createak.c index 7c779298b..8239e5f43 100644 --- a/tools/tpm2_createak.c +++ b/tools/tpm2_createak.c @@ -112,6 +112,7 @@ struct createak_context { struct { UINT8 f :1; } flags; + bool autoflush; }; static createak_context ctx = { @@ -128,6 +129,7 @@ static createak_context ctx = { }, }, .flags = { 0 }, + .autoflush = false }; static tool_rc init_ak_public(TPMI_ALG_HASH name_alg, TPM2B_PUBLIC *public) { @@ -367,7 +369,7 @@ static tool_rc create_ak(ESYS_CONTEXT *ectx) { // If the AK isn't persisted we always save a context file of the // transient AK handle for future tool interactions. tmp_rc = files_save_tpm_context_to_path(ectx, loaded_sha1_key_handle, - ctx.ak.out.ctx_file); + ctx.ak.out.ctx_file, false); if (tmp_rc != tool_rc_success) { rc = tmp_rc; LOG_ERR("Error saving tpm context for handle"); @@ -459,6 +461,9 @@ static bool on_option(char key, char *value) { case 'q': ctx.ak.out.qname_file = value; break; + case 'R': + ctx.autoflush = true; + break; } return true; @@ -479,9 +484,10 @@ static bool tpm2_tool_onstart(tpm2_options **opts) { { "public", required_argument, NULL, 'u' }, { "private", required_argument, NULL, 'r' }, { "ak-qualified-name", required_argument, NULL, 'q' }, + { "autoflush", no_argument, NULL, 'R' }, }; - *opts = tpm2_options_new("P:p:C:c:n:G:g:s:f:u:r:q:", ARRAY_LEN(topts), topts, + *opts = tpm2_options_new("P:p:C:c:n:G:g:s:f:u:r:q:R", ARRAY_LEN(topts), topts, on_option, NULL, 0); return *opts != NULL; diff --git a/tools/tpm2_createek.c b/tools/tpm2_createek.c index 52009bc74..ea1229a5d 100644 --- a/tools/tpm2_createek.c +++ b/tools/tpm2_createek.c @@ -100,6 +100,7 @@ struct createek_context { tpm2_hierarchy_pdata objdata; char *out_file_path; tpm2_convert_pubkey_fmt format; + bool autoflush; struct { UINT8 f :1; UINT8 t :1; @@ -118,7 +119,8 @@ static createek_context ctx = { }, }, .flags = { 0 }, - .find_persistent_handle = false + .find_persistent_handle = false, + .autoflush = false }; typedef struct alg_map alg_map; @@ -334,7 +336,7 @@ static tool_rc create_ek_handle(ESYS_CONTEXT *ectx) { } else { /* If it wasn't persistent, save a context for future tool interactions */ tool_rc rc = files_save_tpm_context_to_path(ectx, - ctx.objdata.out.handle, ctx.auth_ek.ctx_path); + ctx.objdata.out.handle, ctx.auth_ek.ctx_path, ctx.autoflush); if (rc != tool_rc_success) { LOG_ERR("Error saving tpm context for handle"); return rc; @@ -392,6 +394,10 @@ static bool on_option(char key, char *value) { case 't': ctx.flags.t = true; break; + case 'R': + ctx.autoflush = true; + break; + } return true; @@ -407,9 +413,10 @@ static bool tpm2_tool_onstart(tpm2_options **opts) { { "format", required_argument, NULL, 'f' }, { "ek-context", required_argument, NULL, 'c' }, { "template", no_argument, NULL, 't' }, + { "autoflush", no_argument, NULL, 'R' }, }; - *opts = tpm2_options_new("P:w:G:u:f:c:t", ARRAY_LEN(topts), topts, + *opts = tpm2_options_new("P:w:G:u:f:c:tR", ARRAY_LEN(topts), topts, on_option, NULL, 0); return *opts != NULL; diff --git a/tools/tpm2_createprimary.c b/tools/tpm2_createprimary.c index f91e76085..61498f783 100644 --- a/tools/tpm2_createprimary.c +++ b/tools/tpm2_createprimary.c @@ -34,6 +34,7 @@ struct tpm_createprimary_ctx { char *key_auth_str; char *unique_file; char *outside_info_data; + bool autoflush; /* * Outputs @@ -68,6 +69,7 @@ static tpm_createprimary_ctx ctx = { .format = pubkey_format_tss, .auth_hierarchy.ctx_path = "owner", .parameter_hash_algorithm = TPM2_ALG_ERROR, + .autoflush = false, }; static tool_rc createprimary(ESYS_CONTEXT *ectx) { @@ -117,7 +119,7 @@ static tool_rc process_output(ESYS_CONTEXT *ectx) { tpm2_util_public_to_yaml(ctx.objdata.out.public, 0); rc = ctx.context_file ? files_save_tpm_context_to_path(ectx, - ctx.objdata.out.handle, ctx.context_file) : tool_rc_success; + ctx.objdata.out.handle, ctx.context_file, ctx.autoflush) : tool_rc_success; if (rc != tool_rc_success) { LOG_ERR("Failed saving object context."); return rc; @@ -351,6 +353,9 @@ static bool on_option(char key, char *value) { case 'o': ctx.output_path = value; break; + case 'R': + ctx.autoflush = true; + break; /* no default */ } @@ -378,9 +383,10 @@ static bool tpm2_tool_onstart(tpm2_options **opts) { { "cphash", required_argument, 0, 2 }, { "format", required_argument, 0, 'f' }, { "output", required_argument, 0, 'o' }, + { "autoflush", no_argument, 0, 'R' }, }; - *opts = tpm2_options_new("C:P:p:g:G:c:L:a:u:t:d:q:l:o:f:", ARRAY_LEN(topts), + *opts = tpm2_options_new("C:P:p:g:G:c:L:a:u:t:d:q:l:o:f:R", ARRAY_LEN(topts), topts, on_option, 0, 0); return *opts != 0; diff --git a/tools/tpm2_import.c b/tools/tpm2_import.c index f7573e11d..480ed89a3 100644 --- a/tools/tpm2_import.c +++ b/tools/tpm2_import.c @@ -79,6 +79,7 @@ struct tpm_import_ctx { TPM2B_PUBLIC public; char *private_key_file; TPM2B_PRIVATE *imported_private; + bool autoflush; /* * Parameter hashes @@ -96,13 +97,28 @@ static tpm_import_ctx ctx = { .encrypted_seed = TPM2B_EMPTY_INIT, .duplicate = TPM2B_EMPTY_INIT, .parameter_hash_algorithm = TPM2_ALG_ERROR, + .autoflush = false, }; static tool_rc import(ESYS_CONTEXT *ectx) { - return tpm2_import(ectx, &ctx.parent.object, &ctx.enc_sensitive_key, + TSS2_RC rval; + + tool_rc rc = tpm2_import(ectx, &ctx.parent.object, &ctx.enc_sensitive_key, &ctx.public, &ctx.duplicate, &ctx.encrypted_seed, &ctx.sym_alg, &ctx.imported_private, &ctx.cp_hash, ctx.parameter_hash_algorithm); + if (rc != tool_rc_success) { + return rc; + } + if ((ctx.autoflush || tpm2_util_env_yes(TPM2TOOLS_ENV_AUTOFLUSH)) && + ctx.parent.object.path && + (ctx.parent.object.handle & TPM2_HR_RANGE_MASK) == TPM2_HR_TRANSIENT) { + rval = Esys_FlushContext(ectx, ctx.parent.object.tr_handle); + if (rval != TPM2_RC_SUCCESS) { + return tool_rc_general_error; + } + } + return tool_rc_success; } static tool_rc process_output(ESYS_CONTEXT *ectx) { @@ -626,6 +642,9 @@ static bool on_option(char key, char *value) { case 1: ctx.cp_hash_path = value; break; + case 'R': + ctx.autoflush = true; + break; default: LOG_ERR("Invalid option"); return false; @@ -652,9 +671,10 @@ static bool tpm2_tool_onstart(tpm2_options **opts) { { "encryption-key", required_argument, 0, 'k'}, { "passin", required_argument, 0, 0 }, { "cphash", required_argument, 0, 1 }, + { "autoflush", no_argument, 0, 'R' }, }; - *opts = tpm2_options_new("P:p:G:i:C:U:u:r:a:g:s:L:k:", ARRAY_LEN(topts), + *opts = tpm2_options_new("P:p:G:i:C:U:u:r:a:g:s:L:k:R", ARRAY_LEN(topts), topts, on_option, 0, 0); return *opts != 0; diff --git a/tools/tpm2_load.c b/tools/tpm2_load.c index b61da450c..0c01ee983 100644 --- a/tools/tpm2_load.c +++ b/tools/tpm2_load.c @@ -44,14 +44,18 @@ struct tpm_tool_ctx { TPM2B_DIGEST cp_hash; bool is_command_dispatch; TPMI_ALG_HASH parameter_hash_algorithm; + bool autoflush; }; static tpm_load_ctx ctx = { .parameter_hash_algorithm = TPM2_ALG_ERROR, + .autoflush = false, }; static tool_rc load(ESYS_CONTEXT *ectx) { + TSS2_RC rval; + /* * If a tssprivkey was specified, load the private and public from the * parsed TSSPEM file. @@ -62,8 +66,20 @@ static tool_rc load(ESYS_CONTEXT *ectx) { TPM2B_PUBLIC *to_load_pub = ctx.is_tss_pem ? &tpm2_util_object_tsspem_pub : &ctx.object.public; - return tpm2_load(ectx, &ctx.parent.object, to_load_priv, to_load_pub, + tool_rc tmp_rc = tpm2_load(ectx, &ctx.parent.object, to_load_priv, to_load_pub, &ctx.object.handle, &ctx.cp_hash, ctx.parameter_hash_algorithm); + if (tmp_rc != tool_rc_success) { + return tmp_rc; + } + if ((ctx.autoflush || tpm2_util_env_yes(TPM2TOOLS_ENV_AUTOFLUSH)) && + ctx.parent.object.path && + (ctx.parent.object.handle & TPM2_HR_RANGE_MASK) == TPM2_HR_TRANSIENT) { + rval = Esys_FlushContext(ectx, ctx.parent.object.tr_handle); + if (rval != TPM2_RC_SUCCESS) { + return tool_rc_general_error; + } + } + return tool_rc_success; } static tool_rc process_output(ESYS_CONTEXT *ectx) { @@ -110,7 +126,7 @@ static tool_rc process_output(ESYS_CONTEXT *ectx) { } return files_save_tpm_context_to_path(ectx, ctx.object.handle, - ctx.contextpath); + ctx.contextpath, ctx.autoflush); } static tool_rc process_inputs(ESYS_CONTEXT *ectx) { @@ -281,6 +297,10 @@ static bool on_option(char key, char *value) { case 0: ctx.cp_hash_path = value; break; + case 'R': + ctx.autoflush = true; + break; + } return true; @@ -296,9 +316,10 @@ static bool tpm2_tool_onstart(tpm2_options **opts) { { "key-context", required_argument, 0, 'c' }, { "parent-context", required_argument, 0, 'C' }, { "cphash", required_argument, 0, 0 }, + { "autoflush", no_argument, 0, 'R' }, }; - *opts = tpm2_options_new("P:u:r:n:C:c:", ARRAY_LEN(topts), topts, on_option, + *opts = tpm2_options_new("P:u:r:n:C:c:R", ARRAY_LEN(topts), topts, on_option, 0, 0); return *opts != 0; diff --git a/tools/tpm2_loadexternal.c b/tools/tpm2_loadexternal.c index 2371470dd..7a7809f7a 100644 --- a/tools/tpm2_loadexternal.c +++ b/tools/tpm2_loadexternal.c @@ -37,6 +37,7 @@ struct tpm_loadexternal_ctx { char *passin; /* an optional auth string for the input key file for OSSL */ TPM2B_SENSITIVE priv; /* Set the AUTH value for sensitive portion */ TPM2B_PUBLIC pub; /* Load the users specified public object if specified via -u*/ + bool autoflush; /* Flush the object after creation of the ctx file */ /* * TSS Privkey related */ @@ -64,6 +65,7 @@ static tpm_loadexternal_ctx ctx = { */ .hierarchy_value = TPM2_RH_NULL, .parameter_hash_algorithm = TPM2_ALG_ERROR, + .autoflush = false, }; static tool_rc load_external(ESYS_CONTEXT *ectx) { @@ -104,7 +106,7 @@ static tool_rc process_output(ESYS_CONTEXT *ectx) { assert(ctx.name); rc = files_save_tpm_context_to_path(ectx, ctx.handle, - ctx.context_file_path); + ctx.context_file_path, ctx.autoflush); if (rc != tool_rc_success) { goto out; } @@ -406,6 +408,9 @@ static bool on_option(char key, char *value) { case 1: ctx.cp_hash_path = value; break; + case 'R': + ctx.autoflush = true; + break; } return true; @@ -426,9 +431,10 @@ static bool tpm2_tool_onstart(tpm2_options **opts) { { "name", required_argument, 0, 'n'}, { "passin", required_argument, 0, 0 }, { "cphash", required_argument, 0, 1 }, + { "autoflush", no_argument, 0, 'R' }, }; - *opts = tpm2_options_new("C:u:r:c:a:p:L:g:G:n:", ARRAY_LEN(topts), topts, + *opts = tpm2_options_new("C:u:r:c:a:p:L:g:G:n:R", ARRAY_LEN(topts), topts, on_option, 0, 0); return *opts != 0;