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-Code
    memcpy(to_hash, command_code, sizeof(command_code));
    uint16_t offset = sizeof(command_code);

    //Names
    if (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;
    }

    //CpBuffer
    memcpy(to_hash + offset, command_parameters, command_parameters_size);

    //cpHash
    tool_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)

猜你喜欢

转载自blog.csdn.net/phmatthaus/article/details/129819240