blob: d5831b982502ab67bc8ea322a6cd760dd186895a [file] [log] [blame]
Vadim Bendebury56797522015-05-20 10:32:25 -07001// This file was extracted from the TCG Published
2// Trusted Platform Module Library
3// Part 3: Commands
4// Family "2.0"
5// Level 00 Revision 01.16
6// October 30, 2014
7
8#include "InternalRoutines.h"
9#include "ContextSave_fp.h"
10#include "Context_spt_fp.h"
11//
12//
13// Error Returns Meaning
14//
15// TPM_RC_CONTEXT_GAP a contextID could not be assigned for a session context save
16// TPM_RC_TOO_MANY_CONTEXTS no more contexts can be saved as the counter has maxed out
17//
18TPM_RC
19TPM2_ContextSave(
20 ContextSave_In *in, // IN: input parameter list
21 ContextSave_Out *out // OUT: output parameter list
22 )
23{
24 TPM_RC result;
25 UINT16 fingerprintSize; // The size of fingerprint in context
26 // blob.
27 UINT64 contextID = 0; // session context ID
28 TPM2B_SYM_KEY symKey;
29 TPM2B_IV iv;
30
31 TPM2B_DIGEST integrity;
32 UINT16 integritySize;
33 BYTE *buffer;
34
35 // This command may cause the orderlyState to be cleared due to
36 // the update of state reset data. If this is the case, check if NV is
37 // available first
38 if(gp.orderlyState != SHUTDOWN_NONE)
39 {
40 // The command needs NV update. Check if NV is available.
41 // A TPM_RC_NV_UNAVAILABLE or TPM_RC_NV_RATE error may be returned at
42 // this point
43 result = NvIsAvailable();
44 if(result != TPM_RC_SUCCESS) return result;
45 }
46
47// Internal Data Update
48
49 // Initialize output handle. At the end of command action, the output
50 // handle of an object will be replaced, while the output handle
51 // for a session will be the same as input
52 out->context.savedHandle = in->saveHandle;
53
54 // Get the size of fingerprint in context blob. The sequence value in
55 // TPMS_CONTEXT structure is used as the fingerprint
56 fingerprintSize = sizeof(out->context.sequence);
57
58 // Compute the integrity size at the beginning of context blob
59 integritySize = sizeof(integrity.t.size)
60 + CryptGetHashDigestSize(CONTEXT_INTEGRITY_HASH_ALG);
61
62 // Perform object or session specific context save
63 switch(HandleGetType(in->saveHandle))
64 {
65 case TPM_HT_TRANSIENT:
66 {
67 OBJECT *object = ObjectGet(in->saveHandle);
68 OBJECT *outObject =
69 (OBJECT *)(out->context.contextBlob.t.buffer
70 + integritySize + fingerprintSize);
71
72 // Set size of the context data. The contents of context blob is vendor
73 // defined. In this implementation, the size is size of integrity
74 // plus fingerprint plus the whole internal OBJECT structure
75 out->context.contextBlob.t.size = integritySize +
76 fingerprintSize + sizeof(OBJECT);
77 // Make sure things fit
78 pAssert(out->context.contextBlob.t.size
79 < sizeof(out->context.contextBlob.t.buffer));
80
81 // Copy the whole internal OBJECT structure to context blob, leave
82 // the size for fingerprint
83 *outObject = *object;
84
85 // Increment object context ID
86 gr.objectContextID++;
87 // If object context ID overflows, TPM should be put in failure mode
88 if(gr.objectContextID == 0)
89 FAIL(FATAL_ERROR_INTERNAL);
90
91 // Fill in other return values for an object.
92 out->context.sequence = gr.objectContextID;
93 // For regular object, savedHandle is 0x80000000. For sequence object,
94 // savedHandle is 0x80000001. For object with stClear, savedHandle
95 // is 0x80000002
96 if(ObjectIsSequence(object))
97 {
98 out->context.savedHandle = 0x80000001;
99 SequenceDataImportExport(object, outObject, EXPORT_STATE);
100 }
101 else if(object->attributes.stClear == SET)
102 {
103 out->context.savedHandle = 0x80000002;
104 }
105 else
106 {
107 out->context.savedHandle = 0x80000000;
108 }
109
110 // Get object hierarchy
111 out->context.hierarchy = ObjectDataGetHierarchy(object);
112
113 break;
114 }
115 case TPM_HT_HMAC_SESSION:
116 case TPM_HT_POLICY_SESSION:
117 {
118 SESSION *session = SessionGet(in->saveHandle);
119
120 // Set size of the context data. The contents of context blob is vendor
121 // defined. In this implementation, the size of context blob is the
122 // size of a internal session structure plus the size of
123 // fingerprint plus the size of integrity
124 out->context.contextBlob.t.size = integritySize +
125 fingerprintSize + sizeof(*session);
126
127 // Make sure things fit
128 pAssert(out->context.contextBlob.t.size
129 < sizeof(out->context.contextBlob.t.buffer));
130
131 // Copy the whole internal SESSION structure to context blob.
132 // Save space for fingerprint at the beginning of the buffer
133 // This is done before anything else so that the actual context
134 // can be reclaimed after this call
135 MemoryCopy(out->context.contextBlob.t.buffer
136 + integritySize + fingerprintSize,
137 session, sizeof(*session),
138 sizeof(out->context.contextBlob.t.buffer)
139 - integritySize - fingerprintSize);
140
141 // Fill in the other return parameters for a session
142 // Get a context ID and set the session tracking values appropriately
143 // TPM_RC_CONTEXT_GAP is a possible error.
144 // SessionContextSave() will flush the in-memory context
145 // so no additional errors may occur after this call.
146 result = SessionContextSave(out->context.savedHandle, &contextID);
147 if(result != TPM_RC_SUCCESS) return result;
148
149 // sequence number is the current session contextID
150 out->context.sequence = contextID;
151
152 // use TPM_RH_NULL as hierarchy for session context
153 out->context.hierarchy = TPM_RH_NULL;
154
155 break;
156 }
157 default:
158 // SaveContext may only take an object handle or a session handle.
159 // All the other handle type should be filtered out at unmarshal
160 pAssert(FALSE);
161 break;
162 }
163
164 // Save fingerprint at the beginning of encrypted area of context blob.
165 // Reserve the integrity space
166 MemoryCopy(out->context.contextBlob.t.buffer + integritySize,
167 &out->context.sequence, sizeof(out->context.sequence),
168 sizeof(out->context.contextBlob.t.buffer) - integritySize);
169
170 // Compute context encryption key
171 ComputeContextProtectionKey(&out->context, &symKey, &iv);
172
173 // Encrypt context blob
174 CryptSymmetricEncrypt(out->context.contextBlob.t.buffer + integritySize,
175 CONTEXT_ENCRYPT_ALG, CONTEXT_ENCRYPT_KEY_BITS,
176 TPM_ALG_CFB, symKey.t.buffer, &iv,
177 out->context.contextBlob.t.size - integritySize,
178 out->context.contextBlob.t.buffer + integritySize);
179
180 // Compute integrity hash for the object
181 // In this implementation, the same routine is used for both sessions
182 // and objects.
183 ComputeContextIntegrity(&out->context, &integrity);
184
185 // add integrity at the beginning of context blob
186 buffer = out->context.contextBlob.t.buffer;
187 TPM2B_DIGEST_Marshal(&integrity, &buffer, NULL);
188
189 // orderly state should be cleared because of the update of state reset and
190 // state clear data
191 g_clearOrderly = TRUE;
192
193 return TPM_RC_SUCCESS;
194}