From 0a8cb8cfcaa892809bab14126c3f0a4a18966d45 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 indexpendent from the environment variable. Addresses: #1511 Signed-off-by: Juergen Repp --- lib/files.c | 20 ++++++++++++++++---- lib/files.h | 20 ++++++++++++++++++-- lib/tpm2.c | 18 +++++++++++++++++- lib/tpm2.h | 2 +- lib/tpm2_options.h | 2 +- lib/tpm2_session.c | 2 +- man/common/options.md | 5 +++++ 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 ++++++++-- 18 files changed, 203 insertions(+), 36 deletions(-) diff --git a/lib/files.c b/lib/files.c index 7773cb6b2..f39bd89b8 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; } @@ -887,3 +887,15 @@ tool_rc files_load_unique_data(const char *file_path, TPM2B_PUBLIC *public_data) return tool_rc_success; } + + +bool file_exists(const char *fname) +{ + FILE *file; + if ((file = fopen(fname, "r"))) + { + fclose(file); + return true; + } + return false; +} diff --git a/lib/files.h b/lib/files.h index b24112619..6ee26d68a 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. @@ -628,4 +632,16 @@ bool files_load_attest_file(FILE *f, const char *path, TPMS_ATTEST *attest); tool_rc files_load_unique_data(const char *file_path, TPM2B_PUBLIC *public_data); +/** + * @brief + * Check whether file can be read + * + * @param fname + * The file filename of the file to be read. + * @return + * bool signaling whether file can be read. + * + */ +bool file_exists(const char *fname); + #endif /* FILES_H */ diff --git a/lib/tpm2.c b/lib/tpm2.c index 43aa3590b..e175c4ae1 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_getenv(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 666a0edc2..e34ec9d66 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 541a1ad61..64e218cbf 100644 --- a/lib/tpm2_session.c +++ b/lib/tpm2_session.c @@ -398,7 +398,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/man/common/options.md b/man/common/options.md index 565131716..5dab51708 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. 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 650bb4b78..fd968fe6d 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..c16c4581d 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_getenv(TPM2TOOLS_ENV_AUTOFLUSH)) && + file_exists(ctx.parent.ctx_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..dbe51e29b 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_getenv(TPM2TOOLS_ENV_AUTOFLUSH)) && + file_exists(ctx.parent.ctx) && + (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 228148ae3..3defb92da 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_getenv(TPM2TOOLS_ENV_AUTOFLUSH)) && + file_exists(ctx.parent.ctx_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,14 +322,14 @@ 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; } } - if (ctx.rp_hash_path) { + if (ctx.rp_hash_path) { is_file_op_success = files_save_digest(&ctx.rp_hash, ctx.rp_hash_path); if (!is_file_op_success) { @@ -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..2ef764473 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_getenv(TPM2TOOLS_ENV_AUTOFLUSH)) && + file_exists(ctx.parent.ctx_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 8b751f895..3155dcb7d 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_getenv(TPM2TOOLS_ENV_AUTOFLUSH)) && + file_exists(ctx.parent.ctx_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;