接前一篇文章:tpm2-tools源码分析之tpm2_load.c(2)
本文对tpm2_load.c中的tpm2_tool_onrun函数进行i详细解析。
先再次贴出该函数源码:
static tool_rc tpm2_tool_onrun(ESYS_CONTEXT *ectx, tpm2_option_flags flags) {
UNUSED(flags);
/*
* 1. Process options
*/
tool_rc rc = check_options(ectx);
if (rc != tool_rc_success) {
return rc;
}
/*
* 2. Process inputs
*/
rc = process_inputs(ectx);
if (rc != tool_rc_success) {
return rc;
}
/*
* 3. TPM2_CC_<command> call
*/
rc = load(ectx);
if (rc != tool_rc_success) {
return rc;
}
/*
* 4. Process outputs
*/
return process_output(ectx);
}
根据tpm2_tool_onrun函数中的注释,此函数分为4个步骤即调用了4个函数:check_options、process_inputs、load、process_outputs。实际上这个流程也是一个通用流程。
(1)check_options函数
check_options函数的作用是选项检查与处理。它在同文件(tpm2_load.c)中,代码如下:
static tool_rc check_options(ESYS_CONTEXT *ectx) {
UNUSED(ectx);
tool_rc rc = tool_rc_success;
if (!ctx.object.privpath) {
LOG_ERR("Expected private object portion via -r");
rc = tool_rc_option_error;
}
/*
* Check for TSS PEM file input:
* 1. It is specified with the -r,--private option alone.
* 2. The parent and public objects are implicit and read directly from
* the TSS PEM.
*/
ctx.is_tss_pem =
(!ctx.parent.ctx_path && !ctx.object.pubpath && ctx.object.privpath);
if (!ctx.is_tss_pem) {
if (!ctx.parent.ctx_path) {
LOG_ERR("Expected parent object via -C or a PEM file with -r");
rc = tool_rc_option_error;
}
if (!ctx.object.pubpath) {
LOG_ERR("Expected public object portion via -u or a PEM file with -r");
rc = tool_rc_option_error;
}
}
if (!ctx.contextpath && !ctx.cp_hash_path) {
LOG_ERR("Expected option -c");
rc = tool_rc_option_error;
}
if (ctx.contextpath && ctx.cp_hash_path) {
LOG_ERR("Cannot output contextpath when calculating cp_hash");
rc = tool_rc_option_error;
}
return rc;
}
重点说一下ctx。ctx在同文件(tools/tpm2_load.c)中定义并初始化,代码如下:
static tpm_load_ctx ctx = {
.parameter_hash_algorithm = TPM2_ALG_ERROR,
};
ctx是tpm_load_ctx结构的成员,该结构也在同文件中定义,代码如下:
typedef struct tpm_tool_ctx tpm_load_ctx;
struct tpm_tool_ctx {
/*
* Inputs
*/
struct {
const char *ctx_path;
const char *auth_str;
tpm2_loaded_object object;
} parent;
struct {
const char *pubpath;
TPM2B_PUBLIC public;
const char *privpath;
TPM2B_PRIVATE private;
ESYS_TR handle;
} object;
bool is_tss_pem;
/*
* Outputs
*/
const char *namepath;
const char *contextpath;
/*
* Parameter hashes
*/
const char *cp_hash_path;
TPM2B_DIGEST cp_hash;
bool is_command_dispatch;
TPMI_ALG_HASH parameter_hash_algorithm;
};
回到check_options函数中,一上来先做检查,要求ctx.object.privpath不能为空。ctx.object.privpath在tpm2_tool_onstart函数中的tpm2_options_new函数中设置的on_option函数中赋值(详见前一篇文章)。实际上是要求命令行必须带有“-r FILE”或“--private=FILE”。
接下来检查TSS PEM文件输入。代码片断如下:
/*
* Check for TSS PEM file input:
* 1. It is specified with the -r,--private option alone.
* 2. The parent and public objects are implicit and read directly from
* the TSS PEM.
*/
ctx.is_tss_pem =
(!ctx.parent.ctx_path && !ctx.object.pubpath && ctx.object.privpath);
ctx.is_tss_pem的值只在ctx.parent.ctx_path为空并且ctx.object.pubpath为空并且ctx.object.privpath不为空的情况下才能为真,其它情况都为假。ctx.object.privpath上边检查中已经保证了;ctx.parent.ctx_path的值是通过命令行带上“-C OBJECT”或“--parent-context=OBJECT”选项传入的;而ctx.object.pubpath则是通过命令行带上“-u FILE”或“--public=FILE”选项传入的。
接下来,如果ctx.is_tss_pem为假,则要求ctx.parent.ctx_path必须不为空并且tx.object.pubpath也必须不为空,即命令行中必须带有“-C OBJECT”或“--parent-context=OBJECT”和-u FILE”或“--public=FILE”。
最后检查的ctx.contextpath与ctx.cp_hash_path之间的相互约束,代码片断如下:
if (!ctx.contextpath && !ctx.cp_hash_path) {
LOG_ERR("Expected option -c");
rc = tool_rc_option_error;
}
if (ctx.contextpath && ctx.cp_hash_path) {
LOG_ERR("Cannot output contextpath when calculating cp_hash");
rc = tool_rc_option_error;
}
ctx.contextpath和ctx.cp_hash_path不能同时为空,也不能同时不为空。这就是说命令行选项中“-c, --key-context=FILE”与“--cphash=FILE”必须指定其一。
至此,tpm2_tool_onrun函数的第1个函数check_options函数就分析完了。下一篇文章起分析余下的函数。