1 // 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 //
18 TPM_RC
TPM2_ContextSave(ContextSave_In * in,ContextSave_Out * out)19 TPM2_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 INT32 bufferSize;
35
36 // This command may cause the orderlyState to be cleared due to
37 // the update of state reset data. If this is the case, check if NV is
38 // available first
39 if(gp.orderlyState != SHUTDOWN_NONE)
40 {
41 // The command needs NV update. Check if NV is available.
42 // A TPM_RC_NV_UNAVAILABLE or TPM_RC_NV_RATE error may be returned at
43 // this point
44 result = NvIsAvailable();
45 if(result != TPM_RC_SUCCESS) return result;
46 }
47
48 // Internal Data Update
49
50 // Initialize output handle. At the end of command action, the output
51 // handle of an object will be replaced, while the output handle
52 // for a session will be the same as input
53 out->context.savedHandle = in->saveHandle;
54
55 // Get the size of fingerprint in context blob. The sequence value in
56 // TPMS_CONTEXT structure is used as the fingerprint
57 fingerprintSize = sizeof(out->context.sequence);
58
59 // Compute the integrity size at the beginning of context blob
60 integritySize = sizeof(integrity.t.size)
61 + CryptGetHashDigestSize(CONTEXT_INTEGRITY_HASH_ALG);
62
63 // Perform object or session specific context save
64 switch(HandleGetType(in->saveHandle))
65 {
66 case TPM_HT_TRANSIENT:
67 {
68 OBJECT *object = ObjectGet(in->saveHandle);
69 OBJECT *outObject =
70 (OBJECT *)(out->context.contextBlob.t.buffer
71 + integritySize + fingerprintSize);
72
73 // Set size of the context data. The contents of context blob is vendor
74 // defined. In this implementation, the size is size of integrity
75 // plus fingerprint plus the whole internal OBJECT structure
76 out->context.contextBlob.t.size = integritySize +
77 fingerprintSize + sizeof(OBJECT);
78 // Make sure things fit
79 pAssert(out->context.contextBlob.t.size
80 < sizeof(out->context.contextBlob.t.buffer));
81
82 // Copy the whole internal OBJECT structure to context blob, leave
83 // the size for fingerprint
84 *outObject = *object;
85
86 // Increment object context ID
87 gr.objectContextID++;
88 // If object context ID overflows, TPM should be put in failure mode
89 if(gr.objectContextID == 0)
90 FAIL(FATAL_ERROR_INTERNAL);
91
92 // Fill in other return values for an object.
93 out->context.sequence = gr.objectContextID;
94 // For regular object, savedHandle is 0x80000000. For sequence object,
95 // savedHandle is 0x80000001. For object with stClear, savedHandle
96 // is 0x80000002
97 if(ObjectIsSequence(object))
98 {
99 out->context.savedHandle = 0x80000001;
100 SequenceDataImportExport(object, outObject, EXPORT_STATE);
101 }
102 else if(object->attributes.stClear == SET)
103 {
104 out->context.savedHandle = 0x80000002;
105 }
106 else
107 {
108 out->context.savedHandle = 0x80000000;
109 }
110
111 // Get object hierarchy
112 out->context.hierarchy = ObjectDataGetHierarchy(object);
113
114 break;
115 }
116 case TPM_HT_HMAC_SESSION:
117 case TPM_HT_POLICY_SESSION:
118 {
119 SESSION *session = SessionGet(in->saveHandle);
120
121 // Set size of the context data. The contents of context blob is vendor
122 // defined. In this implementation, the size of context blob is the
123 // size of a internal session structure plus the size of
124 // fingerprint plus the size of integrity
125 out->context.contextBlob.t.size = integritySize +
126 fingerprintSize + sizeof(*session);
127
128 // Make sure things fit
129 pAssert(out->context.contextBlob.t.size
130 < sizeof(out->context.contextBlob.t.buffer));
131
132 // Copy the whole internal SESSION structure to context blob.
133 // Save space for fingerprint at the beginning of the buffer
134 // This is done before anything else so that the actual context
135 // can be reclaimed after this call
136 MemoryCopy(out->context.contextBlob.t.buffer
137 + integritySize + fingerprintSize,
138 session, sizeof(*session),
139 sizeof(out->context.contextBlob.t.buffer)
140 - integritySize - fingerprintSize);
141
142 // Fill in the other return parameters for a session
143 // Get a context ID and set the session tracking values appropriately
144 // TPM_RC_CONTEXT_GAP is a possible error.
145 // SessionContextSave() will flush the in-memory context
146 // so no additional errors may occur after this call.
147 result = SessionContextSave(out->context.savedHandle, &contextID);
148 if(result != TPM_RC_SUCCESS) return result;
149
150 // sequence number is the current session contextID
151 out->context.sequence = contextID;
152
153 // use TPM_RH_NULL as hierarchy for session context
154 out->context.hierarchy = TPM_RH_NULL;
155
156 break;
157 }
158 default:
159 // SaveContext may only take an object handle or a session handle.
160 // All the other handle type should be filtered out at unmarshal
161 pAssert(FALSE);
162 break;
163 }
164
165 // Save fingerprint at the beginning of encrypted area of context blob.
166 // Reserve the integrity space
167 MemoryCopy(out->context.contextBlob.t.buffer + integritySize,
168 &out->context.sequence, sizeof(out->context.sequence),
169 sizeof(out->context.contextBlob.t.buffer) - integritySize);
170
171 // Compute context encryption key
172 ComputeContextProtectionKey(&out->context, &symKey, &iv);
173
174 // Encrypt context blob
175 CryptSymmetricEncrypt(out->context.contextBlob.t.buffer + integritySize,
176 CONTEXT_ENCRYPT_ALG, CONTEXT_ENCRYPT_KEY_BITS,
177 TPM_ALG_CFB, symKey.t.buffer, &iv,
178 out->context.contextBlob.t.size - integritySize,
179 out->context.contextBlob.t.buffer + integritySize);
180
181 // Compute integrity hash for the object
182 // In this implementation, the same routine is used for both sessions
183 // and objects.
184 ComputeContextIntegrity(&out->context, &integrity);
185
186 // add integrity at the beginning of context blob
187 buffer = out->context.contextBlob.t.buffer;
188 bufferSize = sizeof(TPM2B_DIGEST);
189 TPM2B_DIGEST_Marshal(&integrity, &buffer, &bufferSize);
190
191 // orderly state should be cleared because of the update of state reset and
192 // state clear data
193 g_clearOrderly = TRUE;
194
195 return TPM_RC_SUCCESS;
196 }
197