summaryrefslogtreecommitdiffstats
path: root/src/tpm2/Object.c
blob: aa69a53d41b96ed229e33c68e0262faa60464a76 (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
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
/********************************************************************************/
/*										*/
/*		Manage the object store of the TPM.    				*/
/*			     Written by Ken Goldman				*/
/*		       IBM Thomas J. Watson Research Center			*/
/*            $Id: Object.c 1658 2021-01-22 23:14:01Z kgoldman $		*/
/*										*/
/*  Licenses and Notices							*/
/*										*/
/*  1. Copyright Licenses:							*/
/*										*/
/*  - Trusted Computing Group (TCG) grants to the user of the source code in	*/
/*    this specification (the "Source Code") a worldwide, irrevocable, 		*/
/*    nonexclusive, royalty free, copyright license to reproduce, create 	*/
/*    derivative works, distribute, display and perform the Source Code and	*/
/*    derivative works thereof, and to grant others the rights granted herein.	*/
/*										*/
/*  - The TCG grants to the user of the other parts of the specification 	*/
/*    (other than the Source Code) the rights to reproduce, distribute, 	*/
/*    display, and perform the specification solely for the purpose of 		*/
/*    developing products based on such documents.				*/
/*										*/
/*  2. Source Code Distribution Conditions:					*/
/*										*/
/*  - Redistributions of Source Code must retain the above copyright licenses, 	*/
/*    this list of conditions and the following disclaimers.			*/
/*										*/
/*  - Redistributions in binary form must reproduce the above copyright 	*/
/*    licenses, this list of conditions	and the following disclaimers in the 	*/
/*    documentation and/or other materials provided with the distribution.	*/
/*										*/
/*  3. Disclaimers:								*/
/*										*/
/*  - THE COPYRIGHT LICENSES SET FORTH ABOVE DO NOT REPRESENT ANY FORM OF	*/
/*  LICENSE OR WAIVER, EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE, WITH	*/
/*  RESPECT TO PATENT RIGHTS HELD BY TCG MEMBERS (OR OTHER THIRD PARTIES)	*/
/*  THAT MAY BE NECESSARY TO IMPLEMENT THIS SPECIFICATION OR OTHERWISE.		*/
/*  Contact TCG Administration (admin@trustedcomputinggroup.org) for 		*/
/*  information on specification licensing rights available through TCG 	*/
/*  membership agreements.							*/
/*										*/
/*  - THIS SPECIFICATION IS PROVIDED "AS IS" WITH NO EXPRESS OR IMPLIED 	*/
/*    WARRANTIES WHATSOEVER, INCLUDING ANY WARRANTY OF MERCHANTABILITY OR 	*/
/*    FITNESS FOR A PARTICULAR PURPOSE, ACCURACY, COMPLETENESS, OR 		*/
/*    NONINFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS, OR ANY WARRANTY 		*/
/*    OTHERWISE ARISING OUT OF ANY PROPOSAL, SPECIFICATION OR SAMPLE.		*/
/*										*/
/*  - Without limitation, TCG and its members and licensors disclaim all 	*/
/*    liability, including liability for infringement of any proprietary 	*/
/*    rights, relating to use of information in this specification and to the	*/
/*    implementation of this specification, and TCG disclaims all liability for	*/
/*    cost of procurement of substitute goods or services, lost profits, loss 	*/
/*    of use, loss of data or any incidental, consequential, direct, indirect, 	*/
/*    or special damages, whether under contract, tort, warranty or otherwise, 	*/
/*    arising in any way out of use or reliance upon this specification or any 	*/
/*    information herein.							*/
/*										*/
/*  (c) Copyright IBM Corp. and others, 2016 - 2021				*/
/*										*/
/********************************************************************************/

/* 8.6 Object.c */
/* 8.6.1 Introduction */
/* This file contains the functions that manage the object store of the TPM. */
/* 8.6.2 Includes and Data Definitions */
#define OBJECT_C
#include "Tpm.h"
#include "NVMarshal.h" // libtpms added
#include "BackwardsCompatibilityObject.h" // libtpms added
/* 8.6.3 Functions */
/* 8.6.3.1 ObjectFlush() */
/* This function marks an object slot as available. Since there is no checking of the input
   parameters, it should be used judiciously. */
/* NOTE: This could be converted to a macro. */
void
ObjectFlush(
	    OBJECT          *object
	    )
{
    object->attributes.occupied = CLEAR;
}
/* 8.6.3.2 ObjectSetInUse() */
/* This access function sets the occupied attribute of an object slot. */
void
ObjectSetInUse(
	       OBJECT          *object
	       )
{
    object->attributes.occupied = SET;
}
/* 8.6.3.3 ObjectStartup() */
/* This function is called at TPM2_Startup() to initialize the object subsystem. */
BOOL
ObjectStartup(
	      void
	      )
{
    UINT32      i;
    // object slots initialization
    for(i = 0; i < MAX_LOADED_OBJECTS; i++)
	{
	    //Set the slot to not occupied
	    ObjectFlush(&s_objects[i]);
	}
    return TRUE;
}
/* 8.6.3.4 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
	    OBJECT      *object = &s_objects[i];
	    if(object->attributes.evict == SET)
		ObjectFlush(object);
	}
    return;
}
/* 8.6.3.5 IsObjectPresent() */
/* 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 Values 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
IsObjectPresent(
		TPMI_DH_OBJECT   handle         // IN: handle to be checked
		)
{
    UINT32          slotIndex = handle - TRANSIENT_FIRST;
    // Since the handle is just an index into the array that is zero based, any
    // handle value outsize of the range of:
    //    TRANSIENT_FIRST -- (TRANSIENT_FIRST + MAX_LOADED_OBJECT - 1)
    // will now be greater than or equal to MAX_LOADED_OBJECTS
    if(slotIndex >= MAX_LOADED_OBJECTS)
	return FALSE;
    // Indicate if the slot is occupied
    return (s_objects[slotIndex].attributes.occupied == TRUE);
}
/* 8.6.3.6 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 Values 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);
    return (object->attributes.hmacSeq == SET
	    || object->attributes.hashSeq == SET
	    || object->attributes.eventSeq == SET);
}
/* 8.6.3.7 HandleToObject() */
/* This function is used to find the object structure associated with a handle. */
/* This function requires that handle references a loaded object or a permanent handle. */
OBJECT*
HandleToObject(
	       TPMI_DH_OBJECT   handle         // IN: handle of the object
	       )
{
    UINT32              index;
    // Return NULL if the handle references a permanent handle because there is no
    // associated OBJECT.
    if(HandleGetType(handle) == TPM_HT_PERMANENT)
	return NULL;
    // In this implementation, the handle is determined by the slot occupied by the
    // object.
    index = handle - TRANSIENT_FIRST;
    pAssert(index < MAX_LOADED_OBJECTS);
    pAssert(s_objects[index].attributes.occupied);
    return &s_objects[index];
}
/* 8.6.3.9 GetQualifiedName() */
/* 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
GetQualifiedName(
		 TPMI_DH_OBJECT   handle,        // IN: handle of the object
		 TPM2B_NAME      *qualifiedName  // OUT: qualified name of the object
		 )
{
    OBJECT      *object;
    switch(HandleGetType(handle))
	{
	  case TPM_HT_PERMANENT:
	    qualifiedName->t.size = sizeof(TPM_HANDLE);
	    UINT32_TO_BYTE_ARRAY(handle, qualifiedName->t.name);
	    break;
	  case TPM_HT_TRANSIENT:
	    object = HandleToObject(handle);
	    if(object == NULL || object->publicArea.nameAlg == TPM_ALG_NULL)
		qualifiedName->t.size = 0;
	    else
		// Copy the name
		*qualifiedName = object->qualifiedName;
	    break;
	  default:
	    FAIL(FATAL_ERROR_INTERNAL);
	}
    return;
}
/* 8.6.3.10 ObjectGetHierarchy() */
/* This function returns the handle for the hierarchy of an object. */
TPMI_RH_HIERARCHY
ObjectGetHierarchy(
		   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;
	}
}
/* 8.6.3.11 GetHierarchy() */
/* This function returns the handle of the hierarchy to which a handle belongs. This function is
   similar to ObjectGetHierarchy() but this routine takes a handle while ObjectGetHierarchy() takes
   a pointer to an object. */
/* This function requires that handle references a loaded object. */
TPMI_RH_HIERARCHY
GetHieriarchy(
	     TPMI_DH_OBJECT   handle         // IN :object handle
	     )
{
    OBJECT          *object = HandleToObject(handle);
    return ObjectGetHierarchy(object);
}
/* 8.6.3.12 FindEmptyObjectSlot() */
/* This function finds an open object slot, if any. It will clear the attributes but will not set
   the occupied attribute. This is so that a slot may be used and discarded if everything does not
   go as planned. */
/* Return Values Meaning */
/* null no open slot found */
/* !=null pointer to available slot */
OBJECT *
FindEmptyObjectSlot(
		    TPMI_DH_OBJECT  *handle         // OUT: (optional)
		    )
{
    UINT32               i;
    OBJECT              *object;
    for(i = 0; i < MAX_LOADED_OBJECTS; i++)
	{
	    object = &s_objects[i];
	    if(object->attributes.occupied == CLEAR)
		{
		    if(handle)
			*handle = i + TRANSIENT_FIRST;
		    // Initialize the object attributes
		    // MemorySet(&object->attributes, 0, sizeof(OBJECT_ATTRIBUTES));
		    MemorySet(object, 0, sizeof(*object)); // libtpms added: Initialize the whole object
		    return object;
		}
	}
    return NULL;
}
/* 8.6.3.13 ObjectAllocateSlot() */
/* This function is used to allocate a slot in internal object array. */
/* Return Values Meaning */
OBJECT *
ObjectAllocateSlot(
		   TPMI_DH_OBJECT  *handle        // OUT: handle of allocated object
		   )
{
    OBJECT          *object = FindEmptyObjectSlot(handle);
    if(object != NULL)
	{
	    // if found, mark as occupied
	    ObjectSetInUse(object);
	}
    return object;
}
/* 8.6.3.14 ObjectSetLoadedAttributes() */
/* This function sets the internal attributes for a loaded object. It is called to finalize the
   OBJECT attributes (not the TPMA_OBJECT attributes) for a loaded object. */
void
ObjectSetLoadedAttributes(
			  OBJECT          *object,        // IN: object attributes to finalize
			  TPM_HANDLE       parentHandle,  // IN: the parent handle
			  SEED_COMPAT_LEVEL seedCompatLevel // IN: seed compat level to use for children
			  )
{
    OBJECT              *parent = HandleToObject(parentHandle);
    TPMA_OBJECT          objectAttributes = object->publicArea.objectAttributes;

    object->seedCompatLevel = seedCompatLevel; // libtpms added
    //
    // Copy the stClear attribute from the public area. This could be overwritten
    // if the parent has stClear SET
    object->attributes.stClear =
	IS_ATTRIBUTE(objectAttributes, TPMA_OBJECT, stClear);
    // If parent handle is a permanent handle, it is a primary (unless it is NULL
    if(parent == NULL)
	{
	    object->attributes.primary = SET;
	    switch(parentHandle)
		{
		  case TPM_RH_ENDORSEMENT:
		    object->attributes.epsHierarchy = SET;
		    break;
		  case TPM_RH_OWNER:
		    object->attributes.spsHierarchy = SET;
		    break;
		  case TPM_RH_PLATFORM:
		    object->attributes.ppsHierarchy = SET;
		    break;
		  default:
		    // Treat the temporary attribute as a hierarchy
		    object->attributes.temporary = SET;
		    object->attributes.primary = CLEAR;
		    break;
		}
	}
    else
	{
	    // is this a stClear object
	    object->attributes.stClear =
		(IS_ATTRIBUTE(objectAttributes, TPMA_OBJECT, stClear)
		 || (parent->attributes.stClear == SET));
	    object->attributes.epsHierarchy = parent->attributes.epsHierarchy;
	    object->attributes.spsHierarchy = parent->attributes.spsHierarchy;
	    object->attributes.ppsHierarchy = parent->attributes.ppsHierarchy;
	    // An object is temporary if its parent is temporary or if the object
	    // is external
	    object->attributes.temporary = parent->attributes.temporary
					   || object->attributes.external;
	}
    // If this is an external object, set the QN == name but don't SET other
    // key properties ('parent' or 'derived')
    if(object->attributes.external)
	object->qualifiedName = object->name;
    else
	{
	    // check attributes for different types of parents
	    if(IS_ATTRIBUTE(objectAttributes, TPMA_OBJECT, restricted)
	       && !object->attributes.publicOnly
	       && IS_ATTRIBUTE(objectAttributes, TPMA_OBJECT, decrypt)
	       && object->publicArea.nameAlg != TPM_ALG_NULL)
		{
		    // This is a parent. If it is not a KEYEDHASH, it is an ordinary parent.
		    // Otherwise, it is a derivation parent.
		    if(object->publicArea.type == TPM_ALG_KEYEDHASH)
			object->attributes.derivation = SET;
		    else
			object->attributes.isParent = SET;
		}
	    ComputeQualifiedName(parentHandle, object->publicArea.nameAlg,
				 &object->name, &object->qualifiedName);
	}
    // Set slot occupied
    ObjectSetInUse(object);
    return;
}
/* 8.6.3.15 ObjectLoad() */
/* Common function to load an object. A loaded object has its public area validated (unless its
   nameAlg is TPM_ALG_NULL). If a sensitive part is loaded, it is verified to be correct and if both
   public and sensitive parts are loaded, then the cryptographic binding between the objects is
   validated. This function does not cause the allocated slot to be marked as in use. */
TPM_RC
ObjectLoad(
	   OBJECT          *object,        // IN: pointer to object slot
	   //     object
	   OBJECT          *parent,        // IN: (optional) the parent object
	   TPMT_PUBLIC     *publicArea,    // IN: public area to be installed in the object
	   TPMT_SENSITIVE  *sensitive,     // IN: (optional) sensitive area to be
	   //      installed in the object
	   TPM_RC           blamePublic,   // IN: parameter number to associate with the
	   //     publicArea errors
	   TPM_RC           blameSensitive,// IN: parameter number to associate with the
	   //     sensitive area errors
	   TPM2B_NAME      *name           // IN: (optional)
	   )
{
    TPM_RC           result = TPM_RC_SUCCESS;
    BOOL             doCheck;
    //
    // Do validations of public area object descriptions
    // Is this public only or a no-name object?
    if(sensitive == NULL || publicArea->nameAlg == TPM_ALG_NULL)
	{
	    // Need to have schemes checked so that we do the right thing with the
	    // public key.
	    result = SchemeChecks(NULL, publicArea);
	}
    else
	{
	    // For any sensitive area, make sure that the seedSize is no larger than the
	    // digest size of nameAlg
	    if(sensitive->seedValue.t.size
	       > CryptHashGetDigestSize(publicArea->nameAlg))
		return TPM_RCS_KEY_SIZE + blameSensitive;
	    // Check attributes and schemes for consistency
	    result = PublicAttributesValidation(parent, publicArea);
	}
    if(result != TPM_RC_SUCCESS)
	return RcSafeAddToResult(result, blamePublic);
    // If object == NULL, then this is am import. For import, load is not called
    // unless the parent is fixedTPM.
    if(object == NULL)
	doCheck = TRUE;// //
    // If the parent is not NULL, then this is an ordinary load and we only check
    // if the parent is not fixedTPM
    else if(parent != NULL)
	doCheck = !IS_ATTRIBUTE(parent->publicArea.objectAttributes,
				TPMA_OBJECT, fixedTPM);
    else
	// This is a loadExternal. Check everything.
	// Note: the check functions will filter things based on the name algorithm
	// and whether or not both parts are loaded.
	doCheck = TRUE;
    // Note: the parent will be NULL if this is a load external. CryptValidateKeys()
    // will only check the parts that need to be checked based on the settings
    // of publicOnly and nameAlg.
    // Note: For an RSA key, the keys sizes are checked but the binding is not
    // checked.
    if(doCheck)
	{
	    // Do the cryptographic key validation
	    result = CryptValidateKeys(publicArea, sensitive, blamePublic,
				       blameSensitive);
	}
    // If this is an import, we are done
    if(object == NULL || result != TPM_RC_SUCCESS)
	return result;
    // Set the name, if one was provided
    if(name != NULL)
	object->name = *name;
    else
	object->name.t.size = 0;
    // Initialize public
    object->publicArea = *publicArea;
    // If there is a sensitive area, load it
    if(sensitive == NULL)
	object->attributes.publicOnly = SET;
    else
	{
	    object->sensitive = *sensitive;
#if ALG_RSA
	    // If this is an RSA key that is not a parent, complete the load by
	    // computing the private exponent.
	    if(publicArea->type == ALG_RSA_VALUE)
		result = CryptRsaLoadPrivateExponent(object);
#endif
	}
    return result;
}
/* 8.6.3.16 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 HASH_OBJECT *
AllocateSequenceSlot(
		     TPM_HANDLE      *newHandle,     // OUT: receives the allocated handle
		     TPM2B_AUTH      *auth           // IN: the authValue for the slot
		     )
{
    HASH_OBJECT      *object = (HASH_OBJECT *)ObjectAllocateSlot(newHandle);
    //
    // Validate that the proper location of the hash state data relative to the
    // object state data. It would be good if this could have been done at compile
    // time but it can't so do it in something that can be removed after debug.
    cAssert(offsetof(HASH_OBJECT, auth) == offsetof(OBJECT, publicArea.authPolicy));
    if(object != NULL)
	{
	    // Set the common values that a sequence object shares with an ordinary object
	    // First, clear all attributes
	    MemorySet(&object->objectAttributes, 0, sizeof(TPMA_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;
	    // 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.
	    SET_ATTRIBUTE(object->objectAttributes, TPMA_OBJECT, noDA);
	    // Copy the authorization value
	    if(auth != NULL)
		object->auth = *auth;
	    else
		object->auth.t.size = 0;
	}
    return object;
}
/* 8.6.3.17 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 */
#if CC_HMAC_Start || CC_MAC_Start
TPM_RC
ObjectCreateHMACSequence(
			 TPMI_ALG_HASH    hashAlg,       // IN: hash algorithm
			 OBJECT          *keyObject,     // IN: the object containing the HMAC key
			 TPM2B_AUTH      *auth,          // IN: authValue
			 TPMI_DH_OBJECT  *newHandle      // OUT: HMAC sequence object handle
			 )
{
    HASH_OBJECT         *hmacObject;
    //
    // Try to allocate a slot for new object
    hmacObject = AllocateSequenceSlot(newHandle, auth);
    if(hmacObject == NULL)
	return TPM_RC_OBJECT_MEMORY;
    // Set HMAC sequence bit
    hmacObject->attributes.hmacSeq = SET;
#if !SMAC_IMPLEMENTED
    if(CryptHmacStart(&hmacObject->state.hmacState, hashAlg,
		      keyObject->sensitive.sensitive.bits.b.size,
		      keyObject->sensitive.sensitive.bits.b.buffer) == 0)
#else
	if(CryptMacStart(&hmacObject->state.hmacState,
			 &keyObject->publicArea.parameters,
			 hashAlg, &keyObject->sensitive.sensitive.any.b) == 0)
#endif // SMAC_IMPLEMENTED
	    return TPM_RC_FAILURE;
    return TPM_RC_SUCCESS;
}
#endif

/* 8.6.3.18 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 = AllocateSequenceSlot(newHandle, auth);
    // See if slot allocated
    if(hashObject == NULL)
	return TPM_RC_OBJECT_MEMORY;
    // Set hash sequence bit
    hashObject->attributes.hashSeq = SET;
    // Start hash for hash sequence
    CryptHashStart(&hashObject->state.hashState[0], hashAlg);
    return TPM_RC_SUCCESS;
}
/* 8.6.3.19 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 = AllocateSequenceSlot(newHandle, auth);
    UINT32               count;
    TPM_ALG_ID           hash;
    // See if slot allocated
    if(hashObject == NULL)
	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 = CryptHashGetAlgByIndex(count)) != TPM_ALG_NULL; count++)
	CryptHashStart(&hashObject->state.hashState[count], hash);
    return TPM_RC_SUCCESS;
}
/* 8.6.3.20 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 *)HandleToObject(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 cryptographic implementation has some context values that need to be
	    // cleaned up (hygiene).
	    //
	    for(count = 0; CryptHashGetAlgByIndex(count) != TPM_ALG_NULL; count++)
		{
		    CryptHashEnd(&hashObject->state.hashState[count], 0, buffer);
		}
	    // Flush sequence object
	    FlushObject(g_DRTMHandle);
	}
    g_DRTMHandle = TPM_RH_UNASSIGNED;
}
/* 8.6.3.21 ObjectContextLoad() */
/* This function loads an object from a saved object context. */
/* Return Values Meaning */
/* NULL if there is no free slot for an object */
/* NON_NULL points to the loaded object */
#if 0			// libtpms added
OBJECT *
ObjectContextLoad(
		  ANY_OBJECT_BUFFER   *object,        // IN: pointer to object structure in saved
		  //     context
		  TPMI_DH_OBJECT      *handle         // OUT: object handle
		  )
{
    OBJECT      *newObject = ObjectAllocateSlot(handle);
    // Try to allocate a slot for new object
    if(newObject != NULL)
	{
	    // Copy the first part of the object
	    MemoryCopy(newObject, object, offsetof(HASH_OBJECT, state));
	    // See if this is a sequence object
	    if(ObjectIsSequence(newObject))
		{
		    // If this is a sequence object, import the data
		    SequenceDataImport((HASH_OBJECT *)newObject,
				       (HASH_OBJECT_BUFFER *)object);
		}
	    else
		{
		    // Copy input object data to internal structure
		    MemoryCopy(newObject, object, sizeof(OBJECT));
		}
	}
    return newObject;
}
#endif 			// libtpms added begin

OBJECT *
ObjectContextLoadLibtpms(BYTE           *buffer,
                         INT32           size,
                         TPMI_DH_OBJECT *handle
                         )
{
    OBJECT      *newObject = ObjectAllocateSlot(handle);
    TPM_RC       rc;
    BYTE        *mybuf  = buffer;
    INT32        mysize = size;

    pAssert(handle);

    // Try to allocate a slot for new object
    if(newObject != NULL)
	{
	    rc = ANY_OBJECT_Unmarshal(newObject, &mybuf, &mysize, false);
	    if (rc) {
	         /* Attempt to load an old OBJECT that was copied out directly from
	          * an older version of OBJECT.
	          */
		rc = OLD_OBJECTToOBJECT(newObject, buffer, size);
		if (rc) {
		    FlushObject(*handle);
		    newObject = NULL;
		}
	    }
	}
    return newObject;
}			// libtpms added end

/* 8.6.3.22 FlushObject() */
/* This function frees an object slot. */
/* This function requires that the object is loaded. */
void
FlushObject(
	    TPMI_DH_OBJECT   handle         // IN: handle to be freed
	    )
{
    UINT32      index = handle - TRANSIENT_FIRST;
    pAssert(index < MAX_LOADED_OBJECTS);
    // Clear all the object attributes
    MemorySet((BYTE*)&(s_objects[index].attributes),
	      0, sizeof(OBJECT_ATTRIBUTES));
    return;
}
/* 8.6.3.23 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].attributes.occupied)          // If found an occupied slot
		{
		    switch(hierarchy)
			{
			  case TPM_RH_PLATFORM:
			    if(s_objects[i].attributes.ppsHierarchy == SET)
				s_objects[i].attributes.occupied = FALSE;
			    break;
			  case TPM_RH_OWNER:
			    if(s_objects[i].attributes.spsHierarchy == SET)
				s_objects[i].attributes.occupied = FALSE;
			    break;
			  case TPM_RH_ENDORSEMENT:
			    if(s_objects[i].attributes.epsHierarchy == SET)
				s_objects[i].attributes.occupied = FALSE;
			    break;
			  default:
			    FAIL(FATAL_ERROR_INTERNAL);
			    break;
			}
		}
	}
    return;
}
/* 8.6.3.24 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
		COMMAND_INDEX    commandIndex   // 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
    object = ObjectAllocateSlot(handle);
    if(object == NULL)
	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(ObjectGetHierarchy(object) == TPM_RH_ENDORSEMENT
       && gc.ehEnable == CLEAR
       && GetCommandCode(commandIndex) != TPM_CC_EvictControl)
	return TPM_RC_HANDLE;
    return result;
}
/* 8.6.3.25 ObjectComputeName() */
/* This does the name computation from a public area (can be marshaled or not). */
TPM2B_NAME *
ObjectComputeName(
		  UINT32           size,          // IN: the size of the area to digest
		  BYTE            *publicArea,    // IN: the public area to digest
		  TPM_ALG_ID       nameAlg,       // IN: the hash algorithm to use
		  TPM2B_NAME      *name           // OUT: Computed name
		  )
{
    // Hash the publicArea into the name buffer leaving room for the nameAlg
    name->t.size = CryptHashBlock(nameAlg, size, publicArea,
				  sizeof(name->t.name) - 2,
				  &name->t.name[2]);
    // set the nameAlg
    UINT16_TO_BYTE_ARRAY(nameAlg, name->t.name);
    name->t.size += 2;
    return name;
}
/* 8.6.3.26 PublicMarshalAndComputeName() */
/* This function computes the Name of an object from its public area. */
TPM2B_NAME *
PublicMarshalAndComputeName(
			    TPMT_PUBLIC     *publicArea,    // IN: public area of an object
			    TPM2B_NAME      *name           // OUT: name of the object
			    )
{
    // Will marshal a public area into a template. This is because the internal
    // format for a TPM2B_PUBLIC is a structure and not a simple BYTE buffer.
    TPM2B_TEMPLATE       marshaled;     // this is big enough to hold a
    //  marshaled TPMT_PUBLIC
    BYTE                *buffer = (BYTE *)&marshaled.t.buffer;
    // if the nameAlg is NULL then there is no name.
    if(publicArea->nameAlg == TPM_ALG_NULL)
	name->t.size = 0;
    else
	{
	    // Marshal the public area into its canonical form
	    marshaled.t.size = TPMT_PUBLIC_Marshal(publicArea, &buffer, NULL);
	    // and compute the name
	    ObjectComputeName(marshaled.t.size, marshaled.t.buffer,
			      publicArea->nameAlg, name);
	}
    return name;
}
/* 8.6.3.28 ComputeQualifiedName() */
/* This function computes the qualified name of an object. */
void
ComputeQualifiedName(
		     TPM_HANDLE       parentHandle,  // IN: parent's handle
		     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
    TPM2B_NAME      parentName;
    if(parentHandle == TPM_RH_UNASSIGNED)
	{
	    MemoryCopy2B(&qualifiedName->b, &name->b, sizeof(qualifiedName->t.name));
	    *qualifiedName = *name;
	}
    else
	{
	    GetQualifiedName(parentHandle, &parentName);
	    //      QN_A = hash_A (QN of parent || NAME_A)
	    // Start hash
	    qualifiedName->t.size = CryptHashStart(&hashState, nameAlg);
	    // Add parent's qualified name
	    CryptDigestUpdate2B(&hashState, &parentName.b);
	    // Add self name
	    CryptDigestUpdate2B(&hashState, &name->b);
	    // Complete hash leaving room for the name algorithm
	    CryptHashEnd(&hashState, qualifiedName->t.size,
			 &qualifiedName->t.name[2]);
	    UINT16_TO_BYTE_ARRAY(nameAlg, qualifiedName->t.name);
	    qualifiedName->t.size += 2;
	}
    return;
}
/* 8.6.3.29 ObjectIsStorage() */
/* This function determines if an object has the attributes associated with a parent. A parent is an
   asymmetric or symmetric block cipher key that has its restricted and decrypt attributes SET, and
   sign CLEAR. */
/* Return Values 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 = HandleToObject(handle);
    TPMT_PUBLIC      *publicArea = ((object != NULL) ? &object->publicArea : NULL);
    //
    return (publicArea != NULL
	    && IS_ATTRIBUTE(publicArea->objectAttributes, TPMA_OBJECT, restricted)
	    && IS_ATTRIBUTE(publicArea->objectAttributes, TPMA_OBJECT, decrypt)
	    && !IS_ATTRIBUTE(publicArea->objectAttributes, TPMA_OBJECT, sign)
	    && (object->publicArea.type == ALG_RSA_VALUE
		|| object->publicArea.type == ALG_ECC_VALUE));
}
/* 8.6.3.30 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 Values 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].attributes.occupied == TRUE)
		{
		    // A valid transient object can not be the copy of a persistent object
		    pAssert(s_objects[i].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;
}
/* 8.6.3.31 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].attributes.occupied == FALSE) num++;
	}
    return num;
}
/* 8.6.3.32 ObjectGetPublicAttributes() */
/* Returns the attributes associated with an object handles. */
TPMA_OBJECT
ObjectGetPublicAttributes(
			  TPM_HANDLE       handle
			  )
{
    return HandleToObject(handle)->publicArea.objectAttributes;
}
#if 0 /* libtpms added */
OBJECT_ATTRIBUTES
ObjectGetProperties(
		    TPM_HANDLE       handle
		    )
{
    return HandleToObject(handle)->attributes;
}
#endif /* libtpms added */