当前位置: 首页 > article >正文

tpm2-tools源码分析之tpm2_load.c(6)

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

上一篇文章分析完了tpm2_load.c中的tpm2_tool_onrun函数的第3个函数load。本文分析第4个函数process_output。

先看一下调用该函数的代码片段:

/*
 * 4. Process outputs
 */
return process_output(ectx);

process_output函数源码如下:

static tool_rc process_output(ESYS_CONTEXT *ectx) {

    UNUSED(ectx);
    /*
     * 1. Outputs that do not require TPM2_CC_<command> dispatch
     */
    bool is_file_op_success = true;
    if (ctx.cp_hash_path) {
        is_file_op_success = files_save_digest(&ctx.cp_hash, ctx.cp_hash_path);

        if (!is_file_op_success) {
            return tool_rc_general_error;
        }
    }

    tool_rc rc = tool_rc_success;
    if (!ctx.is_command_dispatch) {
        return rc;
    }

    /*
     * 2. Outputs generated after TPM2_CC_<command> dispatch
     */
    TPM2B_NAME *name;
    rc = tpm2_tr_get_name(ectx, ctx.object.handle, &name);
    if (rc != tool_rc_success) {
        return rc;
    }

    if (ctx.namepath) {
        bool result = files_save_bytes_to_file(ctx.namepath, name->name,
                name->size);
        free(name);
        if (!result) {
            return tool_rc_general_error;
        }
    } else {
        tpm2_tool_output("name: ");
        tpm2_util_print_tpm2b(name);
        tpm2_tool_output("\n");
        free(name);
    }

    return files_save_tpm_context_to_path(ectx, ctx.object.handle,
            ctx.contextpath);
}

1)files_save_digest

files_save_digest函数在lib/files.c中实现,但是需要做转换。代码如下:

#define SAVE_TYPE(type, name) \
    bool files_save_##name(type *name, const char *path) { \
    \
        size_t offset = 0; \
        UINT8 buffer[sizeof(*name)]; \
        TSS2_RC rc = Tss2_MU_##type##_Marshal(name, buffer, sizeof(buffer), &offset); \
        if (rc != TSS2_RC_SUCCESS) { \
            LOG_ERR("Error serializing "str(name)" structure: 0x%x", rc); \
            return false; \
        } \
    \
        return files_save_bytes_to_file(path, buffer, offset); \
    }

根据上述宏定义,可以推断出files_save_digest函数对应的宏为:

SAVE_TYPE(TPM2B_DIGEST, digest)

对应的源码为:

bool files_save_digest(TPM2B_DIGEST *digest, const char *path) {

    size_t offset = 0;
    UINT8 buffer[sizeof(*digest)];
    TSS2_RC rc = Tss2_MU_TPM2B_DIGEST_Marshal(digest, buffer, sizeof(buffer), &offset);
    if (rc != TSS2_RC_SUCCESS) {
        LOG_ERR("Error serializing "str(digest)" structure: 0x%x", rc);
        return false;
    }

    return files_save_bytes_to_file(path, buffer, offset);
}

TPM2B_DIGEST在/usr/local/include/tss2/tss2_tpm2_types.h中定义,代码如下:

/* Definition of TPM2B_DIGEST Structure */
typedef struct TPM2B_DIGEST TPM2B_DIGEST;
struct TPM2B_DIGEST {
    UINT16 size;
    BYTE buffer[sizeof(TPMU_HA)];
};

TPMU_HA同样在/usr/local/include/tss2/tss2_tpm2_types.h中定义,代码如下:

/* Definition of TPMU_HA Union <INOUT S> */
typedef union TPMU_HA TPMU_HA;
union TPMU_HA {
    BYTE sha [TPM2_SHA_DIGEST_SIZE]; /* TPM2_ALG_SHA */
    BYTE sha1[TPM2_SHA1_DIGEST_SIZE];
    BYTE sha256[TPM2_SHA256_DIGEST_SIZE];
    BYTE sha384[TPM2_SHA384_DIGEST_SIZE];
    BYTE sha512[TPM2_SHA512_DIGEST_SIZE];
    BYTE sm3_256[TPM2_SM3_256_DIGEST_SIZE];
};

files_save_bytes_to_file函数在lib/files.c中,代码如下:

bool files_save_bytes_to_file(const char *path, UINT8 *buf, UINT16 size) {

    if (!buf) {
        return false;
    }

    if (!path && !output_enabled) {
        return true;
    }

    FILE *fp = path ? fopen(path, "wb+") : stdout;
    if (!fp) {
        LOG_ERR("Could not open file \"%s\", error: %s", path, strerror(errno));
        return false;
    }

    bool result = files_write_bytes(fp, buf, size);
    if (!result) {
        LOG_ERR("Could not write data to file \"%s\"", path ? path : "<stdout>");
    }

    if (fp != stdout) {
        fclose(fp);
    }

    return result;
}

代码的意思一目了然,做常规检查后,以二进制读写方式打开文件,然后向打开的文件写入buf中的内容,即Tss2_MU_TPM2B_DIGEST_Marshal函数针对摘要生成的哈希值,最后关闭文件。

Tss2_MU_TPM2B_DIGEST_Marshal函数在tpm2-tss/src/tss2-mu/tpm2b-types.c中,代码如下(需要做一些转换):

TPM2B_MARSHAL  (TPM2B_DIGEST);
#define TPM2B_MARSHAL(type) \
TSS2_RC Tss2_MU_##type##_Marshal(type const *src, uint8_t buffer[], \
                                 size_t buffer_size, size_t *offset) \
{ \
    size_t local_offset = 0; \
    TSS2_RC rc; \
\
    if (src == NULL) { \
        LOG_WARNING("src param is NULL"); \
        return TSS2_MU_RC_BAD_REFERENCE; \
    } \
    if (offset != NULL) { \
        LOG_DEBUG("offset non-NULL, initial value: %zu", *offset); \
        local_offset = *offset; \
    } \
    if (buffer == NULL && offset == NULL) { \
        LOG_WARNING("buffer and offset parameter are NULL"); \
        return TSS2_MU_RC_BAD_REFERENCE; \
    } else if (buffer == NULL && offset != NULL) { \
        *offset += sizeof(src->size) + src->size; \
        LOG_TRACE("buffer NULL and offset non-NULL, updating offset to %zu", \
             *offset); \
        return TSS2_RC_SUCCESS; \
    } else if (buffer_size < local_offset || \
               buffer_size - local_offset < (sizeof(src->size) + src->size)) { \
        LOG_DEBUG( \
             "buffer_size: %zu with offset: %zu are insufficient for object " \
             "of size %zu", \
             buffer_size, \
             local_offset, \
             sizeof(src->size) + src->size); \
        return TSS2_MU_RC_INSUFFICIENT_BUFFER; \
    } else if ((sizeof(type) - sizeof(src->size)) < src->size) { \
        LOG_WARNING(\
             "size: %u for buffer of " #type " is larger than max length" \
             " of buffer: %zu", \
             src->size, \
             (sizeof(type) - sizeof(src->size))); \
        return TSS2_MU_RC_BAD_SIZE; \
    } \
\
    LOG_DEBUG(\
         "Marshalling " #type " from 0x%" PRIxPTR " to buffer 0x%" PRIxPTR \
         " at index 0x%zx, buffer size %zu, object size %u", \
         (uintptr_t)&src, \
         (uintptr_t)buffer, \
         local_offset, \
         buffer_size, \
         src->size); \
\
    rc = Tss2_MU_UINT16_Marshal(src->size, buffer, buffer_size, &local_offset); \
    if (rc) \
        return rc; \
\
    if (src->size) { \
        memcpy(&buffer[local_offset], ((TPM2B *)src)->buffer, src->size); \
        local_offset += src->size; \
    } \
\
    if (offset != NULL) { \
        *offset = local_offset; \
        LOG_DEBUG("offset parameter non-NULL, updated to %zu", *offset); \
    } \
\
    return TSS2_RC_SUCCESS; \
}

2)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;
}

3)files_save_bytes_to_file

files_save_bytes_to_file在上边1)中已经分析过了,此处不再赘述。

4)tpm2_tool_output

tpm2_tool_output函数在lib/tpm2_tool_output.h中,代码如下:

/**
 * prints output to stdout respecting the quiet option.
 * Ie when quiet, don't print.
 * @param fmt
 *  The format specifier, ala printf.
 * @param ...
 *  The varargs, just like printf.
 */
#define tpm2_tool_output(fmt, ...)                   \
    do {                                        \
        if (output_enabled) {                   \
            printf(fmt, ##__VA_ARGS__);         \
        }                                       \
    } while (0)

#endif

5)tpm2_util_print_tpm2b

tpm2_util_print_tpm2b函数在lib/tpm2_util.h中,代码如下:

/**
 * Prints a TPM2B as a hex dump respecting the -Q option
 * to stdout.
 *
 * @param buffer the TPM2B to print.
 */
#define tpm2_util_print_tpm2b(b) _tpm2_util_print_tpm2b((TPM2B *)b)
static inline void _tpm2_util_print_tpm2b(TPM2B *buffer) {

    return tpm2_util_hexdump(buffer->buffer, buffer->size);
}

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

void tpm2_util_hexdump(const BYTE *data, size_t len) {

    if (!output_enabled) {
        return;
    }

    tpm2_util_hexdump2(stdout, data, len);
}

tpm2_util_hexdump2函数就在上边,代码如下:

void tpm2_util_hexdump2(FILE *f, const BYTE *data, size_t len) {

    size_t i;
    for (i = 0; i < len; i++) {
        fprintf(f, "%02x", data[i]);
    }
}

别看函数不少,实际上功能很简单,就是打印出name的十六进制数据。

6)files_save_tpm_context_to_path

files_save_tpm_context_to_path函数同样在lib/files.c中,代码如下:

tool_rc files_save_tpm_context_to_path(ESYS_CONTEXT *context, ESYS_TR handle,
        const char *path) {

    FILE *f = fopen(path, "w+b");
    if (!f) {
        LOG_ERR("Error opening file \"%s\" due to error: %s", path,
                strerror(errno));
        return tool_rc_general_error;
    }

    tool_rc rc = files_save_tpm_context_to_file(context, handle, f);
    fclose(f);
    return rc;
}

files_save_tpm_context_to_file函数就在上边,代码如下:

tool_rc files_save_tpm_context_to_file(ESYS_CONTEXT *ectx, ESYS_TR handle,
        FILE *stream) {

    TPMS_CONTEXT *context = NULL;

    tool_rc rc = tpm2_context_save(ectx, handle, &context);
    if (rc != tool_rc_success) {
        return rc;
    }

    bool result = files_save_context(context, stream);
    free(context);
    return result ? tool_rc_success : tool_rc_general_error;
}

tpm2_context_save函数在lib/tpm2.c中,代码如下:

tool_rc tpm2_context_save(ESYS_CONTEXT *esys_context, ESYS_TR save_handle,
        TPMS_CONTEXT **context) {

    TSS2_RC rval = Esys_ContextSave(esys_context, save_handle, context);
    if (rval != TSS2_RC_SUCCESS) {
        LOG_PERR(Esys_ContextSave, rval);
        return tool_rc_from_tpm(rval);
    }

    return tool_rc_success;
}

files_save_context函数在lib/files.c中,代码如下:

/*
 * Current version to write TPMS_CONTEXT to disk.
 */
#define CONTEXT_VERSION 1

bool files_save_context(TPMS_CONTEXT *context, FILE *stream) {

    /*
     * Saving the TPMS_CONTEXT structure to disk, format:
     * TPM2.0-TOOLS HEADER
     * U32 hierarchy
     * U32 savedHandle
     * U64 sequence
     * U16 contextBlobLength
     * BYTE[] contextBlob
     */
    bool result = files_write_header(stream, CONTEXT_VERSION);
    if (!result) {
        LOG_ERR("Could not write context file header");
        goto out;
    }

    // UINT32
    result = files_write_32(stream, context->hierarchy);
    if (!result) {
        LOG_ERR("Could not write hierarchy");
        goto out;
    }

    result = files_write_32(stream, context->savedHandle);
    if (!result) {
        LOG_ERR("Could not write savedHandle");
        goto out;
    }
    LOG_INFO("Save TPMS_CONTEXT->savedHandle: 0x%x", context->savedHandle);

    // UINT64
    result = files_write_64(stream, context->sequence);
    if (!result) {
        LOG_ERR("Could not write sequence");
        goto out;
    }

    // U16 LENGTH
    result = files_write_16(stream, context->contextBlob.size);
    if (!result) {
        LOG_ERR("Could not write contextBob size");
        goto out;
    }

    // BYTE[] contextBlob
    result = files_write_bytes(stream, context->contextBlob.buffer,
            context->contextBlob.size);
    if (!result) {
        LOG_ERR("Could not write contextBlob buffer");
    }
    /* result is set by file_write_bytes() */

out:
    return result;
}

这里要列出一下TPMS_CONTEXT的定义,在/usr/local/include/tss2/tss2_tpm2_types.h中,如下:

/* Definition of TPMS_CONTEXT Structure */
typedef struct TPMS_CONTEXT TPMS_CONTEXT;
struct TPMS_CONTEXT {
    UINT64 sequence;                /* the sequence number of the context. NOTE Transient object contexts and session contexts used different counters. */
    TPMI_DH_CONTEXT savedHandle;    /* a handle indicating if the context is a session object or sequence objectSee Context Handle Values */
    TPMI_RH_HIERARCHY hierarchy;    /* the hierarchy of the context */
    TPM2B_CONTEXT_DATA contextBlob; /* the context data and integrity HMAC */
};

至此,process_output函数的整体流程就基本分析完了。也就意味着tpm2_tool_onrun函数全部分析完了。


http://www.kler.cn/a/9972.html

相关文章:

  • Docker网络和overlay的基础讲解
  • WPF 应用程序中使用 Prism 框架时,有多种方式可以注册服务和依赖项
  • Nebula NGQL语言的使用 一
  • Mysql数据类型面试题15连问
  • 重学SpringBoot3-整合 Elasticsearch 8.x (三)使用Repository
  • Matlab实现鹈鹕优化算法(POA)求解路径规划问题
  • 【二分汇总】
  • 全国青少年信息素养大赛2023年python·选做题模拟二卷
  • 「计算机控制系统」2. 采样与数据保持
  • houjie-cpp面向对象
  • 刷题day54:柱形图中最大矩形
  • Java多线程基础面试总结(一)
  • 【数据挖掘与商务智能决策】第十一章 AdaBoost与GBDT模型
  • 数字孪生智慧应急怎么实现?
  • 运行时内存数据区之虚拟机栈——操作数栈
  • 你真正了解低代码么?(国内低代码平台状况分析)
  • 国家出手管人工智能AI了
  • Python数据分析案例24——基于深度学习的锂电池寿命预测
  • Difference between HTTP1.0 and HTTP1.1
  • Spring 之依赖注入底层原理
  • like字符通配符%_、查询空值、去重、and、or、MySQL数据库 - 单表查询(二)(头歌实践教学平台)
  • 【数据结构】栈各个接口的实现
  • 详解AUTOSAR:Green Hills Software(GHS)集成DaVinci Configurator生成的代码(RH850)(环境配置篇—1)
  • springboot+vue学生选课管理系统
  • 循环依赖详解及解决方案
  • 闭包和继承