Vadim Bendebury | 5679752 | 2015-05-20 10:32:25 -0700 | [diff] [blame] | 1 | // This file was extracted from the TCG Published |
| 2 | // Trusted Platform Module Library |
| 3 | // Part 4: Supporting Routines |
| 4 | // Family "2.0" |
| 5 | // Level 00 Revision 01.16 |
| 6 | // October 30, 2014 |
| 7 | |
| 8 | #define OBJECT_C |
| 9 | #include "InternalRoutines.h" |
Vadim Bendebury | 5f32063 | 2015-06-01 10:20:42 -0700 | [diff] [blame] | 10 | #include "Platform.h" |
Vadim Bendebury | 5679752 | 2015-05-20 10:32:25 -0700 | [diff] [blame] | 11 | // |
| 12 | // |
| 13 | // Functions |
| 14 | // |
| 15 | // ObjectStartup() |
| 16 | // |
| 17 | // This function is called at TPM2_Startup() to initialize the object subsystem. |
| 18 | // |
| 19 | void |
| 20 | ObjectStartup( |
| 21 | void |
| 22 | ) |
| 23 | { |
| 24 | UINT32 i; |
| 25 | // object slots initialization |
| 26 | for(i = 0; i < MAX_LOADED_OBJECTS; i++) |
| 27 | { |
| 28 | //Set the slot to not occupied |
| 29 | s_objects[i].occupied = FALSE; |
| 30 | } |
| 31 | return; |
| 32 | } |
| 33 | // |
| 34 | // |
| 35 | // ObjectCleanupEvict() |
| 36 | // |
| 37 | // In this implementation, a persistent object is moved from NV into an object slot for processing. It is |
| 38 | // flushed after command execution. This function is called from ExecuteCommand(). |
| 39 | // |
| 40 | void |
| 41 | ObjectCleanupEvict( |
| 42 | void |
| 43 | ) |
| 44 | { |
| 45 | UINT32 i; |
| 46 | // This has to be iterated because a command may have two handles |
| 47 | // and they may both be persistent. |
| 48 | // This could be made to be more efficient so that a search is not needed. |
| 49 | for(i = 0; i < MAX_LOADED_OBJECTS; i++) |
| 50 | { |
| 51 | // If an object is a temporary evict object, flush it from slot |
| 52 | if(s_objects[i].object.entity.attributes.evict == SET) |
| 53 | s_objects[i].occupied = FALSE; |
| 54 | } |
| 55 | return; |
| 56 | } |
| 57 | // |
| 58 | // |
| 59 | // ObjectIsPresent() |
| 60 | // |
| 61 | // This function checks to see if a transient handle references a loaded object. This routine should not be |
| 62 | // called if the handle is not a transient handle. The function validates that the handle is in the |
| 63 | // implementation-dependent allowed in range for loaded transient objects. |
| 64 | // |
| 65 | // Return Value Meaning |
| 66 | // |
| 67 | // TRUE if the handle references a loaded object |
| 68 | // FALSE if the handle is not an object handle, or it does not reference to a |
| 69 | // loaded object |
| 70 | // |
| 71 | BOOL |
| 72 | ObjectIsPresent( |
| 73 | TPMI_DH_OBJECT handle // IN: handle to be checked |
| 74 | ) |
| 75 | { |
| 76 | UINT32 slotIndex; // index of object slot |
| 77 | pAssert(HandleGetType(handle) == TPM_HT_TRANSIENT); |
| 78 | // The index in the loaded object array is found by subtracting the first |
| 79 | // object handle number from the input handle number. If the indicated |
| 80 | // slot is occupied, then indicate that there is already is a loaded |
| 81 | // object associated with the handle. |
| 82 | slotIndex = handle - TRANSIENT_FIRST; |
| 83 | if(slotIndex >= MAX_LOADED_OBJECTS) |
| 84 | return FALSE; |
| 85 | return s_objects[slotIndex].occupied; |
| 86 | } |
| 87 | // |
| 88 | // |
| 89 | // ObjectIsSequence() |
| 90 | // |
| 91 | // This function is used to check if the object is a sequence object. This function should not be called if the |
| 92 | // handle does not reference a loaded object. |
| 93 | // |
| 94 | // Return Value Meaning |
| 95 | // |
| 96 | // TRUE object is an HMAC, hash, or event sequence object |
| 97 | // FALSE object is not an HMAC, hash, or event sequence object |
| 98 | // |
| 99 | BOOL |
| 100 | ObjectIsSequence( |
| 101 | OBJECT *object // IN: handle to be checked |
| 102 | ) |
| 103 | { |
| 104 | pAssert (object != NULL); |
| 105 | if( object->attributes.hmacSeq == SET |
| 106 | || object->attributes.hashSeq == SET |
| 107 | || object->attributes.eventSeq == SET) |
| 108 | return TRUE; |
| 109 | else |
| 110 | return FALSE; |
| 111 | } |
| 112 | // |
| 113 | // |
| 114 | // ObjectGet() |
| 115 | // |
| 116 | // This function is used to find the object structure associated with a handle. |
| 117 | // This function requires that handle references a loaded object. |
| 118 | // |
| 119 | OBJECT* |
| 120 | ObjectGet( |
| 121 | TPMI_DH_OBJECT handle // IN: handle of the object |
| 122 | ) |
| 123 | { |
| 124 | pAssert( handle >= TRANSIENT_FIRST |
| 125 | && handle - TRANSIENT_FIRST < MAX_LOADED_OBJECTS); |
| 126 | pAssert(s_objects[handle - TRANSIENT_FIRST].occupied == TRUE); |
| 127 | // In this implementation, the handle is determined by the slot occupied by the |
| 128 | // object. |
| 129 | return &s_objects[handle - TRANSIENT_FIRST].object.entity; |
| 130 | } |
| 131 | // |
| 132 | // |
| 133 | // ObjectGetName() |
| 134 | // |
| 135 | // This function is used to access the Name of the object. In this implementation, the Name is computed |
| 136 | // when the object is loaded and is saved in the internal representation of the object. This function copies |
| 137 | // the Name data from the object into the buffer at name and returns the number of octets copied. |
| 138 | // This function requires that handle references a loaded object. |
| 139 | // |
| 140 | UINT16 |
| 141 | ObjectGetName( |
| 142 | TPMI_DH_OBJECT handle, // IN: handle of the object |
| 143 | NAME *name // OUT: name of the object |
| 144 | ) |
| 145 | { |
| 146 | OBJECT *object = ObjectGet(handle); |
| 147 | if(object->publicArea.nameAlg == TPM_ALG_NULL) |
| 148 | return 0; |
| 149 | // Copy the Name data to the output |
ChromeOS Developer | e85c65b | 2015-07-10 10:12:43 -0700 | [diff] [blame] | 150 | MemoryCopy(name, object->name.t.name, object->name.t.size, sizeof(NAME)); |
Vadim Bendebury | 5679752 | 2015-05-20 10:32:25 -0700 | [diff] [blame] | 151 | return object->name.t.size; |
| 152 | } |
| 153 | // |
| 154 | // |
| 155 | // ObjectGetNameAlg() |
| 156 | // |
| 157 | // This function is used to get the Name algorithm of a object. |
| 158 | // This function requires that handle references a loaded object. |
| 159 | // |
| 160 | TPMI_ALG_HASH |
| 161 | ObjectGetNameAlg( |
| 162 | TPMI_DH_OBJECT handle // IN: handle of the object |
| 163 | ) |
| 164 | { |
| 165 | OBJECT *object = ObjectGet(handle); |
| 166 | return object->publicArea.nameAlg; |
| 167 | } |
| 168 | // |
| 169 | // |
| 170 | // |
| 171 | // ObjectGetQualifiedName() |
| 172 | // |
| 173 | // This function returns the Qualified Name of the object. In this implementation, the Qualified Name is |
| 174 | // computed when the object is loaded and is saved in the internal representation of the object. The |
| 175 | // alternative would be to retain the Name of the parent and compute the QN when needed. This would take |
| 176 | // the same amount of space so it is not recommended that the alternate be used. |
| 177 | // This function requires that handle references a loaded object. |
| 178 | // |
| 179 | void |
| 180 | ObjectGetQualifiedName( |
| 181 | TPMI_DH_OBJECT handle, // IN: handle of the object |
| 182 | TPM2B_NAME *qualifiedName // OUT: qualified name of the object |
| 183 | ) |
| 184 | { |
| 185 | OBJECT *object = ObjectGet(handle); |
| 186 | if(object->publicArea.nameAlg == TPM_ALG_NULL) |
| 187 | qualifiedName->t.size = 0; |
| 188 | else |
| 189 | // Copy the name |
| 190 | *qualifiedName = object->qualifiedName; |
| 191 | return; |
| 192 | } |
| 193 | // |
| 194 | // |
| 195 | // ObjectDataGetHierarchy() |
| 196 | // |
| 197 | // This function returns the handle for the hierarchy of an object. |
| 198 | // |
| 199 | TPMI_RH_HIERARCHY |
| 200 | ObjectDataGetHierarchy( |
| 201 | OBJECT *object // IN :object |
| 202 | ) |
| 203 | { |
| 204 | if(object->attributes.spsHierarchy) |
| 205 | { |
| 206 | return TPM_RH_OWNER; |
| 207 | } |
| 208 | else if(object->attributes.epsHierarchy) |
| 209 | { |
| 210 | return TPM_RH_ENDORSEMENT; |
| 211 | } |
| 212 | else if(object->attributes.ppsHierarchy) |
| 213 | { |
| 214 | return TPM_RH_PLATFORM; |
| 215 | } |
| 216 | else |
| 217 | { |
| 218 | return TPM_RH_NULL; |
| 219 | } |
| 220 | } |
| 221 | // |
| 222 | // |
| 223 | // ObjectGetHierarchy() |
| 224 | // |
| 225 | // This function returns the handle of the hierarchy to which a handle belongs. This function is similar to |
| 226 | // ObjectDataGetHierarchy() but this routine takes a handle but ObjectDataGetHierarchy() takes an pointer |
| 227 | // to an object. |
| 228 | // This function requires that handle references a loaded object. |
| 229 | // |
| 230 | TPMI_RH_HIERARCHY |
| 231 | ObjectGetHierarchy( |
| 232 | TPMI_DH_OBJECT handle // IN :object handle |
| 233 | ) |
| 234 | { |
| 235 | OBJECT *object = ObjectGet(handle); |
| 236 | return ObjectDataGetHierarchy(object); |
| 237 | } |
| 238 | // |
| 239 | // |
| 240 | // ObjectAllocateSlot() |
| 241 | // |
| 242 | // This function is used to allocate a slot in internal object array. |
| 243 | // |
| 244 | // Return Value Meaning |
| 245 | // |
| 246 | // TRUE allocate success |
| 247 | // FALSE do not have free slot |
| 248 | // |
| 249 | static BOOL |
| 250 | ObjectAllocateSlot( |
| 251 | TPMI_DH_OBJECT *handle, // OUT: handle of allocated object |
| 252 | OBJECT **object // OUT: points to the allocated object |
| 253 | ) |
| 254 | { |
| 255 | UINT32 i; |
| 256 | // find an unoccupied handle slot |
| 257 | for(i = 0; i < MAX_LOADED_OBJECTS; i++) |
| 258 | { |
| 259 | if(!s_objects[i].occupied) // If found a free slot |
| 260 | { |
| 261 | // Mark the slot as occupied |
| 262 | s_objects[i].occupied = TRUE; |
| 263 | break; |
| 264 | } |
| 265 | } |
| 266 | // If we reach the end of object slot without finding a free one, return |
| 267 | // error. |
| 268 | if(i == MAX_LOADED_OBJECTS) return FALSE; |
| 269 | *handle = i + TRANSIENT_FIRST; |
| 270 | *object = &s_objects[i].object.entity; |
| 271 | // Initialize the object attributes |
| 272 | MemorySet(&((*object)->attributes), 0, sizeof(OBJECT_ATTRIBUTES)); |
| 273 | return TRUE; |
| 274 | } |
| 275 | // |
| 276 | // |
| 277 | // ObjectLoad() |
| 278 | // |
| 279 | // This function loads an object into an internal object structure. If an error is returned, the internal state is |
| 280 | // unchanged. |
| 281 | // |
| 282 | // |
| 283 | // |
| 284 | // |
| 285 | // Error Returns Meaning |
| 286 | // |
| 287 | // TPM_RC_BINDING if the public and sensitive parts of the object are not matched |
| 288 | // TPM_RC_KEY if the parameters in the public area of the object are not consistent |
| 289 | // TPM_RC_OBJECT_MEMORY if there is no free slot for an object |
| 290 | // TPM_RC_TYPE the public and private parts are not the same type |
| 291 | // |
| 292 | TPM_RC |
| 293 | ObjectLoad( |
| 294 | TPMI_RH_HIERARCHY hierarchy, // IN: hierarchy to which the object belongs |
| 295 | TPMT_PUBLIC *publicArea, // IN: public area |
| 296 | TPMT_SENSITIVE *sensitive, // IN: sensitive area (may be null) |
| 297 | TPM2B_NAME *name, // IN: object's name (may be null) |
| 298 | TPM_HANDLE parentHandle, // IN: handle of parent |
| 299 | BOOL skipChecks, // IN: flag to indicate if it is OK to skip |
| 300 | // consistency checks. |
| 301 | TPMI_DH_OBJECT *handle // OUT: object handle |
| 302 | ) |
| 303 | { |
| 304 | OBJECT *object = NULL; |
| 305 | OBJECT *parent = NULL; |
| 306 | TPM_RC result = TPM_RC_SUCCESS; |
| 307 | TPM2B_NAME parentQN; // Parent qualified name |
| 308 | // Try to allocate a slot for new object |
| 309 | if(!ObjectAllocateSlot(handle, &object)) |
| 310 | return TPM_RC_OBJECT_MEMORY; |
| 311 | // Initialize public |
| 312 | object->publicArea = *publicArea; |
| 313 | if(sensitive != NULL) |
| 314 | object->sensitive = *sensitive; |
| 315 | // Are the consistency checks needed |
| 316 | if(!skipChecks) |
| 317 | { |
| 318 | // Check if key size matches |
| 319 | if(!CryptObjectIsPublicConsistent(&object->publicArea)) |
| 320 | { |
| 321 | result = TPM_RC_KEY; |
| 322 | goto ErrorExit; |
| 323 | } |
| 324 | if(sensitive != NULL) |
| 325 | { |
| 326 | // Check if public type matches sensitive type |
| 327 | result = CryptObjectPublicPrivateMatch(object); |
| 328 | if(result != TPM_RC_SUCCESS) |
| 329 | goto ErrorExit; |
| 330 | } |
| 331 | } |
| 332 | object->attributes.publicOnly = (sensitive == NULL); |
| 333 | // If 'name' is NULL, then there is nothing left to do for this |
| 334 | // object as it has no qualified name and it is not a member of any |
| 335 | // hierarchy and it is temporary |
| 336 | if(name == NULL || name->t.size == 0) |
| 337 | { |
| 338 | object->qualifiedName.t.size = 0; |
| 339 | object->name.t.size = 0; |
| 340 | object->attributes.temporary = SET; |
| 341 | return TPM_RC_SUCCESS; |
| 342 | } |
| 343 | // If parent handle is a permanent handle, it is a primary or temporary |
| 344 | // object |
| 345 | if(HandleGetType(parentHandle) == TPM_HT_PERMANENT) |
| 346 | { |
| 347 | // initialize QN |
| 348 | parentQN.t.size = 4; |
| 349 | // for a primary key, parent qualified name is the handle of hierarchy |
ChromeOS Developer | e85c65b | 2015-07-10 10:12:43 -0700 | [diff] [blame] | 350 | UINT32_TO_BYTE_ARRAY(parentHandle, parentQN.t.name); |
Vadim Bendebury | 5679752 | 2015-05-20 10:32:25 -0700 | [diff] [blame] | 351 | } |
| 352 | else |
| 353 | { |
| 354 | // Get hierarchy and qualified name of parent |
| 355 | ObjectGetQualifiedName(parentHandle, &parentQN); |
| 356 | // Check for stClear object |
| 357 | parent = ObjectGet(parentHandle); |
| 358 | if( publicArea->objectAttributes.stClear == SET |
| 359 | || parent->attributes.stClear == SET) |
| 360 | object->attributes.stClear = SET; |
| 361 | } |
| 362 | object->name = *name; |
| 363 | // Compute object qualified name |
| 364 | ObjectComputeQualifiedName(&parentQN, publicArea->nameAlg, |
| 365 | name, &object->qualifiedName); |
| 366 | // Any object in TPM_RH_NULL hierarchy is temporary |
| 367 | if(hierarchy == TPM_RH_NULL) |
| 368 | { |
| 369 | object->attributes.temporary = SET; |
| 370 | } |
| 371 | else if(parentQN.t.size == sizeof(TPM_HANDLE)) |
| 372 | { |
| 373 | // Otherwise, if the size of parent's qualified name is the size of a |
| 374 | // handle, this object is a primary object |
| 375 | object->attributes.primary = SET; |
| 376 | } |
| 377 | switch(hierarchy) |
| 378 | { |
| 379 | case TPM_RH_PLATFORM: |
| 380 | object->attributes.ppsHierarchy = SET; |
| 381 | break; |
| 382 | case TPM_RH_OWNER: |
| 383 | object->attributes.spsHierarchy = SET; |
| 384 | break; |
| 385 | case TPM_RH_ENDORSEMENT: |
| 386 | object->attributes.epsHierarchy = SET; |
| 387 | break; |
| 388 | case TPM_RH_NULL: |
| 389 | break; |
| 390 | default: |
| 391 | pAssert(FALSE); |
| 392 | break; |
| 393 | } |
| 394 | return TPM_RC_SUCCESS; |
| 395 | ErrorExit: |
| 396 | ObjectFlush(*handle); |
| 397 | return result; |
| 398 | } |
| 399 | // |
| 400 | // |
| 401 | // |
| 402 | // AllocateSequenceSlot() |
| 403 | // |
| 404 | // This function allocates a sequence slot and initializes the parts that are used by the normal objects so |
| 405 | // that a sequence object is not inadvertently used for an operation that is not appropriate for a sequence. |
| 406 | // |
| 407 | static BOOL |
| 408 | AllocateSequenceSlot( |
| 409 | TPM_HANDLE *newHandle, // OUT: receives the allocated handle |
| 410 | HASH_OBJECT **object, // OUT: receives pointer to allocated object |
| 411 | TPM2B_AUTH *auth // IN: the authValue for the slot |
| 412 | ) |
| 413 | { |
| 414 | OBJECT *objectHash; // the hash as an object |
| 415 | if(!ObjectAllocateSlot(newHandle, &objectHash)) |
| 416 | return FALSE; |
| 417 | *object = (HASH_OBJECT *)objectHash; |
| 418 | // Validate that the proper location of the hash state data relative to the |
| 419 | // object state data. |
| 420 | pAssert(&((*object)->auth) == &objectHash->publicArea.authPolicy); |
| 421 | // Set the common values that a sequence object shares with an ordinary object |
| 422 | // The type is TPM_ALG_NULL |
| 423 | (*object)->type = TPM_ALG_NULL; |
| 424 | // This has no name algorithm and the name is the Empty Buffer |
| 425 | (*object)->nameAlg = TPM_ALG_NULL; |
| 426 | // Clear the attributes |
| 427 | MemorySet(&((*object)->objectAttributes), 0, sizeof(TPMA_OBJECT)); |
| 428 | // A sequence object is considered to be in the NULL hierarchy so it should |
| 429 | // be marked as temporary so that it can't be persisted |
| 430 | (*object)->attributes.temporary = SET; |
| 431 | // A sequence object is DA exempt. |
| 432 | (*object)->objectAttributes.noDA = SET; |
| 433 | if(auth != NULL) |
| 434 | { |
| 435 | MemoryRemoveTrailingZeros(auth); |
| 436 | (*object)->auth = *auth; |
| 437 | } |
| 438 | else |
| 439 | (*object)->auth.t.size = 0; |
| 440 | return TRUE; |
| 441 | } |
| 442 | // |
| 443 | // |
| 444 | // ObjectCreateHMACSequence() |
| 445 | // |
| 446 | // This function creates an internal HMAC sequence object. |
| 447 | // |
| 448 | // Error Returns Meaning |
| 449 | // |
| 450 | // TPM_RC_OBJECT_MEMORY if there is no free slot for an object |
| 451 | // |
| 452 | TPM_RC |
| 453 | ObjectCreateHMACSequence( |
| 454 | TPMI_ALG_HASH hashAlg, // IN: hash algorithm |
| 455 | TPM_HANDLE handle, // IN: the handle associated with sequence |
| 456 | // object |
| 457 | TPM2B_AUTH *auth, // IN: authValue |
| 458 | TPMI_DH_OBJECT *newHandle // OUT: HMAC sequence object handle |
| 459 | ) |
| 460 | { |
| 461 | HASH_OBJECT *hmacObject; |
| 462 | OBJECT *keyObject; |
| 463 | // Try to allocate a slot for new object |
| 464 | if(!AllocateSequenceSlot(newHandle, &hmacObject, auth)) |
| 465 | return TPM_RC_OBJECT_MEMORY; |
| 466 | // Set HMAC sequence bit |
| 467 | hmacObject->attributes.hmacSeq = SET; |
| 468 | // Get pointer to the HMAC key object |
| 469 | keyObject = ObjectGet(handle); |
| 470 | CryptStartHMACSequence2B(hashAlg, &keyObject->sensitive.sensitive.bits.b, |
| 471 | &hmacObject->state.hmacState); |
| 472 | return TPM_RC_SUCCESS; |
| 473 | } |
| 474 | // |
| 475 | // |
| 476 | // ObjectCreateHashSequence() |
| 477 | // |
| 478 | // This function creates a hash sequence object. |
| 479 | // |
| 480 | // Error Returns Meaning |
| 481 | // |
| 482 | // TPM_RC_OBJECT_MEMORY if there is no free slot for an object |
| 483 | // |
| 484 | TPM_RC |
| 485 | ObjectCreateHashSequence( |
| 486 | TPMI_ALG_HASH hashAlg, // IN: hash algorithm |
| 487 | TPM2B_AUTH *auth, // IN: authValue |
| 488 | TPMI_DH_OBJECT *newHandle // OUT: sequence object handle |
| 489 | ) |
| 490 | { |
| 491 | HASH_OBJECT *hashObject; |
| 492 | // Try to allocate a slot for new object |
| 493 | if(!AllocateSequenceSlot(newHandle, &hashObject, auth)) |
| 494 | return TPM_RC_OBJECT_MEMORY; |
| 495 | // Set hash sequence bit |
| 496 | hashObject->attributes.hashSeq = SET; |
| 497 | // Start hash for hash sequence |
| 498 | CryptStartHashSequence(hashAlg, &hashObject->state.hashState[0]); |
| 499 | return TPM_RC_SUCCESS; |
| 500 | } |
| 501 | // |
| 502 | // |
| 503 | // ObjectCreateEventSequence() |
| 504 | // |
| 505 | // This function creates an event sequence object. |
| 506 | // |
| 507 | // Error Returns Meaning |
| 508 | // |
| 509 | // TPM_RC_OBJECT_MEMORY if there is no free slot for an object |
| 510 | // |
| 511 | TPM_RC |
| 512 | ObjectCreateEventSequence( |
| 513 | TPM2B_AUTH *auth, // IN: authValue |
| 514 | TPMI_DH_OBJECT *newHandle // OUT: sequence object handle |
| 515 | ) |
| 516 | { |
| 517 | HASH_OBJECT *hashObject; |
| 518 | UINT32 count; |
| 519 | TPM_ALG_ID hash; |
| 520 | // Try to allocate a slot for new object |
| 521 | if(!AllocateSequenceSlot(newHandle, &hashObject, auth)) |
| 522 | return TPM_RC_OBJECT_MEMORY; |
| 523 | // Set the event sequence attribute |
| 524 | hashObject->attributes.eventSeq = SET; |
| 525 | // Initialize hash states for each implemented PCR algorithms |
| 526 | for(count = 0; (hash = CryptGetHashAlgByIndex(count)) != TPM_ALG_NULL; count++) |
| 527 | { |
| 528 | // If this is a _TPM_Init or _TPM_HashStart, the sequence object will |
| 529 | // not leave the TPM so it doesn't need the sequence handling |
| 530 | if(auth == NULL) |
| 531 | CryptStartHash(hash, &hashObject->state.hashState[count]); |
| 532 | else |
| 533 | CryptStartHashSequence(hash, &hashObject->state.hashState[count]); |
| 534 | } |
| 535 | return TPM_RC_SUCCESS; |
| 536 | } |
| 537 | // |
| 538 | // |
| 539 | // ObjectTerminateEvent() |
| 540 | // |
| 541 | // This function is called to close out the event sequence and clean up the hash context states. |
| 542 | // |
| 543 | void |
| 544 | ObjectTerminateEvent( |
| 545 | void |
| 546 | ) |
| 547 | { |
| 548 | HASH_OBJECT *hashObject; |
| 549 | int count; |
| 550 | BYTE buffer[MAX_DIGEST_SIZE]; |
| 551 | hashObject = (HASH_OBJECT *)ObjectGet(g_DRTMHandle); |
| 552 | // Don't assume that this is a proper sequence object |
| 553 | if(hashObject->attributes.eventSeq) |
| 554 | { |
| 555 | // If it is, close any open hash contexts. This is done in case |
| 556 | // the crypto implementation has some context values that need to be |
| 557 | // cleaned up (hygiene). |
| 558 | // |
| 559 | for(count = 0; CryptGetHashAlgByIndex(count) != TPM_ALG_NULL; count++) |
| 560 | { |
| 561 | CryptCompleteHash(&hashObject->state.hashState[count], 0, buffer); |
| 562 | } |
| 563 | // Flush sequence object |
| 564 | ObjectFlush(g_DRTMHandle); |
| 565 | } |
| 566 | g_DRTMHandle = TPM_RH_UNASSIGNED; |
| 567 | } |
| 568 | // |
| 569 | // |
| 570 | // |
| 571 | // ObjectContextLoad() |
| 572 | // |
| 573 | // This function loads an object from a saved object context. |
| 574 | // |
| 575 | // Error Returns Meaning |
| 576 | // |
| 577 | // TPM_RC_OBJECT_MEMORY if there is no free slot for an object |
| 578 | // |
| 579 | TPM_RC |
| 580 | ObjectContextLoad( |
| 581 | OBJECT *object, // IN: object structure from saved context |
| 582 | TPMI_DH_OBJECT *handle // OUT: object handle |
| 583 | ) |
| 584 | { |
| 585 | OBJECT *newObject; |
| 586 | // Try to allocate a slot for new object |
| 587 | if(!ObjectAllocateSlot(handle, &newObject)) |
| 588 | return TPM_RC_OBJECT_MEMORY; |
| 589 | // Copy input object data to internal structure |
| 590 | *newObject = *object; |
| 591 | return TPM_RC_SUCCESS; |
| 592 | } |
| 593 | // |
| 594 | // |
| 595 | // ObjectFlush() |
| 596 | // |
| 597 | // This function frees an object slot. |
| 598 | // This function requires that the object is loaded. |
| 599 | // |
| 600 | void |
| 601 | ObjectFlush( |
| 602 | TPMI_DH_OBJECT handle // IN: handle to be freed |
| 603 | ) |
| 604 | { |
| 605 | UINT32 index = handle - TRANSIENT_FIRST; |
| 606 | pAssert(ObjectIsPresent(handle)); |
| 607 | // Mark the handle slot as unoccupied |
| 608 | s_objects[index].occupied = FALSE; |
| 609 | // With no attributes |
| 610 | MemorySet((BYTE*)&(s_objects[index].object.entity.attributes), |
| 611 | 0, sizeof(OBJECT_ATTRIBUTES)); |
| 612 | return; |
| 613 | } |
| 614 | // |
| 615 | // |
| 616 | // ObjectFlushHierarchy() |
| 617 | // |
| 618 | // This function is called to flush all the loaded transient objects associated with a hierarchy when the |
| 619 | // hierarchy is disabled. |
| 620 | // |
| 621 | void |
| 622 | ObjectFlushHierarchy( |
| 623 | TPMI_RH_HIERARCHY hierarchy // IN: hierarchy to be flush |
| 624 | ) |
| 625 | { |
| 626 | UINT16 i; |
| 627 | // iterate object slots |
| 628 | for(i = 0; i < MAX_LOADED_OBJECTS; i++) |
| 629 | { |
| 630 | if(s_objects[i].occupied) // If found an occupied slot |
| 631 | { |
| 632 | switch(hierarchy) |
| 633 | { |
| 634 | case TPM_RH_PLATFORM: |
| 635 | if(s_objects[i].object.entity.attributes.ppsHierarchy == SET) |
| 636 | s_objects[i].occupied = FALSE; |
| 637 | break; |
| 638 | case TPM_RH_OWNER: |
| 639 | if(s_objects[i].object.entity.attributes.spsHierarchy == SET) |
| 640 | s_objects[i].occupied = FALSE; |
| 641 | break; |
| 642 | case TPM_RH_ENDORSEMENT: |
| 643 | if(s_objects[i].object.entity.attributes.epsHierarchy == SET) |
| 644 | s_objects[i].occupied = FALSE; |
| 645 | break; |
| 646 | default: |
| 647 | pAssert(FALSE); |
| 648 | break; |
| 649 | } |
| 650 | } |
| 651 | } |
| 652 | return; |
| 653 | } |
| 654 | // |
| 655 | // |
| 656 | // ObjectLoadEvict() |
| 657 | // |
| 658 | // This function loads a persistent object into a transient object slot. |
| 659 | // This function requires that handle is associated with a persistent object. |
| 660 | // |
| 661 | // Error Returns Meaning |
| 662 | // |
| 663 | // TPM_RC_HANDLE the persistent object does not exist or the associated hierarchy is |
| 664 | // disabled. |
| 665 | // TPM_RC_OBJECT_MEMORY no object slot |
| 666 | // |
| 667 | TPM_RC |
| 668 | ObjectLoadEvict( |
| 669 | TPM_HANDLE *handle, // IN:OUT: evict object handle. If success, it |
| 670 | // will be replace by the loaded object handle |
| 671 | TPM_CC commandCode // IN: the command being processed |
| 672 | ) |
| 673 | { |
| 674 | TPM_RC result; |
| 675 | TPM_HANDLE evictHandle = *handle; // Save the evict handle |
| 676 | OBJECT *object; |
| 677 | // If this is an index that references a persistent object created by |
| 678 | // the platform, then return TPM_RH_HANDLE if the phEnable is FALSE |
| 679 | if(*handle >= PLATFORM_PERSISTENT) |
| 680 | { |
| 681 | // belongs to platform |
| 682 | if(g_phEnable == CLEAR) |
| 683 | return TPM_RC_HANDLE; |
| 684 | } |
| 685 | // belongs to owner |
| 686 | else if(gc.shEnable == CLEAR) |
| 687 | return TPM_RC_HANDLE; |
| 688 | // Try to allocate a slot for an object |
| 689 | if(!ObjectAllocateSlot(handle, &object)) |
| 690 | return TPM_RC_OBJECT_MEMORY; |
| 691 | // Copy persistent object to transient object slot. A TPM_RC_HANDLE |
| 692 | // may be returned at this point. This will mark the slot as containing |
| 693 | // a transient object so that it will be flushed at the end of the |
| 694 | // command |
| 695 | result = NvGetEvictObject(evictHandle, object); |
| 696 | // Bail out if this failed |
| 697 | if(result != TPM_RC_SUCCESS) |
| 698 | return result; |
| 699 | // check the object to see if it is in the endorsement hierarchy |
| 700 | // if it is and this is not a TPM2_EvictControl() command, indicate |
| 701 | // that the hierarchy is disabled. |
| 702 | // If the associated hierarchy is disabled, make it look like the |
| 703 | // handle is not defined |
| 704 | if( ObjectDataGetHierarchy(object) == TPM_RH_ENDORSEMENT |
| 705 | && gc.ehEnable == CLEAR |
| 706 | && commandCode != TPM_CC_EvictControl |
| 707 | ) |
| 708 | return TPM_RC_HANDLE; |
| 709 | return result; |
| 710 | } |
| 711 | // |
| 712 | // |
| 713 | // ObjectComputeName() |
| 714 | // |
| 715 | // This function computes the Name of an object from its public area. |
| 716 | // |
| 717 | void |
| 718 | ObjectComputeName( |
| 719 | TPMT_PUBLIC *publicArea, // IN: public area of an object |
| 720 | TPM2B_NAME *name // OUT: name of the object |
| 721 | ) |
| 722 | { |
| 723 | TPM2B_PUBLIC marshalBuffer; |
| 724 | BYTE *buffer; // auxiliary marshal buffer pointer |
Jocelyn Bohr | 32be404 | 2015-07-29 15:14:01 -0700 | [diff] [blame] | 725 | INT32 bufferSize; |
Vadim Bendebury | 5679752 | 2015-05-20 10:32:25 -0700 | [diff] [blame] | 726 | HASH_STATE hashState; // hash state |
| 727 | // if the nameAlg is NULL then there is no name. |
| 728 | if(publicArea->nameAlg == TPM_ALG_NULL) |
| 729 | { |
| 730 | name->t.size = 0; |
| 731 | return; |
| 732 | } |
| 733 | // Start hash stack |
| 734 | name->t.size = CryptStartHash(publicArea->nameAlg, &hashState); |
| 735 | // Marshal the public area into its canonical form |
| 736 | buffer = marshalBuffer.b.buffer; |
Jocelyn Bohr | 5aac585 | 2015-08-20 16:05:05 -0700 | [diff] [blame] | 737 | bufferSize = sizeof(TPMT_PUBLIC); |
Jocelyn Bohr | 32be404 | 2015-07-29 15:14:01 -0700 | [diff] [blame] | 738 | marshalBuffer.t.size = TPMT_PUBLIC_Marshal(publicArea, &buffer, &bufferSize); |
Vadim Bendebury | 5679752 | 2015-05-20 10:32:25 -0700 | [diff] [blame] | 739 | // Adding public area |
| 740 | CryptUpdateDigest2B(&hashState, &marshalBuffer.b); |
| 741 | // Complete hash leaving room for the name algorithm |
ChromeOS Developer | e85c65b | 2015-07-10 10:12:43 -0700 | [diff] [blame] | 742 | CryptCompleteHash(&hashState, name->t.size, &name->t.name[2]); |
Vadim Bendebury | 5679752 | 2015-05-20 10:32:25 -0700 | [diff] [blame] | 743 | // set the nameAlg |
ChromeOS Developer | e85c65b | 2015-07-10 10:12:43 -0700 | [diff] [blame] | 744 | UINT16_TO_BYTE_ARRAY(publicArea->nameAlg, name->t.name); |
Vadim Bendebury | 5679752 | 2015-05-20 10:32:25 -0700 | [diff] [blame] | 745 | // |
| 746 | name->t.size += 2; |
| 747 | return; |
| 748 | } |
| 749 | // |
| 750 | // |
| 751 | // ObjectComputeQualifiedName() |
| 752 | // |
| 753 | // This function computes the qualified name of an object. |
| 754 | // |
| 755 | void |
| 756 | ObjectComputeQualifiedName( |
| 757 | TPM2B_NAME *parentQN, // IN: parent's qualified name |
| 758 | TPM_ALG_ID nameAlg, // IN: name hash |
| 759 | TPM2B_NAME *name, // IN: name of the object |
| 760 | TPM2B_NAME *qualifiedName // OUT: qualified name of the object |
| 761 | ) |
| 762 | { |
| 763 | HASH_STATE hashState; // hash state |
| 764 | // QN_A = hash_A (QN of parent || NAME_A) |
| 765 | // Start hash |
| 766 | qualifiedName->t.size = CryptStartHash(nameAlg, &hashState); |
| 767 | // Add parent's qualified name |
| 768 | CryptUpdateDigest2B(&hashState, &parentQN->b); |
| 769 | // Add self name |
| 770 | CryptUpdateDigest2B(&hashState, &name->b); |
| 771 | // Complete hash leaving room for the name algorithm |
| 772 | CryptCompleteHash(&hashState, qualifiedName->t.size, |
ChromeOS Developer | e85c65b | 2015-07-10 10:12:43 -0700 | [diff] [blame] | 773 | &qualifiedName->t.name[2]); |
| 774 | UINT16_TO_BYTE_ARRAY(nameAlg, qualifiedName->t.name); |
Vadim Bendebury | 5679752 | 2015-05-20 10:32:25 -0700 | [diff] [blame] | 775 | qualifiedName->t.size += 2; |
| 776 | return; |
| 777 | } |
| 778 | // |
| 779 | // |
| 780 | // ObjectDataIsStorage() |
| 781 | // |
| 782 | // This function determines if a public area has the attributes associated with a storage key. A storage key is |
| 783 | // an asymmetric object that has its restricted and decrypt attributes SET, and sign CLEAR. |
| 784 | // |
| 785 | // Return Value Meaning |
| 786 | // |
| 787 | // TRUE if the object is a storage key |
| 788 | // FALSE if the object is not a storage key |
| 789 | // |
| 790 | BOOL |
| 791 | ObjectDataIsStorage( |
| 792 | TPMT_PUBLIC *publicArea // IN: public area of the object |
| 793 | ) |
| 794 | { |
| 795 | if( CryptIsAsymAlgorithm(publicArea->type) // must be asymmetric, |
| 796 | && publicArea->objectAttributes.restricted == SET // restricted, |
| 797 | && publicArea->objectAttributes.decrypt == SET // decryption key |
| 798 | && publicArea->objectAttributes.sign == CLEAR // can not be sign key |
| 799 | ) |
| 800 | return TRUE; |
| 801 | else |
| 802 | return FALSE; |
| 803 | } |
| 804 | // |
| 805 | // ObjectIsStorage() |
| 806 | // |
| 807 | // This function determines if an object has the attributes associated with a storage key. A storage key is an |
| 808 | // asymmetric object that has its restricted and decrypt attributes SET, and sign CLEAR. |
| 809 | // |
| 810 | // Return Value Meaning |
| 811 | // |
| 812 | // TRUE if the object is a storage key |
| 813 | // FALSE if the object is not a storage key |
| 814 | // |
| 815 | BOOL |
| 816 | ObjectIsStorage( |
| 817 | TPMI_DH_OBJECT handle // IN: object handle |
| 818 | ) |
| 819 | { |
| 820 | OBJECT *object = ObjectGet(handle); |
| 821 | return ObjectDataIsStorage(&object->publicArea); |
| 822 | } |
| 823 | // |
| 824 | // |
| 825 | // ObjectCapGetLoaded() |
| 826 | // |
| 827 | // This function returns a a list of handles of loaded object, starting from handle. Handle must be in the |
| 828 | // range of valid transient object handles, but does not have to be the handle of a loaded transient object. |
| 829 | // |
| 830 | // Return Value Meaning |
| 831 | // |
| 832 | // YES if there are more handles available |
| 833 | // NO all the available handles has been returned |
| 834 | // |
| 835 | TPMI_YES_NO |
| 836 | ObjectCapGetLoaded( |
| 837 | TPMI_DH_OBJECT handle, // IN: start handle |
| 838 | UINT32 count, // IN: count of returned handles |
| 839 | TPML_HANDLE *handleList // OUT: list of handle |
| 840 | ) |
| 841 | { |
| 842 | TPMI_YES_NO more = NO; |
| 843 | UINT32 i; |
| 844 | pAssert(HandleGetType(handle) == TPM_HT_TRANSIENT); |
| 845 | // Initialize output handle list |
| 846 | handleList->count = 0; |
| 847 | // The maximum count of handles we may return is MAX_CAP_HANDLES |
| 848 | if(count > MAX_CAP_HANDLES) count = MAX_CAP_HANDLES; |
| 849 | // Iterate object slots to get loaded object handles |
| 850 | for(i = handle - TRANSIENT_FIRST; i < MAX_LOADED_OBJECTS; i++) |
| 851 | { |
| 852 | if(s_objects[i].occupied == TRUE) |
| 853 | { |
| 854 | // A valid transient object can not be the copy of a persistent object |
| 855 | pAssert(s_objects[i].object.entity.attributes.evict == CLEAR); |
| 856 | if(handleList->count < count) |
| 857 | { |
| 858 | // If we have not filled up the return list, add this object |
| 859 | // handle to it |
| 860 | handleList->handle[handleList->count] = i + TRANSIENT_FIRST; |
| 861 | handleList->count++; |
| 862 | // |
| 863 | } |
| 864 | else |
| 865 | { |
| 866 | // If the return list is full but we still have loaded object |
| 867 | // available, report this and stop iterating |
| 868 | more = YES; |
| 869 | break; |
| 870 | } |
| 871 | } |
| 872 | } |
| 873 | return more; |
| 874 | } |
| 875 | // |
| 876 | // |
| 877 | // ObjectCapGetTransientAvail() |
| 878 | // |
| 879 | // This function returns an estimate of the number of additional transient objects that could be loaded into |
| 880 | // the TPM. |
| 881 | // |
| 882 | UINT32 |
| 883 | ObjectCapGetTransientAvail( |
| 884 | void |
| 885 | ) |
| 886 | { |
| 887 | UINT32 i; |
| 888 | UINT32 num = 0; |
| 889 | // Iterate object slot to get the number of unoccupied slots |
| 890 | for(i = 0; i < MAX_LOADED_OBJECTS; i++) |
| 891 | { |
| 892 | if(s_objects[i].occupied == FALSE) num++; |
| 893 | } |
| 894 | return num; |
| 895 | } |