summaryrefslogtreecommitdiffstats
path: root/src/tpm2/ContextCommands.c
blob: c557c883cf24e7d2ca8b8d741aa5f1080fce0fdb (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
/********************************************************************************/
/*										*/
/*			   Context Management	  				*/
/*			     Written by Ken Goldman				*/
/*		       IBM Thomas J. Watson Research Center			*/
/*            $Id: ContextCommands.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				*/
/*										*/
/********************************************************************************/

#include "Tpm.h"
#include "ContextSave_fp.h"
#include "NVMarshal.h" // libtpms added
#if CC_ContextSave  // Conditional expansion of this file
#include "Context_spt_fp.h"
/* Error Returns Meaning */
/* TPM_RC_CONTEXT_GAP a contextID could not be assigned for a session context save */
/* TPM_RC_TOO_MANY_CONTEXTS no more contexts can be saved as the counter has maxed out */
TPM_RC
TPM2_ContextSave(
		 ContextSave_In      *in,            // IN: input parameter list
		 ContextSave_Out     *out            // OUT: output parameter list
		 )
{
    TPM_RC          result = TPM_RC_SUCCESS;
    UINT16          fingerprintSize;    // The size of fingerprint in context
    // blob.
    UINT64          contextID = 0;      // session context ID
    TPM2B_SYM_KEY   symKey;
    TPM2B_IV        iv;
    TPM2B_DIGEST    integrity;
    UINT16          integritySize;
    BYTE            *buffer;
    // This command may cause the orderlyState to be cleared due to
    // the update of state reset data. If the state is orderly and
    // cannot be changed, exit early.
    RETURN_IF_ORDERLY;
    
    // Internal Data Update
    
    // This implementation does not do things in quite the same way as described in
    // Part 2 of the specification. In Part 2, it indicates that the 
    // TPMS_CONTEXT_DATA contains two TPM2B values. That is not how this is 
    // implemented. Rather, the size field of the TPM2B_CONTEXT_DATA is used to 
    // determine the amount of data in the encrypted data. That part is not 
    // independently sized. This makes the actual size 2 bytes smaller than 
    // calculated using Part 2. Since this is opaque to the caller, it is not 
    // necessary to fix. The actual size is returned by TPM2_GetCapabilties().
    
    // Initialize output handle.  At the end of command action, the output
    // handle of an object will be replaced, while the output handle
    // for a session will be the same as input
    out->context.savedHandle = in->saveHandle;
    // Get the size of fingerprint in context blob.  The sequence value in
    // TPMS_CONTEXT structure is used as the fingerprint
    fingerprintSize = sizeof(out->context.sequence);
    // Compute the integrity size at the beginning of context blob
    integritySize = sizeof(integrity.t.size)
		    + CryptHashGetDigestSize(CONTEXT_INTEGRITY_HASH_ALG);
    // Perform object or session specific context save
    switch(HandleGetType(in->saveHandle))
	{
	  case TPM_HT_TRANSIENT:
	      {
		  OBJECT              *object = HandleToObject(in->saveHandle);
		  ANY_OBJECT_BUFFER   *outObject;
		  unsigned char        buffer[sizeof(OBJECT) * 2];		// libtpms changed begin
		  BYTE                *bufptr = &buffer[0];
		  INT32                size = sizeof(buffer);
		  UINT16               written = ANY_OBJECT_Marshal(object, &bufptr, &size);
		  UINT16               objectSize = written;			// libtpms changed end
		  outObject = (ANY_OBJECT_BUFFER *)(out->context.contextBlob.t.buffer
						    + integritySize + fingerprintSize);
		  // Set size of the context data.  The contents of context blob is vendor
		  // defined.  In this implementation, the size is size of integrity
		  // plus fingerprint plus the whole internal OBJECT structure
		  out->context.contextBlob.t.size = integritySize +
						    fingerprintSize + objectSize;
		  // Make sure things fit
		  pAssert(out->context.contextBlob.t.size
			  <= sizeof(out->context.contextBlob.t.buffer));
		  // Copy the whole internal OBJECT structure to context blob
		  MemoryCopy(outObject, buffer, written);			// libtpms changed
		  // Increment object context ID
		  gr.objectContextID++;
		  // If object context ID overflows, TPM should be put in failure mode
		  if(gr.objectContextID == 0)
		      FAIL(FATAL_ERROR_INTERNAL);
		  // Fill in other return values for an object.
		  out->context.sequence = gr.objectContextID;
		  // For regular object, savedHandle is 0x80000000.  For sequence object,
		  // savedHandle is 0x80000001.  For object with stClear, savedHandle
		  // is 0x80000002
		  if(ObjectIsSequence(object))
		      {
			  out->context.savedHandle = 0x80000001;
			/* ANY_OBJECT_Marshal already wrote it			// libtpms changed begin
			  SequenceDataExport((HASH_OBJECT *)object,
					     (HASH_OBJECT_BUFFER *)outObject);
			 */							// libtpms changed end
		      }
		  else
		      out->context.savedHandle = (object->attributes.stClear == SET)
						 ? 0x80000002 : 0x80000000;
		  // Get object hierarchy
		  out->context.hierarchy = ObjectGetHierarchy(object);
		  break;
	      }
	  case TPM_HT_HMAC_SESSION:
	  case TPM_HT_POLICY_SESSION:
	      {
		  SESSION         *session = SessionGet(in->saveHandle);
		  // Set size of the context data.  The contents of context blob is vendor
		  // defined.  In this implementation, the size of context blob is the
		  // size of a internal session structure plus the size of
		  // fingerprint plus the size of integrity
		  out->context.contextBlob.t.size = integritySize +
						    fingerprintSize + sizeof(*session);
		  // Make sure things fit
		  pAssert(out->context.contextBlob.t.size
			  < sizeof(out->context.contextBlob.t.buffer));
		  // Copy the whole internal SESSION structure to context blob.
		  // Save space for fingerprint at the beginning of the buffer
		  // This is done before anything else so that the actual context
		  // can be reclaimed after this call
		  pAssert(sizeof(*session) <= sizeof(out->context.contextBlob.t.buffer)
			  - integritySize - fingerprintSize);
		  MemoryCopy(out->context.contextBlob.t.buffer + integritySize
			     + fingerprintSize, session, sizeof(*session));
		  // Fill in the other return parameters for a session
		  // Get a context ID and set the session tracking values appropriately
		  // TPM_RC_CONTEXT_GAP is a possible error.
		  // SessionContextSave() will flush the in-memory context
		  // so no additional errors may occur after this call.
		  result = SessionContextSave(out->context.savedHandle, &contextID);
		  if(result != TPM_RC_SUCCESS)
		      return result;
		  // sequence number is the current session contextID
		  out->context.sequence = contextID;
		  // use TPM_RH_NULL as hierarchy for session context
		  out->context.hierarchy = TPM_RH_NULL;
		  break;
	      }
	  default:
	    // SaveContext may only take an object handle or a session handle.
	    // All the other handle type should be filtered out at unmarshal
	    FAIL(FATAL_ERROR_INTERNAL);
	    break;
	}
    // Save fingerprint at the beginning of encrypted area of context blob.
    // Reserve the integrity space
    pAssert(sizeof(out->context.sequence) <=
	    sizeof(out->context.contextBlob.t.buffer) - integritySize);
    MemoryCopy(out->context.contextBlob.t.buffer + integritySize,
	       &out->context.sequence, sizeof(out->context.sequence));
    // Compute context encryption key
    ComputeContextProtectionKey(&out->context, &symKey, &iv);
    // Encrypt context blob
    CryptSymmetricEncrypt(out->context.contextBlob.t.buffer + integritySize,
			  CONTEXT_ENCRYPT_ALG, CONTEXT_ENCRYPT_KEY_BITS,
			  symKey.t.buffer, &iv, TPM_ALG_CFB,
			  out->context.contextBlob.t.size - integritySize,
			  out->context.contextBlob.t.buffer + integritySize);
    // Compute integrity hash for the object
    // In this implementation, the same routine is used for both sessions
    // and objects.
    ComputeContextIntegrity(&out->context, &integrity);
    // add integrity at the beginning of context blob
    buffer = out->context.contextBlob.t.buffer;
    TPM2B_DIGEST_Marshal(&integrity, &buffer, NULL);
    // orderly state should be cleared because of the update of state reset and
    // state clear data
    g_clearOrderly = TRUE;
    return result;
}
#endif // CC_ContextSave
#include "Tpm.h"
#include "ContextLoad_fp.h"
#if CC_ContextLoad  // Conditional expansion of this file
#include "Context_spt_fp.h"
TPM_RC
TPM2_ContextLoad(
		 ContextLoad_In      *in,            // IN: input parameter list
		 ContextLoad_Out     *out            // OUT: output parameter list
		 )
{
    TPM_RC              result;
    TPM2B_DIGEST        integrityToCompare;
    TPM2B_DIGEST        integrity;
    BYTE                *buffer;    // defined to save some typing
    INT32               size;       // defined to save some typing
    TPM_HT              handleType;
    TPM2B_SYM_KEY       symKey;
    TPM2B_IV            iv;
    // Input Validation

    // See discussion about the context format in TPM2_ContextSave Detailed Actions

    // IF this is a session context, make sure that the sequence number is
    // consistent with the version in the slot
    // Check context blob size
    handleType = HandleGetType(in->context.savedHandle);
    // Get integrity from context blob
    buffer = in->context.contextBlob.t.buffer;
    size = (INT32)in->context.contextBlob.t.size;
    result = TPM2B_DIGEST_Unmarshal(&integrity, &buffer, &size);
    if(result != TPM_RC_SUCCESS)
	return result;
    // the size of the integrity value has to match the size of digest produced
    // by the integrity hash
    if(integrity.t.size != CryptHashGetDigestSize(CONTEXT_INTEGRITY_HASH_ALG))
	return TPM_RCS_SIZE + RC_ContextLoad_context;
    // Make sure that the context blob has enough space for the fingerprint. This
    // is elastic pants to go with the belt and suspenders we already have to make
    // sure that the context is complete and untampered.
    if((unsigned)size < sizeof(in->context.sequence))
	return TPM_RCS_SIZE + RC_ContextLoad_context;
    // After unmarshaling the integrity value, 'buffer' is pointing at the first
    // byte of the integrity protected and encrypted buffer and 'size' is the number
    // of integrity protected and encrypted bytes.
    // Compute context integrity
    ComputeContextIntegrity(&in->context, &integrityToCompare);
    // Compare integrity
    if(!MemoryEqual2B(&integrity.b, &integrityToCompare.b))
	return TPM_RCS_INTEGRITY + RC_ContextLoad_context;
    // Compute context encryption key
    ComputeContextProtectionKey(&in->context, &symKey, &iv);
    // Decrypt context data in place
    CryptSymmetricDecrypt(buffer, CONTEXT_ENCRYPT_ALG, CONTEXT_ENCRYPT_KEY_BITS,
			  symKey.t.buffer, &iv, TPM_ALG_CFB, size, buffer);
    // See if the fingerprint value matches. If not, it is symptomatic of either
    // a broken TPM or that the TPM is under attack so go into failure mode.
    if(!MemoryEqual(buffer, &in->context.sequence, sizeof(in->context.sequence)))
	FAIL(FATAL_ERROR_INTERNAL);
    // step over fingerprint
    buffer += sizeof(in->context.sequence);
    // set the remaining size of the context
    size -= sizeof(in->context.sequence);
    // Perform object or session specific input check
    switch(handleType)
	{
	  case TPM_HT_TRANSIENT:
	      {
		  OBJECT      *outObject;
		  if(size > (INT32)sizeof(OBJECT))
		      FAIL(FATAL_ERROR_INTERNAL);
		  // Discard any changes to the handle that the TRM might have made
		  in->context.savedHandle = TRANSIENT_FIRST;
		  // If hierarchy is disabled, no object context can be loaded in this
		  // hierarchy
		  if(!HierarchyIsEnabled(in->context.hierarchy))
		      return TPM_RCS_HIERARCHY + RC_ContextLoad_context;
		  // Restore object. If there is no empty space, indicate as much
		  outObject = ObjectContextLoadLibtpms(buffer, size,       // libtpms changed
						       &out->loadedHandle);
		  if(outObject == NULL)
		      return TPM_RC_OBJECT_MEMORY;
		  break;
	      }
	  case TPM_HT_POLICY_SESSION:
	  case TPM_HT_HMAC_SESSION:
	      {
		  if(size != sizeof(SESSION))
		      FAIL(FATAL_ERROR_INTERNAL);
		  // This command may cause the orderlyState to be cleared due to
		  // the update of state reset data.  If this is the case, check if NV is
		  // available first
		  RETURN_IF_ORDERLY;
		  // Check if input handle points to a valid saved session and that the
		  // sequence number makes sense
		  if(!SequenceNumberForSavedContextIsValid(&in->context))
		      return TPM_RCS_HANDLE + RC_ContextLoad_context;
		  // Restore session.  A TPM_RC_SESSION_MEMORY, TPM_RC_CONTEXT_GAP error
		  // may be returned at this point
		  result = SessionContextLoad((SESSION_BUF *)buffer,
					      &in->context.savedHandle);
		  if(result != TPM_RC_SUCCESS)
		      return result;
		  out->loadedHandle = in->context.savedHandle;
		  // orderly state should be cleared because of the update of state
		  // reset and state clear data
		  g_clearOrderly = TRUE;
		  break;
	      }
	  default:
	    // Context blob may only have an object handle or a session handle.
	    // All the other handle type should be filtered out at unmarshal
	    FAIL(FATAL_ERROR_INTERNAL);
	    break;
	}
    return TPM_RC_SUCCESS;
}
#endif // CC_ContextLoad
#include "Tpm.h"
#include "FlushContext_fp.h"
#if CC_FlushContext  // Conditional expansion of this file
TPM_RC
TPM2_FlushContext(
		  FlushContext_In     *in             // IN: input parameter list
		  )
{
    // Internal Data Update
    // Call object or session specific routine to flush
    switch(HandleGetType(in->flushHandle))
	{
	  case TPM_HT_TRANSIENT:
	    if(!IsObjectPresent(in->flushHandle))
		return TPM_RCS_HANDLE + RC_FlushContext_flushHandle;
	    // Flush object
	    FlushObject(in->flushHandle);
	    break;
	  case TPM_HT_HMAC_SESSION:
	  case TPM_HT_POLICY_SESSION:
	    if(!SessionIsLoaded(in->flushHandle)
	       && !SessionIsSaved(in->flushHandle)
	       )
		return TPM_RCS_HANDLE + RC_FlushContext_flushHandle;
	    // If the session to be flushed is the exclusive audit session, then
	    // indicate that there is no exclusive audit session any longer.
	    if(in->flushHandle == g_exclusiveAuditSession)
		g_exclusiveAuditSession = TPM_RH_UNASSIGNED;
	    // Flush session
	    SessionFlush(in->flushHandle);
	    break;
	  default:
	    // This command only takes object or session handle.  Other handles
	    // should be filtered out at handle unmarshal
	    FAIL(FATAL_ERROR_INTERNAL);
	    break;
	}
    return TPM_RC_SUCCESS;
}
#endif // CC_FlushContext
#include "Tpm.h"
#include "EvictControl_fp.h"
#if CC_EvictControl  // Conditional expansion of this file
TPM_RC
TPM2_EvictControl(
		  EvictControl_In     *in             // IN: input parameter list
		  )
{
    TPM_RC      result;
    OBJECT      *evictObject;
    // Input Validation
    // Get internal object pointer
    evictObject = HandleToObject(in->objectHandle);
    // Temporary, stClear or public only objects can not be made persistent
    if(evictObject->attributes.temporary == SET
       || evictObject->attributes.stClear == SET
       || evictObject->attributes.publicOnly == SET)
	return TPM_RCS_ATTRIBUTES + RC_EvictControl_objectHandle;
    // If objectHandle refers to a persistent object, it should be the same as
    // input persistentHandle
    if(evictObject->attributes.evict == SET
       && evictObject->evictHandle != in->persistentHandle)
	return TPM_RCS_HANDLE + RC_EvictControl_objectHandle;
    // Additional authorization validation
    if(in->auth == TPM_RH_PLATFORM)
	{
	    // To make persistent
	    if(evictObject->attributes.evict == CLEAR)
	        {
	            // PlatformAuth can not set evict object in storage or endorsement
	            // hierarchy
	            if(evictObject->attributes.ppsHierarchy == CLEAR)
	                return TPM_RCS_HIERARCHY + RC_EvictControl_objectHandle;
	            // Platform cannot use a handle outside of platform persistent range.
	            if(!NvIsPlatformPersistentHandle(in->persistentHandle))
	                return TPM_RCS_RANGE + RC_EvictControl_persistentHandle;
	        }
	    // PlatformAuth can delete any persistent object
	}
    else if(in->auth == TPM_RH_OWNER)
	{
	    // OwnerAuth can not set or clear evict object in platform hierarchy
	    if(evictObject->attributes.ppsHierarchy == SET)
		return TPM_RCS_HIERARCHY + RC_EvictControl_objectHandle;
	    // Owner cannot use a handle outside of owner persistent range.
	    if(evictObject->attributes.evict == CLEAR
	       && !NvIsOwnerPersistentHandle(in->persistentHandle))
		return TPM_RCS_RANGE + RC_EvictControl_persistentHandle;
	}
    else
	{
	    // Other authorization is not allowed in this command and should have been
	    // filtered out in unmarshal process
	    FAIL(FATAL_ERROR_INTERNAL);
	}
    // Internal Data Update
    // Change evict state
    if(evictObject->attributes.evict == CLEAR)
	{
	    // Make object persistent
	    if(NvFindHandle(in->persistentHandle) != 0)
		return TPM_RC_NV_DEFINED;
	    // A TPM_RC_NV_HANDLE or TPM_RC_NV_SPACE error may be returned at this
	    // point
	    result = NvAddEvictObject(in->persistentHandle, evictObject);
	}
    else
	{
	    // Delete the persistent object in NV
	    result = NvDeleteEvict(evictObject->evictHandle);
	}
    return result;
}
#endif // CC_EvictControl