Line | Count | Source (jump to first uncovered line) |
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 |
19 | | TPM2_ContextSave( |
20 | | ContextSave_In *in, // IN: input parameter list |
21 | | ContextSave_Out *out // OUT: output parameter list |
22 | | ) |
23 | 0 | { |
24 | 0 | TPM_RC result; |
25 | 0 | UINT16 fingerprintSize; // The size of fingerprint in context |
26 | | // blob. |
27 | 0 | UINT64 contextID = 0; // session context ID |
28 | 0 | TPM2B_SYM_KEY symKey; |
29 | 0 | TPM2B_IV iv; |
30 | |
|
31 | 0 | TPM2B_DIGEST integrity; |
32 | 0 | UINT16 integritySize; |
33 | 0 | BYTE *buffer; |
34 | 0 | 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 | 0 | if(gp.orderlyState != SHUTDOWN_NONE) |
40 | 0 | { |
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 | 0 | result = NvIsAvailable(); |
45 | 0 | if(result != TPM_RC_SUCCESS) return result; |
46 | 0 | } |
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 | 0 | 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 | 0 | fingerprintSize = sizeof(out->context.sequence); |
58 | | |
59 | | // Compute the integrity size at the beginning of context blob |
60 | 0 | integritySize = sizeof(integrity.t.size) |
61 | 0 | + CryptGetHashDigestSize(CONTEXT_INTEGRITY_HASH_ALG); |
62 | | |
63 | | // Perform object or session specific context save |
64 | 0 | switch(HandleGetType(in->saveHandle)) |
65 | 0 | { |
66 | 0 | case TPM_HT_TRANSIENT: |
67 | 0 | { |
68 | 0 | OBJECT *object = ObjectGet(in->saveHandle); |
69 | 0 | OBJECT *outObject = |
70 | 0 | (OBJECT *)(out->context.contextBlob.t.buffer |
71 | 0 | + 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 | 0 | out->context.contextBlob.t.size = integritySize + |
77 | 0 | fingerprintSize + sizeof(OBJECT); |
78 | | // Make sure things fit |
79 | 0 | pAssert(out->context.contextBlob.t.size |
80 | 0 | < sizeof(out->context.contextBlob.t.buffer)); |
81 | | |
82 | | // Copy the whole internal OBJECT structure to context blob, leave |
83 | | // the size for fingerprint |
84 | 0 | *outObject = *object; |
85 | | |
86 | | // Increment object context ID |
87 | 0 | gr.objectContextID++; |
88 | | // If object context ID overflows, TPM should be put in failure mode |
89 | 0 | if(gr.objectContextID == 0) |
90 | 0 | FAIL(FATAL_ERROR_INTERNAL); |
91 | | |
92 | | // Fill in other return values for an object. |
93 | 0 | 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 | 0 | if(ObjectIsSequence(object)) |
98 | 0 | { |
99 | 0 | out->context.savedHandle = 0x80000001; |
100 | 0 | SequenceDataImportExport(object, outObject, EXPORT_STATE); |
101 | 0 | } |
102 | 0 | else if(object->attributes.stClear == SET) |
103 | 0 | { |
104 | 0 | out->context.savedHandle = 0x80000002; |
105 | 0 | } |
106 | 0 | else |
107 | 0 | { |
108 | 0 | out->context.savedHandle = 0x80000000; |
109 | 0 | } |
110 | | |
111 | | // Get object hierarchy |
112 | 0 | out->context.hierarchy = ObjectDataGetHierarchy(object); |
113 | |
|
114 | 0 | break; |
115 | 0 | } |
116 | 0 | case TPM_HT_HMAC_SESSION: |
117 | 0 | case TPM_HT_POLICY_SESSION: |
118 | 0 | { |
119 | 0 | 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 | 0 | out->context.contextBlob.t.size = integritySize + |
126 | 0 | fingerprintSize + sizeof(*session); |
127 | | |
128 | | // Make sure things fit |
129 | 0 | pAssert(out->context.contextBlob.t.size |
130 | 0 | < 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 | 0 | MemoryCopy(out->context.contextBlob.t.buffer |
137 | 0 | + integritySize + fingerprintSize, |
138 | 0 | session, sizeof(*session), |
139 | 0 | sizeof(out->context.contextBlob.t.buffer) |
140 | 0 | - 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 | 0 | result = SessionContextSave(out->context.savedHandle, &contextID); |
148 | 0 | if(result != TPM_RC_SUCCESS) return result; |
149 | | |
150 | | // sequence number is the current session contextID |
151 | 0 | out->context.sequence = contextID; |
152 | | |
153 | | // use TPM_RH_NULL as hierarchy for session context |
154 | 0 | out->context.hierarchy = TPM_RH_NULL; |
155 | |
|
156 | 0 | break; |
157 | 0 | } |
158 | 0 | 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 | 0 | pAssert(FALSE); |
162 | 0 | break; |
163 | 0 | } |
164 | | |
165 | | // Save fingerprint at the beginning of encrypted area of context blob. |
166 | | // Reserve the integrity space |
167 | 0 | MemoryCopy(out->context.contextBlob.t.buffer + integritySize, |
168 | 0 | &out->context.sequence, sizeof(out->context.sequence), |
169 | 0 | sizeof(out->context.contextBlob.t.buffer) - integritySize); |
170 | | |
171 | | // Compute context encryption key |
172 | 0 | ComputeContextProtectionKey(&out->context, &symKey, &iv); |
173 | | |
174 | | // Encrypt context blob |
175 | 0 | CryptSymmetricEncrypt(out->context.contextBlob.t.buffer + integritySize, |
176 | 0 | CONTEXT_ENCRYPT_ALG, CONTEXT_ENCRYPT_KEY_BITS, |
177 | 0 | TPM_ALG_CFB, symKey.t.buffer, &iv, |
178 | 0 | out->context.contextBlob.t.size - integritySize, |
179 | 0 | 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 | 0 | ComputeContextIntegrity(&out->context, &integrity); |
185 | | |
186 | | // add integrity at the beginning of context blob |
187 | 0 | buffer = out->context.contextBlob.t.buffer; |
188 | 0 | bufferSize = sizeof(TPM2B_DIGEST); |
189 | 0 | 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 | 0 | g_clearOrderly = TRUE; |
194 | |
|
195 | 0 | return TPM_RC_SUCCESS; |
196 | 0 | } |