TPM2.0已经统一了所有由TPM控制的实体的授权方式。前面的章节已经讨论了口令和HMAC授权需要使用的授权数据。这一章将详细讨论TPM的一个新型的最强大的授权方式,开始我们将说明为什么在TPM中增加这种授权方式,然后我们将层层揭开这种授权方式的多层面纱。
这种新的授权方式有许多功能。总结来说就是,如果一个用户想限制一个实体只能在某些特定情况下才能被使用,使用这种方式就有可能实现。所有针对这个实体使用的限制的总和就叫做一个policy。扩展的授权(EA)Policy可以迅速变得复杂。因此,这一章的描述是渐进式的,最开始先介绍一个非常简单的Policy,然后逐步地增加难度。这个过程是通过探究如何实现以下功能来完成的:
- 简单断言。
- 基于命令的断言。
- 多因素授权。
- 多用户/组合授权。
- 可以在中途修改的灵活Policy。
纵观本章内容,你可以看到在大多数情况下会用到的实用Policy的例子。最后我们会发现创建Policy与使用Policy不同,所以你会了解到一个用户怎样满足一个Policy;此时你也就会明白为什么Policy是安全的。
最后,我们会介绍一些用于解决特殊问题的Policy。这一节可能会激发你的创造性——你将意识到有比你想象中更多的方式来使用Policy。
首先,我们通过比较EA Policy和使用口令授权的异同来开始本章的学习。
所有TPM的实体都可以通过两种基本的方式授权。第一种基于创建实体时指定的口令。另外一种基于创建实体时指定的Policy。一个Policy几乎可以包含任何你能想到的授权方式。一些实体是由TPM本身来创建的(比如组织架构和字典攻击复位的handle),因此它们对于用于来说具有默认的口令和Policy。这些实体的名称是固定的,这些实体的名称不依赖授权Policy。因此实体的Policy是可以改变的。
所有其他的实体——NVRAM索引和密钥——的名称的计算都会包含实体被创建时指定的Policy。这样的结果就是,尽管实体的口令可以改变,但是Policy是不能变的。后面你将会看到,一些Policy可以设置成灵活的Policy,这样一来就可以实现policy的灵活管理而不管Policy本身不可变的特性。
任何通过口令可以做的事情都可以通过Policy来做,但是反过来就不可以。有一些事情(比如复制密钥)只能通过Policy来授权操作。(但是,为了让事情变得更复杂,你仍然可以使用一个口令来授权复制密钥操作,这是通过Policy来指定的(TPM2_PolicyAuthValue))
一个Policy可以被很精细的设置——机会任何事情都是可能的,policy可以被设置成从一个永远不会被满足的NULL Policy到设置成不同命令或者用户有不同授权要求的policy。因此EA可以解决许多应用程序开发者需要处理的问题。
TPM中EA的设计初衷是为了解决TPM实体授权管理的基本问题。让所有的TPM实体都以同样的方式授权,这可以让我们更容易地学习如何使用TPM。同时,EA也允许用户定义授权Policy来解决如下的问题:
- 允许多种变化的授权(口令,生物信息等等)。
- 允许多因素的授权方式(要求多一种的授权类型)。
- 允许在不使用TPM的情况下创建Policy。Policy本身不包含任何秘密信息,所以可以完全由软件来创建。但是这并不等于满足一个Policy不需要秘密信息。
- 允许认证与一个实体相关联的Policy。用户应该能够知道使用一个实体时哪些授权是必须的。
- 允许多个用户或者角色来满足一个Policy。
- 允许限制某一个对象的特定角色的动作或者使用用户。
- 修正了PCR脆弱的问题。在TPM1.2中,如果一个实体被“锁定”到包含特定配置的一组PCR中,一旦配置不得不变化,那这个实体就不能使用了。
现在,许多不同种类的技术和设备被用于授权。口令是最古老授权方式(或许也是强度最弱的)。生物信息比如说指纹,虹膜扫描,脸部识别,手写签名,甚至是心率都被用于授权。数字签名和HMAC是用于密钥的密码学授权方式。银行的时钟把一天中的时间作为授权信息,它不允许在交易时间之外打开金库。
TPM被设计成几乎可以使用任何能想到的授权方式,尽管许多情况下需要额外的硬件。一个Policy可以由一种单独的授权方式或者多种授权变种组成。
多因素认证是安全的多种表现形式之一,并且它在当今很流行。为了授权执行一个命令,需要执行多种授权方式。这些授权可以有很多种形式——智能卡,口令,生物信息,等等。基本的原理就是攻击多种授权比只攻击一种要难。不同类型的授权有不同的优缺点。比如说,口令可以很容易地实现远程提供——但是指纹就没那么容易,尤其实在设计正确的情况下。
TPM2.0的设计允许多种不同的授权,并且提供机制来支持更多的外部设备。每一种可以用于认证的机制被叫做断言。断言包含以下内容:
- 口令。
- HMAC。
- 提供数字签名的智能卡。
- 物理存在/接触(Physical presence)。
- 机器的状态(PCR)。
- TPM的状态(计数器,时间)。
- 外部设备的状态(指纹读卡器,GPS等等)。
一个Policy可以要求任意数量的断言为真来满足它。TPM种EA背后的创新是它将包含多种断言的复杂Policy表现为一个哈希值。
一个Policy就是一个可以表示一组授权的哈希值,这些授权组合起来可以描述如何满足一个Policy。当一个实体(比如说一个密钥)被创建的时候,它可能和一个Policy关联。为了使用这个实体,用户需要向TPM证明这个Policy已经被满足了。
这需要以下三个步骤:
- 创建一个Policy会话。Policy会话被启动时,TPM会为这个会话创建一个会话Policy缓冲区。(缓冲区的大小与创建会话时选择的哈希算法相匹配,并且初始化为全0)
- 用于通过TPM2_PolicyXXX命令向TPM会话提供一个或者多个授权信息。这些操作会改变会话Policy缓冲区的值。这些操作还可能会设置会话的一些标志位,这些标志位用于指示TPM在执行命令时必须执行的一些检查。
- 当一个命令使用一个实体时,TPM会比较会话Policy缓冲区与实体的授权Policy。如果这两者不同,命令就不会被执行。(此时,与Policy授权相关的会话标志位也会被检查。如果它们也不满足,这个命令也不会被执行)
Policy不包含任何秘密信息。也就是说,所有的Policy都可以使用纯软件的方式在TPM之外创建。但是,为了使用它们,TPM必须能够重新生成这些Policy(以会话的Policy摘要的形式)。因为TPM有产生Policy的能力,所以允许用户使用TPM的这个功能来产生Policy就比较合理了。这是通过Trial Policy来实现的。一个Trial Policy不能用于满足一个Policy,但是它可以用于计算一个Policy的哈希值。
用于满足授权Policy的Policy会话在某种程度上要比用于创建Policy的Trial Policy会话复杂。一些Policy命令会立即检查一些断言并更新存储在会话中的Policy缓冲区。另外一些命令则会设置标志或者设置会话中的变量,当命令真正被执行时这些标志和变量会被检查。表14-1什么Policy命令会有这样的检查。
表14-1 会设置标志位的Policy命令
命令 | 设置标志位或者变量用于指示TPM在执行命令时检查它们 |
---|---|
TPM_PolicyAuthorize | 否 |
TPM_PolicyAuthValue | 是——设置标志位指示命令执行时需要使用HMAC会话 |
TPM_PolicyCommandCode | 是——检查是否是一个特定的命令在执行 |
TPM_PolicyCounterTimer | 是——执行针对TPMS_TIME_INFO的逻辑检查 |
TPM_PolicyCpHash | 是——检查命令和参数是特定的值 |
TPM_PolicyLocality | 是——检查命令是通过某一个特定的Locality来执行的 |
TPM_PolicyNameHash | 是——在命令执行时检查对象的身份,也就是名称是否匹配 |
TPM_PolicyOR | 否 |
TPM_PolicyTicket | 否 |
TPM_PolicyPCR | 是——在命令执行时检查PCR的值没有变化 |
TPM_PolicySigned | 否 |
TPM_PolicySecret | 否 |
TPM_PolicyNV | 否 |
TPM_PolicyDuplicationSelect | 是——决定一个密钥被复制到一个特定的密钥对象下面 |
TPM_PolicyPassword | 是——命令执行时检查口令 |
我们可以创建非常复杂的Policy,但是实际应用中不大可能会用到它们。为了解释Policy的创建,这一章人为地对不同类型的Policy进行分类,具体分来如下:
- 简单断言Policy:使用一个认证方式创建Policy。比如口令,智能卡,生物信息,时间等等。
- 多断言Policy:将几种断言结合起来,比如同时要求生物信息和口令;或者智能卡和PIN码;或者口令,智能卡,生物信息,以及GPS位置信息。这样的Policy等价于使用AND操作将多种断言组合。
- 混合Policy:这里引入逻辑操作OR,比如说”Bill可以使用一个智能卡授权或者Sally可以使用口令授权“。混合Policy可以由任何其他种类的Policy组成。
- 灵活多变的Policy:使用通配符或者占位符,具体的授权内容以后定义。一个Policy的特定部分可以被其他允许的Policy替换。这看起来像是一个简单的断言,但是实际上是任意的(简单或者复杂的)Policy都可以替换它。
前面已经提到,一个Policy是一个哈希值,这个哈希值表现为满足这个Policy的方式。一个Policy启动时表现为一个缓冲区,缓冲区大小为相关实体的哈希算法对应的哈希长度,缓冲区会被初始化成全0。当部分Policy被满足时,这个缓冲区会被扩展能够表示这一事件(具体来说就是Policy相关命令的执行)的值。扩展缓冲区的操作就是连接缓冲区当前值和新的数据,然后使用指定的哈希算法对上述的连接结果做哈希,将缓冲区更新成这个哈希值。下面让我们使用最简单的Policy来展示这个过程:最简单的Policy就是指哪些仅仅需要一种授权认证方式的Policy。
一个简单的EA Policy:也就是只包含一种认证方式的简单断言Policy,它可以是如下形式的一种:
- 口令或者HMAC(需要向TPM证明,用户知道对象的口令的Policy)。
- 数字签名(智能卡)。
- 外部设备的认证(一个生物信息读卡器用于验证特定的用户身份,或者一个用于证明机器在特定位置的GPS设备)。
- 物理存在(是一个类似开关的指示,它可以证明一个用户可以在物理上接触到TPM。尽管这个在规范中有定义,但是很可能不会实现,所以我们后续会忽略这个功能)。
- PCR(TPM宿主设备的状态)。
- Locality(表示发出TPM命令的软件所在的系统特权级别)。
- TPM内部状态(计数器值,定时器的值等等)。
可以使用TPM创建一个简单断言Policy,步骤如下:
- 建一个Trial Policy会话。仅仅需要执行下面的命令:
TPM2_StartAuthSession
需要传递一个参数TPM_SE_TRIAL来告知TPM启动一个Trial会话,还需要一个哈希算法的参数用于计算Policy的值。这个命令会返回(还有其他的信息)Trial会话的handle。这里我们成为myTrialSessionHandle。
- 执行TPM2的Policy命令(后面很快会介绍)。
- 通过执行下面的命令要求TPM提供Policy的值
TPM2_PolicyGetDigest
这个命令需要传递Trial会话的Handle:myTrialSessionHandle。
- 通过执行如下命令来结束会话(或者如果你还想再次使用这个会话就复位这个会话)
TPM2_FlushContext
这个命令同样需要传递Trial会话的Handle:myTrialSessionHandle。
因为对于简单的断言Policy来说步骤1,3,4是通用的,后面将不再重复;下面我们将介绍第2步中涉及到的每个命令。
口令是现在最常用的认证方式,但是它还远远谈不上安全。尽管如此,因为太多设备在使用口令了,所以TPM支持口令授权是很重要的。(TPM1.2不支持明文口令——仅支持能够证明用户知道口令的HMAC方式。TPM2.0则两种都支持。)TPM会假设当用户使用口令时,会有一个口令输入接口到TPM设备的可信通道。如果不存在这样的可信通道,TPM2.0的架构也支持使用加盐的HAMC会话来证明用户知道口令,这样口令就不用以明文的方式传送了,13章有相关的介绍。当一个对象被加载到TPM设备后,TPM知道与对象相关的口令。因此,一个Policy并不需要包含口令信息。这样一来,一个Policy就可以应用于具有不同口令的实体。
创建一个简单的断言Policy可以缩减成如下四个步骤:
- 配置Policy缓冲区并清零,缓冲区长度设置为哈希算法的输出长度。
图14-1 初始化Policy : 0x0000....0000
- 将缓冲区与TPM_CC_PolicyAuthValue连接在一起。
图14-2 根据规范将缓冲区与Policy数据连接在一起:0x0000....0000TPM_CC_PolicyAuthValue
- 根据TPM2.0规范第2部分将TPM_CC_PolicyAuthValue替换成对应的数值。
图14-3 替换TPM_CC_PolicyAuthValue:0x0000....000016B
- 计算上述连接后数值的哈希值,然后将结果置于缓冲区中。这个最终的结果就是一个简单断言的Policy。
图14-4 计算连接值得哈希并更新到缓冲区中:0x8fcd2169ab92694................1fc7ac1eddc1fddb0e
当Policy命令被执行时,Policy会话的缓冲区将会被设置成上述过程最终的哈希值。另外,TPM的会话还会设置一个标志用于指示TPM,当一个命令使用的对象需要这个Policy授权时,用户还必须通过口令会话(默认存在的)提供对象的口令,TPM要检查这个口令是否与对象的口令匹配。
类似的情况是,当一个Policy使用HMAC断言时,会发生下面两件事情:
- Policy的缓冲区被扩展,使用TPM_CC_PolicyAuthValue。
- TPM的会话还会设置一个标志用于指示TPM,当一个命令使用的对象需要使用这个Policy授权时,还需要一个独立的HMAC会话。TPM会检查口令HAMC值并且与对象的授权值比较,如果匹配才会允许访问(参考第13章)。
如果你正在使用一个Trial Policy会话来创建一个Policy,需要执行TPM2_PolicyAuthValue命令并且向命令传递Trial会话的handle。
这种授权的方式意味着当你使用口令时,不论口令是以明文还是以HMAC的形式,明文口令或者HMAC形式的口令都必须与Policy会话结合起来授权对象的使用。TPM_CC_PolicyAuthValue刚刚在前面的描述中出现了两次,这不是排版错误:这个重复意味着,选择使用明文口令还是HMAC不是在Policy创建的时候决定的,而是在非Policy相关的命令执行时决定的。具体来讲,怎么样向TPM证明用户知道口令(明文还是HMAC)是用户在使用对象的时候由用户自己决定的,而不是创建Policy的时候决定(这听起来很Make Sense)。
口令并不是最安全的授权方式。一个比口令安全得多的方式是使用数字签名,通常使用智能卡来实现,比如DoD(United States Department of Defense)的CAC(Common Access Card)卡或者PIV(United States Federal Personal Identity Verification)卡。
TPM2.0的一个一个新的(并且非常有用)断言Policy是,要求用户知道与当前被授权实体不同的实体的口令。尽管这一开始听起来很奇怪,但是因为NVRAM实体和密钥对象行为的不同,这个功能会很有用。当一个密钥对象的口令通过TPM2_ChangeAuth命令被修改时,实际上发生的事情是这个密钥被复制一份并且使用新的口令。并且并不能保证旧版本的密钥会被丢弃。因为密钥对象通常会以文件的形式存在于TPM设备之外,因此TPM也就不能保证旧版本密钥文件会被删除。但是,NV实体是完全存在于TPM中的:如果口令被修改,它就真的修改了。旧版本的实体就再也不能被使用了。
这就意味着,如果创建一个密钥的时候使用一个要求用户输入一个NV实体的口令的Policy,那就可以修改密钥Policy对应的NV的口令,同时不同担心原来的口令任然可以用于授权这个密钥。在这个案例中,修改NV的口令就有效地(“真正地”)修改了密钥的“授权口令”。因此,TPM2.0允许你使用NVRAM实体的口令来授权一个密钥的使用。
更进一步讲,这个特性也使得管理大量实体的口令成为可能。假设你创建了一个要求一个特定NV索引口令的Policy,并且将这个Policy与很多数量的密钥关联。那么你可以通过修改一个NV索引的口令有效地实现修改大量密钥的授权口令。
TPM2_PolicySecret命令需要你传递对象的名称,并且Policy会检查这个对象的口令(言外之意就是,如果你用TPM2_PolicySecret创建一个Policy,那必须同时包含TPM2_PolicyAuthValue命令)。有一点可能不是特别明显,那就是当你为一个对象创建Policy时,你不能在对象创建之前向TPM2_PolicySecret命令传递对象的名称。这是因为对象的名称本身就是依赖对象的Policy来计算的,同时一个使用TPM2_PolicySecret的Policy又依赖对象的名称,这就是一个恶性死循环。这就解释了为什么这样的Policy同时还要使用TPM2_PolicyAuthValue命令(注意,此时应该是指使用另外一个对象的口令)。因为TPM2_PolicyAuthValue提供了一种指向被授权对象的授权区域的方法。(目前这里还不是很理解,参考一下第11章中的“USE CASE: STORING A COMMON PASSWORD”,这一章结束以后再思考)
为了在Trial会话中计算Policy,你会执行TPM2_PolicySecret命令并传递Trial会话的handle,同时还有授权需要的另外一个对象(比如上述的NV实体)的handle。这个操作就会使用TPM_CC_PolicySecret||authObject->Name||policyRef来扩展Policy缓冲区。传递到命令的参数是Policy将会用到的对象的handle。前面已经提到,TPM会使用对象的名称来扩展会话的Policy缓冲区。不使用Handle就避免了修改对象handle(使用ResourceManager有可能会的,参考前面几章的相关描述)造成安全信息泄露。
技术上来说,执行TPM2_PolicySecret需要你提供一个授权会话用于对象Handle的授权(不太明白这个说法,以NV的例子来说,实际上就是提供NV的授权口令)。尽管规范上说在Trial会话中不必如此,但是大多数的实现中是需要的。因此,执行这个命令的时候你必须也得提供正确的口令或者HMAC会话。当然,如果你使用纯软件的方式来计算Policy,就不需要了。
通常来说使用私钥来授权TPM1.2的实体是不可能的。在TPM2.0中是可以的。也就是说,TPM2.0可以使用数字签名来做访问控制。当一个Policy包含这样的断言时,Policy的值会被扩展以下内容:TPM_CC_PolicySigned,SHA256(publicKey)以及一个policyRef。(一个policyRef用于精确地指定签名过的断言如何被使用。通常情况下它是一个空缓冲区,但是如果用户是在认证一个远程操作,他可能想精确地识别在授权什么动作。如果Policy中包含policyRef,授权方在授权动作时必须对这个值签名。)
用户可以在Trial会话中执行TPM2_PolicySigned命令创建上述的Policy;但是在创建Policy之前,TPM必须知道用于验证签名的公钥。因此,在此之前要将公钥加载到TPM中。一种简单的方式就是使用TPM2_LoadExternal命令将公钥TPM_RH_NULL组织架构下。当你调用TPM2_LoadExternal时,需要传递一个公钥的数据结构。
TPM2_LoadExternal命令会返回一个已加载公钥的handle,现在我们称作aPublicHandle。然后你就可以执行TPM2_PolicySigned命令,并且传递Trial会话的handle和刚刚加载的公钥handle。
满足这个Policy是一个骗局。向TPM证明用户拥有一个包含公钥对应的私钥的智能卡才是更关键的。证明的方式就是用私钥签名由TPM产生的一个nonce值。本章的最后会详细介绍。
Policy还可以要求另外一种断言:TPM所在的宿主机环境是正常的。这是通过PCR来实现的。
TPM中的PCR通常会被启动前后的软件扩展,从而用于表示当前系统运行软件的状态。在TPM1.2的设计中,只有很少一部分功能可以使用这种授权。更槽糕的是,因为使用PCR授权TPM1.2的秘钥是一种很脆弱的操作,这个限制也让PCR很难用于授权。
TPM2.0的设计允许包含特定值的PCR用于授权任何命令或者实体。Policy只需要指定被引用PCR的序号以及相应的哈希值。另外,TPM2.0包含了多种方式来处理PCR的脆弱性。重申一次,所有的Policy都由一个大小和哈希算法对应的全0缓冲区开始。为了使用PCR断言,policy会被扩展以下值:TPM_CC_PolicyPCR||PCRs selected||digest of the values to be in the PCRs selected。
如果使用一个Trial会话计算Policy,用户首先要选择期望的PCR值,并将它们存入TPML_PCR_SELECTION。然后计算这些值的哈希,将这个哈希值称为pcrDigest。然后用户执行TPM2_PolicyPCR命令,并且传递Trial会话的handle以及选择的PCR和刚刚计算出的pcrDigest。
当用户想访问被锁定到PCR的实体时,他们需要使用TPM2_PolicyPCR命令,同时传递一个PCR索引及其期望值pcrDigest的列表。TPM会计算这些PCR的哈希值并与传递的值相比较,如果匹配,TPM就会扩展Policy授权会话中Policy哈希的值:TPM_CC_PolicyPCR||PCRs selected||digest of the values currently in the PCRs selected。
这里可能会留下一个安全漏洞——万一上述的断言通过之后PCR的值发生变化怎么办?在执行TPM_PolicyPCR命令时,TPM会通过记录TPM会话状态中的PCR生成计数器来阻止这样的漏洞。当Policy会话正在用于一个命令的授权时,TPM会检查当前PCR的计数器与之前记录的值是否匹配,如果不匹配,那这个会话就不能用于授权。
作为额外的灵活特性,平台相关的规范可以指定某些PCR的值不会更新TPM内部的计数器。因此,修改这些PCR的值不会影响会话的授权功能。
TPM1.2版本的设计中有一个特性叫做Locality,它用于决定发送到TPM设备的命令来自于什么样的软件栈。TPM1.2中,Locality的主要用途是用于证明CPU处于一个特殊的模式中,这个特殊的模式是指进入Intel TXT或者AMD-V命令模式(这两种模式分别位于Intel和AMD的CPU中)。这些命令主要用于当机器处于不可信的系统运行状态时执行动态信任根测量(DRTM),这样一来就可以可信地报告软件的状态。
在TPM2.0中,就像PCR断言被扩展到任意的授权应用中一样,Locality也被扩展到通用的断言操作中。当Policy的一个断言使用Locality时,会话的Policy摘要会被扩展以下值:TPM_CC_PolicyLocality||locality(ies)。
如果使用Trial会话来计算Policy,需要执行TPM2_PolicyLocality命令,同时传递Trial会话的handle以及Locality数据结构(指定哪一个Locality),TPMA_Locality,TPM规范的第2部分会有这个数据结构的定义。
当需要满足一个会话的Locality断言时,用户同样需要使用TPM2_PolicyLocality命令来传递与这个会话绑定的Locality信息。此时会发生以下两件事:
- 会话的摘要被扩展以下的值:TPM_CC_PolicyLocality||locality(ies)。
- 一个会话的变量被设置成命令的参数Locality。
当用户使用这个会话执行命令时,TPM会比较命令数据中的Locality信息(查看以下PTP规范中的Bit Protocol)和会话之前用变量记录的Locality信息。如果不匹配,命令就不会执行。
在TPM1.2规范中,一共有5个Locality——0,1,2,3,以及4——它们分别使用一个字节中的一个比特位来表示。这种表现方式可以允许你一次选择多个Locality:比如说,0b00011101表示选择Locality0,2,3以及4。在TPM2.0规范中,可以通过PolicyOr命令来实现这样的操作(言外之意就是不允许像1.2中这样操作了呗?);但是为了降低人们从TPM1.2到2.0迁移的认知难度,在2.0中,Locality0-4的表示方法还和以前一样。
用位域表示Locality的问题就是,一个字节可以表示的Locality数量太少了。出去已有的5个Locality,只可能再增加3个Locality,分别用5,6,和7。但是,TCG的移动和虚拟化工作组想要更多的Locality,所以高于一个字节中5位以上的值被表示成单独的Locality。最后的结果就是,2.0中的Locality由以下内容组成——0,1,2,3,4,32,33,34,...255。也就是说,为了与TPM1.2兼容,2.0扩展Locality后不能表示Locality5-31。表14-2展示了这一点,注意一下当Locality值是32时的变化。
表14-2 Locality表示方法
Value | Binary Representation | Locality(ies) Represented |
---|---|---|
0 | 0b00000000 | None |
1 | 0b00000001 | Locality 0 |
2 | 0b00000010 | Locality 1 |
3 | 0b00000011 | Localities 0,1 |
4 | 0b00000100 | Locality 2 |
5 | 0b00000101 | Localities 0,2 |
6 | 0b00000110 | Localities 1,2 |
7 | 0b00000111 | Localities 0,1,2 |
8 | 0b00001000 | Locality 3 |
9-30 | ... | ... |
31 | 0b00011111 | Localities 0,1,2,3,4 |
32 | 0b00100000 | Locality 32 |
33 | 0b00100001 | Locality 33 |
34 | 0b00100010 | Locality 34 |
35-254 | ... | ... |
255 | 0b11111111 | Locality 255 |
Locality可以应用于很多地方。它可以用于表示创建实体的命令的来源。它们还可以用于将一些功能绑定到到特定的软件上。在1.2中,Locality会用于将CPU与复位和扩展特定的PCR绑定在一起(比如PCR17,18),这样是为了在DRTM之前将机器复位成一个已知的状态。SourceForge上的tboot软件展示了它是怎样使用Locality的;来自于CMU的Flicker使用tboot在与OS独立的内存空间内执行安全相关的操作。
因此,Locality会告诉TPM当前这个命令来自于什么软件(或者硬件)。因为TPM天生就知道命令的具体信息(这意思是说,TPM自己在解析命令的时候可以根据Bit Protocol解析出Locality等信息),Locality可以用于授权。
TPM1.2设备有一个内部定时器用于测量TPM上次启动到现在经过的时间(这个值可能和外部的时间相关),还有一个内部的单向计数器。但是这两种特性都不能用于授权。TPM2.0有一个定时器,一个时钟,以及启动计数器,它们可以通过复杂的配置方式来提供新的断言。启动计数器用于记录设备已经启动的次数。定时器用于记录TPM设备当次启动后经过的时间。时钟与定时器很像,但是时钟只能向前更新,并且可以被设置成与外部时间相同的值,在TPM掉电以后也就停止工作(这与主板上的RTC就不同了,这个时钟不需要额外的电池供电)。
上述这些特点可以用于限制TPM实体只能在启动计数器没有变化,或者时钟在某一个时间段的情况下使用。实体的使用也可以被限制在白天的时间使用。后者是最有可能的应用场景——将一个计算机的文件访问限制在白天的工作时间内,这有助于阻止黑客在夜晚非法访问文件。
TPM一直都可以检查内部时钟和启动计数器的值,所以它们被成为内部状态。内部状态断言要求在被授权的命令执行之前创建Policy会话,并且还要在命令执行之前这些断言是通过的。命令执行时这些断言并不一定通过。
上述过程使用以下值扩展Policy:TPM_CC_PolicyCounterTimer||HASH(Time or Counter value||offset to either the internal clock or the boot counter|| operation)。这个operation参数指示了需要做的比较操作。TPM规范的第2部分有操作相关的列表:操作是一个两字节的值,可以表示相等,不相等,大于,小于等等操作。
使用trial会话来创建这样的Policy时需要执行TPM2_PolicyCounterTimer命令,并且传递如下四个参数:Trial会话的handle;指示比较操作的对象是定时器,时钟,或者是启动计数器;需要比较的值;以及具体的比较操作。
尽管NV索引对应的内存区域的值被认为是TPM内部状态,但是TPM可以读取任意NV索引区域。这些值同样也可以用于Policy相关的命令。
TPM2.0规范新增加了一个命令,它用于使用特定NVRAM区域存储的值来授权TPM实体的访问。举例来说,如果一个NV索引对应一个32比特的内存区域,你可以使用其中一位的状态来控制TPM实体的访问权限。如果每一个比特都被分配给不同的用户,一个用户访问一个特定实体的权限可以通过修改NVRAM中响应比特的值来撤销或者使能。当然,这也意味着拥有权限写这个NVRAM区域的人拥有最高的秘钥使用权限。
这个命令的功能不止于此,因为TPM允许针对NVRAM区域执行逻辑操作。所以你可以设定如下的断言条件:
6 <= NVRAM location < 8 OR 9 < NVRAM location < 23
TPM2.0的NVRAM区域可以被配置成计数器。这就意味着你可以在Policy中通过灵活的配置将计数器配置成只能使用n次。本章后续会介绍这样的应用案例。
这样的Policy需要将Policy缓冲区扩展以下的值:TPM_CC_PolicyNV||calculated Value||name of NV location。calculated value表示HASH(value to compare to || offset inito the NVRAM location) || number that represents the operation),operation是以下操作的一种:
- Equal。
- Not equal。
- Signed greater than。
- Unsigned greater than。
- Signed less than。
- Unsigned less than。
- Unsigned greater than or equal。
- Signed greater than or equal。
- Unsigned less than or equal。
- Signed greater than or equal。
- All bits match the challenge。
- If a bit is clear in the challenge, it's also clear in memory。
使用这些功能,你可以设定所有的值大于1,或者小于1000。当你读到多元素认证时,你可以将这两者结合起来让这个值大于1并且小于1000,可以是开区间或者闭区间(大于等于,小于等于)。
如果通过Trial会话创建Policy,你需要执行TPM2_PolicyNV命令,传递的参数与命令TPM2_PolicyCounterTimer相同:Trial会话的handle,需要比较的NV索引(以及由起始索引到所引用位置的偏移),需要比较的值,以及怎样比较。
如果你将一个实体看作一个锁,那NVRAM区域中的值就像是锁的制动栓。如果他们的值是正确的,就可以使用这个实体。如果实体内部的状态正确,锁就会被打开。
但是,TPM2.0还可以做更有趣的事情:一个实体的授权可以受控于一个TPM之外的设备的状态。
或许TPM2.0设计中最有意思的新的断言方式就是,断言依赖于一个外部设备的状态。这个外部的设备可以代表一个公私秘钥对儿。设备的状态可以是任何可以用它的私钥签名的东西(当然还要结合TPM产生的nonce值)。如果设备是一个生物信息设备,授权的形式可以是“Bob 向我证明了他的身份”。如果设备是一个GPS设备,那就是“我现在的位置是巴尔的摩市”。如果是一个时间服务,断言有可能是“当前的时间是交易时间”。相关的断言会识别代表设备的公钥以及代表设备状态的值(一个签名值)。TPM仅仅是比较签名和期望的鉴定信息。TPM不会对比较的结果做任何进一步计算,所以是(making the representation)设备需要决定它的输入与它签名的内容一致。
这个特点为生物信息提供了灵活性:如果Bob向指纹识别器注册了几个手指的指纹,TPM不需要知道到底是哪一个指纹信息被签名——只需要知道这个比较对应用户Bob。一个GPS设备不需要特别精确——仅仅是指定的一个区域即可。断言不需要指定一个特别精确的时间,而是指定一个可以接受的时间段就行。但是这个灵活性也不是完全通用的。这不是在说“一些指纹识别器已经证明Bob已经向设备做了身份认证”;而是说“这个特定的指纹识别器已经证明Bob已经向设备做了身份认证”。这个就允许Policy的创建者决定使用他信任的生物信息设备,从而防止被轻易地欺骗。
一旦这个Policy被满足,就没有进一步的检查了,所以有可能在一个命令执行的时候,相关的断言已经再也不能通过了。
创建这样的Policy同样由一个和哈希算法匹配的全0缓冲区开始。然后这个缓冲区会被扩展以下的值:TPM_CC_PolicySigned||SHA256(publicKey)|| stateOfRemoteDevice,stateOfRemoteDevice有两部分组成:描述的大小,和描述本书。
如果使用Trial会话创建这个Policy,需要执行TPM2_PolicySigned命令。再次说明,必须传递Trial会话的handle,与设备的私钥相对应的公钥handle,远程设备的状态。举例来说,如果远程设备是指纹识别器,它可以对这个信息签名“Sally correctly authenticated”。
有时候对象的创建者真得不知道他们创建的秘钥将会在什么情况下使用。或者秘钥会在紧急情况下使用,但是秘钥创建者不知道谁会用,会怎么用。这就是通用型Policy的应用场景。
TPM1.2设计的一个主要问题是PCR太脆弱。当一个实体被锁定到一个PCR后,就不能修改PCR的值了。PCR0用于表示BIOS固件,安全性很重要。如果PCR0的值变化了,那可能表示有了安全性漏洞。微软的BitLocker应用就使用它来提供安全性。但是,BIOS固件可能需要升级。当升级完成以后,PCR0的值就会改变,也就使得锁定到旧PCR值的实体再也不能用了。
应用程序可以绕过这个PCR的限制,它是通过在升级BIOS之前将被锁定的秘钥解密,然后升级,最后使用新的PCR0的值来锁定秘钥。但是这个过程很烦琐,并且在升级BIOS期间这些秘钥是处于明文状态的。因此,EA能够允许修改PCR的值但是不用解密锁定的数据这个特点很重要。但是这仍然需要很明显地检查在什么情况下Policy可以改变。有很多可能的方案被考虑过,包括增加一个专门用于修改这个policy的授权。
最终的解决方案很机智,它通过使用TPM2_PolicyAuthorize命令来实现,我称这种方法为通配型Policy。在玩扑克时,一个通配卡可以替代任何通配卡持有者想要替换的卡。一个通配型的Policy同样也可以替换任何持有者想要换的Policy。更进一步讲,任何通配Policy所有者同意的Policy都可以用于满足这个通配型的Policy。在创建一个通配型的Policy时,可以通过一个wildCardName参数来限制Policy。这就是说通配型Policy的所有者可以选择具有特定名称的Policy可以满足通配型Policy。一个与OEM的BIOS签名秘钥相关的通配Policy理论上可以被任何经过BIOS签名的Policy替换。
通配型Policy的创建方式与使用外部设备状态的Policy类似。通过将Policy会话扩展以下内容:TPM_CC_PolicyAuthorize||keySign->nameAlg||keyName||wildCardName。与PolicySigned断言一样,如果你使用Trial会话创建通配型的Policy,首先需要加载一个公钥到TPM(使用TPM2_LoadExternal命令),然后执行PolicyAuthorize命令。
TPM2_LoadExternal命令会返回已加载公钥的handle,这里叫做aPublicHandle。然后你就可以执行TPM2_PolicyAuthorize,并传递Trial会话的handle,wildCardName,以及aPublicHandle。
TPM2_PolicyAuthorize是TPM中最有用的Policy之一,因此它是在对象创建之后可以修改对象Policy的唯一方式。这就意味着如果如果对象已经被锁定到一组PCR值(对应一个特定的系统配置),然后系统的配置发生了变化,对象的Policy可以通过这个方式被有效地修改从而与新的配置匹配。你将会在“示例”那一节看到更多其他的例子。
尽管这个特性严格来说并不是一个断言,TPM可以限制一个Policy只能被特定的命令使用。比如说,你可以限制一个秘钥只能用于签名但是不能用于认证其他秘钥。如果做了这个限制,Policy只能被这个特定的命令使用。通常来说,这个不会限制不会作为一个单独的断言,但是非要这样做技术上也没有问题。在一个秘钥的Policy中声明这个秘钥只能用于签名,那这个秘钥既不能认证其他的秘钥也不能被其他秘钥认证。这是因为当一个秘钥在做认证或者被认证时,它需要提供它不能提供的授权(???)。
为了创建这样的Policy断言,你首先将与哈希算法匹配的缓冲区初始化为全0。然后使用以下的值扩展:TPM_CC_PolicyCommandCode||the command code to which the policy is to be restricted。如果是使用Trial会话来创建这个Policy,需要执行TPM2_PolicyCommandCode,同时传递Trial会话的handle以及相应的命令代码(command code)。
通常来说,如果你限制一个实体比如秘钥只能用于一个命令,你应该也会认证这个命令的使用。这就要求对这个秘钥施加不止一种限制,这就是多元素认证的主题了。
TPM知道怎样使用断言来做认证。它还可以多个断言来做。举例来说,登录一台PC时,用户可能需要同时提供指纹和只能卡用于身份认证。
我们已经在前面的介绍中看到,Policy的创建的过程与PCR扩展的操作类似。它们都有一组全0的值开始(这组值的大小取决于创建Policy时选择的哈希算法)。当一个Policy命令被调用时,当前Policy的值就会被更新,首先在旧值的基础上扩展新参数,然后对这个结果做哈希,最后用新的哈希值替换旧的哈希值。这个操作在PCR中叫做扩展。一个针对Policy的逻辑AND操作就是通过在Policy上扩展新的断言来实现的。就像一个PCR一样,Policy在第一个断言之前是初始化的全0,但是之后断言就会在原有的基础上更新。
如果你正在使用Trial会话创建这种类型的Policy,开始和结束的方法与之前相同——你只需要在中间执行AND操作对应的命令。
如果你希望在Policy中包含一个口令和使用一个秘钥签名并且对应公钥为S的智能卡断言,创建Policy时,可以首先用以下的值扩展全0的缓冲区:
TPM_CC_PolicySigned||SHA256(publicKey)||0x0000=0x0000060||SHA256(S)||0x0000
注:最后的0x0000表示你没有为签名提供PolicyReference,所以最后的值是2个字节的全零。
然后再扩展口令相关的要求
TPM_CC_PolicyAuthValue=0x0000016B
如果你希望这个命令只能在Locality4中执行,还需要扩展如下的值:
TPM_CC_PolicyLocality||Locality4
扩展一个新的要求等价于执行一个逻辑AND操作。
使用Trial会话来创建Policy时,你需要授权加载公钥到TPM,然后执行以下命令:TPM2_PolicySigned,TPM2_PolicyAuthValue,以及TPM2_PolicyLocality。
在这个例子中,Bob创建了一个秘钥,它要求这个秘钥只能用于签名,并且还要提供秘钥的口令。有全零的缓冲区开始,首先扩展以下的值:
TPM_CC_PolicyCommandCode|| TPM_CC_Sign=0x0000016C||0x0000015D
然后扩展以下的值:
TPM_CC_PolicyAuthValue=0x0000016B
在这个例子中国,Bob创建了一个秘钥,它要求PCR1的值为approvedPCRdigest,一个口令,以及一个指纹信息。当创建一个涉及到PCR摘要的Policy时,首先做PCR相关的操作是一个很好的习惯。这是因为如果这个操作失败了,不需要打扰用户让他们提供口令和指纹。
使用TPM创建这个Policy的过程如下:
- 启动一个Trial会话。
- 使用TPM2_PolicyPCR命令来将Policy锁定到approvedPCRdigest。
- 使用TPM_PolicyAuthValue命令(指示TPM在命令执行时输入口令)。
- 加载指纹识别器的publicKey到TPM中。
- 使用TPM2_PolicySigned并传递公钥的handle和stateOfRemoteDevice(也就是“Bob的指纹信息”)。
- 从TPM获取Policy的值。
- 结束会话。
在这个示例中,IT管理员只在一次启动周期内授权(比如说一个技术人员)使用之前创建的秘钥。首先,管理员想要技术人员使用这个秘钥,他会通过TPM2_GetCapability读取当前的启动计数器值,然后授权一个秘钥的Policy,这个Policy会声明,在授权秘钥使用时启动计数器的值必须是当前刚读到的值。管理员会使用他们的私钥签名这个新的Policy,叫做newPolicy。如果秘钥在管理自己的TPM中,他就可以用TPM2_Sign命令来签名。然后管理员将这个policy和对应的签名发送给技术人员。技术人员首先会使用TPM2_LoadExternal命令加载管理员的公钥到TPM中,然后使用TPM2_VerifySignature命令来验证这个这个新Policy的签名。这个命令会返回一个凭据(ticket)。
技术人员使用这个秘钥时会首先启动一个Policy会话,然后执行TPM2_PolicyCounterTimer命令并传递一个指向启动计数器的偏移。这个操作满足了newPolicy。接下来技术人员会执行TPM2_PolicyAuthorize命令,传递参数newPolicy和刚刚收到的凭据,以及管理员公钥的handle。TPM会用公钥验证凭据对newPolicy是有效的。此时,技术人员就可以在这次启动周期内使用这个秘钥了。
当PC重启以后,启动计数器的值会增加。如果技术人员试图再次使用newPolicy,就再也不能成功了,因此他也就不能使用这个秘钥了。
在这个示例中,假设IT管理员想要将一个全磁盘加密应用的秘钥锁定到一组代表BIOS固件的PCR中。但是管理员意识到BIOS可能会更新,所以他使用TPM2_PolicyAuthorize命令来增加灵活性,灵活性主要体现在使用什么样的PCR值来释放硬盘加密秘钥。
管理员的秘钥在创建时仅仅使用TPM2_PolicyAuthorize,但是他可以授权新的Policy,并要求PCR值匹配。然后管理员使用TPM2_VerifySignature来生成一个凭据用于验证新Policy的使用。
当需要使用解密秘钥时,响应的软件需要做以下事情:
- 启动一个新的Policy会话。
- 使用TPM2_PolicyPCR来复制TPM中的新Policy。
- 使用TPM2_PolicyAuthorize(提供管理员公钥,新的Policy,以及Policy凭据)让TPM修改当前会话内部的Policy缓冲区为原始的PolicyAuthorize Policy的值。
- 使用刚刚满足的Policy会话来释放磁盘解密秘钥。
如果管理员需要修改被验证的PCR的值,他可以给用户提供针对新的PCR值的Policy,用户可以使用这个新的Policy创建一个新的ticket以供应用软件使用。
在这个示例中,假设一组人被授予访问部门秘钥的权限。但是因为部门的人会不断更新,一些人的权限被取消,另外一些人需要授予权限。部门中的每一个人都有权限访问代表他们自己的私钥。通过巧妙地使用TPM2_PolicyNV,TPM2_PolicyAuthorize,和TPM2_PolicySigned命令可以实现这个功能。
首先,你需要创建一个NV索引,对应的内存区域有64位(假设你的部门的人数永远不会超过64人,注:那么问题来了,万一超了呢?)。只有IT管理员有这个NV的写权限,管理员会使用他的私钥。管理员会将NV的值全写0。然后他还会创建一个部门的秘钥,秘钥使用PolicyAuthorize Policy,对应的公钥为部门IT管理员的公钥。
IT管理员为这个部门的每个人分配一个NV区域中的比特位。为了授予用户使用秘钥的权限,管理员创建并且“同意”一个要求对应NV比特位为1的Policy(使用命令PolicyNV),并且要求用户使用他们自己的私钥来做身份验证,这通过PolicySigned来实现。当管理员想要撤销用于使用秘钥的权限,他只需要将对应的NV比特位写0。然后管理对这些新的Policy签名然后分发给对应的用户。
当用户想要使用这个秘钥时,他们会做以下事情:
- 启动一个Policy会话。
- 执行PolicyNV命令来验证这个用户仍然在这个部门里。
- 执行PolicySigned命令向TPM证明当前用户就是Policy中指定的人。
- 执行PolicyAuthorize命令将TPM内部的Policy缓冲区更新成PolicyAuthorize Policy。
- 使用这个秘钥。
前面已经提到,这个功能只需要执行两个命令:一个命令指定NVRAM的值大于1,另外一个命令指定它小于100。在这个例子中,允许的NV值为2,3,4,...99。
TPM2_PolicyOR是最后一个用于Policy的逻辑组合命令,这样一来,用户就可以创建有用的Policy,这些Policy可以做任何逻辑上可行的事情。这个命令可以让用户将多个Policy组合成多个分支,每一个分支都可以用于满足一个混合型的Policy,如图14-5所示。
图14-5 将一个混合Policy看作是一个电路图
尽管TPM2_PolicyOR命令可以用于更加复杂的配置中,但是最简单的方式是先创建一些独立的用于特定授权实体使用方法的Policy,然后通过TPM2_PolicyOR将它们组合成一个混合Policy。通常情况下需要先通过AND操作,将一组表示一个用户或者角色的断言组合成一些简单的Policy,然后再通过OR操作将这些简单Policy组合。
假设有以下的应用场景:
- Dave使用一台机器时使用一个需要指纹和口令的Policy来做身份验证。
- Dave还可以使用口令和智能卡来做身份验证。
- Sally使用智能卡和虹膜扫描器来做身份验证。
- IT管理员只能使用秘钥复制功能,并且必须在系统的PCR0-5包含已知的值时通过智能卡来授权这个操作。
这个应用场景可以使用图14-5的电路图来图形化地表达。
创建这个复合Policy的一个简单的方式是首先创建四个独立的分支Policy,分别对应图中的Dave1,Dave2,Sally,以及IT。
第一个Policy指定Dave必须通过一个外部设备(指纹识别器)来认证自己的身份。然后他还必须提供口令。之前我们已经有相关的介绍,具体的步骤如下:
- 启动一个Trial会话。
- 执行TPM2_PolicySigned命令(传递指纹识别器的公钥和合适的policyRef值)。
- 执行TPM2_PolicyAuthValue。
- 从TPM拿到Policy的值,我们称为policyDave1。
- 结束会话。
第二个Policy(Dave2)要求Dave输入口令并且使用智能卡签名一个来自TPM的nonce值,从而证明他是智能卡的所有者:
- 启动一个Trial会话。
- 执行TPM2_PolicyAuthValue。
- 执行TPM2_PolicySigned命令(提供智能卡的公钥)。
- 从TPM获取Policy的值。我们称为policyDave2。
- 结束会话。
第三个Policy要求Sally必须首先使用她的智能卡签名一个来自TPM的nonce来证明她是智能卡的授权拥有者,然后通过外部设备来授权她自己,即虹膜扫描仪,从而让外部设备来向TPM证明Sally的身份:
- 启动一个Trial会话。
- 执行TPM2_PolicySigned命令(使用智能卡的公钥)。
- 执行TPM2_PolicySigned命令(提供虹膜扫描仪的公钥和合适的policyRef)。
- 从TPM获取Policy的值。我们称为policySally。
- 结束会话。
最后,IT管理员的Policy要求管理员使用它的智能卡签名一个TPM产生的nonce,然后检查PCR0-5在期望的状态。更进一步,IT管理员只能用这个授权做秘钥复制:
- 启动一个Trial会话。
- 执行TPM2_PolicySigned(使用智能卡的公钥)。
- 执行TPM2_PolicyPCR(传递选择的PCR,和它们的期望值)。
- 执行TPM2_PolicyCommandCode,传递TPM_CC_Duplicate。
- 从TPM拿到Policy的值。我们称为policyIT。
- 结束会话。
上述的每一个Policy都可以被单独地分配给一个TPM实体。但是,如果你希望其中任何一个Policy都可以用于授权Policy时,使用TPM2_PolicyOR来实现:
- 启动一个Trial会话。
- 执行TPM2_PolicyOR命令,传递一个Policy列表:policyDave1,policyDave2,policySally,以及policyIT。
- 从TPM获取Policy的值,我们称为policyOR。
- 结束会话。
按照上述方式在一个TPM中创建的Policy可以用于任何其他TPM中。PolicyOR的一个限制是,它最多只允许将8个Policy组合在一起。但是就像是电路设计一样,PolicyOR的结果又可以使用PolicyOR组合起来,所以最终等价于理论上无限多的OR操作。举例来说,如果X是8个Policy使用PolicyOR组合的结果,Y是另外8个Policy使用PolicyOR组合的结果,你可以通过PolicyOR将X,Y组合起来,这等价于一次使用PolicyOR将16个Policy组合起来。
假设John有一个家庭PC,这个PC配有一个指纹识别器。他还有一个工作PC,这个PC使用智能卡做认证。John想要授权两台机器都可以读取云端的加密数据。他可以将云端加密数据的密钥锁定到一个特定的Policy来实现。这个Policy要求它的家庭PC使用指纹识别器做授权,要求工作PC使用智能卡做授权。
他首先要为家庭PC创建一个Policy。他会读取指纹识别器的公钥并且配置识别器在他的手指划过识别器时对“John’s fingerprint”签名:
- 启动一个Trial会话。
- 执行TPM2_LoadExternal命令将指纹识别器的公钥加载到家庭PC的TPM中。
- 执行TPM2_PolicySigned命令(传递指纹识别器的公钥handle以及合适的policyRef)。
- 从TPM获取Policy值。我们称为HomeFingerprintPolicy。
- 结束会话。
然后John来到他的工作电脑上:
- 启动一个Trial会话。
- 使用TPM2_LoadExternal将智能卡的公钥加载到TPM中。
- 执行TPM2_PolicySigned命令(传递智能卡的公钥和一个空的policyRef)。
- 从TPM中拿到Policy的值,我们称为WorkSmartcardPolicy。
- 结束会话。
现在John可以创建一个可以满足两台机器授权的混合Policy了:
- 启动一个Trial会话。
- 执行TPM2_PolicyOR命令,传递由HomeFingerprintPolicy和WorkSmartcardPolicy组成的Policy列表。
- 从TPM中拿到Policy的值。我们称为WorkOrHomePolicy。
- 结束会话。
最后这个Policy就是John用于创建密钥的Policy。他会将这个密钥复制到其他的机器上,然后就可以安全地在这些电脑上使用这个密钥。(这里遗留了一些问题:创建密钥以后怎么复制呢?复制完成以后具体使用的时候又该怎么操作呢?且看后续分解)
在大多数的应用场景中,Policy应该代表使用TPM实体时的角色——通常情况下只有少量的角色。
这个角色描述了用户使用一个实体时的认证。使用一个实体表示做以下的事情:
- 使用一个密钥签名。
- 读取NV区域。
- 写一个NV区域。
- 使用一个密钥做引用(Quote)操作。
- 创建密钥。
实体的管理员可能针对不同的实体做不同的事情。对于NVRAM来说,他们可能负责管理有限的资源,这可能包括以下操作:
- 对于NV:
- 创建和销毁NV索引。
- 对于密钥:
- 授权复制密钥。
- 使用PolicyAuthorize修改密钥的授权方式。
如果一个密钥的用户离开公司或者因为某种原因不能使用一个必须的密钥来获取公司相关的数据时,另外一个人(比如说这个用户的上级)能够使用密钥就显得很重要了。这就是候补角色。
一个办公室角色就是公司管理员角色和用户角色使用PolicyOR组合的结果。(这个翻译可能不太准确)
一个家庭角色是由一个管理员和终端用户组成的角色。它可以包含一个具有如下功能的角色,这个角色可以在不同机器上以不同的角色使用相同的TPM实体,因为同一个实体可能在不同的机器上有不同认证方式。(比如说,一台机器上有生物信息识别器而另外一台木有)。
一旦定义好角色后,就可以为他们创建相应的Policy。这些Policy创建之后,可以在创建其他实体的时候复用它们,从而避免每次都重新创建它们。
我们已经介绍了怎样满足很多简单的Policy。我们可以看到满足这样的Policy的步骤很相似:
- 启动一个Policy会话。
- 满足Policy(这个可能需要很多步骤)。
- 执行被授权的命令。
- 结束会话。
这个步骤与创建Policy的过程类似,但是真正满足一个Policy经常需要额外的操作。在一个高层次的API中,大部分繁杂的工作已经为用户做好了;但是如果你是直接和TPM通信,还需要了解其中的一些细节。
在第13章中我们看到,动Policy会话很简单。它就是通过TPM2_StartAuthSession命令来实现的。这个命令会返回很多内容,包括一个会话的handle,这里我们称作myPolicySessionHandle;一个TPM产生的nonce值,这里我们称作nonceTPM。为了满足Policy,你会用到这两个变量。
当我们满足不同类型的Policy时——简单断言,多元素断言,混合断言,以及灵活断言——需要考虑的事情会有略微不同,所以让我们来分别介绍一下。需要强调的是,记住满足Policy时的内部操作顺序是很重要的。一个由TPM2_PolicyPCR,然后是TPM2_PolicyPassword构建的Policy与先执行TPM2_PolicyPCR,然后是TPM2_PolicyPassword构建的Policy是不同的。总结来说就是,Policy命令之间没有互换性。
大多数的简单断言很容易应用到Policy中。口令,PCR,Locality,TPM内部状体,NVRAM区域的内部状态,以及基于命令的断言等,它们的使用方式和创建Policy时相同,唯一不同的是使用的会话不同,满足Policy时我们使用myPolicySessionHandle。另外一些需要验证签名的命令需要更多的操作(比如TPM2_PolicySigned命令,使用或者不使用policyRef)。
具体来说,如果正在使用一个需要输入口令的Policy,你需要执行TPM2_PolicyPassword命令。这个时候并没有真正向TPM传递口令。这个命令仅仅告诉这个会话,当执行与这个对象相关的命令时,用户必须向TPM证明他知道口令,并且需要以明文或者会话HMAC的方式传递口令。
为了满足包含TPM2_PolicySigned的Policy,需要一个签名,签名的对象是包含上次TPM返回的nonceTPM及其他内容的哈希值。另外,TPM内部必须有已经被加载的公钥,从而用于验证签名。
加载公钥和前面介绍的创建Policy时的操作一样,都是使用TPM2_LoadExternal。这个命令会返回已加载公钥的handle,这里我们称作aPublicHandle。在调用PolicySigned命令时会用到这个handle,但是再此之前,你需要向TPM传递一个签名。为了传递签名,你首先又需要构造一个哈希值,然后对它签名。哈希值由以下内容组成:
aHash = HASH(nonceTPM || expiration = 0 || cpHashA = NULL || policyRef = 0x0000)
上述公式中,nonceTPM是启动会话时TPM返回,expiration是全0(没有终止日期),cpHash=Empty Auth,policyRef是空缓冲区emptyBuffer。(如果你正在验证生物信息识别器,那policyRef就是通过生物信息认证的用户的名称)。公钥对应的私钥用于签名这个哈希值;当签名完成以后,这个结果叫作mySignature。
下一步你需要执行TPM2_PolicySigned命令,传递的参数包括会话的handle,aPublicHandle,以及mySignature。此时TPM会在内部使用公钥验证签名,如果验证通过,就会扩展Policy缓冲区。现在,任何需要具有上述Policy的对象的TPM命令都可以顺利执行了。
如果Policy是混合的Policy——也就是说,它是PolicyOR将几个Policy分支组合的结果——用户需要确定他们正在使用哪一个分支来满足Policy。一旦用户选择好Policy分支之后,他们会首先满足这个Policy分支,然后执行一个TPM2_PolicyOR命令,这个命令会将已经满足的Policy转换成最终可以授权动作的Policy。如图14-6所示。
图14-6 一个使用OR的例子
这个图展示了有四种方法可以满足这个Policy。你可以通过使用指纹识别器和口令满足第一个分支Dave1:
- 启动一个Policy会话。
- 满足Dave1的分支Policy:
- 使用TPM2_PolicySigned满足指纹相关的断言。
- 使用TPM2_PolicyPassword满足口令断言。
-
在会话中设置标志,告诉会话当执行最终的命令时用户必须输入口令。
-
使用TPM2_PolicyOR将会话的Policy缓冲区转换成最终的Policy值。
-
执行命令,传递Policy会话和另外一个满足上述标志的会话,后者是用于传递口令(可以使用永久性的口令会话)。
注意: 我们可以告诉Policy会话在成功执行命令以后自动关闭。如果失败,你可以手动关闭。
为了满足Policy的第一个断言,你需要通过指纹识别器的公钥向TPM证明,Dave的指纹与指纹识别器中的内容匹配。为了实现这个目的,你需要向指纹识别器传递一个消息用于签名。这个消息是一个包含上次TPM返回的nonceTPM以及其他信息的哈希值。这个值被发送到指纹识别器之后,Dave用他的手指划过指纹识别器的传感器接口,如果指纹信息匹配,它就会用它自己的私钥对这个哈希值做签名,哈希值得计算过程如下:
aHash = SHA256(nonceTPM || expiration=0 || cpHash=NULL || state of Remote Device)
这里需要注意的是,policyRef是一个远程设备的状态。具体来说就是,指纹识别器需要签名这样一个事实:Dave刚刚用他的手指划过识别器,他的指纹与设备中存储的模板匹配。这个签名操作的结果叫做fingerprint_Signature。
接下来你需要加载指纹识别器的公钥。回忆一下,这个公钥的handle叫做aPub。
然后,执行TPM2_PolicySigned命令,需要传递的参数是aPub和fingerprint_Signature。
接下来你还需要执行PolicyAuthValue命令,这就保证当用户请求TPM执行一个对象相关的命令时,他必须提供对象的口令。这个操作涉及的具体命令是TPM2_PolicyAuthValue。
现在为止,你已经满足了其中一个分支Policy,还需要执行TPM2_PolicyOR命令来将会话内部的Policy缓冲区修改成最终的混合Policy,这个命令需要传递在Policy创建阶段生成的Policy的列表。
满足一个通配型的Policy要比创建这样一个Policy复杂。当我们创建一个通配型Policy时,仅仅认证了可以授权最终要使用Policy的一方的公钥。当我们真正使用Policy时,必须事先创建一个实现经过授权的Policy,并且提供一个可以证明这个Policy已经被授权所必须的凭据(ticket)。然后用户需要满足这个被授权的Policy,然后执行TPM2_PolicyAuthorize命令。TPM会检查Policy缓冲区和approvedPolicy匹配并且这个approvedPolicy确实是授权过的(通过检查ticket),如果这写检查都通过,它就把这个Policy缓冲区更新成最终的灵活policy(只有PolicyAuthorize的Policy)。
这样一来,准备一个Policy就是一个包含两个步骤的过程。首先,执行授权的一方必须允许一个Policy被使用,这是通过使用他们的私钥签名HASH(approved Policy || wildCardName=policyRef)来实现的。签名值回发送给最终的用户。
用户会加载上述授权方的公钥到TPM中,然后使用TPM2_VerifySignature命令来验证收到的签名,传递已加载公钥的handle。在验证签名的同时,TPM会产生一个Ticket(就是前面说的凭据)。
当用户想要使用这个新被允许的Policy时,他首先用通用的方式满足这个Policy,然后通过TPM2_PolicyAuthorize让TPM将这个Policy的值修改成灵活的Policy值(只有PolicyAuthorize的Policy,建议参考一下规范中PolicyAuthorize命令的描述,有一个图表述得很清楚),同时还要传递以下参数:刚刚满足Policy的会话的handle,被允许的Policy值,wildCardName,keyName,以及Ticket。TPM会验证ticket是正确的,并比较参数中的Policy值和会话Policy缓冲区的值。如果都匹配,这个会话Policy的缓冲区就会被更新成灵活Policy的值。
因此,创建一个灵活Policy包含以下两个过程。
扼要重述:首先创建Policy本省:
- 启动Tiral会话。
- 加载管理员的公钥。
- 使用TPM2_PolicyAuthorize命令指向管理员的公钥。
- 从TPM获取Policy的值,我们称为workSmartcardPolicy。
- 结束会话。
然后创建Policy并使用管理员的私钥签名:
- 创建一个Policy。
- 加载管理员的私钥。
- 使用管理员的私钥签名这个Policy。
- 使用这个Policy最终被使用的TPM来验证签名(这回产生一个ticket)(注意,这一步的TPM可能和前面步骤的TPM不同)
满足授权过的Policy时,这个Policy就是我们唯一需要关心的Policy。这个授权过的Policy是什么类型的并不重要,简单,混合或者灵活的Policy都没关系。满足之后,它最终会被转换。
接着上面的描述,现在TPM的Policy缓冲区的值已经和授权过的Policy值相同了,你可以通过执行TPM2_PolicyAuthorize命令将它转换成灵活Policy的值,同时还需要传递以下参数:当前Policy缓冲区的值(也就是授权的Policy值),PolicyTicket,以及AdministratorPublicKeyHandle。TPM会检查Policy缓冲区的值与刚刚的Policy参数匹配,并且这个Policy确实是被允许使用的(使用Ticket),如果上述检查都通过就修改Policy缓冲区的值。此时,需要使用与灵活Policy相关的对象的命令就可以执行了。
尽管TPM增加灵活Policy的初衷是为脆弱的PCR提供解决方案,但是它却可以解决更多的难题。它允许管理员在对象创建以后决定对象的Policy应该怎样被满足。因为对象的名称(或者NV索引的名称)是根据对象的Policy来计算的,所以不可能修改一个NV索引或者密钥的Policy。但是使用上述的灵活Policy,你却可以修改满足Policy的方式。
假设一个密钥创建的时候使用灵活的Policy,然后这个灵活Policy的管理员想要按照如图14-6的方式来满足Policy。他可以使用自己的私钥对图14-6中的Policy签名然后发送给最终的用户。用户必须完成前述创建Ticket的步骤,也就是通过执行TPM2_VerifySignature来生成Ticket。这步之后,用户只需要满足14-6中的Policy,然后执行PolicyAuthorize操作来向TPM证明他们满足的Policy已经被管理员允许了。
最后需要介绍的一个Policy用途就是,它可以用于证明一个特定的实体跟它是绑定的。当我们使用墨水来签订一个合同时,这个签名就和签订人不可逆转地绑定在一起,这是通过可以代表一个人的肌肉和神经系统的生物计量信息来实现的。这些生物计量信息决定了签名笔画的特点。电子签名从来不会以上述方式与一个人绑定。通常来说,电子签名是与一个口令绑定在一起的(一些人知道这个口令),或者是和智能卡(一些拥有的),又或者是生物信息绑定在一起。生物信息计量设备有可能被损坏,所以在大多数的实现中,总是有一个备份口令用于生物信息设备不能工作的情况。(有趣的是,墨水签名也有相同的问题,因为人们的手可能会受伤。)
TPM2.0中,你可以将一个密钥的使用与生物计量信息绑定,并且证明它们确实绑定在一起了。首先,要创建一个不可复制的密钥,密钥authValue属性设置,这样口令就不能用户授权,只能使用Policy来授权密钥的使用。Policy被设置成只能通过生物信息识别设备来认证,这还需要TPM2_PolcySign和当生物信息匹配用户时生物信息识别设备产生并签名的policyRef。上述创建的密钥只能在经过生物信息识别设备的身份认证后执行签名操作。我们将这个密钥称为A。
接下来,TPM2_Certify命令使用一个经过认证的,不可复制的限制性签名密钥对密钥A的名称进行签名。这个签名会绑定密钥的公钥部分(密钥的名称就是包含公钥及其他信息的哈希),密钥的authValue(这个信息也在名称中),以及密钥的Policy(同样包含在名称中)。通过检查限制性签名密钥的证书,一个远程认证机构可以验证这个由TPM2_Certify产生的证书(证书中包含签名信息,这里也是指这个命令产生的签名)是有效的。然后,认证机构将密钥的公共部分做哈希,然后验证密钥的名称是否正确。这个过程就验证了授权这个密钥签名的唯一方式是使用Policy,而不是口令(这里的结论有点突然)。密钥的Policy通过生物信息识别器的公钥来验证,证明只能在用户的指纹信息匹配时才可以满足Policy(这里的表述也有点绕,重点理解之前相关操作的描述)。
通过这样的认证方式,一个密钥的电子签名就和指纹信息绑定在一起了。使用类似的方式,可以生成与Policy绑定的密钥的证书(签名),这些证书可以向审计者证明密钥使用的授权Policy符合公司的安全标准。这也就解决了最后一个需要EA解决的问题。
这一章我们研究了TPM2.0新的增强版的授权方式,它可以用于授权任意TPM实体。你已经看到,EA Policy可以用于创建多种断言的逻辑组合(AND和OR)——这些断言的判断信息从口令以及智能卡到TPM内部状体或者远程设备的状态等。我们也介绍了使用用于多用户,多元素认证的EA示例,以及创建可以被灵活管理的Policy的方式。本章展示了许多使用相关命令解决各种各样问题的示例。然后你还看到了上述类型的Policy是怎样被满足的。最后,我们还了解了一个密钥怎样被绑定到它的Policy。TPM2.0的EA是其最复杂的技术之一,但是同时也是新设计中最有用的功能。