tpm2-tools源码分析之tpm2_getrandom.c(3)

接前一篇文章:tpm2-tools源码分析之tpm2_getrandom.c(2)

本文对tpm2_getrandom.c中的tpm2_tool_onrun函数进行详细解析。

先再次贴出该函数源码:

static tool_rc tpm2_tool_onrun(ESYS_CONTEXT *ectx, tpm2_option_flags flags) {

    UNUSED(flags);

    /*
     * 1. Process options
     */

    /*
     * 2. Process inputs
     */
    tool_rc rc = process_inputs(ectx);
    if (rc != tool_rc_success) {
        return rc;
    }

    /*
     * 3. TPM2_CC_<command> call
     */
    rc = get_random(ectx);
    if (rc != tool_rc_success) {
        return rc;
    }

    /*
     * 4. Process outputs
     */
    return process_outputs();
}

根据tpm2_tool_onrun函数中的注释,此函数分为4个步骤。不过第1个步骤没有任何函数和动作,因此实际上调用了3个函数:process_inputs、ger_random、process_outputs。实际上这个流程也是一个通用流程。

(1)process_inputs函数

process_inputs函数的作用是输入的处理。它在同文件(tpm2_getrrandom.c)中,代码如下:

process_inputs

这个函数又分为以下几个步骤:

1)对象和授权的初始化

由于tpm2_getrandom不需要授权,因此这一步骤实际上不需要。

2)恢复辅助会话

调用tpm2_util_aux_sessions_setup函数恢复辅助会话。对应代码片段如下:

tool_rc rc = tpm2_util_aux_sessions_setup(ectx, ctx.aux_session_cnt,
    ctx.aux_session_path, ctx.aux_session_handle, ctx.aux_session);
if (rc != tool_rc_success) {
    return rc;
}

tpm2_util_aux_sessions_setup函数在lib/tpm2_util.c中,代码如下:

#define MAX_SESSION_CNT 3
tool_rc tpm2_util_aux_sessions_setup(ESYS_CONTEXT *ectx, uint8_t session_cnt,
    const char **session_path, ESYS_TR *session_handle,
    tpm2_session **session) {

    /*
     * If no aux sessions were specified, simply return.
     */
    if (!session_cnt) {
        return tool_rc_success;
    }

    if (session_cnt > MAX_SESSION_CNT) {
        LOG_ERR("A max of 3 sessions allowed");
        return tool_rc_general_error;
    }

    uint8_t session_idx = 0;
    for (session_idx = 0; session_idx < (session_cnt); session_idx++) {
        if (session_path[session_idx]) {
                tool_rc rc = tpm2_session_restore(ectx,
                    session_path[session_idx], false, &session[session_idx]);
            if (rc != tool_rc_success) {
                LOG_ERR("Could not restore aux-session #%s",
                session_path[session_idx]);
                return rc;
            }
            session_handle[session_idx] =
                tpm2_session_get_handle(session[session_idx]);
        }
    }

    return tool_rc_success;
}

对于lib库中的代码,后续会有专门的文章进行分析,在此不作重点分析。

再来重点说一下ctx。ctx在同文件(tools/tpm2_getrandom.c)中定义并初始化,代码如下:

static tpm_random_ctx ctx = {
    .aux_session_handle[0] = ESYS_TR_NONE,
    .aux_session_handle[1] = ESYS_TR_NONE,
    .aux_session_handle[2] = ESYS_TR_NONE,
    .parameter_hash_algorithm = TPM2_ALG_ERROR,
};

ctx是tpm_random_ctx结构的成员,该结构也在同文件中定义,代码如下:

typedef struct tpm_random_ctx tpm_random_ctx;
#define MAX_AUX_SESSIONS 3
#define MAX_SESSIONS 3
struct tpm_random_ctx {
    /*
     * Input options
     */
    UINT16 num_of_bytes;
    bool force;
    bool hex;

    /*
     * Outputs
     */
    char *output_file;
    TPM2B_DIGEST *random_bytes;

    /*
     * Parameter hashes
     */
    const char *cp_hash_path;
    TPM2B_DIGEST cp_hash;
    const char *rp_hash_path;
    TPM2B_DIGEST rp_hash;
    TPMI_ALG_HASH parameter_hash_algorithm;
    bool is_command_dispatch;

    /*
     * Aux Sessions
     */
    uint8_t aux_session_cnt;
    tpm2_session *aux_session[MAX_AUX_SESSIONS];
    const char *aux_session_path[MAX_AUX_SESSIONS];
    ESYS_TR aux_session_handle[MAX_AUX_SESSIONS];
};

3)特定于命令的初始化

对应代码片段如下:

 /*
     * Error if bytes requested is bigger than max hash size, which is what TPMs
     * should bound their requests by and always have available per the spec.
     *
     * Per 16.1 of:
     *  - https://trustedcomputinggroup.org/wp-content/uploads/TPM-Rev-2.0-Part-3-Commands-01.38.pdf
     *
     *  Allow the force flag to override this behavior.
     */
    if (!ctx.force) {
        UINT32 max = 0;
        rc = get_max_random(ectx, &max);
        if (rc != tool_rc_success) {
            return rc;
        }

        if (ctx.num_of_bytes > max) {
            LOG_ERR("TPM getrandom is bounded by max hash size, which is: "
                    "%"PRIu32"\n"
                    "Please lower your request (preferred) and try again or"
                    " use --force (advanced)", max);
            return tool_rc_general_error;
        }
    }

这段代码的意思是:如果命令参数选项中并未指定-f即强制选项,则需要检查并确保请求的大小在TPM的哈希大小限制内。最大字节数通过get_max_random函数获得,该函数在同文件(tools/tpm2_getrandom.c)中,代码如下:

static tool_rc get_max_random(ESYS_CONTEXT *ectx, UINT32 *value) {

    TPMS_CAPABILITY_DATA *cap_data = NULL;
    tool_rc rc = tpm2_capability_get(ectx, TPM2_CAP_TPM_PROPERTIES,
            TPM2_PT_FIXED, TPM2_MAX_TPM_PROPERTIES, &cap_data);
    if (rc != tool_rc_success) {
        return rc;
    }

    UINT32 i;
    for (i = 0; i < cap_data->data.tpmProperties.count; i++) {
        TPMS_TAGGED_PROPERTY *p = &cap_data->data.tpmProperties.tpmProperty[i];
        if (p->property == TPM2_PT_MAX_DIGEST) {
            *value = p->value;
            free(cap_data);
            return tool_rc_success;
        }
    }

    LOG_ERR("TPM does not have property TPM2_PT_MAX_DIGEST");
    free(cap_data);

    return tool_rc_general_error;
}

可见,get_max_random函数的核心是调用了tpm2_capability_get函数。tpm2_capability_get函数在lib/tpm2_capability.c中,代码如下:

tool_rc tpm2_capability_get(ESYS_CONTEXT *ectx, TPM2_CAP capability,
        UINT32 property, UINT32 count,
        TPMS_CAPABILITY_DATA **capability_data) {

    return tpm2_capability_get_ex(ectx, capability,
            property, count, false, capability_data);
}

4)用于计算pHash的配置

此步骤又分为2个子步骤:

4.a)确定哈希和算法

对应代码片断如下:

/*
 * 4.a Determine pHash length and alg
 */
tpm2_session *all_sessions[MAX_SESSIONS] = {
    ctx.aux_session[0],
    ctx.aux_session[1],
    ctx.aux_session[2]
};

const char **cphash_path = ctx.cp_hash_path ? &ctx.cp_hash_path : 0;
const char **rphash_path = ctx.rp_hash_path ? &ctx.rp_hash_path : 0;

ctx.parameter_hash_algorithm = tpm2_util_calculate_phash_algorithm(ectx,
    cphash_path, &ctx.cp_hash, rphash_path, &ctx.rp_hash, all_sessions);

4.b)确定哈希和算法

对应代码片断如下:

 /*
     * 4.b Determine if TPM2_CC_<command> is to be dispatched
     * !rphash && !cphash [Y]
     * !rphash && cphash  [N]
     * rphash && !cphash  [Y]
     * rphash && cphash   [Y]
     */
    ctx.is_command_dispatch = (ctx.cp_hash_path && !ctx.rp_hash_path) ?
        false : true;

这一段代码就对应上一篇文章中提到的“当cphash被选择,而rphash选项没有被选择,则该工具不会实际执行命令,它只是返回一个cpHash。

至此,tpm2_tool_onrun函数的第1个函数process_inputs函数就分析完了。下一篇文章起分析余下的函数。

猜你喜欢

转载自blog.csdn.net/phmatthaus/article/details/129670652
今日推荐