/src/ibmswtpm2/src/IntegrityCommands.c
Line | Count | Source (jump to first uncovered line) |
1 | | /********************************************************************************/ |
2 | | /* */ |
3 | | /* Integrity Collection (PCR) */ |
4 | | /* Written by Ken Goldman */ |
5 | | /* IBM Thomas J. Watson Research Center */ |
6 | | /* $Id: IntegrityCommands.c 1272 2018-07-20 17:46:57Z kgoldman $ */ |
7 | | /* */ |
8 | | /* Licenses and Notices */ |
9 | | /* */ |
10 | | /* 1. Copyright Licenses: */ |
11 | | /* */ |
12 | | /* - Trusted Computing Group (TCG) grants to the user of the source code in */ |
13 | | /* this specification (the "Source Code") a worldwide, irrevocable, */ |
14 | | /* nonexclusive, royalty free, copyright license to reproduce, create */ |
15 | | /* derivative works, distribute, display and perform the Source Code and */ |
16 | | /* derivative works thereof, and to grant others the rights granted herein. */ |
17 | | /* */ |
18 | | /* - The TCG grants to the user of the other parts of the specification */ |
19 | | /* (other than the Source Code) the rights to reproduce, distribute, */ |
20 | | /* display, and perform the specification solely for the purpose of */ |
21 | | /* developing products based on such documents. */ |
22 | | /* */ |
23 | | /* 2. Source Code Distribution Conditions: */ |
24 | | /* */ |
25 | | /* - Redistributions of Source Code must retain the above copyright licenses, */ |
26 | | /* this list of conditions and the following disclaimers. */ |
27 | | /* */ |
28 | | /* - Redistributions in binary form must reproduce the above copyright */ |
29 | | /* licenses, this list of conditions and the following disclaimers in the */ |
30 | | /* documentation and/or other materials provided with the distribution. */ |
31 | | /* */ |
32 | | /* 3. Disclaimers: */ |
33 | | /* */ |
34 | | /* - THE COPYRIGHT LICENSES SET FORTH ABOVE DO NOT REPRESENT ANY FORM OF */ |
35 | | /* LICENSE OR WAIVER, EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE, WITH */ |
36 | | /* RESPECT TO PATENT RIGHTS HELD BY TCG MEMBERS (OR OTHER THIRD PARTIES) */ |
37 | | /* THAT MAY BE NECESSARY TO IMPLEMENT THIS SPECIFICATION OR OTHERWISE. */ |
38 | | /* Contact TCG Administration (admin@trustedcomputinggroup.org) for */ |
39 | | /* information on specification licensing rights available through TCG */ |
40 | | /* membership agreements. */ |
41 | | /* */ |
42 | | /* - THIS SPECIFICATION IS PROVIDED "AS IS" WITH NO EXPRESS OR IMPLIED */ |
43 | | /* WARRANTIES WHATSOEVER, INCLUDING ANY WARRANTY OF MERCHANTABILITY OR */ |
44 | | /* FITNESS FOR A PARTICULAR PURPOSE, ACCURACY, COMPLETENESS, OR */ |
45 | | /* NONINFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS, OR ANY WARRANTY */ |
46 | | /* OTHERWISE ARISING OUT OF ANY PROPOSAL, SPECIFICATION OR SAMPLE. */ |
47 | | /* */ |
48 | | /* - Without limitation, TCG and its members and licensors disclaim all */ |
49 | | /* liability, including liability for infringement of any proprietary */ |
50 | | /* rights, relating to use of information in this specification and to the */ |
51 | | /* implementation of this specification, and TCG disclaims all liability for */ |
52 | | /* cost of procurement of substitute goods or services, lost profits, loss */ |
53 | | /* of use, loss of data or any incidental, consequential, direct, indirect, */ |
54 | | /* or special damages, whether under contract, tort, warranty or otherwise, */ |
55 | | /* arising in any way out of use or reliance upon this specification or any */ |
56 | | /* information herein. */ |
57 | | /* */ |
58 | | /* (c) Copyright IBM Corp. and others, 2016 - 2018 */ |
59 | | /* */ |
60 | | /********************************************************************************/ |
61 | | |
62 | | #include "Tpm.h" |
63 | | #include "PCR_Extend_fp.h" |
64 | | #if CC_PCR_Extend // Conditional expansion of this file |
65 | | TPM_RC |
66 | | TPM2_PCR_Extend( |
67 | | PCR_Extend_In *in // IN: input parameter list |
68 | | ) |
69 | 0 | { |
70 | 0 | UINT32 i; |
71 | | // Input Validation |
72 | | // NOTE: This function assumes that the unmarshaling function for 'digests' will |
73 | | // have validated that all of the indicated hash algorithms are valid. If the |
74 | | // hash algorithms are correct, the unmarshaling code will unmarshal a digest |
75 | | // of the size indicated by the hash algorithm. If the overall size is not |
76 | | // consistent, the unmarshaling code will run out of input data or have input |
77 | | // data left over. In either case, it will cause an unmarshaling error and this |
78 | | // function will not be called. |
79 | | // For NULL handle, do nothing and return success |
80 | 0 | if(in->pcrHandle == TPM_RH_NULL) |
81 | 0 | return TPM_RC_SUCCESS; |
82 | | // Check if the extend operation is allowed by the current command locality |
83 | 0 | if(!PCRIsExtendAllowed(in->pcrHandle)) |
84 | 0 | return TPM_RC_LOCALITY; |
85 | | // If PCR is state saved and we need to update orderlyState, check NV |
86 | | // availability |
87 | 0 | if(PCRIsStateSaved(in->pcrHandle)) |
88 | 0 | RETURN_IF_ORDERLY; |
89 | | // Internal Data Update |
90 | | // Iterate input digest list to extend |
91 | 0 | for(i = 0; i < in->digests.count; i++) |
92 | 0 | { |
93 | 0 | PCRExtend(in->pcrHandle, in->digests.digests[i].hashAlg, |
94 | 0 | CryptHashGetDigestSize(in->digests.digests[i].hashAlg), |
95 | 0 | (BYTE *)&in->digests.digests[i].digest); |
96 | 0 | } |
97 | 0 | return TPM_RC_SUCCESS; |
98 | 0 | } |
99 | | #endif // CC_PCR_Extend |
100 | | #include "Tpm.h" |
101 | | #include "PCR_Event_fp.h" |
102 | | #if CC_PCR_Event // Conditional expansion of this file |
103 | | TPM_RC |
104 | | TPM2_PCR_Event( |
105 | | PCR_Event_In *in, // IN: input parameter list |
106 | | PCR_Event_Out *out // OUT: output parameter list |
107 | | ) |
108 | 0 | { |
109 | 0 | HASH_STATE hashState; |
110 | 0 | UINT32 i; |
111 | 0 | UINT16 size; |
112 | | // Input Validation |
113 | | // If a PCR extend is required |
114 | 0 | if(in->pcrHandle != TPM_RH_NULL) |
115 | 0 | { |
116 | | // If the PCR is not allow to extend, return error |
117 | 0 | if(!PCRIsExtendAllowed(in->pcrHandle)) |
118 | 0 | return TPM_RC_LOCALITY; |
119 | | // If PCR is state saved and we need to update orderlyState, check NV |
120 | | // availability |
121 | 0 | if(PCRIsStateSaved(in->pcrHandle)) |
122 | 0 | RETURN_IF_ORDERLY; |
123 | 0 | } |
124 | | // Internal Data Update |
125 | 0 | out->digests.count = HASH_COUNT; |
126 | | // Iterate supported PCR bank algorithms to extend |
127 | 0 | for(i = 0; i < HASH_COUNT; i++) |
128 | 0 | { |
129 | 0 | TPM_ALG_ID hash = CryptHashGetAlgByIndex(i); |
130 | 0 | out->digests.digests[i].hashAlg = hash; |
131 | 0 | size = CryptHashStart(&hashState, hash); |
132 | 0 | CryptDigestUpdate2B(&hashState, &in->eventData.b); |
133 | 0 | CryptHashEnd(&hashState, size, |
134 | 0 | (BYTE *)&out->digests.digests[i].digest); |
135 | 0 | if(in->pcrHandle != TPM_RH_NULL) |
136 | 0 | PCRExtend(in->pcrHandle, hash, size, |
137 | 0 | (BYTE *)&out->digests.digests[i].digest); |
138 | 0 | } |
139 | 0 | return TPM_RC_SUCCESS; |
140 | 0 | } |
141 | | #endif // CC_PCR_Event |
142 | | #include "Tpm.h" |
143 | | #include "PCR_Read_fp.h" |
144 | | #if CC_PCR_Read // Conditional expansion of this file |
145 | | TPM_RC |
146 | | TPM2_PCR_Read( |
147 | | PCR_Read_In *in, // IN: input parameter list |
148 | | PCR_Read_Out *out // OUT: output parameter list |
149 | | ) |
150 | 0 | { |
151 | | // Command Output |
152 | | // Call PCR read function. input pcrSelectionIn parameter could be changed |
153 | | // to reflect the actual PCR being returned |
154 | 0 | PCRRead(&in->pcrSelectionIn, &out->pcrValues, &out->pcrUpdateCounter); |
155 | 0 | out->pcrSelectionOut = in->pcrSelectionIn; |
156 | 0 | return TPM_RC_SUCCESS; |
157 | 0 | } |
158 | | #endif // CC_PCR_Read |
159 | | #include "Tpm.h" |
160 | | #include "PCR_Allocate_fp.h" |
161 | | #if CC_PCR_Allocate // Conditional expansion of this file |
162 | | TPM_RC |
163 | | TPM2_PCR_Allocate( |
164 | | PCR_Allocate_In *in, // IN: input parameter list |
165 | | PCR_Allocate_Out *out // OUT: output parameter list |
166 | | ) |
167 | 0 | { |
168 | 0 | TPM_RC result; |
169 | | // The command needs NV update. Check if NV is available. |
170 | | // A TPM_RC_NV_UNAVAILABLE or TPM_RC_NV_RATE error may be returned at |
171 | | // this point. |
172 | | // Note: These codes are not listed in the return values above because it is |
173 | | // an implementation choice to check in this routine rather than in a common |
174 | | // function that is called before these actions are called. These return values |
175 | | // are described in the Response Code section of Part 3. |
176 | 0 | RETURN_IF_NV_IS_NOT_AVAILABLE; |
177 | | // Command Output |
178 | | // Call PCR Allocation function. |
179 | 0 | result = PCRAllocate(&in->pcrAllocation, &out->maxPCR, |
180 | 0 | &out->sizeNeeded, &out->sizeAvailable); |
181 | 0 | if(result == TPM_RC_PCR) |
182 | 0 | return result; |
183 | | // |
184 | 0 | out->allocationSuccess = (result == TPM_RC_SUCCESS); |
185 | | // if re-configuration succeeds, set the flag to indicate PCR configuration is |
186 | | // going to be changed in next boot |
187 | 0 | if(out->allocationSuccess == YES) |
188 | 0 | g_pcrReConfig = TRUE; |
189 | 0 | return TPM_RC_SUCCESS; |
190 | 0 | } |
191 | | #endif // CC_PCR_Allocate |
192 | | #include "Tpm.h" |
193 | | #include "PCR_SetAuthPolicy_fp.h" |
194 | | #if CC_PCR_SetAuthPolicy // Conditional expansion of this file |
195 | | TPM_RC |
196 | | TPM2_PCR_SetAuthPolicy( |
197 | | PCR_SetAuthPolicy_In *in // IN: input parameter list |
198 | | ) |
199 | 0 | { |
200 | 0 | UINT32 groupIndex; |
201 | | // The command needs NV update. Check if NV is available. |
202 | | // A TPM_RC_NV_UNAVAILABLE or TPM_RC_NV_RATE error may be returned at |
203 | | // this point |
204 | 0 | RETURN_IF_NV_IS_NOT_AVAILABLE; |
205 | | // Input Validation: |
206 | | // Check the authPolicy consistent with hash algorithm |
207 | 0 | if(in->authPolicy.t.size != CryptHashGetDigestSize(in->hashAlg)) |
208 | 0 | return TPM_RCS_SIZE + RC_PCR_SetAuthPolicy_authPolicy; |
209 | | // If PCR does not belong to a policy group, return TPM_RC_VALUE |
210 | 0 | if(!PCRBelongsPolicyGroup(in->pcrNum, &groupIndex)) |
211 | 0 | return TPM_RCS_VALUE + RC_PCR_SetAuthPolicy_pcrNum; |
212 | | // Internal Data Update |
213 | | // Set PCR policy |
214 | 0 | gp.pcrPolicies.hashAlg[groupIndex] = in->hashAlg; |
215 | 0 | gp.pcrPolicies.policy[groupIndex] = in->authPolicy; |
216 | | // Save new policy to NV |
217 | 0 | NV_SYNC_PERSISTENT(pcrPolicies); |
218 | 0 | return TPM_RC_SUCCESS; |
219 | 0 | } |
220 | | #endif // CC_PCR_SetAuthPolicy |
221 | | #include "Tpm.h" |
222 | | #include "PCR_SetAuthValue_fp.h" |
223 | | #if CC_PCR_SetAuthValue // Conditional expansion of this file |
224 | | // CC_PCR_SetAuthPolicy |
225 | | TPM_RC |
226 | | TPM2_PCR_SetAuthValue( |
227 | | PCR_SetAuthValue_In *in // IN: input parameter list |
228 | | ) |
229 | 0 | { |
230 | 0 | UINT32 groupIndex; |
231 | | // Input Validation: |
232 | | // If PCR does not belong to an auth group, return TPM_RC_VALUE |
233 | 0 | if(!PCRBelongsAuthGroup(in->pcrHandle, &groupIndex)) |
234 | 0 | return TPM_RC_VALUE; |
235 | | // The command may cause the orderlyState to be cleared due to the update of |
236 | | // state clear data. If this is the case, Check if NV is available. |
237 | | // A TPM_RC_NV_UNAVAILABLE or TPM_RC_NV_RATE error may be returned at |
238 | | // this point |
239 | 0 | RETURN_IF_ORDERLY; |
240 | | // Internal Data Update |
241 | | // Set PCR authValue |
242 | 0 | MemoryRemoveTrailingZeros(&in->auth); |
243 | 0 | gc.pcrAuthValues.auth[groupIndex] = in->auth; |
244 | 0 | return TPM_RC_SUCCESS; |
245 | 0 | } |
246 | | #endif // CC_PCR_SetAuthValue |
247 | | #include "Tpm.h" |
248 | | #include "PCR_Reset_fp.h" |
249 | | #if CC_PCR_Reset // Conditional expansion of this file |
250 | | TPM_RC |
251 | | TPM2_PCR_Reset( |
252 | | PCR_Reset_In *in // IN: input parameter list |
253 | | ) |
254 | 0 | { |
255 | | // Input Validation |
256 | | // Check if the reset operation is allowed by the current command locality |
257 | 0 | if(!PCRIsResetAllowed(in->pcrHandle)) |
258 | 0 | return TPM_RC_LOCALITY; |
259 | | // If PCR is state saved and we need to update orderlyState, check NV |
260 | | // availability |
261 | 0 | if(PCRIsStateSaved(in->pcrHandle)) |
262 | 0 | RETURN_IF_ORDERLY; |
263 | | // Internal Data Update |
264 | | // Reset selected PCR in all banks to 0 |
265 | 0 | PCRSetValue(in->pcrHandle, 0); |
266 | | // Indicate that the PCR changed so that pcrCounter will be incremented if |
267 | | // necessary. |
268 | 0 | PCRChanged(in->pcrHandle); |
269 | 0 | return TPM_RC_SUCCESS; |
270 | 0 | } |
271 | | #endif // CC_PCR_Reset |
272 | | |
273 | | #include "Tpm.h" |
274 | | /* This function is called to process a _TPM_Hash_Start() indication. */ |
275 | | LIB_EXPORT void |
276 | | _TPM_Hash_Start( |
277 | | void |
278 | | ) |
279 | 4.12k | { |
280 | 4.12k | TPM_RC result; |
281 | 4.12k | TPMI_DH_OBJECT handle; |
282 | | // If a DRTM sequence object exists, free it up |
283 | 4.12k | if(g_DRTMHandle != TPM_RH_UNASSIGNED) |
284 | 908 | { |
285 | 908 | FlushObject(g_DRTMHandle); |
286 | 908 | g_DRTMHandle = TPM_RH_UNASSIGNED; |
287 | 908 | } |
288 | | // Create an event sequence object and store the handle in global |
289 | | // g_DRTMHandle. A TPM_RC_OBJECT_MEMORY error may be returned at this point |
290 | | // The NULL value for the first parameter will cause the sequence structure to |
291 | | // be allocated without being set as present. This keeps the sequence from |
292 | | // being left behind if the sequence is terminated early. |
293 | 4.12k | result = ObjectCreateEventSequence(NULL, &g_DRTMHandle); |
294 | | // If a free slot was not available, then free up a slot. |
295 | 4.12k | if(result != TPM_RC_SUCCESS) |
296 | 0 | { |
297 | | // An implementation does not need to have a fixed relationship between |
298 | | // slot numbers and handle numbers. To handle the general case, scan for |
299 | | // a handle that is assigned and free it for the DRTM sequence. |
300 | | // In the reference implementation, the relationship between handles and |
301 | | // slots is fixed. So, if the call to ObjectCreateEvenSequence() |
302 | | // failed indicating that all slots are occupied, then the first handle we |
303 | | // are going to check (TRANSIENT_FIRST) will be occupied. It will be freed |
304 | | // so that it can be assigned for use as the DRTM sequence object. |
305 | 0 | for(handle = TRANSIENT_FIRST; handle < TRANSIENT_LAST; handle++) |
306 | 0 | { |
307 | | // try to flush the first object |
308 | 0 | if(IsObjectPresent(handle)) |
309 | 0 | break; |
310 | 0 | } |
311 | | // If the first call to find a slot fails but none of the slots is occupied |
312 | | // then there's a big problem |
313 | 0 | pAssert(handle < TRANSIENT_LAST); |
314 | | // Free the slot |
315 | 0 | FlushObject(handle); |
316 | | // Try to create an event sequence object again. This time, we must |
317 | | // succeed. |
318 | 0 | result = ObjectCreateEventSequence(NULL, &g_DRTMHandle); |
319 | 0 | if(result != TPM_RC_SUCCESS) |
320 | 0 | FAIL(FATAL_ERROR_INTERNAL); |
321 | 0 | } |
322 | 4.12k | return; |
323 | 4.12k | } |
324 | | |
325 | | #include "Tpm.h" |
326 | | /* This function is called to process a _TPM_Hash_Data() indication. */ |
327 | | LIB_EXPORT void |
328 | | _TPM_Hash_Data( |
329 | | uint32_t dataSize, // IN: size of data to be extend |
330 | | unsigned char *data // IN: data buffer |
331 | | ) |
332 | 450 | { |
333 | 450 | UINT32 i; |
334 | 450 | HASH_OBJECT *hashObject; |
335 | 450 | TPMI_DH_PCR pcrHandle = TPMIsStarted() |
336 | 450 | ? PCR_FIRST + DRTM_PCR : PCR_FIRST + HCRTM_PCR; |
337 | | // If there is no DRTM sequence object, then _TPM_Hash_Start |
338 | | // was not called so this function returns without doing |
339 | | // anything. |
340 | 450 | if(g_DRTMHandle == TPM_RH_UNASSIGNED) |
341 | 290 | return; |
342 | 160 | hashObject = (HASH_OBJECT *)HandleToObject(g_DRTMHandle); |
343 | 160 | pAssert(hashObject->attributes.eventSeq); |
344 | | // For each of the implemented hash algorithms, update the digest with the |
345 | | // data provided. |
346 | 800 | for(i = 0; i < HASH_COUNT; i++) |
347 | 640 | { |
348 | | // make sure that the PCR is implemented for this algorithm |
349 | 640 | if(PcrIsAllocated(pcrHandle, |
350 | 640 | hashObject->state.hashState[i].hashAlg)) |
351 | | // Update sequence object |
352 | 640 | CryptDigestUpdate(&hashObject->state.hashState[i], dataSize, data); |
353 | 640 | } |
354 | 160 | return; |
355 | 160 | } |
356 | | |
357 | | #include "Tpm.h" |
358 | | /* This function is called to process a _TPM_Hash_End() indication. */ |
359 | | LIB_EXPORT void |
360 | | _TPM_Hash_End( |
361 | | void |
362 | | ) |
363 | 3.28k | { |
364 | 3.28k | UINT32 i; |
365 | 3.28k | TPM2B_DIGEST digest; |
366 | 3.28k | HASH_OBJECT *hashObject; |
367 | 3.28k | TPMI_DH_PCR pcrHandle; |
368 | | // If the DRTM handle is not being used, then either _TPM_Hash_Start has not |
369 | | // been called, _TPM_Hash_End was previously called, or some other command |
370 | | // was executed and the sequence was aborted. |
371 | 3.28k | if(g_DRTMHandle == TPM_RH_UNASSIGNED) |
372 | 226 | return; |
373 | | // Get DRTM sequence object |
374 | 3.05k | hashObject = (HASH_OBJECT *)HandleToObject(g_DRTMHandle); |
375 | | // Is this _TPM_Hash_End after Startup or before |
376 | 3.05k | if(TPMIsStarted()) |
377 | 0 | { |
378 | | // After |
379 | | // Reset the DRTM PCR |
380 | 0 | PCRResetDynamics(); |
381 | | // Extend the DRTM_PCR. |
382 | 0 | pcrHandle = PCR_FIRST + DRTM_PCR; |
383 | | // DRTM sequence increments restartCount |
384 | 0 | gr.restartCount++; |
385 | 0 | } |
386 | 3.05k | else |
387 | 3.05k | { |
388 | 3.05k | pcrHandle = PCR_FIRST + HCRTM_PCR; |
389 | 3.05k | g_DrtmPreStartup = TRUE; |
390 | 3.05k | } |
391 | | // Complete hash and extend PCR, or if this is an HCRTM, complete |
392 | | // the hash, reset the H-CRTM register (PCR[0]) to 0...04, and then |
393 | | // extend the H-CRTM data |
394 | 15.2k | for(i = 0; i < HASH_COUNT; i++) |
395 | 12.2k | { |
396 | 12.2k | TPMI_ALG_HASH hash = CryptHashGetAlgByIndex(i); |
397 | | // make sure that the PCR is implemented for this algorithm |
398 | 12.2k | if(PcrIsAllocated(pcrHandle, |
399 | 12.2k | hashObject->state.hashState[i].hashAlg)) |
400 | 12.2k | { |
401 | | // Complete hash |
402 | 12.2k | digest.t.size = CryptHashGetDigestSize(hash); |
403 | 12.2k | CryptHashEnd2B(&hashObject->state.hashState[i], &digest.b); |
404 | 12.2k | PcrDrtm(pcrHandle, hash, &digest); |
405 | 12.2k | } |
406 | 12.2k | } |
407 | | // Flush sequence object. |
408 | 3.05k | FlushObject(g_DRTMHandle); |
409 | 3.05k | g_DRTMHandle = TPM_RH_UNASSIGNED; |
410 | 3.05k | return; |
411 | 3.28k | } |