tpm2-tools源码分析之tpm2_load.c(5)
接前一篇文章:tpm2-tools源码分析之tpm2_load.c(4)
上一篇文章分析完了tpm2_load.c中的tpm2_tool_onrun函数的第2个函数process_inputs。本文分析第3个函数load。
先看一下调用该函数的代码片段:
/ 3. TPM2_CC_<command> call*/
rc = load(ectx);
if (rc != tool_rc_success) {return rc;
}
load函数的源码如下:
static tool_rc load(ESYS_CONTEXT *ectx) {/ If a tssprivkey was specified, load the private and public from the* parsed TSSPEM file.*/TPM2B_PRIVATE *to_load_priv =ctx.is_tss_pem ? &tpm2_util_object_tsspem_priv : &ctx.object.private;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,&ctx.object.handle, &ctx.cp_hash, ctx.parameter_hash_algorithm);
}
ctx.is_tss_pem的取值在《tpm2-tools源码分析之tpm2_load.c(3)》中进行了分析。此处是根据ctx.is_tss_pem的值确定tp_load_priv指针的指向。如果ctx.is_tss_pem为True,则指向tpm2_util_object_tsspem_priv;如果ctx.is_tss_pem为False,则指向&ctx.object.private。
对于to_load_pub指针来说,也是同样的机制。
tpm2_util_object_tsspem_priv和tpm2_util_object_tsspem_pub在lib/object.c中定义,代码如下:
TPM2B_PRIVATE tpm2_util_object_tsspem_priv = { 0 };
TPM2B_PUBLIC tpm2_util_object_tsspem_pub = { 0 };
以上代码实际上就是判断公私钥是从PEM中来还是从文件中来。
tpm2_util_object_tsspem_priv和tpm2_util_object_tsspem_pub是在lib/object.c中的tpm2_util_object_load_tsspem函数中被赋值的,该函数代码如下:
static tool_rc tpm2_util_object_load_tsspem(ESYS_CONTEXT *ctx,const char *objectstr, tpm2_loaded_object *outobject) {/ fetch out the various parts of the PEM file using openssl API*/tool_rc rc = tpm2_util_object_fetch_priv_pub_from_tpk(objectstr,&tpm2_util_object_tsspem_pub, &tpm2_util_object_tsspem_priv);if (rc != tool_rc_success) {LOG_ERR("Unable to fetch public/private portions of TSS PRIVKEY");return rc;}uint64_t val;rc = tpm2_util_object_fetch_parent_from_tpk(objectstr, &val);if (rc != tool_rc_success) {return rc;}bool is_persistent_parent = (val != TPM2_RH_OWNER && val != 0);if (!is_persistent_parent) {ESYS_TR obj_parent = ESYS_TR_NONE;rc = tpm2_util_object_setup_primary(ctx, &obj_parent);if (rc != tool_rc_success) {LOG_ERR("Unable to create parent using createprimary");return rc;}outobject->tr_handle = obj_parent;rc = Esys_TR_GetTpmHandle(ctx, obj_parent,&outobject->handle);if (rc != TSS2_RC_SUCCESS) {LOG_ERR("Unable to fetch TPM handle from ESYS TR handle");return rc;}} else {ESYS_TR tr_parent = ESYS_TR_NONE;rc = tpm2_from_tpm_public(ctx, val, ESYS_TR_NONE, ESYS_TR_NONE,ESYS_TR_NONE, &tr_parent);if (rc != tool_rc_success) {LOG_ERR("Unable to fetch TR Handle for persistent parent");return rc;}outobject->tr_handle = tr_parent;}return rc;
}
回到load函数中。tpm2_load函数是load函数的核心函数,实际上也是tpm2_load命令的核心函数,其在lib/tpm2.c中,代码如下:
tool_rc tpm2_load(ESYS_CONTEXT *esys_context, tpm2_loaded_object *parentobj,const TPM2B_PRIVATE *in_private, const TPM2B_PUBLIC *in_public,ESYS_TR *object_handle, TPM2B_DIGEST *cp_hash,TPMI_ALG_HASH parameter_hash_algorithm) {ESYS_TR parent_object_session_handle = ESYS_TR_NONE;tool_rc rc = tpm2_auth_util_get_shandle(esys_context, parentobj->tr_handle,parentobj->session, &parent_object_session_handle);if (rc != tool_rc_success) {LOG_ERR("Failed to get parent object session handle");return rc;}if (cp_hash && cp_hash->size) {/ Need sys_context to be able to calculate CpHash*/TSS2_SYS_CONTEXT *sys_context = 0;rc = tpm2_getsapicontext(esys_context, &sys_context);if(rc != tool_rc_success) {LOG_ERR("Failed to acquire SAPI context.");return rc;}TSS2_RC rval = Tss2_Sys_Load_Prepare(sys_context, parentobj->handle,in_private, in_public);if (rval != TPM2_RC_SUCCESS) {LOG_PERR(Tss2_Sys_Load_Prepare, rval);return tool_rc_general_error;}TPM2B_NAME *name1 = 0;rc = tpm2_tr_get_name(esys_context, parentobj->tr_handle,&name1);if (rc != tool_rc_success) {goto tpm2_load_free_name1;}rc = tpm2_sapi_getcphash(sys_context, name1, 0, 0,parameter_hash_algorithm, cp_hash);/ Exit here without making the ESYS call since we just need the cpHash*/
tpm2_load_free_name1:Esys_Free(name1);goto tpm2_load_skip_esapi_call;}TSS2_RC rval = Esys_Load(esys_context, parentobj->tr_handle,parent_object_session_handle, ESYS_TR_NONE, ESYS_TR_NONE, in_private,in_public, object_handle);if (rval != TPM2_RC_SUCCESS) {LOG_PERR(Eys_Load, rval);return tool_rc_from_tpm(rval);}tpm2_load_skip_esapi_call:return rc;
}
1)tpm2_auth_util_get_shandle
tpm2_auth_util_get_shandle函数在lib/tpm2_auth_util.c中,代码如下:
tool_rc tpm2_auth_util_get_shandle(ESYS_CONTEXT *ectx, ESYS_TR object,tpm2_session *session, ESYS_TR *out) {*out = tpm2_session_get_handle(session);const TPM2B_AUTH *auth = tpm2_session_get_auth_value(session);return tpm2_tr_set_auth(ectx, object, auth);
}
2)tpm2_getsapicontext
tpm2_getsapicontext函数在lib/tpm2.c中,代码如下:
tool_rc tpm2_getsapicontext(ESYS_CONTEXT *esys_context,TSS2_SYS_CONTEXT sys_context) {TSS2_RC rval = Esys_GetSysContext(esys_context, sys_context);if (rval != TPM2_RC_SUCCESS) {LOG_PERR(Esys_GetSysContext, rval);return tool_rc_from_tpm(rval);}return tool_rc_success;
}
3)Tss2_Sys_Load_Prepare
Tss2_Sys_Load_Prepare函数的实现在tpm2-tools源码路径下是找不到的,其是在tpm2-tss源码中声明和实现的。声明是在tpm2-tss/include/tss2/tss2_sys.h中,实现是在tpm2-tss/src/tss2-sys/api/Tss2_Sys_Load.c中。由于不是本系列重点,在此不作深入讲解。只给出函数声明,如下所示:
TSS2_RC Tss2_Sys_Load_Prepare(TSS2_SYS_CONTEXT *sysContext,TPMI_DH_OBJECT parentHandle,const TPM2B_PRIVATE *inPrivate,const TPM2B_PUBLIC *inPublic);
4)tpm2_tr_get_name
tpm2_tr_get_name函数在lib/tpm2.c中,代码如下:
tool_rc tpm2_tr_get_name(ESYS_CONTEXT *esys_context, ESYS_TR handle,TPM2B_NAME name) {TSS2_RC rval = Esys_TR_GetName(esys_context, handle, name);if (rval != TSS2_RC_SUCCESS) {LOG_PERR(Esys_TR_GetName, rval);return tool_rc_from_tpm(rval);}return tool_rc_success;
}
5)tpm2_sapi_getcphash
tpm2_sapi_getcphash函数在lib/tpm2.c中,代码如下:
tool_rc tpm2_sapi_getcphash(TSS2_SYS_CONTEXT *sys_context,const TPM2B_NAME *name1, const TPM2B_NAME *name2, const TPM2B_NAME *name3,TPMI_ALG_HASH halg, TPM2B_DIGEST *cp_hash) {uint8_t command_code[4];TSS2_RC rval = Tss2_Sys_GetCommandCode(sys_context, &command_code[0]);if (rval != TPM2_RC_SUCCESS) {LOG_PERR(Tss2_Sys_GetCommandCode, rval);return tool_rc_general_error;}const uint8_t *command_parameters;size_t command_parameters_size;rval = Tss2_Sys_GetCpBuffer(sys_context, &command_parameters_size,&command_parameters);if (rval != TPM2_RC_SUCCESS) {LOG_PERR(Tss2_Sys_GetCpBuffer, rval);return tool_rc_general_error;}uint16_t to_hash_len = sizeof(command_code) + command_parameters_size;to_hash_len += name1 ? name1->size : 0;to_hash_len += name2 ? name2->size : 0;to_hash_len += name3 ? name3->size : 0;uint8_t *to_hash = malloc(to_hash_len);if (!to_hash) {LOG_ERR("oom");return tool_rc_general_error;}//Command-Codememcpy(to_hash, command_code, sizeof(command_code));uint16_t offset = sizeof(command_code);//Namesif (name1) {memcpy(to_hash + offset, name1->name, name1->size);offset += name1->size;}if (name2) {memcpy(to_hash + offset, name2->name, name2->size);offset += name2->size;}if (name3) {memcpy(to_hash + offset, name3->name, name3->size);offset += name3->size;}//CpBuffermemcpy(to_hash + offset, command_parameters, command_parameters_size);//cpHashtool_rc rc = tool_rc_success;bool result = tpm2_openssl_hash_compute_data(halg, to_hash, to_hash_len,cp_hash);free(to_hash);if (!result) {LOG_ERR("Failed cpHash digest calculation.");rc = tool_rc_general_error;}return rc;
}
6)Esys_Load
Esys_Load函数在tpm2-tss/src/tss2-esys/api/Esys_Load.c中实现。由于不是本系列重点,在此不作深入讲解。只给出函数声明和部分函数注释,如下所示:
/ One-Call function for TPM2_Load This function invokes the TPM2_Load command in a one-call* variant. This means the function will block until the TPM response is* available. All input parameters are const. The memory for non-simple output* parameters is allocated by the function implementation.
……
*/
TSS2_RC
Esys_Load(ESYS_CONTEXT *esysContext,ESYS_TR parentHandle,ESYS_TR shandle1,ESYS_TR shandle2,ESYS_TR shandle3,const TPM2B_PRIVATE *inPrivate,const TPM2B_PUBLIC *inPublic, ESYS_TR *objectHandle)