TPM分析笔记(四)TPM-TSS协议栈

TPM-TSS文档下载路径

tpm2-tss Documentation

[1] TCG TSS 2.0 Overview and Common Structures Specification
[2] TCG TSS 2.0 TPM Command Transmission Interface (TCTI) API Specification
[3] TCG TSS 2.0 Marshaling/Unmarshaling API Specification
[4] TCG TSS 2.0 System API (SAPI) Specification
[5] TCG TSS 2.0 Enhanced System API (ESAPI) Specification
[6] TCG TSS 2.0 Feature API (FAPI) Specification
[7] TCG TSS 2.0 TAB and Resource Manager Specification

在这里插入图片描述This repository hosts source code implementing the Trusted Computing Group’s (TCG) TPM2 Software Stack (TSS). This stack consists of the following layers from top to bottom:

  • Feature API (FAPI) as described in the TCG Feature API (FAPI) Specification along with TCG TSS 2.0 JSON Data Types and Policy Language Specification This API is designed to be very high-level API, intended to make programming with the TPM as simple as possible. The API functions are exposed through a single library: libtss2-fapi.

  • Enhanced System API (ESAPI) as described in the TCG TSS 2.0 Enhanced System API (ESAPI) Specification This API is a 1-to-1 mapping of the TPM2 commands documented in Part 3 of the TPM2 specification. Additionally there are asynchronous versions of each command. In addition to SAPI, the ESAPI performs tracking of meta data for TPM object and automatic calculation of session based authorization and encryption values. Both the synchronous and asynchronous API are exposed through a single library: libtss2-esys.

  • System API (SAPI) as described in the TCG TSS 2.0 System Level API (SAPI) Specification This API is a 1-to-1 mapping of the TPM2 commands documented in Part 3 of the TPM2 specification. Additionally there are asynchronous versions of each command. These asynchronous variants may be useful for integration into event-driven programming environments. Both the synchronous and asynchronous API are exposed through a single library: libtss2-sys.

  • Marshaling/Unmarshaling (MU) as described in the TCG TSS 2.0 Marshaling/Unmarshaling API Specification This API provides a set of marshaling and unmarshaling functions for all data types define by the TPM library specification. The Marshaling/Unmarshaling API is exposed through a library called libtss2-mu.

  • TPM Command Transmission Interface (TCTI) as described in the TCG TSS 2.0 TPM Command Transmission Interface (TCTI) API Specification. This API provides a standard interface to transmit / receive TPM command / response buffers. It is expected that any number of libraries implementing the TCTI API will be implemented as a way to abstract various platform specific IPC mechanisms. Currently this repository provides several TCTI implementations: libtss2-tcti-device, libtss2-tcti-tbs (for Windows), libtss2-tcti-swtpm and libtss2-tcti-mssim. The former should be used for direct access to the TPM through the Linux kernel driver. The latter implements the protocol exposed by the Microsoft software TPM2 simulator.

  • The TCG TSS 2.0 Overview and Common Structures Specification forms the basis for all implementations in this project. NOTE: We deviate from this specification by increasing the value of TPM2_NUM_PCR_BANKS from 3 to 16 to ensure compatibility with TPM2 implementations that have enabled a larger than typical number of PCR banks. This larger value for TPM2_NUM_PCR_BANKS is expected to be included in a future revision of the specification.

开源软件工程

tpm-tss 代码github工程

|-- doc     : various bits of documentation\
|-- include : header files installed in $(includedir)\
|   +-- tss2      : all public headers for this project\
|-- lib     : data files used by the build or installed into $(libdir)\
|-- m4      : autoconf support macros\
|-- man     : man pages\
|-- script  : scripts used by the build or CI\
|-- src     : all source files\
|   |-- tss2-esys : enhanced system API (ESAPI) implementation\
|   |   +-- api   : ESAPI TPM API implementation\
|   |-- tss2-mu   : TPM2 type marshaling/unmarshaling (MU) API implementation\
|   |-- tss2-sys  : system API (SAPI) implementation\
|   |   +-- api   : SAPI public API implementation\
|   |-- tss2-tcti : TCTI implementations for device and mssim\
|   +-- util      : Internal utility library (e.g. logging framework)\
+-- test    : test code\
    |-- integration : integration test harness and test cases\
    |-- tpmclient   : monolithic, legacy test application\
    +-- unit        : unit tests

TPM-TSS 协议栈

TSS2.0软件栈结构

在这里插入图片描述在这里插入图片描述
TPM-TSS包含以下由高到低的几层软件:FAPI,ESAPI,SAPI,TCTI(TPM Command Transmission Interface),TAB(TPM Access Broker),RM(Resource Manager),和设备驱动

大多数的用户层引用程序基于FAPI开发就可以了,因为FAPI实现了TPM百分之八十的常用应用场景。使用这一层开发应用就像是使用JAVA,C#等高级语言开发应用一样方便。

往下一层是ESAPI,它需要你对TPM了解很深,但是同时提供了会话管理以及加解密的辅助功能。这有点像使用C++开发应用程序。

应用程序也可以直接基于SAPI这一层,但这需要你对TPM了如指掌。这就像是使用C语言编写应用程序,而不是用高级语言。它提供了TPM的所有功能,但是要想用好它你必须对TPM有很深的理解

TCTI层用于向TPM发送命令并接收TPM对命令的响应。应用可以直接通过TCTI发送命令的数据流并解析接收到的响应数据流。对于使用者来说,组装和解析完全是黑盒,完全屏蔽了数据流实现细节。

TAB这一层主要负责多线程环境下TPM资源的同步。也就是说它允许多个线程同时访问TPM而不发生冲突

因为TPM内部的存储资源非常有限,所以需要一个资源管理器RM,它的原理于虚拟内存管理类似,它可以将TPM对象和会话换进换出TPM

最后一层就是设备驱动,它主要是控制通信外设与TPM互相传输数据。如果你愿意的话,直接调用设备驱动接口来编写应用程序也是可以的,目前Linux已经集成了此驱动。

![在这里插入图片描述](https://img-blog.csdnimg.cn/4404884f42ed46a8b6d5922f5276c572.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA54uC5aWU55qE5LmM6b6f,size_20,color_FFFFFF,t_70,g_se,x_16

SAPI 软件栈结构

前面我们已经提到,TPM2.0的SAPI这一层软件使用相当于用C语言编写软件。SAPI实现了TPM2.0所有的功能。SAPI就像是C语言一样,它是一个功能强大的工具,但是需要非常专业的只是来用好它。如果只将TPM作为为可信启动服务安全模块,TPM-TSS只需要使用SAPI功能即可,不需要FAPI、EAPI等花里胡哨的功能。

TPM SAPI协议栈部分,主要分为两层,一为上层开发者提供和封装统一的调用接口(SAPI),二为上层提供了访问底层硬件资源接口(核心层-含字节流命令组装&解析、会话管理等)。

其核心的架构图如下图所示:
在这里插入图片描述
SAPI规范可以在以下网址找到:TCG TSS 2.0 System Level API (SAPI)
Specification

SAPI的主要设计目标如下:

  • 提供所有TPM功能的访问接口。
  • 可以在尽可能多的平台上使用,从高度嵌入式,内存受限的环境到多核的服务器上都可以使用。为了支持较小的应用,SAPI的代码需要考虑很多,从而可以让内存使用最小化或者提供最小化的选项。
  • 在提供所有功能的前提下,尽可能让程序员的工作容易。
  • 支持同步和异步调用。
  • SAPI的实现本身不需要申请任何内存。同时SAPI的使用者要负责申请所有SAPI使用的内存。
  • SAPI提供了四组命令:TPM命令上下文的申请,命令准备,命令执行,命令完成。这一节将描述这几组命令。在命令准备,执行和完成这几组命令中会有一些辅助函数被调用,这些函数应用于所有TPM规范第三部分定义的所有TPM命令,其他的函数则是因命令不同而不同。

TPM TSS SAPI关键API分析(持续完善中)

首先我们会概括性地介绍每一组命令。介绍这些命令时,我们会列出TPM2_GetTestResult示例的代码片段。最后我们将这些代码片段组合起来,并使用三种方法来执行TPM2_GetTestResult这个命令:单独的一次调用,异步调用,同步的多次调用。SAPI函数的代码示例要求了解会话,授权,加解密等概念,后面补充。只有当你真正理解了这些TPM功能之后,SAPI的这些函数才有意义。

命令上下文申请函数

下面要介绍的函数用于申请SAPI命令上下文数据结构的内存空间。这些难懂的数据结构用于维护TPM2.0命令执行时的状态数据。

  • Tss2_Sys_GetContextSize这个函数用于决定SAPI上下文数据结构需要多少内存空间。这个命令会返回内存空间的大小能够满足执行任何TPM2.0规范第三部分中描述的命令。或者调用者也可以提供最大的命令和响应大小,这个函数会计算所需的上下文大小。

  • Tss2_Sys_Initialize用于初始化SAPI的上下文。它需要如下四个参数:一个指向足够用于上下文的内存区域的指针;Tss2_Sys_GetContextSize返回的上下文大小;指向TCTI上下文的指针,这个上下文定义了发送命令和接收命令响应的方法;最后还有SAPI版本信息。

/** Tss2_Sys_Initialize一般和Tss2_Sys_GetContextSize结合使用
 */
int
test_invoke (TSS2_SYS_CONTEXT *sys_context)
{
    TSS2_RC rc;
    UINT32 contextSize;
    TSS2_TCTI_CONTEXT *tcti_context = NULL;
    TSS2_ABI_VERSION tstAbiVersion = { 
		TSSWG_INTEROP, 
		TSS_SYS_FIRST_FAMILY, 
		TSS_SYS_FIRST_LEVEL, 
		TSS_SYS_FIRST_VERSION 
   };

    LOG_INFO( "ABI NEGOTIATION TESTS" );

    /* Get the size needed for sys context structure. */
    contextSize = Tss2_Sys_GetContextSize( 0 );

    rc = Tss2_Sys_GetTctiContext (sys_context, &tcti_context);
    if( rc != TSS2_RC_SUCCESS )
    {
        LOG_ERROR("ABIVersion FAILED! Response Code : %x", rc);
        exit(1);
    }

    /* Initialize the system context structure. */
    tstAbiVersion.tssCreator = 0xF0000000;
    rc = Tss2_Sys_Initialize( sys_context, contextSize, 
    tcti_context, &tstAbiVersion );
    if( rc != TSS2_SYS_RC_ABI_MISMATCH )
    {
        LOG_ERROR("ABIVersion FAILED! Response Code : %x", rc);
        exit(1);
    }

    tstAbiVersion.tssCreator = TSSWG_INTEROP;
    tstAbiVersion.tssFamily = 0xF0000000;
    rc = Tss2_Sys_Initialize( sys_context, contextSize, 
    tcti_context, &tstAbiVersion );
    if( rc != TSS2_SYS_RC_ABI_MISMATCH )
    {
        LOG_ERROR("ABIVersion FAILED! Response Code : %x", rc);
        exit(1);
    }

    tstAbiVersion.tssFamily = TSS_SYS_FIRST_FAMILY;
    tstAbiVersion.tssLevel = 0xF0000000;
    rc = Tss2_Sys_Initialize( sys_context, contextSize, 
    tcti_context, &tstAbiVersion );
    if( rc != TSS2_SYS_RC_ABI_MISMATCH )
    {
        LOG_ERROR("ABIVersion FAILED! Response Code : %x", rc);
        exit(1);
    }

    tstAbiVersion.tssLevel = TSS_SYS_FIRST_LEVEL;
    tstAbiVersion.tssVersion = 0xF0000000;
    rc = Tss2_Sys_Initialize( sys_context, contextSize, 
    tcti_context, &tstAbiVersion );
    if( rc != TSS2_SYS_RC_ABI_MISMATCH )
    {
        LOG_ERROR("ABIVersion FAILED! Response Code : %x", rc);
    }


    LOG_INFO("ABIVersion Test Passed!");
    return 0;
}

命令执行函数

这一组函数用于向TPM发送命令和从TPM接收命令响应数据。命令可以被以同步或者异步的方式发送。同步发送又分为两种:3-5个函数调用;或者是完成所有事情的一次调用。支持同步,异步和单次,多次调用主要是为了支持尽可能多的应用架构。

  • Tss2_Sys_ExecuteAsync是发送命令的最基础方法。它使用TCTI发送函数来发送命令,并尽快返回。如下是一个示例:
rval = Tss2_Sys_ExecuteAsync( sysContext );
  • Tss2_Sys_ExecuteFinish是与ExecuteAsync配套的函数。它会调用TCTI函数来接收命令响应数据。这个函数有一个timeout参数用于决定要命令响应的超时时间。下面是一个响应超时设置为20ms的例子:
rval = Tss2_Sys_ExecuteFinish( sysContext, 20 );
  • Tss2_Sys_Execute是与Tss2_Sys_ExecuteAsync功能相同的异步方法。在这个函数调用之后就是 Tss2_Sys_ExecuteFinish,它同样是同步的方法,所以相当于无限大的timeout。如下是一个调用示例:
rval = Tss2_Sys_Execute( sysContext );

这一组中的最后一个函数是 Tss2_Sys_XXXX,他就是针对不同命令的一次调用完成所有任务的函数。这个函数假设对应的操作不需要授权,或者仅仅需要一个简单的口令授权,又或者是HMAC和Policy授权已经计算完成。同样地,规范第三部分中的每个命令对应一个函数。比如说,Tpm2_StartAuthSession这个命令对应的一次性调用函数就是Tss2_Sys_StartAuthSession。这个函数和Tss2_Sys_XXXX_Prepare配合使用就可以完成各种类型的授权。但是这样做的一个有意思的副作用就是命令的参数将会被标准化两次:一次在Tss2_Sys_XXXX_Prepare调用,一次是在一次性的执行函数调用中。这种设计上的妥协是因为一次性的函数需要包含Tss2_Sys_XXXX_Prepare 所具备的功能。下面是一个不需要授权的命令的一次性调用执行示例:

命令完成函数

这一组函数用于TPM命令的后处理。这些后处理包括命令响应的HMAC计算,以及在加密会话中命令响应参数的解密。

  • Tss2_Sys_GetRpBuffer需要一个指向命令响应参数数据的指针,以及参数数据的大小作为参数。知道这两个参数后,用户就可以计算命令响应的HMAC,然后与命令响应授权区域的HMAC比较。

  • Tss2_Sys_GetRspAuths用于获取命令响应授权区的数据。比如上面刚刚提到的HMAC。

完成响应数据的验证后,如果命令响应是通过加密会话传输的,就可以进一步通过Tss2_Sys_GetEncryptParam和Tss2_Sys_SetEncryptParam解密响应参数,并将它们插入到响应的数据流中,后续的反标准化(unmarshalling)操作会将它们解析成对应的数据结构。后续再分析此函数。

响应参数被解密后,数据流就可以被反标准化了。这个操作使用Tss2_Sys_XXXX_Complete。因为不同的命令有不同的响应参数,所有规范第三部分中的每个命令也对应一个函数。示例如下:

rval = Tss2_Sys_GetTestResult_Complete( sysContext, &outData, 
&testResult );

TPM TSS TCTI

Allows Connection to Various Target TPMs

在这里插入图片描述

TCTI关键API(持续完善中)

前面我们已经分析了SAPI的函数,但是仍需要解决的疑问是,命令的数据流究竟是怎样被发送到TPM设备的,应用程序又是如何从TPM设备接收命令响应数据的。答案就是TPM命令传输接口(TCTI)。在Tss2_Sys_Initialize的介绍中简单提到过这个问题。Tss2_Sys_Initialize接收一个TCTI上下文结构体作为它的第一个参数。现在我们将详细介绍TCTI。

TCTI上下文结构体用于指示SAPI函数如何与TPM设备通信。这个结构体包含了TCTI最重要的两个函数的指针,transmit和receive;以及相对较少使用的cancel,setLocality,和其他函数的指针。如果一个应用程序需要和多个TPM通信,它可以创建多个TCTI上下文,然后设置好相应与TPM通信的函数指针。

TCTI上下文结构是进程和TPM相关的数据结构,初始化代码负责配置这个数据结构。具体来说,它可以在编译时初始化,也在在OS启动时动态初始化。系统的一些进程必须可以发现TPM设备或者是提前知道远程TPM的相关信息,然后用相应用于通信的函数指针来初始化这个结构。发现设备和初始化的过程已经超出了SAPI和TCTI规范的范畴

最常用也是必须有的两个函数指针是transmit和receive,它们完成你期望的事情,发送和接受数据。这两个函数都接收一个缓冲区指针和大小作为参数。当SAPI函数准备好发送和接受时就会调用相应的函数,它们会正确地完成该做的任务。

cancel函数用于支持TPM2.0的新功能:在命令发送到TPM之后可以取消命令的执行。这个功能可以让一些耗时的命令中途被取消。比如说,在一些TPM设备上生成秘钥有可能花费超过90秒的时间。如果在此期间系统因为响应用户操作需要进入睡眠,系统在执行睡眠操作之前可以通过这个命令取消TPM操作,从而使系统合理的处理当前的状态然后进入睡眠。

getPollHandles这个函数指针用于SAPI使用异步方式发送和接收命令数据时,也就是执行Tss2_Sys_ExecuteAsync和Tss2_Sys_ExecuteFinish时。这个函数的实现与系统相关,它可以用于等待接收命令响应时机。

最后一个要介绍的函数指针是finalize,它用于在TCTI连接中断之前做一些清理工作。

TCTI可以应用于TPM软件栈中任何标准化的数据流发送和接收的地方。当前的想法是,它可以出现在两个地方:在SAPI和TAB之间,或者RM和设备驱动之间。

TPM访问代理(TPM Access Broker)

TAB用于多个进程共享一个TPM时的控制和同步操作。当一个进程在发送和接收数据时,其他的进程不能访问TPM。这是TAB主要的任务。TAB的另外一个任务是阻止进程访问不属于他的TPM会话,对象,以及哈希和事件的序列。资源的所有权在使用对应的TCTI连接加载对象,开启会话,或者启动一个事件序列的时候就确定了。

在大多数的实现中,TAB和RM是集成到一起组成一个软件模块。这样做的主要原因是,对RM做一些简单修改就可以完成一个典型的TAB实现。

TPM-RM(资源管理器)

RM的角色和操作系统中的虚拟内存管理器类似。因为TPM通常有非常有限的片上内存资源,所以对象,会话,和操作序列等资源必须换入换出TPM来保证命令的执行。一个TPM命令最多可以使用三个资源实体handle和三个会话handle。所有这些handle都需要在TPM内部的内存中,这样TPM命令才能够执行。RM的工作就是解析TPM命令数据流,决定哪些资源需要加载到TPM中,加载资源之前还要换出一些TPM资源为加载留出足够空间,然后加载所需的TPM资源。对于TPM对象和操作序列来说,因为它们在加载到TPM知道可能包含多个handle,RM需要将这些handle虚拟化之后再返回给调用者。(正是由于这个原因,授权信息的计算不包含handle信息,因为应用看到的是经过RM虚拟化的handle,而TPM则使用实际的handle,这样就会导致授权认证失败。)

RM和TAB通常组成一个软件组件,就是TAB/RM,并且一个TPM对应一个这样的软件组件;这是一个软件设计上的决定,但通常也是这样实现的。但是如果想要一个TAB/RM提供对多个TPM的访问功能,那么TAB/RM就需要跟踪所有的handle的信息,比如handle属于哪一个TPM,并且将它们分开管理。这种情况已经超出了TSS规范的范畴。所以不管是使用不同的可执行文件还是使用同一份代码中的不同列表来实现不同TPM的资源界限,这一层必须要实现不同TPM资源的清晰区分。

TAB和RM在大部分情况下对上层的软件栈来说是透明的,但是同时这两层是可选的。对于上层软件栈来说,不管是直接和TPM设备通信还是通过TAB/RM来发送和接收TPM命令数据,它们的操作都是一样的,这也就是“透明”的含义。但是,如果没有TAB/RM这一层,上层的软件必须在发送TPM命令之前,实现TAB/RM的操作,这样就能保证命令正确执行。通常情况下,应用程序会在多线程或者多进程环境中实现一个TAB/RM来隔离底层的信息。单线程或者高度嵌入式的应用通常不需要TAB/RM层。

TPM-Drv设备驱动

当FAPI,ESAPI,SAPI,TCTI,TAB和RM完成它们的任务之后,就到最后一级的设备驱动程序登场了。设备驱动程序接收命令数据缓冲区及其大小,然后做必要的硬件操作来想TPM设备发送数据。当收到上层软件的请求之后,设备驱动会发送数据并阻塞直到命令响应数据准备好,然后返回到上层软件。

设备驱动用于和TPM通信的物理层和逻辑层接口不在TPM2.0规范的范畴内,它们在平台相关的规范中定义。目前为止,在PC上可选的TPM接口是FIFO和CRB(Command Response Buffer)。FIFO是先进先出字节传输接口,它使用固定的地址来发送和接收数据,同时还附带一些用于握手和状态操作的地址(寄存器接口)。FIFO接口在TPM2.0中没有太大的变化,只有一小部分的修改。FIFO接口可以使用SPI或者LPC总线。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

狂奔的乌龟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值