尽管已经有10亿以上的TPM设备被部署在商业个人电脑和服务器上,仍然仅有很少人知道TPM。同时当许多知道TPM的人了解到已经有很多针对TPM的应用时也会感到惊喜(这说明TPM的广泛应用和被人熟知还有很长的路要走)。其实现在有很多种方法来帮助我们编写应用TPM1.2设备的软件。对于TPM2.0来说,因为现在仍处于应用的初期,所以我们看不到很多可直接应用TPM2.0的软件也不足为奇了。这本书的目的就是帮助你基于TPM2.0的基本功能和高级功能开发相关的应用程序。
这一章首先介绍各种各样用于和TPM硬件交互的软件接口。然后介绍几个已经在使用TPM的应用。这其中我们会指出一些在我们看来应该使用但却没有使用的软件(期望读者可以改进它们),这或许是这个章节中最有意思的部分。
最后我们还给程序员提出一些在使用TPM开发应用时的一些建议和他们应该注意的地方,以及当前应用软件是如何处理与之相关的问题的。
当前使用TPM1.2和TPM2.0的软件有很多中类型,我们可以根据它们使用的应用程序接口分为以下几类:
- 直接使用TPM设备的私有软件
- 使用中间件来和TPM设备通信的旧应用,比如说PKCS#11和微软的CAPI。当PKCS#11可以在TPM2.0上使用时,这些应用仍然可以使用。这些软件在所有支持TPM1.2的操作系统上都是可用。微软的CAPI更是从Win8就开始同时支持TPM1.2和TPM2.0。
- 使用TSS接口来和TPM设备通信的应用(IBM,Infineon和NCP都有自己私有的TSS,同时也有叫做TrouSerS的开源TSS。注:现在它们应该是全部转向TPM2-TSS(github)了)。当然这些都是针对TPM1.2的,同时他们也正在如火如荼地开发TPM2.0版本的接口。
- 使用JAVA接口来和TPM设备通信的应用。目前仅有TPM1.2版本的软件,不过TPM2.0版本的软件应该很快就会出现。使用JAVA接口的设备主要是移动设备,尤其是运行Android系统的平台
- 使用微软TBS(TPM Base Services)的windows应用。它们可以支持TPM1.2和TPM2.0。当然新规范中增加的功能只有TPM2.0设备才支持。
- 支持TPM2.0的微软TSS.net,它同时附带有一个TPM2.0模拟器。不过需要说明的是,TSS.net不兼容TCG标准,并且现在只能在Windows平台上应用。
第一代使用TPM的软件是在具有第一版TPM的设备上运行的私有软件。比如说IBM的口令管理器和文件系统加密器,它们使用TPM来加密软件中涉及的密钥。Dell,HP,Infineon也有各种各样的类似软件。一般来说,这类软件运行良好,但是它们都是功能比较单一的应用案例。
另外一类使用TPM的应用来自于密码服务供应商(CryptographicServiceProviders)。它们主要包含两种主要类型:一种使用CAPI,另外一种使用RSA公司的PKCS#11。任何应用都可以通过这两种API来使用TPM的密码学服务。幸运的是,大多数软件都使用了以上两种API,使用它们的好处是显而易见的。大家都知道,开发密码学接口是非常困难的,尤其是在需要考虑容易受到攻击的地方,比如如何防止侧信道攻击。目前比较靠谱的方式就是让密码学专家来实现这些密码服务接口。另外,在政府应用环境中,这些密码学服务需要通过NIST的相关认证才能被使用。
以上两种API都提供一些钩子接口,它们可以用来替换那些之前用软件来实现的密码学服务。这个特性可以利用TPM基于硬件的密码服务接口来抵御软件攻击。在window上,使用CAPI和PKCS接口的此类密码服务供应商都有。比如,SecurityInnovation,WaveSystems,Infineon和Lenovo都有类似的实现。这种密码服务通常是和计算机供应商绑定在一起的。值得注意的是,Infineon的CSP可以检测系统中可以使用他们服务的应用,从而让用户通过它们的服务来使用TPM。在其他的操作系统上,比如Linux,BSD,MAC OS,Solaris,PKCS#11实现了使用TPM产生公钥和随机数。并且这些实现是免费的。另外,一些公司也实现了中间件来用于构建基于TPM的密码服务,比如Charismathics。
使用上述旧的接口(PKCS#11和MS CAPI)的问题是只能使用TPM的基础功能,比如说密钥生成和签名功能。所以想要利用TPM来做计算机系统健康状态认证或者米密钥迁移的软件就不能使用这些中间件。这客观上促成了TSS(TCG software stack)规范的产生。IBM开发了一个叫做TrouSerS的开源TSS实现,后来来自意大利Politecnico di Torino大学将它移植到windows平台上。当前TSS仅仅支持TPM1.2,针对TPM2.0的更新正在紧张开发中。(到2017的版本已经比较成熟了)
相较于JAVA,TSS软件库更适合用C语言开发。因此,MIT的一些研究者开发了JAVA版本的TPM应用接口。(官网上溜了一圈,github上简单看了看,感觉好久没更新了)。
自Windows Vista开始,微软开始通过TBS接口提供几乎可以直接访问TPM的应用接口。TBS接口接收符合TPM规范合适的字节流并返回相应的命令响应字节流。因为TBS是一个相对底层的接口,所以你可以使用很多上层软件库,这些库可以将应用层接口转变成TPM字节流。
除了比较完善的TPM功能,TBS还提供了以下额外的功能。第一,它可以支持多线程。这主要通过内部用于维护命令的队列来实现。第二,因为TPM支持使用save和load命令来做上下文管理,TBS利用这一点来实现虚拟TPM,从而支持多种应用理论上拥有不受限制的密钥存储空间,并且应用之间互不干涉。第三,应用软件通过TBS上下文来提交TPM命令,TBS上下文能够自动管理TPM资源和内部上下文,例如进程推出时它们会负责清理相关资源(linux平台上的tpm2-software/tpm2-abrmd也有类似的功能,还没有仔细研究)。
此外,windows平台在TPM的管理基础上实现了分层安全机制。它解决了由一些TPM命令引起的问题,这些问题主要是TPM命令可能会影响操作系统及应用的稳定性和正确执行。比如说,PCR的更新应该由系统的可信基来授权,但是TPM并有相关的规定(注:这个看起来很致命,不知道规范有没有更新,如果没有,又是基于什么样的考虑?)。因此,在windows Vista和Windows 7中只有管理员有权访问TBS服务。在Windows 8中,TPM命令被分成以下几组:
- 不能访问:包括TPM2_ContextSave 和 TPM2_ContextLoad。
- 仅限于管理员权限访问:包括TPM2_PCR_Extend在内的隐私敏感操作。
- 常规访问:秘钥的创建和使用等等。
同时,系统的管理员可以编辑管理员权限和常规权限中的内容,从而可以做定制化管理(注:这个还是要想好了)。此外,操作系统会在注册表中保存TPM相关访问入口的授权值得副本。《Using the Windows8 Platform Crypto Provider and Associated TPM Functionality》这个文档中详细介绍了这一点。
除了比较底层的TBS外,windows还提供了实现TPM部分功能的五种高层应用接口。
windows通过GUI工具和可以脚本化的远程编程接口WMI提供了很多TPM管理功能。这些管理功能包括开启,清除和关闭TPM等,并且它们能够无缝兼容TPM1.2和TPM2.0.
大多数的windows应用通过一组叫做CNG(CryptographyNextGeneration)的接口来使用密码服务。CNG将密码学服务封装成统一的编程接口,这些接口的实现可以是软件也可是硬件(例如HSM)。例如windows 8提供平台密码学服务(PlatformCryptoProvider),它可以让用户选择使用TPM来保护相关的密码学应用。同时,PCP也有一些与TPM功能类似的特性,比如“引述(quoting)”和秘钥认证。
windows 8还进一步提取了TPM中与智能卡相似的功能,并将它们封装成类似虚拟智能卡的应用。企业和网络登录中都有相关的应用。
表4-1是当前正在使用TPM的应用软件,同时包括他们使用的软件接口和支持的操作系统。所有的应用都支持TPM1.2,有一些也会支持TPM2.0(会标注出来)。
“表”
正如上表所示,已经有许多应用在使用TPM设备了。甚至有一些大型的公司都在使用这些软件。其中,被广泛应用的BitLocker使用了TPM的一些扩展功能。WaveSystem的EmbassySuite也是如此。但是也经常会出现因为一个系统上运行多个TPM应用而产生冲突的情况。
在TPM1.2规范中,只有一个SRK(storage root key),所有使用TPM的应用必须共享这个秘钥的授权。但是不幸的是,规范并没有一个统一的SKM创建方式。你可以将SRK的授权配置成不需要授权,为人熟知的20字节0,或者是口令的哈希值。更严重的是,TPM所有者授权也比较脆弱,因为它既可以用来复位字典攻击机制,也可以用于复位整个TPM或者创建认证秘钥。这从应用的角度来说是不合适的,我们之前也提到过。
更加不幸的是,TPM所有者权限还可用来授权分配NVRAM空间,这意味着需要使用NVRAM的应用必须知道这个授权值。不同的应用拿到TPM所有者权限后,将权限口令设置成 随机值,这些值将由统一的后台管理应用维护,而终端用户甚至可能都不知道。实际上就有这样的应用,因为不知道如何正确地和这些后台管理应用交互,最终让他们没办法工作。
这种问题在仅仅使用PKCS#11或者MSCAPI的应用上有所减缓,因为这两种接口只允许一种应用可以管理TPM。但是遗憾的是,这两种接口不支持高级TPM功能,比如认证功能(这个认证和前文说的TPM内部的认证功能还不太一样)。当然类似的问题也在慢慢改善,比如说WaveSystem的软件可以支持TPM的认证功能和BitLocker。
尽管TPM2.0规范仍然需要在授权上做一些协调工作,但是它可以支持用户使用多个SRK。这样就可以根本上解决不用应用的授权问题,从而大大减少不同应用同时使用TPM时需要做的协调工作。
在调研TPM应用时我们发现,商业软件支持大多数我们容易想到的TPM应用场景。但是,也有一些特别明显的TPM应该被应用的场景却没有在商业软件中出现。
近年来,基于web的应用数量增长了不少。其中主要是用于备份和存储的应用。尽管很多公司有这样的服务,但是到目前为止我们还有发现可以支持用户将密钥存储到TPM的应用。如果应用能支持的话,就可以与TPM在多台机器上复制备份的功能完美结合。因此,这对于开发者来说是一个好机会。
远程管理软件是另外一个越来越有用的应用。许多公司提供可以允许一台机器远程接管另一台机器的服务。比如说你可以远程管理你的网络,或者远程帮助家人解决计算机问题。但是,这些服务同样也都是使用我们熟悉的口令来做访问授权。尽管使用一个特别难记住的口令密码可以增加一些安全性,但是有时候这真的很麻烦,忘记密码可以让人抓狂。所以在这些地方,看起来使用TPM是一个理想的解决方案,这样远程机器只允许与它建立公私钥连接的机器访问(可以理解为一种基于TPM的远程认证机制)。现在还没有商业应用这样使用TPM,甚至大部分的应用都不支持使用其他的密码设备(智能卡)来增加安全性。而且原因也不是缺乏相关的软件开发包,因为确实有这样的开发包可供使用。
在使用TPM构建应用软件之前,很重要的一件事是决定是否要使用超出PKCS和MS CAPI功能之外的TPM高级功能。如果不适用高级功能,那就可以使用这两种接口。这样一来,这些应用也可以在没有TPM设备的系统上运行。但是如果要使用诸如设备认证,扩展授权,Localities或者NVRAM,那你就没得选择,必须使用定制化的TPM接口。
幸运的是,也有一些定制化的API用于开发这种应用。因为tss1.2让人难以理解,所以有人开发了替代的软件。MIT开发了TPM/J,旨在提供一种面向对象的tpm开发接口。Graz大学的IAIK提供了TrustedJava(感觉已经很久不更了)。Sirrix提供了microTSS,试图让TSS规范变的简单。
另外,IBM在SourceForge上发布了TPM模拟器和命令行工具。这样一来就可以使用脚本文件练习使用TPM命令。
虽然微软的TBS开始时仅仅有基础的TPM应用接口,但是随着它的不断完善,最后很可能成为编写TPM应用的好帮手。TBS相关的最大新闻来自Windows8,此时它抽象出了TPM1.2和TPM2.0的不同,从而使所有相关的API都能兼容两种设备。这对于目前仅仅支持TPM1.2功能的应用来说非常有用。同时微软也发布了可以直接向TPM设备发送命令的TSS.net,当前它还没有用于TPM2.0新功能的高层次接口。
windows8和TPM2.0规范发布时还没有TPM编程标准。微软为了填补这个空缺开发了TSS.net和TSS。C++这两个开源软件库,程序员可以使用它们开发比CNG和虚拟智能卡更复杂的TPM应用软件。
TSS.net和TSS.C++分别为托管代码和本地代码提供了一层简单的封装。并且它们都支持应用使用TPM设备(通过TBS)或者TPM模拟器(通过TCP/IP连接)。尽管TSS.net和TSS.C++相对来说算是底层软件库,但是它们的开发人员也不断努力让编写TPM应用程序变得简单。比方说下面就是一个通过TPM获取随机书的例子:
void GetRandomTbs()
{
// Create a TpmDevice object and attach it to the TPM. Here you
// use the Windows TPM Base Services OS interface.
TpmTbsDevice device;
if (!device.Connect()) {
cerr << "Could not connect to the TPM device";
return;
}
// Create a Tpm2 object "on top" of the device.
Tpm2 tpm(device);
// Get 20 bytes of random data from
std::vector<BYTE> rand = tpm.GetRandom(20);
// Print it out.
cout << "Random bytes: " << rand << endl;
return;
}
当然了,所有这些接口比如TBS,都是特别针对windows操作系统开发的。如果你想开发一个跨平台的应用程序,那就最好使用除此之外的软件库。对于TPM1.2来说,当前应用最广泛的软件库是TSS。下一小结我们就将介绍一个通过TSS使用TPM高级功能的应用软件。
WaveSystem通过TPM底层软件接口来开发应用软件,而不是类似PKCS#11这样的高层级接口。事实它必须这样做才能有效利用TPM的远程认证功能。因为其他密码协处理器没有远程认证功能,所以可以使用多种硬件设备的标准PKCS#11也没有这样的功能。最终WaveSystem使用TCG-TSS的开源实现TrouSerS来与TPM交互。它可以实现管理TPM所有者的口令,创建认证身份密钥,或者通过一个叫做TrustedNetworkConnect的标准认证一些值并返回给管理服务器。如果管理服务器发现PCR值发生变化时就会通知IT工作人员。有一些PCR(比如PCR0存储了BIOS固件的测量值)是不能改变的,当然BIOS升级的情况除外,所以这些值的变化需要引起管理员的注意。TSS1.2可以在多种操作系统平台上使用,比如windows,linux,solaris,BSD,甚至时MACOS。同样的,TSS2.0也具备这样优秀的跨平台特性,当需要把你的软件移植到其他平台时这是不错的选择。
TSS2.0被做了针对性的设计,从而尽可能地让基于TPM的软件开发容易实现。整个设计是分层实现的,所以可以通过最底层软件直接与TPM交互。通常情况下,使用密码协处理器的软件被设计成非常容易使用,因为它们只提供较高层次的应用编程接口就可以。但是,对于TPM的开发者来说,还是有一些需要特别注意的基本规则。
当我们开发基于TPM的应用软件时,有两种主要的陷阱主要注意。首先要意识到作为主板的一个独立组建的TPM是有可能坏掉的,或者用户可能会更新他们的设备。而如果主板被更换,那任何被TPM锁定的密钥都将丢失。第二点是,对于被锁定到PCR的数据(使用sealing命令)来说,当被测量的事物发生永久变化时,这些数据也就丢失了。
以上两种问题都说明一点:我们需要认真考虑如何管理密钥和被TPM锁定的数据。一个很好的软件示例是WindowsVista中首次发布的BitLocker。
微软在开发BitLocker时小心地考虑了前文描述的两种问题。这个软件用于对包含有windows系统文件的磁盘做加密。为了实现全磁盘加密,BitLocker在系统启动的早期会从TPM拿到一个密钥。这个密钥被锁定在一些PCR中,这些PCR保存了由系统启动开始到操作系统内核被加载到内存时的测量值。BitLocker还可以允许用户设定一个口令。为了实现密钥的管理,被PCR锁定的密钥,也被称作密钥加密密钥(KeyEncryptingKey),用于加密全磁盘加密所需的密钥。同时,直接用于加密磁盘的密钥也可以通过使用一个很长的随机数口令加密的方式来做备份。这个用于备份的随机数口令可以放在其他安全的地方,比如放在USB密码器中。这样一来,一旦更换主板,TPM损坏或者磁盘被用于其他的机器时,还能保证数据是可以访问的。
另一方面,微软还考虑到了因为升级BIOS引起的问题。前文也已经有介绍,BIOS升级后将导致TPM不能“吐出”KEK。尽管用于备份的随机数口令可以恢复KEK,但是微软还是想让管理员更方便地升级BIOS。因为管理员具有解密数据的访问权限,所以干脆就让KEK在BIOS升级时暂时免于被锁定到PCR中(以明文的形式存在)。当升级完成以后,重新把KEK锁定到新的PCR值中。需要强调的是,有时候通过牺牲一点安全性来使用户的操作更容易,这通常来说是一个很好的妥协,即双赢。如果一种安全技术很难使用,那它将很难被广泛应用,这样的安全也仅仅是一纸空文。
在BitLocker出现几年之前,当IBM开始做它的第一个TPM解决方案时也不得不时时考虑密钥管理相关的问题。
IBM在使用存储密钥加密文件和文件夹时也遇到了类似的问题,并且它也使用与微软类似的解决方案。在具体实现上的不同是,IBM为了恢复加密密钥会要求用户回答问题,而不是使用微软的备份随机数口令。相同的是,磁盘加密密钥同样被KEK加密,而KEK受TPM保护。这种实现方式的风险就是,攻击者可能会多次尝试找到问题的正确答案从而恢复可以解密数据的密钥。为了解决这个问题,IBM想出了一个巧妙的办法。设计人员意识到,虽然在正常使用时可能要求密钥立即解锁,但是在试图恢复一个密钥时花费几分钟的时间是可以接受的。因此,IBM最后的备份的做法如下,首先对用户设定好的问题的答案连续做几分钟的哈希,并记下哈希操作的次数,然后使用最终的哈希值作为备份加密密钥加密用于文件的密钥。哈希操作的次数和加密过的密钥就存放在磁盘上的某个位置。当用户试图恢复密钥时,他的每一次尝试都会经过几分钟的哈希操作,这样就让我们之前提到的“猜答案”攻击变得不太现实,但是,在用户知道答案的情况下仅仅需要几分钟的时间来恢复(毕竟用户自己设定的问题和答案,通常用户会被提醒选择自己相对有把握的问题和答案,这样一来,即使一次不过,几次之后也基本都会试到正确的答案)。
TPM架构师在设计TPM2.0规范时已经意识到很多TPM管理引起的问题。所以他们增加了新功能来解决这些问题。其中一个在安全软件中老生常谈的问题就是授权管理(密钥管理)。比方说,有人在飞机上或者深夜的旅馆中修改了密码,并且设备没有连接到网络。然后第二天他们忘了密码。还有一种情况是,公司职员在离职或者突然去世时,因为不能及时交接(密码告接任者)导致公司的加密数据不能恢复。这种情况下即使通常被认为神通广大的IT也无能为力了。TPM2.0规范完善了密钥授权机制,从而解决了类似的密钥管理问题。
应用软件可以使用与TPM1.2相同的技术来解决密钥管理的问题,但是TPM2.0提供了更多的解决方案。在公司里,丢失密码或者授权信息是一个很严重的问题,每天都有很多人忘记密码或者丢失智能卡。当然这并不是什么可耻的事情,这是人之常情,我们几乎都曾经忘记过密码,不是吗?
通常情况下,在TPM中创建一个认证过的密钥是比较困难的,但是这对于TPM2.0来说很容在初始配置的时候实现。但是如果用户现需要在这方面重新配置TPM,这将加重IT的管理负担。因为通常情况下,在公司中负责设备采购和配置的是IT组织,所以TPM规范架构师需要解决这个问题。TPM2.0的设计不仅具备密钥的管理功能,还有操作授权的管理。我们将在强化的授权机制一章详细介绍这一点。现在已经足够明确的一点是,TPM2.0主要的功能加强都是为了解决类似的管理问题。
这一章我们了解了很多可以用来使用TPM的软件接口和许多已经在使用TPM的应用软件。其中一些仅仅提供了和密码协处理器类似的TPM标准功能,比如说密钥创建和存储。已经有大量的应用在使用像MS CAPI和PKCS这样的标准接口了。如果需要使用TPM的高级功能,比如一些软件具有的认证功能,就需要使用特殊的TPM接口而不是上述的标准接口。当前至少有两种特别的针对TPM1.2的接口:微软的TBS和TCG的TSS。
最后,我们认识到了在开发基于密码协处理器如TPM的应用软件时,有很多我们应该特别注意的问题:主要由密码协处理器可能损坏或者主板可能被更换引起。更糟糕的情况是,一个只有一个人知道的密钥很有可能以内突发事件永远不能访问。为了增强可管理性,我们需要一种在特殊情况下可以恢复功能的管理策略。TPM2.0最新引入的增强的管理功能就满足了这个要求。第14章将详细介绍。
为了帮助我们继续在TPM2.0知识的海洋里前行,下一章我们首先开始TPM2.0规范的阅读和理解。