tpm_emulator 搭建 TPM 仿真环境

版权声明:欢迎转载,不必客气。 https://blog.csdn.net/CSDN_FengXingwei/article/details/89342797

1. 平台环境

1.1. 系统平台

宿主机系统:Windows 10 Pro
虚拟机工具:VMware® Workstation 15 Pro
虚拟机系统:CentOS Linux release 7.6.1810 (Core) 64位
本文在 centos 虚拟机上搭建 TPM 仿真环境。

1.2. TPM 仿真环境结构

下面是TPM仿真环境软件包依赖关系图,搭建环境应该是由下至上按部就班的安装。
在这里插入图片描述

2. cmake

2.1. cmake 简介

CMake 是一个跨平台的自动化建构系统,它使用一个名为 CMakeLists.txt 的文件来描述构建过程,可以产生标准的构建文件,如 Unix 的 Makefile 或Windows Visual C++ 的 projects/workspaces 。文件 CMakeLists.txt 需要手工编写,也可以通过编写脚本进行半自动的生成。CMake 提供了比 autoconfig 更简洁的语法。在 linux 平台下使用 CMake 生成 Makefile 并编译的流程如下:
(1)编写 CmakeLists.txt。
(2)执行命令“cmake PATH”或者“ccmake PATH”生成 Makefile ( PATH 是 CMakeLists.txt 所在的目录 )。
(3)使用 make 命令进行编译。

2.2. 安装 cmake

[root@linuxprobe:~]# yum -y install cmake

3. m4

3.1. m4 简介

m4 是一种宏处理器,它扫描用户输入的文本并将其输出,期间如果遇到宏就将其展开后输出。宏有两种,一种是内建的,另一种是用户自定义的,它们能接受任意数量的参数。除了做展开宏的工作之外,m4 内建的宏能够加载文件,执行 Shell 命令,做整数运算,操纵文本,形成递归等等。m4 可用作编译器的前端,或者单纯作为宏处理器来用。

3.2. 安装 m4

[root@linuxprobe:~]# yum -y install m4

4. GNU MP Library

4.1. GMP 简介

gmp是一个可以进行任意精度算术的自由库,可以操作有符号整数、有理数和浮点数。除了运行gmp的机器中可用内存所暗示的精度外,没有实际限制。gmp有一套丰富的功能,这些功能有一个常规的接口(本文不研究这个接口)。
gmp的主要目标应用是密码学应用与研究、互联网安全应用、代数系统、计算代数研究等。
gmp基于m4,所以在安装gmp之前要先安装m4。

4.2. 安装 GMP

下载地址:http://gmplib.org

我下载的版本:gmp-6.1.2.tar.bz2

执行下列命令进行编译和安装:

[root@linuxprobe:~]# tar -jxvf gmp-6.1.2.tar.bz2
[root@linuxprobe:~]# cd gmp-6.1.2
[root@linuxprobe:~/gmp-6.1.2]# ./configure
[root@linuxprobe:~/gmp-6.1.2]# make
[root@linuxprobe:~/gmp-6.1.2]# make check
[root@linuxprobe:~/gmp-6.1.2]# make install

Tips:
还有 gmp-6.1.2.tar.lz 版本的压缩包,它是使用 lzip 工具生成的,需要使用 lunzip 工具进行解压。
lzip下载地址:http://www.nongnu.org/lzip/lzip.html
lunzip下载地址:http://www.nongnu.org/lzip/lunzip.html

5. TPM_Emulator

下载地址:https://github.com/PeterHuewe/tpm-emulator/releases

我下载的版本:tpm-emulator-0.7.5.tar.gz

该程序主要包含三个部分:
(1)tpmd:实现 TPM 仿真器的用户空间应用程序,可以通过 Unix 域套接字(Unix)或命名管道(Windows)进行访问。
(2)tpmd_dev:一个内核模块,它提供设备 /dev/tpm 以实现向后兼容,并将收到的命令转发给 tpmd(仅限Unix和Mac OS X)。

向后兼容(Backward Compatibility),又称作向下兼容(Downward Compatibility)。在计算机中指在一个程序或者类库更新到较新的版本后,用旧的版本程序创建的文档或系统仍能被正常操作或使用,或在旧版本的类库的基础上开发的程序仍能正常编译运行的情况。

(3)tddl:TPM 仿真器的 TSS 符合设备驱动程序库。
在这里插入图片描述

5.1. 编译和安装 TPM_Emulator

TPM 仿真器包的编译和安装基于 CMake 构建环境(2.6或更高版本),并要求在您的系统上正确安装 GNU MP 库(版本4.0或更高版本)。因为前面已经安装过了,所以这里直接执行下列命令进行编译和安装:

[root@linuxprobe:~]# tar –zxvf tpm-emulator-0.7.5.tar.gz
[root@linuxprobe:~]# cd tpm-emulator-0.7.5
[root@linuxprobe:~/tpm-emulator-0.7.5]# mkdir build
[root@linuxprobe:~/tpm-emulator-0.7.5]# cd build
[root@linuxprobe:~/tpm-emulator-0.7.5/build]# cmake ../
[root@linuxprobe:~/tpm-emulator-0.7.5/build]# make
[root@linuxprobe:~/tpm-emulator-0.7.5/build]# make install

我在执行 make 时遇到的错误:

[root@linuxprobe:~/tpm-emulator-0.7.5/build]# make
...省略部分输出...
[ 97%] Generating linux/tpmd_dev.ko
make: *** /lib/modules/3.10.0-957.10.1.el7.x86_64/build: 没有那个文件或目录。 停止。
make[3]: *** [all] 错误 2
make[2]: *** [tpmd_dev/linux/tpmd_dev.ko] 错误 2
make[1]: *** [tpmd_dev/CMakeFiles/tpmd_dev.dir/all] 错误 2
make: *** [all] 错误 2

原因:

提示 /lib/modules/3.10.0-957.10.1.el7.x86_64/build 软链接没有指向正确的 kernel source,后来知道因为那个文件根本就不存在,我们需要下载它。

解决方法:
(1)看一下 build 软链接指向哪个文件:

[root@linuxprobe:~]# cd /lib/modules/3.10.0-957.10.1.el7.x86_64/
[root@linuxprobe:/lib/modules/3.10.0-957.10.1.el7.x86_64]# ll
total 3244
lrwxrwxrwx.  1 root root     43 Mar  21 15:03 build -> /usr/src/kernels/3.10.0-957.10.1.el7.x86_64

在 centos 7.x 下 build -> /usr/src/kernels/3.10.0-957.10.1.el7.x86_64 不停地闪烁,说明 /usr/src/kernels/3.10.0-957.10.1.el7.x86_64 不存在。

(2)进入 /usr/src/kernels/ 目录,看一下有没有相应的内核开发包 3.10.0-957.10.1.el7.x86_64:

[root@linuxprobe:~]# cd /usr/src/kernels/
[root@linuxprobe:/usr/src/kernels]# ll
total 0

没有则下载。

(3)下载 3.10.0-957.10.1.el7.x86_64 内核开发包:

[root@linuxprobe:/usr/src/kernels]# yum -y install kernel-devel-$(uname -r)
[root@linuxprobe:/usr/src/kernels]# ll
total 4
drwxr-xr-x. 22 root root 4096 Apr 16 17:43 3.10.0-957.10.1.el7.x86_64

再次执行 make 就没问题了。


5.2. 初始化 TPM_Emulator

TPM的启动模式(参见TPM规范第1部分)由启动模式参数定义,可以设置为clear,save(默认)或deactivated,对应的中文意思分别是清除,保存和停用。 下面简单介绍tpmd的用法以及参数的含义:

usage: tpmd [-d] [-f] [-s storage file] [-u unix socket name]
            [-o user name] [-g group name] [-h] [startup mode]
参数的含义:
d:启用调试模式
f:强制应用程序在前台运行
s:要使用的存储文件(默认值:/var/lib/tpm/tpm_emulator-1_2_0_7)
u:要使用的unix套接字名称(默认值:/var/run/tpm/tpmd_socket:0)
o:应用程序运行的有效用户
g:应用程序应运行的有效组
h:打印此帮助信息
startup mode:必须是“clear”,“save”(默认)或“deactivated”

如果模拟器以“save”模式启动并且无法加载先前存储的TPM状态,则它将进入“fail-stop”模式并且必须重新加载。 因此,第一次启动TPM仿真器时,参数必须设置为“clear”。 想要恢复处于“fail-stop”模式的TPM仿真器,首先将其停用,然后以“clear”模式重新加载,我们执行下列命令进行初始化:

[root@linuxprobe:~]# tpmd deactivated
[root@linuxprobe:~]# killall tpmd
[root@linuxprobe:~]# tpmd clear

5.3. 启动 TPM_Emulator

要想在 Unix 或 Mac OS X 上使用 TPM 仿真器,必须先启动 TPM 仿真器的守护程序(tpmd)并加载 TPM 设备转发模块(tpmd_dev)。 我们执行下列命令进行启动:

[root@linuxprobe:~]# modprobe tpmd_dev
[root@linuxprobe:~]# tpmd -f -d

注释:
(1)若在执行第一条命令时遇到:Module tpmd_dev not found,则执行命令:depmod -a

(2)modprobe命令:
modprobe命令用于智能地向内核中加载模块或者从内核中移除模块。
modprobe可载入指定的个别模块,或是载入一组相依的模块。modprobe会根据depmod所产生的相依关系,决定要载入哪些模块。若在载入过程中发生错误,在modprobe会卸载整组的模块。

(3)depmod命令:
depmod命令可产生模块依赖的映射文件,在构建嵌入式系统时,需要由这个命令来生成相应的文件,由modprobe使用。


启动时遇到的错误:

[root@linuxprobe:~]# tpmd -f -d
...省略部分输出...
tpmd.c:313: Error: bind(/var/run/tpm/tpmd_socket:0) failed: Address already in use

解决方法:

[root@linuxprobe:~]# rm -f /var/run/tpm/tpmd_socket:0

再次启动 tpmd 就没有问题了。


6. TSS 协议栈

下载地址:https://sourceforge.net/projects/trousers/files/

我下载的版本:trousers-0.3.14.tar.gz

该程序是由 IBM 创建和发布的开源 TCG 软件栈。

6.1. 编译和安装 Trousers


Tips:
如果直接解压 trousers 的压缩包,它的各种文件会分散在父目录里面,所以要在解压时为其指定一个解压目录。当然,如果不小心直接解压了,也可以使用下列命令撤销解压操作:

[root@linuxprobe:~]# tar -zxvf trousers-0.3.14.tar.gz #解压
[root@linuxprobe:~]# tar -tf trousers-0.3.14.tar.gz | xargs rm -rf #撤销解压

我们先为 trousers 创建一个目录,再将其进行解压:

[root@linuxprobe:~]# mkdir trousers-0.3.14
[root@linuxprobe:~]# tar -zxvf trousers-0.3.14.tar.gz -C trousers-0.3.14
[root@linuxprobe:~]# cd trousers-0.3.14

看一下 README 文件,并按要求安装如下的依赖包:

automake > 1.4
autoconf > 1.4
pkgconfig
libtool
gtk2-devel
openssl-devel >= 0.9.7
pthreads library (glibc-devel)

安装完上述的依赖包后再执行下面的命令进行编译和安装:

[root@linuxprobe:~/trousers-0.3.14]# sh bootstrap.sh #没有则不用执行
[root@linuxprobe:~/trousers-0.3.14]# ./configure
[root@linuxprobe:~/trousers-0.3.14]# make
[root@linuxprobe:~/trousers-0.3.14]# make install

Tips:
网上有说需要修改 Makefile.amMakefile.in 文件,但那些都是 trousers-0.3.8 版本的教程,那个版本会遇到 Werror、ld 链接库等报错的问题。本文使用 trousers-0.3.14 版本,没有修改 Makefile.* 文件,直接编译安装成功无报错。

6.2. 启动 TCSD

Tips:
在执行下列命令之前需要先启动 TPM_Emulator,否则会提示找不到设备。

[root@linuxprobe:~]# tcsd -e -f

启动时遇到的错误:

[root@linuxprobe:~]# tcsd -e -f
...省略部分输出...
TCSD TCS ERROR: TCS GetCapability failed with result = 0x1c

解决方法:
带上 clear 参数重启 tpm-emulator:

[root@linuxprobe:~]# tpmd -d -f clear

再次启动 tcsd 就没有问题了。

7. tpm-tools

7.1. tpm-tools 简介

tpm-tools 是一组管理和利用可信计算组织的 TPM 硬件的工具。 TPM 硬件可以安全地创建,存储和使用 RSA密钥(不会暴露在内存中),使用加密哈希等来验证平台的软件状态。该程序包含的工具允许平台管理员管理和诊断平台的 TPM 硬件。 此外,该程序还包含命令,以利用 openCryptoki 项目中实现的 TPM PKCS#11 接口中提供的某些功能。

7.2. 安装 tpm-tools

[root@linuxprobe:~]# yum -y install tpm-tools

8. 测试 TPM 环境是否搭建成功

(1)先启动 tpmd
(2)再启动 tcsd
(3)最后使用 tpm-tools 工具的命令加以验证:

[root@linuxprobe:~]# tpm_version
[root@linuxprobe:~]# tpm_getpubek
[root@linuxprobe:~]# tpm_takeownership

要运行 tpm-tools 工具的命令,必须先启动 tpmd 和 tcsd,缺一不可。

9. 运行测试程序

9.1. 在 tpm-emulator-0.7.5/tddl/ 目录下有测试程序

在编译时链接 libtddl.a 静态库,编译时没有问题,运行时出现如下错误:

[root@linuxprobe:~/tpm-emulator-0.7.5/tddl] # ll
total 36
-rw-rw-r--. 1 root root 1150 Sep 16  2018 CMakeLists.txt
-rw-rw-r--. 1 root root 8129 Sep 16  2018 tddl.c
-rw-rw-r--. 1 root root 7313 Sep 16  2018 tddl-tpm-emulator.h
-rw-rw-r--. 1 root root 2245 Sep 16  2018 tddl_unix.h
-rw-rw-r--. 1 root root 2202 Sep 16  2018 tddl_windows.h
-rw-rw-r--. 1 root root 4887 Sep 16  2018 test_tddl.c
[root@linuxprobe:~/tpm-emulator-0.7.5/tddl] # gcc -o test_tddl test_tddl.c -ltddl
[root@linuxprobe:~/tpm-emulator-0.7.5/tddl] # ll
total 56
-rw-rw-r--. 1 root root  1150 Sep 16  2018 CMakeLists.txt
-rw-rw-r--. 1 root root  8129 Sep 16  2018 tddl.c
-rw-rw-r--. 1 root root  7313 Sep 16  2018 tddl-tpm-emulator.h
-rw-rw-r--. 1 root root  2245 Sep 16  2018 tddl_unix.h
-rw-rw-r--. 1 root root  2202 Sep 16  2018 tddl_windows.h
-rwxr-xr-x. 1 root root 18424 Apr 17 20:08 test_tddl
-rw-rw-r--. 1 root root  4887 Sep 16  2018 test_tddl.c
[root@linuxprobe:~/tpm-emulator-0.7.5/tddl] # ./test_tddl 
Error: Tddli_GetStatus() failed: unknown error (1006)
PS:解决后再更新???

9.2. 对TSS协议栈进行测试

9.2.1. 测试程序
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <tss/platform.h>
#include <tss/tss_error.h>
#include <tss/tss_defines.h>
#include <tss/tss_structs.h>
#include <tss/tss_typedef.h>
#include <tss/tss_error_basics.h>
#include <tss/tspi.h>
#include <trousers/tss.h>
#include <tss/tpm.h>

const char *get_error(TSS_RESULT res)
{
    switch(ERROR_CODE(res))
    {        
        case 0x0001L:
            return "Authentication failed";
        case TSS_SUCCESS:
            return "success";
        case TSS_E_INVALID_HANDLE:
            return "hContext or phObject is an invalid handle";
        case TSS_E_BAD_PARAMETER:
            return "persistentstoragetype is not valid/One or more parameters is incorrect";
        case TSS_E_INTERNAL_ERROR:
            return "an error occurred internal to the TSS";
        case TSS_E_PS_KEY_NOTFOUND:
            return "NOT FOUND SRK";
        case TSS_E_INVALID_ATTRIB_FLAG:
            return "attribflag is incorrect";
        case TSS_E_INVALID_ATTRIB_SUBFLAG:
            return "subflag is incorrect";
        case TSS_E_INVALID_ATTRIB_DATA:
            return "ulAttrib is incorrect";
        case TSS_E_KEY_ALREADY_REGISTERED:
            return "UUID used";
        case TSS_E_KEY_NOT_LOADED:
            return "the addressed key is currently not loaded";
        default:
            return "unknown error";
    }
}

int main(int argc,char *argv)
{
    TSS_RESULT result;
    TSS_HTPM hTPM;
    TSS_HCONTEXT hContext;
    TSS_HPOLICY hownerpolicy,hSRKPolicy;
    TSS_HKEY hSRK;
    TSS_HKEY hkey,hkey2;
    TSS_UUID SRK_UUID=TSS_UUID_SRK;
    TSS_FLAG initFlags;            //密钥标记
    TSS_UUID bindkeyUUID=TSS_UUID_USK1;    //用户的绑定密钥

    printf("创建上下文对象......\n");
    result=Tspi_Context_Create(&hContext);
    if(result!=TSS_SUCCESS)
    {
        printf("Context_Create ERROR:%s(%04x)\n",get_error(result),result);
    }
    result=Tspi_Context_Connect(hContext,NULL);
    if(result!=TSS_SUCCESS)
    {
        printf("Context_Connect ERROR:%s(%04x)\n",get_error(result),result);
    }

    printf("创建TPM对象......\n");
    result=Tspi_Context_GetTpmObject(hContext,&hTPM);
    if(result!=TSS_SUCCESS)
    {
        printf("Tspi_Context_GetTpmObject ERROR:%s(%04x)\n",get_error(result),result);
    }
    result=Tspi_GetPolicyObject(hTPM,TSS_POLICY_USAGE,&hownerpolicy);
    if(result!=TSS_SUCCESS)
    {
        printf("Tspi_GetPolicyObject ERROR:%s(%04x)\n",get_error(result),result);
    }
    result=Tspi_Policy_SetSecret(hownerpolicy,TSS_SECRET_MODE_POPUP,0,NULL);
    if(result!=TSS_SUCCESS)
    {
        printf("Tspi_Policy_SetSecret ERROR:%s(%04x)\n",get_error(result),result);
    }
    printf("载入SRK密钥......\n");
    result=Tspi_Context_LoadKeyByUUID(hContext,TSS_PS_TYPE_SYSTEM,SRK_UUID,&hSRK);
    if(result!=TSS_SUCCESS)
    {
        printf("Tspi_Context_LoadKeyByUUID ERROR:%s(%04x)\n",get_error(result),result);
    }
    printf("获取SRK的策略对象......");
    result=Tspi_GetPolicyObject(hSRK,TSS_POLICY_USAGE,&hSRKPolicy);
    if(result!=TSS_SUCCESS)
    {
        printf("Tspi_GetPolicyObject ERROR:%s(%04x)\n",get_error(result),result);
    }
    printf("设置SRK的策略授权......");
    result=Tspi_Policy_SetSecret(hSRKPolicy,TSS_SECRET_MODE_POPUP,0,NULL);
    if(result!=TSS_SUCCESS)
    {
        printf("Tspi_Policy_SetSecret ERROR:%s(%04x)\n",get_error(result),result);
    }
    printf("创建绑定密钥......\n");
    initFlags=TSS_KEY_TYPE_BIND|TSS_KEY_SIZE_512|TSS_KEY_NO_AUTHORIZATION;                //设置密钥标记
    result=Tspi_Context_CreateObject(hContext,TSS_OBJECT_TYPE_RSAKEY,initFlags,&hkey);        //创建绑定密钥
    if(result!=TSS_SUCCESS)
    {
        printf("Tspi_Context_CreateObject ERROR:%s(%04x)\n",get_error(result),result);
    }

    printf("在TPM产生密钥前,设置填充类型......\n");
    result=Tspi_SetAttribUint32(hkey,TSS_TSPATTRIB_KEY_INFO,TSS_TSPATTRIB_KEYINFO_ENCSCHEME,TSS_ES_RSAESPKCSV15);
    if(result!=TSS_SUCCESS)
    {
        printf("Tspi_SetAttribUint32 ERROR:%s(%04x)\n",get_error(result),result);
    }
    printf("产生密钥,该密钥不合PCR绑定\n");
    result=Tspi_Key_CreateKey(hkey,hSRK,0);
    if(result!=TSS_SUCCESS)
    {
        printf("Tspi_Key_CreateKey ERROR:%s(%04x)\n",get_error(result),result);
    }                

    printf("装载绑定密钥到UUID......\n");
    result=Tspi_Context_RegisterKey(hContext,hkey,TSS_PS_TYPE_USER,bindkeyUUID,TSS_PS_TYPE_SYSTEM,SRK_UUID);
    if(result!=TSS_SUCCESS)
    {
        if(ERROR_CODE(result)==TSS_E_KEY_ALREADY_REGISTERED)
        {
            printf("UUID已被使用,注销此密钥......\n");
            result=Tspi_Context_UnregisterKey(hContext,TSS_PS_TYPE_USER,bindkeyUUID,&hkey);
            if(result!=TSS_SUCCESS)
                printf("UUID注销失败 Tspi_Context_UnregisterKey ERROR :%s(%04x)\n",get_error(result),result);

            result=Tspi_Context_RegisterKey(hContext,hkey,TSS_PS_TYPE_USER,bindkeyUUID,TSS_PS_TYPE_SYSTEM,SRK_UUID);
            if(result!=TSS_SUCCESS)
                printf("Tspi_Context_RegisterKey ERROR:%s(%04x)\n",get_error(result),result);
        }
    }
    printf("SUCCESS!\n");
    Tspi_Context_Close(hContext);
    return 0;
}
9.2.2. 该程序实现的操作

创建上下文对象…
创建TPM对象…
载入SRK密钥…
获取SRK的策略对象…
设置SRK的策略授权…
创建绑定密钥…
装载绑定密钥到UUID…

9.2.3. 编译和执行

Tips:
要先启动 tpmd 和 tcsd 进程,再运行测试程序的可执行文件。

[root@linuxprobe:~/test-tpm-tss] # gcc -o generate_key generate_key.c -ltspi
[root@linuxprobe:~/test-tpm-tss] # ll
total 24
-rwxr-xr-x. 1 root root 13288 Apr 17 10:57 generate_key
-rw-r--r--. 1 root root  5267 Apr 17 10:56 generate_key.c
[root@linuxprobe:~/test-tpm-tss] # ./generate_key 
创建上下文对象......
创建TPM对象......
载入SRK密钥......
获取SRK的策略对象......设置SRK的策略授权......创建绑定密钥......
在TPM产生密钥前,设置填充类型......
产生密钥,该密钥不合PCR绑定
TSS Authentication Dialog
Enter PIN:
Tspi_Key_CreateKey ERROR:persistentstoragetype is not valid/One or more parameters is incorrect(0003)
装载绑定密钥到UUID......
UUID已被使用,注销此密钥......
SUCCESS!

遇到如下的错误:
Tspi_Key_CreateKey ERROR:persistentstoragetype is not valid/One or more parameters is incorrect(0003)

PS:解决后再更新???

猜你喜欢

转载自blog.csdn.net/CSDN_FengXingwei/article/details/89342797