aboutsummaryrefslogtreecommitdiff
path: root/Object.c
blob: 14ec018f0a7960d25563963bce39148075bda16f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
// This file was extracted from the TCG Published
// Trusted Platform Module Library
// Part 4: Supporting Routines
// Family "2.0"
// Level 00 Revision 01.16
// October 30, 2014

#define OBJECT_C
#include "InternalRoutines.h"
#include "Platform.h"
//
//
//            Functions
//
//             ObjectStartup()
//
//       This function is called at TPM2_Startup() to initialize the object subsystem.
//
void
ObjectStartup(
     void
     )
{
     UINT32        i;
     // object slots initialization
     for(i = 0; i < MAX_LOADED_OBJECTS; i++)
     {
         //Set the slot to not occupied
         s_objects[i].occupied = FALSE;
     }
     return;
}
//
//
//             ObjectCleanupEvict()
//
//       In this implementation, a persistent object is moved from NV into an object slot for processing. It is
//       flushed after command execution. This function is called from ExecuteCommand().
//
void
ObjectCleanupEvict(
     void
     )
{
     UINT32        i;
     // This has to be iterated because a command may have two handles
     // and they may both be persistent.
     // This could be made to be more efficient so that a search is not needed.
     for(i = 0; i < MAX_LOADED_OBJECTS; i++)
     {
         // If an object is a temporary evict object, flush it from slot
         if(s_objects[i].object.entity.attributes.evict == SET)
             s_objects[i].occupied = FALSE;
     }
   return;
}
//
//
//          ObjectIsPresent()
//
//     This function checks to see if a transient handle references a loaded object. This routine should not be
//     called if the handle is not a transient handle. The function validates that the handle is in the
//     implementation-dependent allowed in range for loaded transient objects.
//
//     Return Value                      Meaning
//
//     TRUE                              if the handle references a loaded object
//     FALSE                             if the handle is not an object handle, or it does not reference to a
//                                       loaded object
//
BOOL
ObjectIsPresent(
   TPMI_DH_OBJECT        handle              // IN: handle to be checked
   )
{
   UINT32              slotIndex;                  // index of object slot
   pAssert(HandleGetType(handle) == TPM_HT_TRANSIENT);
   // The index in the loaded object array is found by subtracting the first
   // object handle number from the input handle number. If the indicated
   // slot is occupied, then indicate that there is already is a loaded
   // object associated with the handle.
   slotIndex = handle - TRANSIENT_FIRST;
   if(slotIndex >= MAX_LOADED_OBJECTS)
       return FALSE;
   return s_objects[slotIndex].occupied;
}
//
//
//          ObjectIsSequence()
//
//     This function is used to check if the object is a sequence object. This function should not be called if the
//     handle does not reference a loaded object.
//
//     Return Value                      Meaning
//
//     TRUE                              object is an HMAC, hash, or event sequence object
//     FALSE                             object is not an HMAC, hash, or event sequence object
//
BOOL
ObjectIsSequence(
   OBJECT              *object               // IN: handle to be checked
   )
{
   pAssert (object != NULL);
   if(   object->attributes.hmacSeq == SET
      || object->attributes.hashSeq == SET
      || object->attributes.eventSeq == SET)
       return TRUE;
   else
       return FALSE;
}
//
//
//           ObjectGet()
//
//      This function is used to find the object structure associated with a handle.
//      This function requires that handle references a loaded object.
//
OBJECT*
ObjectGet(
    TPMI_DH_OBJECT       handle             // IN: handle of the object
    )
{
    pAssert(   handle >= TRANSIENT_FIRST
            && handle - TRANSIENT_FIRST < MAX_LOADED_OBJECTS);
    pAssert(s_objects[handle - TRANSIENT_FIRST].occupied == TRUE);
    // In this implementation, the handle is determined by the slot occupied by the
    // object.
    return &s_objects[handle - TRANSIENT_FIRST].object.entity;
}
//
//
//           ObjectGetName()
//
//      This function is used to access the Name of the object. In this implementation, the Name is computed
//      when the object is loaded and is saved in the internal representation of the object. This function copies
//      the Name data from the object into the buffer at name and returns the number of octets copied.
//      This function requires that handle references a loaded object.
//
UINT16
ObjectGetName(
    TPMI_DH_OBJECT       handle,            // IN: handle of the object
    NAME                *name               // OUT: name of the object
    )
{
    OBJECT      *object = ObjectGet(handle);
    if(object->publicArea.nameAlg == TPM_ALG_NULL)
        return 0;
    // Copy the Name data to the output
    MemoryCopy(name, object->name.t.name, object->name.t.size, sizeof(NAME));
    return object->name.t.size;
}
//
//
//           ObjectGetNameAlg()
//
//      This function is used to get the Name algorithm of a object.
//      This function requires that handle references a loaded object.
//
TPMI_ALG_HASH
ObjectGetNameAlg(
    TPMI_DH_OBJECT       handle             // IN: handle of the object
    )
{
    OBJECT                   *object = ObjectGet(handle);
    return object->publicArea.nameAlg;
}
//
//
//
//           ObjectGetQualifiedName()
//
//      This function returns the Qualified Name of the object. In this implementation, the Qualified Name is
//      computed when the object is loaded and is saved in the internal representation of the object. The
//      alternative would be to retain the Name of the parent and compute the QN when needed. This would take
//      the same amount of space so it is not recommended that the alternate be used.
//      This function requires that handle references a loaded object.
//
void
ObjectGetQualifiedName(
    TPMI_DH_OBJECT       handle,            // IN: handle of the object
    TPM2B_NAME          *qualifiedName      // OUT: qualified name of the object
    )
{
    OBJECT      *object = ObjectGet(handle);
    if(object->publicArea.nameAlg == TPM_ALG_NULL)
        qualifiedName->t.size = 0;
    else
        // Copy the name
        *qualifiedName = object->qualifiedName;
    return;
}
//
//
//           ObjectDataGetHierarchy()
//
//      This function returns the handle for the hierarchy of an object.
//
TPMI_RH_HIERARCHY
ObjectDataGetHierarchy(
    OBJECT              *object             // IN :object
    )
{
    if(object->attributes.spsHierarchy)
    {
        return TPM_RH_OWNER;
    }
    else if(object->attributes.epsHierarchy)
    {
        return TPM_RH_ENDORSEMENT;
    }
    else if(object->attributes.ppsHierarchy)
    {
        return TPM_RH_PLATFORM;
    }
    else
    {
        return TPM_RH_NULL;
    }
}
//
//
//          ObjectGetHierarchy()
//
//      This function returns the handle of the hierarchy to which a handle belongs. This function is similar to
//      ObjectDataGetHierarchy() but this routine takes a handle but ObjectDataGetHierarchy() takes an pointer
//      to an object.
//      This function requires that handle references a loaded object.
//
TPMI_RH_HIERARCHY
ObjectGetHierarchy(
    TPMI_DH_OBJECT        handle              // IN :object handle
    )
{
    OBJECT               *object = ObjectGet(handle);
    return ObjectDataGetHierarchy(object);
}
//
//
//           ObjectAllocateSlot()
//
//      This function is used to allocate a slot in internal object array.
//
//      Return Value                       Meaning
//
//      TRUE                               allocate success
//      FALSE                              do not have free slot
//
static BOOL
ObjectAllocateSlot(
    TPMI_DH_OBJECT       *handle,             // OUT: handle of allocated object
    OBJECT               **object             // OUT: points to the allocated object
    )
{
    UINT32          i;
    // find an unoccupied handle slot
    for(i = 0; i < MAX_LOADED_OBJECTS; i++)
    {
        if(!s_objects[i].occupied)          // If found a free slot
        {
            // Mark the slot as occupied
            s_objects[i].occupied = TRUE;
            break;
        }
    }
    // If we reach the end of object slot without finding a free one, return
    // error.
    if(i == MAX_LOADED_OBJECTS) return FALSE;
    *handle = i + TRANSIENT_FIRST;
    *object = &s_objects[i].object.entity;
    // Initialize the container.
    MemorySet(*object, 0, sizeof(**object));
    return TRUE;
}
//
//
//           ObjectLoad()
//
//      This function loads an object into an internal object structure. If an error is returned, the internal state is
//      unchanged.
//
//
//
//
//      Error Returns                     Meaning
//
//      TPM_RC_BINDING                    if the public and sensitive parts of the object are not matched
//      TPM_RC_KEY                        if the parameters in the public area of the object are not consistent
//      TPM_RC_OBJECT_MEMORY              if there is no free slot for an object
//      TPM_RC_TYPE                       the public and private parts are not the same type
//
TPM_RC
ObjectLoad(
   TPMI_RH_HIERARCHY        hierarchy,               //   IN: hierarchy to which the object belongs
   TPMT_PUBLIC             *publicArea,              //   IN: public area
   TPMT_SENSITIVE          *sensitive,               //   IN: sensitive area (may be null)
   TPM2B_NAME              *name,                    //   IN: object's name (may be null)
   TPM_HANDLE               parentHandle,            //   IN: handle of parent
   BOOL                     skipChecks,              //   IN: flag to indicate if it is OK to skip
                                                     //       consistency checks.
   TPMI_DH_OBJECT          *handle                   //   OUT: object handle
   )
{
   OBJECT                   *object = NULL;
   OBJECT                   *parent = NULL;
   TPM_RC                    result = TPM_RC_SUCCESS;
   TPM2B_NAME                parentQN;         // Parent qualified name
   // Try to allocate a slot for new object
   if(!ObjectAllocateSlot(handle, &object))
       return TPM_RC_OBJECT_MEMORY;
   // Initialize public
   object->publicArea = *publicArea;
   if(sensitive != NULL)
       object->sensitive = *sensitive;
   // Are the consistency checks needed
   if(!skipChecks)
   {
       // Check if key size matches
       if(!CryptObjectIsPublicConsistent(&object->publicArea))
       {
           result = TPM_RC_KEY;
           goto ErrorExit;
       }
       if(sensitive != NULL)
       {
           // Check if public type matches sensitive type
           result = CryptObjectPublicPrivateMatch(object);
           if(result != TPM_RC_SUCCESS)
               goto ErrorExit;
       }
   }
   object->attributes.publicOnly = (sensitive == NULL);
   // If 'name' is NULL, then there is nothing left to do for this
   // object as it has no qualified name and it is not a member of any
   // hierarchy and it is temporary
   if(name == NULL || name->t.size == 0)
   {
       object->qualifiedName.t.size = 0;
       object->name.t.size = 0;
       object->attributes.temporary = SET;
       return TPM_RC_SUCCESS;
   }
   // If parent handle is a permanent handle, it is a primary or temporary
   // object
   if(HandleGetType(parentHandle) == TPM_HT_PERMANENT)
   {
       // initialize QN
       parentQN.t.size = 4;
        // for a primary key, parent qualified name is the handle of hierarchy
        UINT32_TO_BYTE_ARRAY(parentHandle, parentQN.t.name);
   }
   else
   {
       // Get hierarchy and qualified name of parent
       ObjectGetQualifiedName(parentHandle, &parentQN);
        // Check for stClear object
        parent = ObjectGet(parentHandle);
        if(    publicArea->objectAttributes.stClear == SET
            || parent->attributes.stClear == SET)
             object->attributes.stClear = SET;
   }
   object->name = *name;
   // Compute object qualified name
   ObjectComputeQualifiedName(&parentQN, publicArea->nameAlg,
                              name, &object->qualifiedName);
   // Any object in TPM_RH_NULL hierarchy is temporary
   if(hierarchy == TPM_RH_NULL)
   {
       object->attributes.temporary = SET;
   }
   else if(parentQN.t.size == sizeof(TPM_HANDLE))
   {
       // Otherwise, if the size of parent's qualified name is the size of a
       // handle, this object is a primary object
       object->attributes.primary = SET;
   }
   switch(hierarchy)
   {
       case TPM_RH_PLATFORM:
           object->attributes.ppsHierarchy = SET;
           break;
       case TPM_RH_OWNER:
           object->attributes.spsHierarchy = SET;
           break;
       case TPM_RH_ENDORSEMENT:
           object->attributes.epsHierarchy = SET;
           break;
       case TPM_RH_NULL:
           break;
       default:
           pAssert(FALSE);
           break;
   }
   return TPM_RC_SUCCESS;
ErrorExit:
   ObjectFlush(*handle);
   return result;
}
//
//
//
//          AllocateSequenceSlot()
//
//      This function allocates a sequence slot and initializes the parts that are used by the normal objects so
//      that a sequence object is not inadvertently used for an operation that is not appropriate for a sequence.
//
static BOOL
AllocateSequenceSlot(
   TPM_HANDLE          *newHandle,             // OUT: receives the allocated handle
   HASH_OBJECT         **object,               // OUT: receives pointer to allocated object
   TPM2B_AUTH          *auth                   // IN: the authValue for the slot
   )
{
   OBJECT                   *objectHash;                   // the hash as an object
   if(!ObjectAllocateSlot(newHandle, &objectHash))
       return FALSE;
   *object = (HASH_OBJECT *)objectHash;
   // Validate that the proper location of the hash state data relative to the
   // object state data.
   pAssert(&((*object)->auth) == &objectHash->publicArea.authPolicy);
   // Set the common values that a sequence object shares with an ordinary object
   // The type is TPM_ALG_NULL
   (*object)->type = TPM_ALG_NULL;
   // This has no name algorithm and the name is the Empty Buffer
   (*object)->nameAlg = TPM_ALG_NULL;
   // Clear the attributes
   MemorySet(&((*object)->objectAttributes), 0, sizeof(TPMA_OBJECT));
   // A sequence object is considered to be in the NULL hierarchy so it should
   // be marked as temporary so that it can't be persisted
   (*object)->attributes.temporary = SET;
   // A sequence object is DA exempt.
   (*object)->objectAttributes.noDA = SET;
   if(auth != NULL)
   {
       MemoryRemoveTrailingZeros(auth);
       (*object)->auth = *auth;
   }
   else
       (*object)->auth.t.size = 0;
   return TRUE;
}
//
//
//          ObjectCreateHMACSequence()
//
//      This function creates an internal HMAC sequence object.
//
//      Error Returns                     Meaning
//
//      TPM_RC_OBJECT_MEMORY              if there is no free slot for an object
//
TPM_RC
ObjectCreateHMACSequence(
   TPMI_ALG_HASH        hashAlg,               // IN: hash algorithm
   TPM_HANDLE           handle,                // IN: the handle associated with sequence
                                               //     object
   TPM2B_AUTH         *auth,                 // IN: authValue
   TPMI_DH_OBJECT     *newHandle             // OUT: HMAC sequence object handle
   )
{
   HASH_OBJECT               *hmacObject;
   OBJECT                    *keyObject;
   // Try to allocate a slot for new object
   if(!AllocateSequenceSlot(newHandle, &hmacObject, auth))
       return TPM_RC_OBJECT_MEMORY;
   // Set HMAC sequence bit
   hmacObject->attributes.hmacSeq = SET;
   // Get pointer to the HMAC key object
   keyObject = ObjectGet(handle);
   CryptStartHMACSequence2B(hashAlg, &keyObject->sensitive.sensitive.bits.b,
                            &hmacObject->state.hmacState);
   return TPM_RC_SUCCESS;
}
//
//
//         ObjectCreateHashSequence()
//
//      This function creates a hash sequence object.
//
//      Error Returns                   Meaning
//
//      TPM_RC_OBJECT_MEMORY            if there is no free slot for an object
//
TPM_RC
ObjectCreateHashSequence(
   TPMI_ALG_HASH       hashAlg,              // IN: hash algorithm
   TPM2B_AUTH         *auth,                 // IN: authValue
   TPMI_DH_OBJECT     *newHandle             // OUT: sequence object handle
   )
{
   HASH_OBJECT               *hashObject;
   // Try to allocate a slot for new object
   if(!AllocateSequenceSlot(newHandle, &hashObject, auth))
       return TPM_RC_OBJECT_MEMORY;
   // Set hash sequence bit
   hashObject->attributes.hashSeq = SET;
   // Start hash for hash sequence
   CryptStartHashSequence(hashAlg, &hashObject->state.hashState[0]);
   return TPM_RC_SUCCESS;
}
//
//
//         ObjectCreateEventSequence()
//
//      This function creates an event sequence object.
//
//      Error Returns                   Meaning
//
//      TPM_RC_OBJECT_MEMORY            if there is no free slot for an object
//
TPM_RC
ObjectCreateEventSequence(
   TPM2B_AUTH          *auth,              // IN: authValue
   TPMI_DH_OBJECT      *newHandle          // OUT: sequence object handle
   )
{
   HASH_OBJECT              *hashObject;
   UINT32                    count;
   TPM_ALG_ID                hash;
   // Try to allocate a slot for new object
   if(!AllocateSequenceSlot(newHandle, &hashObject, auth))
       return TPM_RC_OBJECT_MEMORY;
   // Set the event sequence attribute
   hashObject->attributes.eventSeq = SET;
   // Initialize hash states for each implemented PCR algorithms
   for(count = 0; (hash = CryptGetHashAlgByIndex(count)) != TPM_ALG_NULL; count++)
   {
       // If this is a _TPM_Init or _TPM_HashStart, the sequence object will
       // not leave the TPM so it doesn't need the sequence handling
       if(auth == NULL)
            CryptStartHash(hash, &hashObject->state.hashState[count]);
       else
            CryptStartHashSequence(hash, &hashObject->state.hashState[count]);
   }
   return TPM_RC_SUCCESS;
}
//
//
//          ObjectTerminateEvent()
//
//      This function is called to close out the event sequence and clean up the hash context states.
//
void
ObjectTerminateEvent(
   void
   )
{
   HASH_OBJECT         *hashObject;
   int                  count;
   BYTE                 buffer[MAX_DIGEST_SIZE];
   hashObject = (HASH_OBJECT *)ObjectGet(g_DRTMHandle);
   // Don't assume that this is a proper sequence object
   if(hashObject->attributes.eventSeq)
   {
       // If it is, close any open hash contexts. This is done in case
       // the crypto implementation has some context values that need to be
       // cleaned up (hygiene).
       //
       for(count = 0; CryptGetHashAlgByIndex(count) != TPM_ALG_NULL; count++)
       {
           CryptCompleteHash(&hashObject->state.hashState[count], 0, buffer);
       }
       // Flush sequence object
       ObjectFlush(g_DRTMHandle);
   }
   g_DRTMHandle = TPM_RH_UNASSIGNED;
}
//
//
//
//          ObjectContextLoad()
//
//      This function loads an object from a saved object context.
//
//      Error Returns                     Meaning
//
//      TPM_RC_OBJECT_MEMORY              if there is no free slot for an object
//
TPM_RC
ObjectContextLoad(
    OBJECT              *object,               // IN: object structure from saved context
    TPMI_DH_OBJECT      *handle                // OUT: object handle
    )
{
    OBJECT         *newObject;
    // Try to allocate a slot for new object
    if(!ObjectAllocateSlot(handle, &newObject))
        return TPM_RC_OBJECT_MEMORY;
    // Copy input object data to internal structure
    *newObject = *object;
    return TPM_RC_SUCCESS;
}
//
//
//          ObjectFlush()
//
//      This function frees an object slot.
//      This function requires that the object is loaded.
//
void
ObjectFlush(
    TPMI_DH_OBJECT        handle               // IN: handle to be freed
    )
{
    UINT32      index = handle - TRANSIENT_FIRST;
    pAssert(ObjectIsPresent(handle));
    // Mark the handle slot as unoccupied
    s_objects[index].occupied = FALSE;
    // With no attributes
    MemorySet((BYTE*)&(s_objects[index].object.entity.attributes),
               0, sizeof(OBJECT_ATTRIBUTES));
    return;
}
//
//
//          ObjectFlushHierarchy()
//
//      This function is called to flush all the loaded transient objects associated with a hierarchy when the
//      hierarchy is disabled.
//
void
ObjectFlushHierarchy(
    TPMI_RH_HIERARCHY          hierarchy             // IN: hierarchy to be flush
    )
{
    UINT16              i;
    // iterate object slots
    for(i = 0; i < MAX_LOADED_OBJECTS; i++)
    {
        if(s_objects[i].occupied)           // If found an occupied slot
        {
            switch(hierarchy)
            {
                case TPM_RH_PLATFORM:
                    if(s_objects[i].object.entity.attributes.ppsHierarchy == SET)
                         s_objects[i].occupied = FALSE;
                    break;
                case TPM_RH_OWNER:
                    if(s_objects[i].object.entity.attributes.spsHierarchy == SET)
                         s_objects[i].occupied = FALSE;
                    break;
                case TPM_RH_ENDORSEMENT:
                    if(s_objects[i].object.entity.attributes.epsHierarchy == SET)
                         s_objects[i].occupied = FALSE;
                    break;
                default:
                    pAssert(FALSE);
                    break;
            }
        }
    }
    return;
}
//
//
//           ObjectLoadEvict()
//
//      This function loads a persistent object into a transient object slot.
//      This function requires that handle is associated with a persistent object.
//
//      Error Returns                     Meaning
//
//      TPM_RC_HANDLE                     the persistent object does not exist or the associated hierarchy is
//                                        disabled.
//      TPM_RC_OBJECT_MEMORY              no object slot
//
TPM_RC
ObjectLoadEvict(
    TPM_HANDLE           *handle,             // IN:OUT: evict object handle. If success, it
                                              // will be replace by the loaded object handle
    TPM_CC                commandCode         // IN: the command being processed
    )
{
    TPM_RC               result;
    TPM_HANDLE           evictHandle = *handle;           // Save the evict handle
    OBJECT               *object;
    // If this is an index that references a persistent object created by
    // the platform, then return TPM_RH_HANDLE if the phEnable is FALSE
    if(*handle >= PLATFORM_PERSISTENT)
    {
        // belongs to platform
        if(g_phEnable == CLEAR)
            return TPM_RC_HANDLE;
    }
    // belongs to owner
    else if(gc.shEnable == CLEAR)
        return TPM_RC_HANDLE;
   // Try to allocate a slot for an object
   if(!ObjectAllocateSlot(handle, &object))
       return TPM_RC_OBJECT_MEMORY;
   // Copy persistent object to transient object slot. A TPM_RC_HANDLE
   // may be returned at this point. This will mark the slot as containing
   // a transient object so that it will be flushed at the end of the
   // command
   result = NvGetEvictObject(evictHandle, object);
   // Bail out if this failed
   if(result != TPM_RC_SUCCESS)
       return result;
   // check the object to see if it is in the endorsement hierarchy
   // if it is and this is not a TPM2_EvictControl() command, indicate
   // that the hierarchy is disabled.
   // If the associated hierarchy is disabled, make it look like the
   // handle is not defined
   if(     ObjectDataGetHierarchy(object) == TPM_RH_ENDORSEMENT
        && gc.ehEnable == CLEAR
        && commandCode != TPM_CC_EvictControl
      )
        return TPM_RC_HANDLE;
   return result;
}
//
//
//          ObjectComputeName()
//
//      This function computes the Name of an object from its public area.
//
void
ObjectComputeName(
   TPMT_PUBLIC         *publicArea,       // IN: public area of an object
   TPM2B_NAME          *name              // OUT: name of the object
   )
{
   TPM2B_PUBLIC               marshalBuffer;
   BYTE                      *buffer;               // auxiliary marshal buffer pointer
   INT32                      bufferSize;
   HASH_STATE                 hashState;            // hash state
   // if the nameAlg is NULL then there is no name.
   if(publicArea->nameAlg == TPM_ALG_NULL)
   {
       name->t.size = 0;
       return;
   }
   // Start hash stack
   name->t.size = CryptStartHash(publicArea->nameAlg, &hashState);
   // Marshal the public area into its canonical form
   buffer = marshalBuffer.b.buffer;
   bufferSize = sizeof(TPMT_PUBLIC);
   marshalBuffer.t.size = TPMT_PUBLIC_Marshal(publicArea, &buffer, &bufferSize);
   // Adding public area
   CryptUpdateDigest2B(&hashState, &marshalBuffer.b);
   // Complete hash leaving room for the name algorithm
   CryptCompleteHash(&hashState, name->t.size, &name->t.name[2]);
   // set the nameAlg
   UINT16_TO_BYTE_ARRAY(publicArea->nameAlg, name->t.name);
//
   name->t.size += 2;
   return;
}
//
//
//          ObjectComputeQualifiedName()
//
//      This function computes the qualified name of an object.
//
void
ObjectComputeQualifiedName(
   TPM2B_NAME          *parentQN,             //   IN: parent's qualified name
   TPM_ALG_ID           nameAlg,              //   IN: name hash
   TPM2B_NAME          *name,                 //   IN: name of the object
   TPM2B_NAME          *qualifiedName         //   OUT: qualified name of the object
   )
{
   HASH_STATE          hashState;         // hash state
   //         QN_A = hash_A (QN of parent || NAME_A)
   // Start hash
   qualifiedName->t.size = CryptStartHash(nameAlg, &hashState);
   // Add parent's qualified name
   CryptUpdateDigest2B(&hashState, &parentQN->b);
   // Add self name
   CryptUpdateDigest2B(&hashState, &name->b);
   // Complete hash leaving room for the name algorithm
   CryptCompleteHash(&hashState, qualifiedName->t.size,
                     &qualifiedName->t.name[2]);
   UINT16_TO_BYTE_ARRAY(nameAlg, qualifiedName->t.name);
   qualifiedName->t.size += 2;
   return;
}
//
//
//          ObjectDataIsStorage()
//
//      This function determines if a public area has the attributes associated with a storage key. A storage key is
//      an asymmetric object that has its restricted and decrypt attributes SET, and sign CLEAR.
//
//      Return Value                      Meaning
//
//      TRUE                              if the object is a storage key
//      FALSE                             if the object is not a storage key
//
BOOL
ObjectDataIsStorage(
   TPMT_PUBLIC         *publicArea            // IN: public area of the object
   )
{
   if(   CryptIsAsymAlgorithm(publicArea->type)                          //   must be asymmetric,
      && publicArea->objectAttributes.restricted == SET                  //   restricted,
      && publicArea->objectAttributes.decrypt == SET                     //   decryption key
      && publicArea->objectAttributes.sign == CLEAR                      //   can not be sign key
     )
       return TRUE;
   else
       return FALSE;
}
//
//          ObjectIsStorage()
//
//      This function determines if an object has the attributes associated with a storage key. A storage key is an
//      asymmetric object that has its restricted and decrypt attributes SET, and sign CLEAR.
//
//      Return Value                    Meaning
//
//      TRUE                            if the object is a storage key
//      FALSE                           if the object is not a storage key
//
BOOL
ObjectIsStorage(
     TPMI_DH_OBJECT     handle              // IN: object handle
     )
{
     OBJECT           *object = ObjectGet(handle);
     return ObjectDataIsStorage(&object->publicArea);
}
//
//
//          ObjectCapGetLoaded()
//
//      This function returns a a list of handles of loaded object, starting from handle. Handle must be in the
//      range of valid transient object handles, but does not have to be the handle of a loaded transient object.
//
//      Return Value                    Meaning
//
//      YES                             if there are more handles available
//      NO                              all the available handles has been returned
//
TPMI_YES_NO
ObjectCapGetLoaded(
     TPMI_DH_OBJECT     handle,             // IN: start handle
     UINT32             count,              // IN: count of returned handles
     TPML_HANDLE       *handleList          // OUT: list of handle
     )
{
     TPMI_YES_NO             more = NO;
     UINT32                  i;
     pAssert(HandleGetType(handle) == TPM_HT_TRANSIENT);
     // Initialize output handle list
     handleList->count = 0;
     // The maximum count of handles we may return is MAX_CAP_HANDLES
     if(count > MAX_CAP_HANDLES) count = MAX_CAP_HANDLES;
     // Iterate object slots to get loaded object handles
     for(i = handle - TRANSIENT_FIRST; i < MAX_LOADED_OBJECTS; i++)
     {
         if(s_objects[i].occupied == TRUE)
         {
             // A valid transient object can not be the copy of a persistent object
             pAssert(s_objects[i].object.entity.attributes.evict == CLEAR);
              if(handleList->count < count)
              {
                  // If we have not filled up the return list, add this object
                  // handle to it
                  handleList->handle[handleList->count] = i + TRANSIENT_FIRST;
                  handleList->count++;
//
                 }
                 else
                 {
                     // If the return list is full but we still have loaded object
                     // available, report this and stop iterating
                     more = YES;
                     break;
                 }
          }
     }
     return more;
}
//
//
//             ObjectCapGetTransientAvail()
//
//      This function returns an estimate of the number of additional transient objects that could be loaded into
//      the TPM.
//
UINT32
ObjectCapGetTransientAvail(
     void
     )
{
     UINT32          i;
     UINT32          num = 0;
     // Iterate object slot to get the number of unoccupied slots
     for(i = 0; i < MAX_LOADED_OBJECTS; i++)
     {
         if(s_objects[i].occupied == FALSE) num++;
     }
     return num;
}