github.com/jlmucb/cloudproxy@v0.0.0-20170830161738-b5aa0b619bc4/Doc/KeysAndTrust.txt (about) 1 April 20, 2014 - Kevin Walsh 2 3 == Status quo (in Tom's implementation) == 4 5 Each Tao layer has its own public key pair and its own symmetric key. 6 - The public key pair is used to make signed attestations. 7 - The symmetric key is used to seal things on behalf of its "hosted" children. 8 9 Ignoring C++isms, the Tao layer provides this interface to its hosted children: 10 - Init() and Destroy() 11 These are just C++-isms, and I'll ignore them. 12 - (success, identifier) = StartHostedProgram(name, arglist) 13 Starts a hosted program, returns status and a unique identifier. 14 For the LinuxTao, "name" is a path to an executable in the local filesystem, 15 and args are passed to main's argv. 16 For KvmTao, name is a unique ID of some sort, and args contains a path to a 17 "vm spec" template, a path to a kernel file, a path to an initrd file, a path 18 to a disk image file, and some encoded channel parameters. 19 The TPM doesn't implement this at all. 20 - RemoveHostedProgram(child_hash) 21 Unregisters (but probably doesn't kill) a hosted program. Maybe "disown" would 22 be a better name. 23 The TPM doesn't implement this at all. 24 - bytes = GetRandomBytes(size) 25 Get strong random bytes. The root Tao has a way to generate strong random 26 numbers (i.e. the presumed special hardware in the TPM). And a hosted Tao can 27 either us use its own special technique or just pass the call down to its 28 parent Tao. 29 JLM: Or, more likely, seed a psuedo random nubmer generator using hardware entropy or 30 random numbers collected from it's host Tao. 31 - blob = Seal(data) 32 Seal the data into a blob that can be unsealed later. 33 - data = Unseal(blob) 34 Unseal a blob that was previously sealed. The blob must have been created via 35 a Seal request to this same Tao by the same hosted program. Here, "same hosted 36 program" means a program with the same child hash. And "same Tao" means "has 37 the same symmetric key", which in practice means the Tao and all its parent 38 Tao parents down to the root all have the same has as they did when the seal 39 operation happened, and they are all running on the same physical TPM. 40 - attestation = Attest(data) 41 Produce a signed attestation that essentially conveys "Tao says (child says 42 data)", where "Tao" is really the Tao's public key, and "child" is the hash of 43 the hosted program making the request. Ideally, a hosted program would make a 44 call where data conveys "(time<T) implies MyKeyIs(K)" for some values of T and 45 K, so the resulting attestation would convey "Tao says (child says ((time<T) 46 implies MyKeyIs(K)))". Actually, the it is the host Tao that puts in the 47 expiration, so the meaning is "Tao says ((time < T) implies (child says 48 MyKeyIs(K)))". The TPM implements this, sort of (see below). 49 50 Observation: GetRandomBytes seems out of place. Presumably, the TPM is a "good" 51 source of strong randomness (maybe?), so we want to provide a way for hosted 52 programs, regardless of how deep in the Tao stack, to access this randomness. 53 JLM: The TPM is an OK source of RNG's but its quite slow. Always asking for fresh 54 random numbers from your host is very expensive and more likely you'd use a PRNG 55 seeded occasionally by host entropy. Some Tao layers have direct access to very 56 fast hardware RNG's like RDRAND in the new Haswell chip. GetRandomBytes is not 57 out of place though since, absent special knowledge, the host is the only GUARANTEED 58 RNG source. 59 60 Observation: There is no uniform semantics or mechanism for "starting' a hosted 61 child. And why is there a remove operation but no kill? Every Tao is embedded in 62 some other entity (Linux, KVM, hypervisor) which has some mechanism for starting 63 and stopping children. In the C++ Tao implementation, we will of course have 64 some "register/unregister child" hooks that are hopefully generic enough to make 65 the Tao embedding trivial. But let's not pretend the Tao is providing much here 66 beyond whatever Linux (or KVM or hypervisor) already provides. 67 68 == Is the TPM a Tao? == 69 70 There are 5 essential Tao operations. 71 - The TPM implements 2 (Seal and Unseal) operations with normal semantics. 72 - The TPM does not implement 2 (StartHostedProgram, RemoveHostedProgram) at all. 73 JLM: Yes it does, in conjuction with the chipset it boots the trusted hypervisor 74 or OS and, in fact, a TPM owner can set policy on which initial programs it is 75 willint to boot. So it does do this. It only has one hosted system however and 76 in that way it may differ from Tao's higher in the stack. 77 - The TPM implements 1 (Attest) with basically the right semantics, but in a way 78 such that causes anyone that uses the result to have special TPM-specific 79 code. 80 JLM: Yes, this is unfortunate. It will be better with TPM2.0. 81 82 This is because the format of the resulting attestation is completely different 83 than the format of attestations produced by all other Taos. For the TPM, "child" 84 is a weird TPM-specific PCR datastructure, and the signature is over a messy 85 struct involving the data (and the expiration) and those PCRs. For all other 86 Taos, "child" is a simple hash, the attestation is a straight signature over a 87 simple data structure (defined in attestation.proto) that includes an expiration 88 time, the data, a hash algorithm ID, and the child hash. 89 90 == Trust among Taos == 91 92 It may not be obvious, but every hosted program (or hosted Tao) necessarily 93 trusts its host (or parent) Tao completely. Normally, a hosted program gives all 94 of its private keys, which are among its most important secrets, to the host Tao 95 for safe keeping via the Seal operation. So the Tao, if corrupt, could directly 96 impersonate any hosted program below it, or leak the keys and allow other 97 principals to do the same. 98 99 Even if the hosted program did not use Seal (perhaps it instead uses ephemeral 100 keys generated on each execution), the way the hosted program authenticates to 101 other principals is by way of an attestation from the host Tao. If the host tao 102 were corrupt, the host Tao could lie about the hash for some second (real or 103 imaginary) hosted program, and this second hosted program could then impersonate 104 the first hosted program for all remote authentication. 105 106 Suppose a hosted program does not use keys at all, has no long-term secrets, and 107 does not do remote authentication, Does this hosted program, which does not use 108 Seal or Attest, still trust the Tao completely? One might be tempted to say no, 109 because (in some situations and in the current implementation) the Tao service 110 doesn't have full kernel privileges, but instead runs as a separate user-level 111 linux process. However, we rely on the host Tao to start hosted programs. So a 112 corrupt host tao could covertly inject vulnerabilities into the hosted program 113 before the hosted program starts. Moreover, as the parent process, the host Tao 114 process has a lot of direct control over a hosted process. 115 116 To summarize: in practice, a hosted process necessarily and fully trusts its 117 host Tao, and this trust extends all the way down the stack of Tao hosts. 118 JLM: Yes, in fact this is VERY explicit which is why the policy key owner 119 may need to know the entire hosted path to make a signing decision over 120 Tao Keys. The most difficult job of the Tao Host is provide isolation between 121 its hosted programs. Hoe is does this varies depending on the Tao level. 122 123 == Trust for the TaoCA == 124 125 It has been said that every hosted program has one (and only one?) embed ed 126 policy key, and the hosted program trusts that policy key completely. Or at 127 least, for all authorization and authentication decisions. 128 129 This clearly doesn't include the root Taos, i.e. the TPMs, since they don't have 130 a policy key. And it may or may not include the FakeTaos (actually, at one point 131 I had code that could configure FakeTao to run as a pseudo-TPM, i.e. without an 132 attestation, or as a pseudo-hosted-Tao with an attestation but no parent). 133 JLM: The sort of do have an implicit policy key, namely the EK which must be 134 certified by a "trusted provider". Absent even the "key" paradigm, TPMs 135 have owner set policy which corresponds to the policy generally delegated by a key. 136 137 Do hosted programs actually fully trust the policy key? It is not clear that 138 this is necessary or even desirable. 139 140 If a hosted program gets an attestation chain from the policy key, and it uses 141 that attestation chain as its only means for authentication, then yes, the 142 hosted program necessarily fully trusts the policy key. This is the same 143 situation as described above for the parent Tao. Essentially, once the hosted 144 program takes on the new identity, it "becomes" the principal named by that 145 identity. 146 147 But I see no reason that a hosted program could not use multiple identities 148 (i.e. multiple attestation chains) for different purposes. In this case, the 149 hosted program merely "speaks for" the principals named by those identities. And 150 if anything, this is the opposite of trusting the policy server -- the policy 151 server is trusting the hosted program to not abuse the privileges associated 152 with that identity. 153 JLM: This idea of code identity is that it is immutable (i.e.-represents 154 ultimately the exact same code (and possibly critical data). You should NOT 155 have multiple code identities although you certainly could participate in multiple 156 security domains either by explicity having multiple policy keys or letting the 157 master policy key delegate to others. 158 159 Here is a concrete example: Suppose we build a secure write-only logging 160 service, and the policy server (TaoCA) wants to use this service. The TaoCA can 161 provide the logging program with an attestation, and the logging program can use 162 that attestation to gain access to certain resources (say, confidential old 163 logs). But the logging service might have other secrets, e.g. keys that it uses 164 to ensure the write-only property of the logs, and there is no reason that the 165 logging program should trust the policy server on these matters. In fact, the 166 point is that we explicitly do not trust the policy server to do its own 167 logging, but we do trust the logging server to do it. 168 JLM: This is an example of limited delegate trust to perform a service but it 169 is not the same kind of "trust" you have to have in your hosts (and their hosts) 170 which is basically unrestricted at least on a designated stack. 171 172 Are there compelling examples of hosted programs that should necessarily and 173 fully trust the policy server? 174 JLM: Yes in practice, I think there is. Ultimately this becomes a 175 "policy distribution" problem analogous to a "symmetric key distribution" problem 176 without asymmetric ciphers and an n^2 policy problem is probably unmanageable for n>2. 177 As you point out, we may have constrained trust in a program operating elsewhere, written 178 by another entity with a different policy key (or no policy key) but this is always constrained. 179 Further, absent a "central" policy key, each program must maintain a list of things they trust, 180 which is stateful and presents distribution problems (just like CRLs). It becomes worse as 181 some Tao element underneath get compromised. For example, how does the program know 182 other programs have been determined to be flawed? Basically, the authority tells them and 183 they recover. I'm convinced that the notion of a policy key representing a well defined policy 184 domain is basic. Without it, I really have no overall sense of end-to-end security for an 185 "activity" as a practical matter. Finally, there is an (implicit) single root of policy in 186 practice anyway for the program: the person who wrote the final version of the program (and embedded 187 the key); whether he embedded a key or not we trust the program in this model. 188 189 == Key Rotation == 190 191 NIST suggests (a) all keys should be rotated about every year, and (b) all data 192 should be re-keyed every every one to three years. 193 194 In the current implementation, there are a lot of keys to keep secret: every Tao 195 layer has two (a private key and a symmetric key), and most of the "leaf" hosted 196 processes at least two as well. 197 198 The public key pairs used for authentication can be easily rotated. With two 199 exceptions (below), a principal can unilaterally discard its authentication key 200 pair at any time, generate a new key pair, then obtain a new attestation for the 201 new key from its host Tao. The process can discard the old key pair immediately. 202 For each processes with attestation chains involving the old public key, the 203 process can either (a) simply retain the old pubic key and attestation chain 204 until it expires, or (b) request a new attestation chain using the new public 205 key. Processes can make this choice independently. 206 207 The policy CA (aka TaoCA aka "key nego server?") can't unilaterally discard its 208 authentication key, since lots of other principals rely on it for authentication 209 and have copies of the policy CA's public key. The key must must be known by all 210 Tao layers and hosted programs so that they can validate attestation chains 211 rooted in the policy key or create authenticated network channels to the policy 212 CA and other principals. Currently, the policy key is given to each participant 213 through a (presumably) secure, offline channel at "setup time", and there is no 214 rollover mechanism. Since authenticated network connections rely on attestation 215 chains rooted in the policy key for that domain, an online key rollover would be 216 required: the new policy public key would be sent to all participants over a 217 channel authenticated using the old policy key. Any recipients could begin using 218 the new key immediately, but all would need to to keep the old policy public key 219 alongside the new one until all existing chains that might use the old key have 220 expired. 221 222 A root Tao (i.e. the TPM) similarly can't unilaterally discard its 223 authentication key (the TPM EK). In practice, of course, the TPM EK is permanent 224 and can not be changed. But even if it could, rotation would be difficult for 225 the same reasons as for the policy CA. 226 227 The symmetric keys are difficult to rotate. A "leaf" hosted process can normally 228 unilaterally select a new symmetric key at any time. Before it discards the old 229 key, it must re-encrypt all of its data using the new key. So long as the hosted 230 process manages and stores all of this encrypted data locally, this might be 231 plausible. 232 233 A host Tao (and some leaf hosted processes) can not easily rotate its symmetric 234 key because the encrypted data is held and manged by child hosted processes. We 235 might include an expiration and a "rollover" period in the seal operation. When 236 the rollover period starts, the host Tao can pick a new key. During the rollover 237 period, all hosted processes would be required to exchange all of their sealed 238 secrets for newly encrypted copies, or simply re-seal the original data. At 239 expiration (the end of the rollover period), the host Tao can discard the old 240 symmetric key. The TPM probably does not support this. 241 242 If symmetric keys are not ever rotated, and private keys are sealed using the 243 symmetric keys, is there a reason to rotate the asymmetric keys? Presumably yes: 244 the symmetric keys are used only (or mostly?) locally, but the asymmetric keys 245 are used on the network. 246 JLM: You're right with respect to the "hardware" key. To rotate it, you throw away 247 the hardware (or in some cases, you solder something to the board). In practice, 248 at every other lever keys can rotate; if only by distributing new versions of the 249 program with new policy keys. 250 251 == Alternative designs == 252 253 I see no reason for Tao to closely follow the abstractions presented by the TPM 254 interface, since nearly everything that talks to the TPM or deals with output 255 from the TPM has to use special-purpose TPM-specific code. So long as the Tao 256 API can be implemented on top of the TPM API, then nothing is lost in 257 implementation "elegance". There is some extra conceptual overhead for those 258 trying to understand the internals of how Tao is implemented, but users of Tao 259 need only understand the Tao API, not the TPM API. 260 JLM: yes, I agree. 261 262 With that in mind, here are some API suggestions. 263 264 == Tao generates keys for hosted program (idea #0) == 265 266 On balance, this is probably not worth implementing. 267 268 Currently, every hosted program needs a symmetric key pair, attested to by its 269 JLM: DO you mean asymmetric key pair? 270 parent Tao. This is done in three steps: call GetRandomBytes() from the parent 271 Tao, then generate the key locally in the hosted program, followed by calling 272 Attest() from the parent Tao. We could condense this into a single Tao call: 273 - (keypair, cert) = GenerateAuthenticationKey(suggested_expiration, other key details) 274 The host Tao (or one of its parent Taos) would generate a fresh key pair and a 275 matching signed attestation that the child can use for remote authentication. 276 277 Currently, GetRandomBytes() is used only for generating keys, but there are 278 plenty of other possible uses for GetRandomBytes(). So this proposal does not 279 eliminate getRandomBytes. 280 281 Currently, Attest() is used only for attesting to keys. If that remains the 282 case, then GetAuthenticationKey would obviate the need for Attest(). On the 283 284 JLM: GetAuthenticationKey has to have a mechanism to verify the identity of 285 the thing (program) it is giving its key to. I think this is morally equivalent 286 to Attest. Of course, for some hosts, you could have a different mechanism 287 to do this but since the bottom layer in a distributed system is stuck with a 288 public key based attest and since there are no performance or flexibility problems 289 with this, I don't know that we want another mechanism to worry about. 290 291 other hand, we can't eliminate Attest() if it evolves into a general-purpose 292 "says" operation that allows, for example, a hosted program without its own key 293 to get a signed credential to the effect of "Tao says child says stmt" for some 294 arbitrary statement. 295 296 Pros: 297 - Slightly more efficient. 298 - Maybe eliminate the Attest operation, whose semantics are currently hazy. 299 JLM: I'm not quite sure what you mean by hazy. Attest means "The signed data (usually 300 a key as you point out) came from the program with the following identity (the hash) which 301 was isolated by me (the host)." This seems like a very clear (and useful) assertion. 302 303 Cons: 304 - If we don't eliminate Attest(), then it makes the Tao API larger. 305 JLM: Why does it become larger? You argue above that we need Attest somewhere 306 (maybe only in HW) so it seems an alternate mechanism adds surface area. I'm not 307 sure I understand this comment. 308 - Functionality easily implemented in the hosted program using the existing API. 309 310 == A minimalist API (idea #1) == 311 312 I don't think we should do this, but I think it is a useful point of comparison. 313 314 Tao layers and other hosted programs form a tree. But currently, except for 315 GetRandomBytes(), there is no interaction between layers except during startup. 316 Upon startup, a hosted Tao does either a single Seal() and a single Attest(), if 317 this is the first execution and keys need to be generated, or it does a single 318 Unseal() to recover its previously-generated keys. From then on it has its own 319 set of keys, which it uses to implement Seal(), Unseal(), and Attest() for 320 hosted child processes. 321 JLM: There is continued interaction for StartHostedPrograms as new hosted systems 322 start and, of course, the hosted program can use the Generate/Attest/Seal/Unseal 323 dance to rotate keys (although this presumably doesn't happen too often. 324 325 If this is the case, why not simplify the API and eliminate the channels between 326 layers entirely? When a hosted program is about to be started, the host Tao 327 checks if sealed keys and an attestation exist for that program. If so, Tao 328 unseals the keys, and passes the keys and attestation as parameters to the 329 hosted program. If not, Tao generates a set of keys, seals them, makes an 330 attestation for them, then passes the keys and attestations as parameters to the 331 hosted program. There is no API for hosted programs to communicate with the host 332 Tao (except maybe GetRandomBytes). If a hosted program wants to keep secrets, it 333 can encrypt them itself using its own key. If it wants to do remote 334 authentication, it has a suitable key and matching attestation. 335 336 All of this applies to "leaf" hosted programs and to hosted Taos alike. The TPM 337 would be a special case (as it is now). In order to launch the first real Tao 338 layer, sitting directly above the TPM, someone (either that Tao or some helper 339 program) would need to open a connection to the TPM and make the necessary 340 seal/unseal/attest requests. This special-case code is really implementing the 341 TPM's missing StartHostedProgram() call. 342 343 Pros: 344 - Simpler (trivial) API and implementation. 345 JLM: Again, to my mind this seems more complicated. Since you need the Tao at the lowest level 346 adding additional mechanism just adds to surface area. Of course, you could package the basic 347 dance so that layers that don't care about it make simpler calls but you've added complication 348 (as measured by mechanisms and code). Packaging the mechanisms is fine and represents a saving 349 in terms of how many people implement what but it doesn't save, and in fact increases, the "minimal" 350 implmentation footprint. 351 - Efficiency: no need to keep secure channels (pipes) open. 352 - Hosted programs don't need generate or rotate their own keys. 353 JLM: They still may need to rotate their keys. The hosts are not necessarily in the same 354 trust domain as the children. Policy only requires that host adhere with their contract not 355 that they be able to carry out all security related domain actions. In fact, the idea is to 356 let lower Tao levels be as simple as possible to avoid security issues that will necessarily affect 357 their hosted programs. By contrast, two hosted programs in the same security domain can 358 actually segregate duties, thus preventing a single program from causing universal damage. 359 360 Cons: 361 - Hosted programs don't control their own key generation or rotation. 362 - Hosted program keys are in memory during the entire program execution, with no 363 flexibility to do seal-then-reseal for shorter intervals. 364 - Hosted programs can't easily have multiple keys (say, with different 365 expirations or strengths), multiple attestations (say, from different policy 366 servers), etc. 367 368 == Sealing with expirations (idea #2) == 369 370 I think we should at least do option (b) below. It is simple but it adds some 371 nice functionality that is currently missing. 372 373 To facilitate rotating the symmetric keys, seal/unseal should really have an 374 expiration. When a hosted program seals data, the hosted program and the host 375 Tao agree on some expiration date. The host Tao promises to keep the sealing key 376 available until that expiration, but no longer. The sealed bundle is only 377 guaranteed to be unsealable until the expiration, and it is up to the hosted 378 program to ask for the sealed bundle to be rekeyed with a new expiration date 379 before the original expires. 380 381 There are choices: 382 383 (a) The Tao keeps a set of one or two sealing keys, one active, one old, both 384 with expirations. When the old key expires, it is discarded. When the active key 385 nears expiration, it becomes the old key and a new active key is generated. Tao 386 uses the active key for sealing, and refuses to seal data with an expiration 387 past the active key's expiration. For unsealing, Tao uses whichever key is 388 needed. 389 390 Pros: 391 - Easy to implement host Tao (small delta from current implementation). 392 393 Cons: 394 - Painful for hosted programs, which must re-seal according to host Tao's 395 schedule. 396 - Hard to chose expiration for host Tao key -- too short forces repeated 397 re-sealing, too long adds unnecessary risk. 398 399 (b) Same as (a), but Tao could instead keep multiple key sets with different 400 expiration schedules. So there might be five key sets that rotate every hour, 401 week, day, year, and decade. When a hosted program requests to seal data with 402 some expiration time, Tao just uses the active key for the shortest appropriate 403 set. 404 405 Pros: 406 - Simpler semantics for hosted programs: they can chose any reasonable 407 expiration. 408 409 Cons: 410 - More state for Tao, but not significant and could be made constant. 411 - Expirations of sealing key will not exactly match expiration for data. So a 412 2-year sealed bundle might have been signed with a key that is kept for a 413 decade. 414 415 (c) Tao could use a unique symmetric key for every seal operation, with the key 416 expiration chosen to match the requested expiration of the data. During seal, 417 Tao generates the key, sets its expiration, and returns the encrypted data to 418 the hosted program. Tao manages the sealing key just like it manages its other 419 secret data, i.e. by asking its parent Tao to seal it or by encrypting it and 420 having its parent Tao seal the encryption key. 421 422 Pros: 423 - Simple semantics for hosted programs: they can chose any expiration. 424 - Expiration of sealing key exactly matches expiration of data. 425 - Amortization of costs and extra state management adds complexity to host Tao. 426 427 Cons: 428 - Expensive: potentially multiple key generations and encryptions (as 429 many as one for each Tao layer, including one for the TPM) for every Seal() 430 operation. Similar for Unseal. 431 - Cost for recursive calls might be amortized across Seal/Unseal operations: 432 host Tao could wait some time or until it has generated N sealing keys, then ask 433 its parent Tao to seal them all together or use its own symmetric key to encrypt 434 them. 435 - More state for each Tao layer, grows with number of Seal() operations. 436 - Because of state growth, may want way to reclaim keys that are not expired but 437 no longer needed. 438 439 (d) Same as (c), but the host Tao doesn't manage the sealing key. Instead, it 440 generates a per-bundle sealing key, then asks its own parent Tao (or the TPM) to 441 seal that sealing key. Then encrypted data and encrypted key make up the sealed 442 bundle. During unseal, Tao asks its parent to unseal the key, then uses the key 443 to decrypt the data. This is recursive, with each layer generating a key then 444 asking its parent to seal that key. Alternatively, the same effect can be 445 achieved by just having Tao append the child name to the data, then pass this to 446 its parent Tao for sealing. The parent will in turn append a name and pass it to 447 its own parent. During unseal, each layer asks the parent to unseal, then checks 448 the name at the end (as it currently does), then passes the result back to the 449 requester. 450 451 Pros: 452 - Simple semantics for hosted programs: they can chose any expiration. 453 - Expiration of sealing key exactly matches expiration of data. 454 - Simple implementation: no extra state stored by host Tao. 455 456 Cons: 457 - Expensive: always multiple key generations and multiple encryptions (one for 458 each Tao layer, including one for the TPM) for every Seal() operation. 459 Unseal() is similarly expensive. 460 461 == TaoCA is a Tao (idea #3) == 462 463 Though I haven't digested this idea completely yet, I don't like it. 464 465 I argued above that hosted programs should not normally fully trust the TaoCA 466 server (aka policy server). But if we are going to go with the idea that each 467 hosted program has an embed ed policy key that it fully trusts for all important 468 decisions... then why not consider TaoCA to be a Tao? 469 470 The requirement for being a parent (i.e. a Tao) are: 471 - There is a secure authenticated channel from parent to each child (or one can 472 be created when needed). 473 - The parent can recognize and identify its children. 474 - The parent can provide the Tao API operations for its children. 475 476 TaoCA can easily generate keys sufficient to implement the Tao operations 477 (except getRandomBytes and start/remove hosted program). It basically implements 478 Attest() already. And even though it doesn't implement start/remove hosted 479 program, it has enough information that it can recognize its own children, e.g. 480 its list of approved TPM EKs. It can create authenticated TLS channels to its 481 children because it happens that every one of its children either (a) possesses a 482 TPM EK the TaoCA knows about or (b) possesses an attestation chain from a TPM EK 483 that the TaoCA knows about. 484 485 Here, a hosted Tao can have more than one parent Tao. LinuxTao might have the 486 TPM as one parent and a TaoCA as a second parent. Other layers hosted on that 487 Tao might have additional (or the same) TaoCAs as parents. Even a "leaf" hosted 488 program may have multiple Tao ancestors, because its host Tao and/or other 489 ancestor Taos have multiple parent Taos. So some Tao operations may require 490 extra parameters to specify which line of ancestry to follow for that call. For 491 example, Attest() would need to specify a complete path from some root Tao, 492 among all the possible root ancestor Taos, all the way down to itself. 493 494 JLM: While I don't think of the TaoCA as a Tao, it could and probably should 495 be able to negotiate and shared keys within a domain. For me, multiple Tao hosts 496 makes end-to-end evaluation of hosted programs too complicated and error prone 497 and given the distributed policy, I just don't see the need. 498 499 Pros: 500 - Formalizes the role of the TaoCA and its (trust) relationship with hosted 501 programs, hosted Taos, etc. 502 503 Cons: 504 - I think hosted programs do not really (and should not) full trust any policy 505 server under normal circumstances. 506 507 == Use symmetric keys within a machine (idea #4) == 508 509 I think we should do this. 510 511 We should add functionality to the Tao API to support the creation of 512 authenticated channels between Tao-relatives, i.e. between two hosted programs 513 that share a common Tao ancestor. The processes are necessarily on the same 514 machine since they are all under the same TPM, and fully trust their common 515 ancestors, so there isn't much reason to be doing expensive public key 516 encryption. 517 518 Every hosted program is already assumed to have a authenticated private channel 519 to its host Tao and, indirectly, to every ancestor Tao as well. A call to 520 GetRandomBytes, for example, might be passed down to some distant ancestor. 521 522 For any given pair of Tao hosted programs (or hosted Taos) running on the same 523 machine, there is one or more common ancestor Taos that is necessarily trusted 524 by both. We can use a common ancestor Tao to distribute a shared symmetric key 525 to the pair of hosted programs. The two programs can then use TLS-PSK to 526 communicate. 527 528 Elsewhere [Cryptography.txt, AuthenticationImplementation.txt] I explore some 529 possibilities. To summarize the options: 530 * (a) Currently we use TLS and policy-attested (or Tao-attested) public keys for 531 all authentication between local programs, even if they share a common 532 ancestor. 533 * (b) We could instead rely instead on channels implemented by the OS or vm, 534 with no TLS at all. Basically, pipes. 535 * (c) This proposal. 536 537 Option (a) is slow/expensive, and you have to worry about exposure of long-lived 538 keys (the policy key, the public keys of each hosted program and each Tao). 539 540 Option (b) is fast/cheap, but it would make the Tao implementation and API much 541 more complex. And there is no common mechanism that could be written just once: 542 every Tao (for linux, kvm, evmm, etc.) would need separate mechanisms for 543 managing the channels. Implementing this would be like implementing 544 StartHostedProgram, but worse. 545 546 Option (c), this proposal, has moderate speed and expense, and the 547 implementation and API is fairly simple. Once a pair of hosted programs has a 548 shared symmetric key, they can use TLS-PSK to communicate, which relies only on 549 symmetric cryptography and avoids the use of asymmetric keys. 550 551 As with sealing, the symmetric keys should have an expiration negotiated between 552 the requesting hosted program and the common ancestor Tao. Basically, each of 553 the two hosted programs can independently ask their parents for a suitable 554 symmetric key to talk to the other, using an API like this: 555 - shared_key = GenerateSharedKey(my_name, peer_name, requested_expiration) 556 Just like GetRandomBytes, the call can traverse down the chain of parent Taos, 557 stopping when it reaches a common ancestor. If the common ancestor can use a 558 key-generation key (KGK) to deterministically generate the shared key as a 559 function of the two peer names and its actual expiration. As long as that Tao 560 keeps and uses the same KGK until after the expiration, and the generation 561 function is deterministic, then both hosted programs will get the same key. 562 563 The my_name parameter is only needed if hosted programs can be identified by 564 more than a single name. Currently, every hosted program is identified by a hash 565 of the program binary and the command-line arguments. But we could have other 566 identifiers that mix in the process id, time of process creation, etc., yielding 567 identifiers with various levels of detail. The my_name parameter would let the 568 caller chose which granularity to use. 569 570 Note: the hosted programs do not need to store (or seal) the shared keys, 571 because the key generation is deterministic. At any time, if they simply 572 re-request the a key with the same expiration, they should receive the same 573 shared_key result from the ancestor Tao. Just like for sealing, the ancestor Tao 574 needs to keep the key-generation keys available, and might have multiple 575 key-generation keys to use with different expirations. 576 577 Note: The TPM doesn't support this directly. The first real Tao, sitting 578 directly above the TPM, would need to implement this feature using a combination 579 of TPM Seal/Unseal/Random operations. 580 581 == Use symmetric keys with a cloud, after bootstrapping (idea #5) == 582 583 I don't think we should implement this yet: the benefit isn't obvious enough. 584 585 The idea above for using symmetric keys and TLS-PSK for communication between 586 two hosted programs works when we have an already-established secure 587 authenticated channel from each of the two hosted programs to some trusted third 588 party. There, two hosted programs within the same machine used an ancestor Tao 589 as the trusted third party, and the channels to it went through the stack of 590 parent Taos. 591 592 For two hosted programs executing on different machines but in the same cloud 593 (aka "Cloud-relative", i.e. programs executing in the same Tao domain, i.e. 594 governed by the same policy key), the policy server can serve as a trusted third 595 party to distributed shared keys. We just to "bootstrap" this by creating an 596 authenticated, secure channel from the hosted programs to the policy server. 597 598 When a hosted program wants to communicate with some Cloud-relative program, the 599 hosted program establishes a TLS channel to the policy server as usual, 600 authenticated using its parent-Tao attested asymmetric key. The hosted program 601 then does a GenerateSharedKey() RPC to obtain a shared key that it can use to 602 communicate with the specified Cloud-relative. As before, both peers make this 603 call independently, so the policy server will need to generate they shared keys 604 deterministically. 605 606 Note: It might be the case that the hosted program's parent Tao will be governed 607 by the same policy server as the hosted program itself, but I don't think this 608 is always the case. If it were the case, then the hosted program could ask its 609 parent Tao (or, indirectly, its ancestor Tao) to contact the policy server on 610 its behalf, saving the cost of the TLS setup for each hosted program. 611 612 The cost for avoiding asymmetric operations with the peer is the asymmetric-key 613 TLS setup for the channel to the policy server. But this cost is amortized over 614 all connections to the peer during the same execution. And once we have a shared 615 symmetric key, we can seal it on the peer to avoid the need to talk to the 616 policy server during subsequent executions (assuming the hosted program identity 617 doesn't change between executions). The cost can also be amortized over multiple 618 operations with the policy server: once the channel is open to the policy 619 server, the hosted program can obtain shared symmetric keys for many peers. 620 621 To summarize: 622 * (a) Currently we use TLS and policy-attested (or Tao-attested) public keys for 623 all authentication between remote programs, even if they share a common 624 trusted policy server. 625 * (b) We could simply use the TLS session-resume feature. 626 This just uses asymmetric-key TLS on the first TLS connection to a peer, then 627 uses that session to establish a shared symmetric key to be used for 628 subsequent TLS connections. 629 * (c) This proposal. 630 631 Option (a) requires expensive asymmetric-key operations once per connection, and 632 you have to worry about exposure of long-lived public keys (the policy key, the 633 public keys of each hosted program and each Tao). 634 635 Option (b) amortizes expensive asymmetric-key operations to once per pair of 636 communicating hosted programs, at best. But it simple to implement, and requires 637 no Tao infrastructure. You still have to worry about exposure of long-lived keys 638 because of the initial TLS session to the peer. 639 640 Option (c) amortizes expensive asymmetric-key operations to once per hosted 641 program, at best. It seems a bit complex to implement (managing the amortization 642 across executions), and it requires Tao infrastructure (generating shared keys 643 at the policy server). It's also not clear that the extra amortization beyond 644 option (b) is significant. And you still have to worry about exposure of 645 long-lived public keys because of the initial TLS session to the policy server. 646 647 On the other hand, with option (c), there is no longer any need for 648 policy-attested public keys, since all communication between hosted programs 649 would use parent-Tao attested keys to create the connection to the policy 650 server, then shared keys to communicate with each other. 651 652 == Eliminate seal and unseal, use hosted program keys instead (idea #6) == 653 654 I like this idea, and I think we should implement it. 655 656 If we can outfit each hosted program with a symmetric key that is available only 657 to that hosted program (and, of course, its necessarily-trusted parent and 658 ancestor Taos), then a hosted program can implement Seal and Unseal operations 659 without further help from its parent Tao. Seal and Unseal instead become 660 convenience library functions, executed entirely locally within each hosted 661 program or hosted Tao: The hosted program uses its symmetric key to used to 662 encrypt program data, creating a sealed bundle, then later during the same or 663 subsequent executions, it uses the same key to decrypt the sealed bundle and 664 recover the data. 665 666 Idea #4 above provides a way for any hosted program to obtain a program-specific 667 symmetric key by making a request to its parent Tao. Essentially, a program 668 would ask to obtain a key that is shared with future versions of itself, by 669 calling: 670 - shared_key = GenerateSharedKey(my_name, my_future_name, requested_expiration) 671 672 == Summary of revised Tao API == 673 674 I will outline a revised Tao API using these decisions: 675 . Reject idea #0 - Tao generates keys for hosted program 676 . Reject idea #1 - A minimalist API 677 ~ Accept idea #2 - Sealing with expirations, option (b), sort of 678 . Reject idea #3 - TaoCA is a Tao 679 * Accept idea #4 - Use symmetric keys within a machine 680 . Reject idea #5 - Use symmetric keys with a cloud, after bootstrapping 681 * Accept idea #6 - Eliminate seal and unseal, use hosted program keys instead 682 683 Ignoring C++-isms, the revised tao API would look like this: 684 - Unspecified: implementation/context-specific hooks for managing the lifecycle 685 of hosted programs and the Tao service itself. 686 - bytes = GetRandomBytes(size) 687 Same as current API. 688 - attestation = Attest(statement) 689 Same as current API, but with a statement in some logic not a blob of opaque 690 data. The returned attestation conveys "Tao says (child says statement)", 691 where "Tao" is really the Tao's public key, and "child" is the hash of the 692 hosted program making the request. 693 - shared_key = GenerateSharedKey(my_name, peer_name, requested_expiration) 694 Generate a shared symmetric key that is available only to hosted programs with 695 name my_name or peer_name. The call is only successful if my_name is one of 696 the caller's identities. Otherwise, exchanging my_name and peer_name doesn't 697 affect the result. The call is only successful if the expiration has not past. 698 699 Convenience/library methods implemented locally in hosted programs: 700 - (keypair, cert) = GenerateAuthenticationKey(suggested_expiration, other key details) 701 Calls GetRandomBytes(), then generates a key pair, then calls Attest() with an 702 appropriate statement describing the public key, its expiration, and possibly 703 other key details (e.g. key usage?). This just packages up what all of the 704 current hosted programs already do. 705 - sealing_key = GenerateSealingKey(my_name, requested_expiration) 706 Calls GenerateSharedKey(my_name, my_name, requested_expiration). 707 - blob = Seal(my_name, data, requested_expiration) 708 Calls GenerateSealingKey(my_name, requested_expiration), then uses the 709 resulting key to encrypt the data. Maybe attach requested_expiration to the 710 blob. Maybe also attach my_name. 711 - data = Unseal(my_name, requested_expiration, blob) 712 Calls GenerateSealingKey(my_name, requested_expiration), then uses the 713 resulting key to decrypt blob and recover the data. If we attach my_name and 714 requested_expiration to the blob during Seal(), then we don't need to pass 715 them as parameters here. As with the current Seal() implementation, the blob 716 must have been created via a Seal request to by the same hosted program 717 running on the same parent Tao. 718 719 Observation: There is nothing here about authentication between hosted programs 720 and the outside world. That already requires different mechanisms, e.g. using 721 x509 certificates and https (and there is no simple way to convey all the 722 information in a Tao attestation chain, since those chains are rooted in the TPM 723 which does not generate x509-compatible certificates. Currently, 724 https-compatible x509 chains are produced by the policy server. Aside from 725 this, there isn't much of a role for the policy server. 726 727 == Groups and Sub-principals == 728 729 It is tempting to use subprincipals and delegation instead of groups and 730 membership. For example, K_policy::TrustedPlatform could be the name for some 731 group of TPM-based platforms. K_policy can issue delegations that effectively 732 convey group membership, e.g. 733 K_policy says (K_tpm speaksfor K_policy::TrustedPlatform) 734 from which we can derive: 735 K_tpm speaksfor K_policy::TrustedPlatform 736 From here, K_tpm can speak for the group. 737 738 But things get complicated quickly. Each time the TPM speaks, we must decide 739 whether it should speak as K_tpm or as K_policy::TrustedPlatform. And for a 740 program OS hosted on this TPM, we must decide if the program should be identified 741 as a subprincipal of K_tpm or as a subprincipal of K_policy::TrustedPlatform. 742 The latter, e.g. K_policy::TrustedPlatform::TrustedOS, is tempting because 743 K_policy is likely to be a well known name (whereas K_tpm and its subprincipals are 744 possibly known only locally and to K_policy). So we are effectively creating a 745 "sub-group", K_policy::TrustedPlatform::TrustedOS, containing all instances of 746 certain programs hosted on some platform in the K_policy::TrustedPlatform group. 747 This makes the job of writing policies somewhat easy. For example, 748 K_policy::TrustedPlatform::TrustedOS can be put on an ACL, and that will cover 749 all of the instances of OS. Or, we can arrange for OS to have its own key, K_os, 750 and create delegations K_os speaksfor K_policy::TrustedPlatform::TrustedOS. Or 751 create a chain of delegations, e.g. K_os speaksfor 752 K_policy::TrustedPlatform::PCRs(...), K_policy::TrustedPlatform::PCRs(...) 753 speaksfor K_policy::TrustedPlatform::TrustedOS. Or maybe keep the names shorter 754 with a chain K_os speaksfor K_policy::TrustedPlatform::PCRs(...), 755 K_policy::TrustedPlatform::PCRs(...) speaksfor K_policy::TrustedOS. The 756 variations are seemginly endless. 757 758 But notice that according to the logic, if mutually inconsistent statements are 759 made by any of the platforms, the entire group is compromised. When we make a 760 group in this way, we are essentially taking all the statements of the members 761 and taking the closure. Also, a lot of policy-relevant decision making has to be 762 done at the time statements and delegations are issued and when naming 763 principals. Ideally, every Tao has some well defined name or names, and uses 764 those names in simple, clear, and consistent ways that do not depend on the 765 vagaries of higher-level policy. 766 767 So it seems that when a Tao obtains and makes use of some policy attestation, 768 this is treating K_policy as if it were a "parent" Tao, and ionly leads to 769 trouble and confusion. 770 771 One alternative to using a subprincipal as groups is to use an intensional group 772 defined by a characteristic predicate. Here, we would put on the ACL something 773 like: 774 { p : (exists t, o : 775 p speaksfor o::Prog(h) and K_policy says isTrustedProgram(h) and 776 o speaksfor t::PCRS(r) and K_policy says isTrustedOS(r) and 777 K_policy says isTrustedPlatform(t) ) } 778 And we arrange for K_policy to define each predicate, e.g. 779 K_policy says isTrustedPlatform(K_tpm) 780 K_policy says isTrustedOS("...pcrs...") 781 K_policy says isTrustedProgram("...hash..."); 782 783 Notice that here, the TPM always speaks using its single identity, K_tpm. A 784 hosted Tao always speaks as a subprincipal, e.g. K_tpm::PCRs(...). For 785 performance reasons, a hosted Tao can create its own key K_os, and then obtain 786 from its parent a delegation K_os speaksfor K_tpm::PCRs(...). This allowing it 787 to speak as K_tpm::PCRs(...) while actually doing cryptography using the local 788 key K_os. A child of this hosted Tao would always speak as 789 K_tpm::PCRs(...)::Prog(...), and so on, and these too could make similar 790 performance optimizations using their own local keys. 791 792 A second alternative way to implement groups is to make use of predicates 793 directly, and not use groups at all. So we might say that a principal P 794 is authorized perform some operation "op" if 795 K_policy says Authorized(P, "op") 796 And we arrange for K_policy to define this predicate, e.g. 797 K_policy says Authorized(K_tpm::PCRs(...)::Prog(...), "op") 798 or: 799 K_policy says 800 ((exists t, o : 801 P speaksfor o::Prog(h) and K_policy says isTrustedProgram(h) and 802 o speaksfor t::PCRS(r) and K_policy says isTrustedOS(r) and 803 K_policy says isTrustedPlatform(t) ) 804 implies (K_policy says Authorized("op", P))) 805 The latter would be coupled with the same kinds of predicate definitions we saw 806 above, e.g.: 807 K_policy says isTrustedPlatform(K_tpm) 808 K_policy says isTrustedOS("...pcrs...") 809 K_policy says isTrustedProgram("...hash..."); 810 811 Let's take this second alternative and try it out.