TCSSM源码阅读

启动度量模块

tckx_tcf_bmeasure.h

  • #define MAX_BOOT_HASH_VERSION_NUMBER 8: 最大boot hash 版本数,例如 BIOS、bootloader、kernel 升级后 hash 会变,为了兼容多个合法版本,基准库里一个条目可以保存多个 hash

  • #define MAX_BOOT_EXTERN_SIZE 255

  • #define MAX_BOOT_REFERENCE_ITEM_SIZE (sizeof (struct boot_ref_item) + DEFAULT_HASH_SIZE * MAX_BOOT_HASH_VERSION_NUMBER + MAX_BOOT_EXTERN_SIZE + MAX_PATH_LENGTH)

    定义启动基准项最多占多大内存,

    1
    sizeof(struct boot_ref_item)
    • 固定头部结构大小
    1
    DEFAULT_HASH_SIZE * MAX_BOOT_HASH_VERSION_NUMBER
    • hash 数组最大空间
    1
    MAX_BOOT_EXTERN_SIZE
    • 扩展字段最大空间
    1
    MAX_PATH_LENGTH
    • 名称或路径字段最大空间

定义了存储启动度量存放PCR和扩展PCR的结构体

1
2
3
4
5
6
7
8
9
10
11
struct boot_ref_item_user{
int hash_length; //单个hash长度
int hash_number; //总hash数量
int stage; //启动阶段
int is_control;//bool 控制策略,语义上为bool值,说明阻断启动或报警
int is_enable;//bool 是否启用
char *hash;//这是一个连续缓冲区,总长度为hash_length *hash_number,可能存了多个 hash,挨着排放
char *name; //基准项名称
int extend_size; //扩展区长度
char *extend_buffer; //扩展数据指针
};

定义启动度量结果

1
2
3
4
5
6
7
8
struct boot_measure_record_user{
int hash_length; //最终hash长度
int stage; //启动阶段
uint32_t result; //结果
uint64_t measure_time; //度量时间
char hash[DEFAULT_HASH_SIZE]; //单次测量结果
char *name; //对应对象名称
};

定义了各个启动度量函数,下一节详细说明

tckx_tcf_bmeasure.c

tckx_tcf_prepare_update_boot_measure_references

整理并生成一份启动度量基准值的更新数据包,函数流程:
mermaid-diagram

具体来说的话

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
int tckx_tcf_prepare_update_boot_measure_references(
const struct boot_ref_item_user *references,int num,
unsigned char *tpcm_id,int tpcm_id_length,
int action, uint64_t replay_counter,
struct boot_references_update **obuffer,int *olen)
{
int i = 0;
int ret = 0;
int ref_opt = 0;
int name_length = 0;
int item_size = 0;
int hash_total_length = 0;
struct boot_ref_item *ref = NULL;
struct boot_references_update *ref_update = NULL;
//防错处理:
if ((num && !references) || !tpcm_id || !olen) return TCDEF_TCF_ERROR_INVALID_PARAM;
if (tpcm_id_length > MAX_TPCM_ID_SIZE){
tckx_error ("tpcm_id_length is too long (%d > %d)\n", tpcm_id_length, MAX_TPCM_ID_SIZE);
return TCDEF_TCF_ERROR_INPUT_EXCEEDED;
}//end
//申请存放打包后数据的内存
if (NULL == (ref_update = tcutils_malloc (sizeof (struct boot_references_update) + MAX_BOOT_REFERENCE_ITEM_SIZE * num))){
tckx_error ("No mem for ref update data!\n");
return TCDEF_TCF_ERROR_NO_MEMORY;
}//end
memset (ref_update, 0, sizeof (struct boot_references_update) + MAX_BOOT_REFERENCE_ITEM_SIZE * num);
for (i = 0; i < num; i ++){
ref = (struct boot_ref_item *)(ref_update->data + ref_opt);
//针对当前数据进行合法性检查
if (!references[i].name || !references[i].hash){
tcutils_free (ref_update);
return TCDEF_TCF_ERROR_INVALID_PARAM;
}
if ((references[i].hash_number < 0) || (references[i].hash_number > MAX_BOOT_HASH_VERSION_NUMBER)){
tckx_error ("Invalid hash version number: %d\n", references[i].hash_number);
tcutils_free (ref_update);
return TCDEF_TCF_ERROR_INVALID_PARAM;
}
if (references[i].hash_length != DEFAULT_HASH_SIZE){
tckx_error ("Invalid hash_length: %d\n", references[i].hash_length);
tcutils_free (ref_update);
return TCDEF_TCF_ERROR_INVALID_PARAM;
}
if (references[i].extend_size && !references[i].extend_buffer){
tckx_error ("extend_size: %d, extend_buffer: %p\n", references[i].extend_size, references[i].extend_buffer);
tcutils_free (ref_update);
return TCDEF_TCF_ERROR_INVALID_PARAM;
}
if (references[i].extend_buffer
&& ((references[i].extend_size <= 0)
|| (references[i].extend_size > MAX_BOOT_EXTERN_SIZE))){
tckx_error ("Invalid extend_size: %d\n", references[i].extend_size);
tcutils_free (ref_update);
return TCDEF_TCF_ERROR_INVALID_PARAM;
}//end
//计算当前数据实际占用多少字节
//算出名字长度并检查是否超长
name_length = strlen ((const char *)references[i].name) + 1;
if (name_length > MAX_PATH_LENGTH){
tckx_error ("Invalid name_length: %d\n", name_length);
tcutils_free (ref_update);
return TCDEF_TCF_ERROR_INVALID_PARAM;
}//end
//算出所有hash加起来的长度
hash_total_length = references[i].hash_length * references[i].hash_number;//end
//计算总长度,强制把扩展数据和名字占据的长度补齐到4的整数倍。底层硬件在读取4字节对齐的内存时才不会出错。
item_size = sizeof (struct boot_ref_item) + hash_total_length
+ TCUTILS_ALIGN_SIZE (references[i].extend_size + name_length, 4);//end
//检查会不会超过一开始申请的总内存容量
if ((ref_opt + item_size) > MAX_BOOT_REFERENCE_ITEM_SIZE * num){
tckx_error ("Invalid item data\n");
tcutils_free (ref_update);
return TCDEF_TCF_ERROR_INVALID_PARAM;
}//end
//使用htons将数字转换成网络字节序
ref->be_hash_length = htons (references[i].hash_length);//end
//验证 is_enable 和 is_control 是不是合法的布尔值
if (!is_bool_value_legal(references[i].is_enable)){
tckx_error ("Invalid item data, is_enable:%d, not in (ture,false)\n", references[i].is_enable);
tcutils_free (ref_update);
return TCDEF_TCF_ERROR_INVALID_PARAM;
}
if (!is_bool_value_legal(references[i].is_control)){
tckx_error ("Invalid item data, is_control:%d, not in (ture,false)\n", references[i].is_control);
tcutils_free (ref_update);
return TCDEF_TCF_ERROR_INVALID_PARAM;
}//end
//使用左移操作 << 和按位或操作 |,把这两个布尔状态压缩进 be_flags 这一个16位的变量里
ref->be_flags = htons ((references[i].is_enable << BOOT_REFERENCE_FLAG_ENABLE)
| (references[i].is_control << BOOT_REFERENCE_FLAG_CONTROL));//end
//随后把阶段值 stage、扩展数据大小等属性都用 htons 转换格式后赋给当前内存块 ref
ref->be_name_length = htons (name_length);
ref->be_hash_number = htons (references[i].hash_number);
if ((references[i].stage < 0) || (references[i].stage > ((1 << (sizeof(ref->be_stage)*8)) - 1))){
tckx_error ("Invalid stage : %d\n", references[i].stage);
tcutils_free (ref_update);
return TCDEF_TCF_ERROR_INVALID_PARAM;
}
ref->be_stage = htons (references[i].stage);
ref->be_extend_size = htons (references[i].extend_size);//end
//把实质性的内容搬进内存
memcpy (ref->data, references[i].hash, references[i].hash_length * references[i].hash_number); /** hash */
if (references[i].extend_buffer) memcpy (ref->data + hash_total_length, references[i].extend_buffer, references[i].extend_size); /** extern data */
memcpy (ref->data + hash_total_length + references[i].extend_size, references[i].name, name_length); /** name */
//把写入游标向后移动 item_size 个字节,开始下一次循环
ref_opt += item_size;//end
//end
}
//逐个填写大内存的全局头部
ref_update->be_size = htonl (sizeof (struct boot_references_update));//头部结构体本身的大小
ref_update->be_action = htonl (action);//操作类型
ref_update->be_replay_counter = htonll (replay_counter);//防重放计数
ref_update->be_item_number = htonl (num);//处理的条目总数
ref_update->be_data_length = htonl (ref_opt);//
memcpy (ref_update->tpcm_id, tpcm_id, tpcm_id_length);
*obuffer = ref_update;
*olen = sizeof (struct boot_references_update) + ref_opt;
return ret;
}

tckx_tcf_update_boot_measure_references

把在上一个函数里打包好的基准值数据包,下发给底层去执行,同时在本地留一份文件备份

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
int tckx_tcf_update_boot_measure_references(struct boot_references_update *references,
const char *uid, int auth_type,
int auth_length, unsigned char *auth)
{
int ret = 0;
int status = 0;
unsigned int references_len = 0;
char file_path[MAX_PATH_LENGTH] = {0};
//上一个函数为了适应底层,把长度信息转换成了大端序。这里为了能在普通系统里做加法计算,调用 ntohl 把大端序换回我们系统正常的数字,加上头部大小,算出整个数据包的真实总长度。
references_len = sizeof(struct boot_references_update) + ntohl(references->be_data_length);//end
//调用 tckx_get_record_file_path,根据策略类型拿到本地存放备份的具体路径。
tckx_get_record_file_path(TC_POLICY_TYPE_BMEASURE_REF, file_path);//end
//调用tckx_save_policy_to_file,把完整的数据包连同用户的认证信息(密码或密钥等),一起写进刚才获取到的本地文件里。
tckx_save_policy_to_file(file_path, references_len, (char *)references,
uid, auth_type, auth_length, auth);//end
//调用tckx_tcs_update_boot_measure_references将数据包发送给TCS层进行处理,底层处理结果会直接赋值给ret
ret = tckx_tcs_update_boot_measure_references(references, uid, auth_type, auth_length, auth);//end
//这里如果返回失败了,为了防止本地账本和底层实际状态对不上,立刻调用 tcutils_sys_remove_files_default 把刚才第二步存的本地文件删掉。然后把状态标记为失败,跳到out结束。
if (ret) {
tcutils_sys_remove_files_default(file_path);
status = SET_POLICY_FAIL;
goto out;
}
out:
tckx_write_version_notices(htonll(references->be_replay_counter),
TC_POLICY_TYPE_BMEASURE_REF, status);
return ret;
}

函数将数据包通过tckx_tcs_update_boot_measure_references发送给TCS层进行处理,此函数具体流程在下一节进行分析,点击此处快速跳转

TCS

transmit.c

tpcm_transmit


TCSSM源码阅读
http://yzsandw.com/2026/03/05/TCSSM源码阅读/
作者
5Y2z
发布于
2026年3月5日
许可协议