/src/libtpms/src/tpm12/tpm_nvram.c
Line | Count | Source |
1 | | /********************************************************************************/ |
2 | | /* */ |
3 | | /* NVRAM Utilities */ |
4 | | /* Written by Ken Goldman */ |
5 | | /* IBM Thomas J. Watson Research Center */ |
6 | | /* $Id: tpm_nvram.c 4724 2014-08-11 20:33:23Z kgoldman $ */ |
7 | | /* */ |
8 | | /* (c) Copyright IBM Corporation 2006, 2010. */ |
9 | | /* */ |
10 | | /* All rights reserved. */ |
11 | | /* */ |
12 | | /* Redistribution and use in source and binary forms, with or without */ |
13 | | /* modification, are permitted provided that the following conditions are */ |
14 | | /* met: */ |
15 | | /* */ |
16 | | /* Redistributions of source code must retain the above copyright notice, */ |
17 | | /* this list of conditions and the following disclaimer. */ |
18 | | /* */ |
19 | | /* Redistributions in binary form must reproduce the above copyright */ |
20 | | /* notice, this list of conditions and the following disclaimer in the */ |
21 | | /* documentation and/or other materials provided with the distribution. */ |
22 | | /* */ |
23 | | /* Neither the names of the IBM Corporation nor the names of its */ |
24 | | /* contributors may be used to endorse or promote products derived from */ |
25 | | /* this software without specific prior written permission. */ |
26 | | /* */ |
27 | | /* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ |
28 | | /* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT */ |
29 | | /* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR */ |
30 | | /* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT */ |
31 | | /* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */ |
32 | | /* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */ |
33 | | /* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, */ |
34 | | /* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY */ |
35 | | /* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */ |
36 | | /* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE */ |
37 | | /* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ |
38 | | /********************************************************************************/ |
39 | | |
40 | | #include <stdio.h> |
41 | | #include <string.h> |
42 | | #include <stdlib.h> |
43 | | #include <errno.h> |
44 | | |
45 | | #include "tpm_auth.h" |
46 | | #include "tpm_crypto.h" |
47 | | #include "tpm_cryptoh.h" |
48 | | #include "tpm_debug.h" |
49 | | #include "tpm_digest.h" |
50 | | #include "tpm_error.h" |
51 | | #include "tpm_io.h" |
52 | | #include "tpm_memory.h" |
53 | | #include "tpm_nvfile.h" |
54 | | #include "tpm_pcr.h" |
55 | | #include "tpm_permanent.h" |
56 | | #include "tpm_platform.h" |
57 | | #include "tpm_process.h" |
58 | | #include "tpm_secret.h" |
59 | | #include "tpm_storage.h" |
60 | | #include "tpm_structures.h" |
61 | | |
62 | | #include "tpm_nvram.h" |
63 | | |
64 | | /* |
65 | | NV Defined Space Utilities |
66 | | */ |
67 | | |
68 | | /* |
69 | | TPM_NV_ATTRIBUTES |
70 | | */ |
71 | | |
72 | | /* TPM_NVAttributes_Init() |
73 | | |
74 | | sets members to default values |
75 | | sets all pointers to NULL and sizes to 0 |
76 | | always succeeds - no return code |
77 | | */ |
78 | | |
79 | | void TPM_NVAttributes_Init(TPM_NV_ATTRIBUTES *tpm_nv_attributes) |
80 | 0 | { |
81 | 0 | printf(" TPM_NVAttributes_Init:\n"); |
82 | 0 | tpm_nv_attributes->attributes = 0; |
83 | 0 | return; |
84 | 0 | } |
85 | | |
86 | | /* TPM_NVAttributes_Load() |
87 | | |
88 | | deserialize the structure from a 'stream' |
89 | | 'stream_size' is checked for sufficient data |
90 | | returns 0 or error codes |
91 | | |
92 | | Before use, call TPM_NVAttributes_Init() |
93 | | After use, call TPM_NVAttributes_Delete() to free memory |
94 | | */ |
95 | | |
96 | | TPM_RESULT TPM_NVAttributes_Load(TPM_NV_ATTRIBUTES *tpm_nv_attributes, |
97 | | unsigned char **stream, |
98 | | uint32_t *stream_size) |
99 | 0 | { |
100 | 0 | TPM_RESULT rc = 0; |
101 | |
|
102 | 0 | printf(" TPM_NVAttributes_Load:\n"); |
103 | | /* check tag */ |
104 | 0 | if (rc == 0) { |
105 | 0 | rc = TPM_CheckTag(TPM_TAG_NV_ATTRIBUTES, stream, stream_size); |
106 | 0 | } |
107 | | /* load attributes */ |
108 | 0 | if (rc == 0) { |
109 | 0 | rc = TPM_Load32(&(tpm_nv_attributes->attributes), stream, stream_size); |
110 | 0 | } |
111 | 0 | return rc; |
112 | 0 | } |
113 | | |
114 | | /* TPM_NVAttributes_Store() |
115 | | |
116 | | serialize the structure to a stream contained in 'sbuffer' |
117 | | returns 0 or error codes |
118 | | */ |
119 | | |
120 | | TPM_RESULT TPM_NVAttributes_Store(TPM_STORE_BUFFER *sbuffer, |
121 | | const TPM_NV_ATTRIBUTES *tpm_nv_attributes) |
122 | 0 | { |
123 | 0 | TPM_RESULT rc = 0; |
124 | |
|
125 | 0 | printf(" TPM_NVAttributes_Store:\n"); |
126 | | /* store tag */ |
127 | 0 | if (rc == 0) { |
128 | 0 | rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_NV_ATTRIBUTES); |
129 | 0 | } |
130 | 0 | if (rc == 0) { |
131 | 0 | rc = TPM_Sbuffer_Append32(sbuffer, tpm_nv_attributes->attributes); |
132 | 0 | } |
133 | 0 | return rc; |
134 | 0 | } |
135 | | |
136 | | /* TPM_NVAttributes_Delete() |
137 | | |
138 | | No-OP if the parameter is NULL, else: |
139 | | frees memory allocated for the nv_attributes |
140 | | sets pointers to NULL |
141 | | calls TPM_NVAttributes_Init to set members back to default values |
142 | | The object itself is not freed |
143 | | */ |
144 | | |
145 | | void TPM_NVAttributes_Delete(TPM_NV_ATTRIBUTES *tpm_nv_attributes) |
146 | 0 | { |
147 | 0 | printf(" TPM_NVAttributes_Delete:\n"); |
148 | 0 | if (tpm_nv_attributes != NULL) { |
149 | 0 | TPM_NVAttributes_Init(tpm_nv_attributes); |
150 | 0 | } |
151 | 0 | return; |
152 | 0 | } |
153 | | |
154 | | void TPM_NVAttributes_Copy(TPM_NV_ATTRIBUTES *tpm_nv_attributes_dest, |
155 | | TPM_NV_ATTRIBUTES *tpm_nv_attributes_src) |
156 | 0 | { |
157 | 0 | tpm_nv_attributes_dest->attributes = tpm_nv_attributes_src->attributes; |
158 | 0 | return; |
159 | 0 | } |
160 | | |
161 | | /* |
162 | | TPM_NV_DATA_PUBLIC |
163 | | */ |
164 | | |
165 | | /* TPM_NVDataPublic_Init() |
166 | | |
167 | | sets members to default values |
168 | | sets all pointers to NULL and sizes to 0 |
169 | | always succeeds - no return code |
170 | | */ |
171 | | |
172 | | void TPM_NVDataPublic_Init(TPM_NV_DATA_PUBLIC *tpm_nv_data_public) |
173 | 0 | { |
174 | 0 | printf(" TPM_NVDataPublic_Init:\n"); |
175 | 0 | tpm_nv_data_public->nvIndex = TPM_NV_INDEX_LOCK; /* mark unused */ |
176 | 0 | TPM_PCRInfoShort_Init(&(tpm_nv_data_public->pcrInfoRead)); |
177 | 0 | TPM_PCRInfoShort_Init(&(tpm_nv_data_public->pcrInfoWrite)); |
178 | 0 | TPM_NVAttributes_Init(&(tpm_nv_data_public->permission)); |
179 | 0 | tpm_nv_data_public->bReadSTClear = FALSE; |
180 | 0 | tpm_nv_data_public->bWriteSTClear = FALSE; |
181 | 0 | tpm_nv_data_public->bWriteDefine = FALSE; |
182 | 0 | tpm_nv_data_public->dataSize = 0; |
183 | 0 | return; |
184 | 0 | } |
185 | | |
186 | | /* TPM_NVDataPublic_Load() |
187 | | |
188 | | deserialize the structure from a 'stream' |
189 | | 'stream_size' is checked for sufficient data |
190 | | returns 0 or error codes |
191 | | |
192 | | Before use, call TPM_NVDataPublic_Init() |
193 | | After use, call TPM_NVDataPublic_Delete() to free memory |
194 | | */ |
195 | | |
196 | | TPM_RESULT TPM_NVDataPublic_Load(TPM_NV_DATA_PUBLIC *tpm_nv_data_public, |
197 | | unsigned char **stream, |
198 | | uint32_t *stream_size, |
199 | | TPM_BOOL optimize) |
200 | 0 | { |
201 | 0 | TPM_RESULT rc = 0; |
202 | |
|
203 | 0 | printf(" TPM_NVDataPublic_Load:\n"); |
204 | | /* check tag */ |
205 | 0 | if (rc == 0) { |
206 | 0 | rc = TPM_CheckTag(TPM_TAG_NV_DATA_PUBLIC, stream, stream_size); |
207 | 0 | } |
208 | | /* load nvIndex */ |
209 | 0 | if (rc == 0) { |
210 | 0 | rc = TPM_Load32(&(tpm_nv_data_public->nvIndex), stream, stream_size); |
211 | 0 | } |
212 | | /* load pcrInfoRead */ |
213 | 0 | if (rc == 0) { |
214 | 0 | rc = TPM_PCRInfoShort_Load(&(tpm_nv_data_public->pcrInfoRead), stream, stream_size, optimize); |
215 | 0 | } |
216 | | /* load pcrInfoWrite */ |
217 | 0 | if (rc == 0) { |
218 | 0 | rc = TPM_PCRInfoShort_Load(&(tpm_nv_data_public->pcrInfoWrite), stream, stream_size, optimize); |
219 | 0 | } |
220 | | /* load permission */ |
221 | 0 | if (rc == 0) { |
222 | 0 | rc = TPM_NVAttributes_Load(&(tpm_nv_data_public->permission), stream, stream_size); |
223 | 0 | } |
224 | | /* load bReadSTClear */ |
225 | 0 | if (rc == 0) { |
226 | 0 | rc = TPM_LoadBool(&(tpm_nv_data_public->bReadSTClear), stream, stream_size); |
227 | 0 | } |
228 | | /* load bWriteSTClear */ |
229 | 0 | if (rc == 0) { |
230 | 0 | rc = TPM_LoadBool(&(tpm_nv_data_public->bWriteSTClear), stream, stream_size); |
231 | 0 | } |
232 | | /* load bWriteDefine */ |
233 | 0 | if (rc == 0) { |
234 | 0 | rc = TPM_LoadBool(&(tpm_nv_data_public->bWriteDefine), stream, stream_size); |
235 | 0 | } |
236 | | /* load dataSize */ |
237 | 0 | if (rc == 0) { |
238 | 0 | rc = TPM_Load32(&(tpm_nv_data_public->dataSize), stream, stream_size); |
239 | 0 | } |
240 | 0 | return rc; |
241 | 0 | } |
242 | | |
243 | | /* TPM_NVDataPublic_Store() |
244 | | |
245 | | serialize the structure to a stream contained in 'sbuffer' |
246 | | returns 0 or error codes |
247 | | */ |
248 | | |
249 | | TPM_RESULT TPM_NVDataPublic_Store(TPM_STORE_BUFFER *sbuffer, |
250 | | const TPM_NV_DATA_PUBLIC *tpm_nv_data_public, |
251 | | TPM_BOOL optimize) |
252 | 0 | { |
253 | 0 | TPM_RESULT rc = 0; |
254 | |
|
255 | 0 | printf(" TPM_NVDataPublic_Store:\n"); |
256 | | /* store tag */ |
257 | 0 | if (rc == 0) { |
258 | 0 | rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_NV_DATA_PUBLIC); |
259 | 0 | } |
260 | | /* store nvIndex */ |
261 | 0 | if (rc == 0) { |
262 | 0 | rc = TPM_Sbuffer_Append32(sbuffer, tpm_nv_data_public->nvIndex); |
263 | 0 | } |
264 | | /* store pcrInfoRead */ |
265 | 0 | if (rc == 0) { |
266 | 0 | rc = TPM_PCRInfoShort_Store(sbuffer, &(tpm_nv_data_public->pcrInfoRead), optimize); |
267 | 0 | } |
268 | | /* store pcrInfoWrite */ |
269 | 0 | if (rc == 0) { |
270 | 0 | rc = TPM_PCRInfoShort_Store(sbuffer, &(tpm_nv_data_public->pcrInfoWrite), optimize); |
271 | 0 | } |
272 | | /* store permission */ |
273 | 0 | if (rc == 0) { |
274 | 0 | rc = TPM_NVAttributes_Store(sbuffer, &(tpm_nv_data_public->permission)); |
275 | 0 | } |
276 | | /* store bReadSTClear */ |
277 | 0 | if (rc == 0) { |
278 | 0 | rc = TPM_Sbuffer_Append(sbuffer, &(tpm_nv_data_public->bReadSTClear), sizeof(TPM_BOOL)); |
279 | 0 | } |
280 | | /* store bWriteSTClear */ |
281 | 0 | if (rc == 0) { |
282 | 0 | rc = TPM_Sbuffer_Append(sbuffer, &(tpm_nv_data_public->bWriteSTClear), sizeof(TPM_BOOL)); |
283 | 0 | } |
284 | | /* store bWriteDefine */ |
285 | 0 | if (rc == 0) { |
286 | 0 | rc = TPM_Sbuffer_Append(sbuffer, &(tpm_nv_data_public->bWriteDefine), sizeof(TPM_BOOL)); |
287 | 0 | } |
288 | | /* store dataSize */ |
289 | 0 | if (rc == 0) { |
290 | 0 | rc = TPM_Sbuffer_Append32(sbuffer, tpm_nv_data_public->dataSize); |
291 | 0 | } |
292 | 0 | return rc; |
293 | 0 | } |
294 | | |
295 | | /* TPM_NVDataPublic_Delete() |
296 | | |
297 | | No-OP if the parameter is NULL, else: |
298 | | frees memory allocated for the object |
299 | | sets pointers to NULL |
300 | | calls TPM_NVDataPublic_Init to set members back to default values |
301 | | The object itself is not freed |
302 | | */ |
303 | | |
304 | | void TPM_NVDataPublic_Delete(TPM_NV_DATA_PUBLIC *tpm_nv_data_public) |
305 | 0 | { |
306 | 0 | printf(" TPM_NVDataPublic_Delete:\n"); |
307 | 0 | if (tpm_nv_data_public != NULL) { |
308 | 0 | TPM_PCRInfoShort_Delete(&(tpm_nv_data_public->pcrInfoRead)); |
309 | 0 | TPM_PCRInfoShort_Delete(&(tpm_nv_data_public->pcrInfoWrite)); |
310 | 0 | TPM_NVAttributes_Delete(&(tpm_nv_data_public->permission)); |
311 | 0 | TPM_NVDataPublic_Init(tpm_nv_data_public); |
312 | 0 | } |
313 | 0 | return; |
314 | 0 | } |
315 | | |
316 | | /* |
317 | | TPM_NV_DATA_SENSITIVE |
318 | | */ |
319 | | |
320 | | /* TPM_NVDataSensitive_Init() |
321 | | |
322 | | sets members to default values |
323 | | sets all pointers to NULL and sizes to 0 |
324 | | always succeeds - no return code |
325 | | */ |
326 | | |
327 | | void TPM_NVDataSensitive_Init(TPM_NV_DATA_SENSITIVE *tpm_nv_data_sensitive) |
328 | 0 | { |
329 | 0 | printf(" TPM_NVDataSensitive_Init:\n"); |
330 | 0 | TPM_NVDataPublic_Init(&(tpm_nv_data_sensitive->pubInfo)); |
331 | 0 | TPM_Secret_Init(tpm_nv_data_sensitive->authValue); |
332 | 0 | tpm_nv_data_sensitive->data = NULL; |
333 | 0 | TPM_Digest_Init(tpm_nv_data_sensitive->digest); |
334 | 0 | return; |
335 | 0 | } |
336 | | |
337 | | /* TPM_NVDataSensitive_Load() |
338 | | |
339 | | deserialize the structure from a 'stream' |
340 | | 'stream_size' is checked for sufficient data |
341 | | returns 0 or error codes |
342 | | |
343 | | Before use, call TPM_NVDataSensitive_Init() |
344 | | After use, call TPM_NVDataSensitive_Delete() to free memory |
345 | | */ |
346 | | |
347 | | TPM_RESULT TPM_NVDataSensitive_Load(TPM_NV_DATA_SENSITIVE *tpm_nv_data_sensitive, |
348 | | TPM_TAG nvEntriesVersion, |
349 | | unsigned char **stream, |
350 | | uint32_t *stream_size) |
351 | 0 | { |
352 | 0 | TPM_RESULT rc = 0; |
353 | 0 | TPM_BOOL optimize; |
354 | 0 | TPM_BOOL isGPIO; |
355 | |
|
356 | 0 | printf(" TPM_NVDataSensitive_Load: nvEntriesVersion %04hx\n", nvEntriesVersion); |
357 | | /* check tag */ |
358 | 0 | if (rc == 0) { |
359 | 0 | rc = TPM_CheckTag(TPM_TAG_NV_DATA_SENSITIVE, stream, stream_size); |
360 | 0 | } |
361 | | /* load pubInfo */ |
362 | 0 | if (rc == 0) { |
363 | | /* versions after V1 optimise the serialization */ |
364 | 0 | optimize = (nvEntriesVersion != TPM_TAG_NVSTATE_NV_V1); |
365 | 0 | rc = TPM_NVDataPublic_Load(&(tpm_nv_data_sensitive->pubInfo), |
366 | 0 | stream, stream_size, |
367 | 0 | optimize); /* optimize digestAtRelease */ |
368 | 0 | } |
369 | | /* load authValue */ |
370 | 0 | if (rc == 0) { |
371 | 0 | rc = TPM_Secret_Load(tpm_nv_data_sensitive->authValue, stream, stream_size); |
372 | 0 | } |
373 | | /* is the nvIndex GPIO space */ |
374 | 0 | if (rc == 0) { |
375 | 0 | rc = TPM_NVDataSensitive_IsGPIO(&isGPIO, tpm_nv_data_sensitive->pubInfo.nvIndex); |
376 | 0 | } |
377 | | /* allocate memory for data */ |
378 | 0 | if ((rc == 0) && !isGPIO) { |
379 | 0 | rc = TPM_Malloc(&(tpm_nv_data_sensitive->data), |
380 | 0 | tpm_nv_data_sensitive->pubInfo.dataSize); |
381 | 0 | } |
382 | | /* load data */ |
383 | 0 | if ((rc == 0) && !isGPIO) { |
384 | 0 | rc = TPM_Loadn(tpm_nv_data_sensitive->data, tpm_nv_data_sensitive->pubInfo.dataSize, |
385 | 0 | stream, stream_size); |
386 | 0 | } |
387 | | /* create digest. The digest is not stored to save NVRAM space */ |
388 | 0 | if (rc == 0) { |
389 | 0 | rc = TPM_SHA1(tpm_nv_data_sensitive->digest, |
390 | 0 | sizeof(TPM_NV_INDEX), |
391 | 0 | (unsigned char *)&tpm_nv_data_sensitive->pubInfo.nvIndex, |
392 | 0 | TPM_AUTHDATA_SIZE, tpm_nv_data_sensitive->authValue, |
393 | 0 | 0, NULL); |
394 | 0 | } |
395 | 0 | return rc; |
396 | 0 | } |
397 | | |
398 | | /* TPM_NVDataSensitive_Store() |
399 | | |
400 | | serialize the structure to a stream contained in 'sbuffer' |
401 | | returns 0 or error codes |
402 | | |
403 | | nvWrite TRUE indicates a write command, not a command to define the space. |
404 | | */ |
405 | | |
406 | | TPM_RESULT TPM_NVDataSensitive_Store(TPM_STORE_BUFFER *sbuffer, |
407 | | const TPM_NV_DATA_SENSITIVE *tpm_nv_data_sensitive) |
408 | 0 | { |
409 | 0 | TPM_RESULT rc = 0; |
410 | 0 | TPM_BOOL isGPIO; |
411 | |
|
412 | 0 | printf(" TPM_NVDataSensitive_Store:\n"); |
413 | | /* store tag */ |
414 | 0 | if (rc == 0) { |
415 | 0 | rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_NV_DATA_SENSITIVE); |
416 | 0 | } |
417 | | /* store pubInfo */ |
418 | 0 | if (rc == 0) { |
419 | 0 | rc = TPM_NVDataPublic_Store(sbuffer, &(tpm_nv_data_sensitive->pubInfo), |
420 | 0 | TRUE); /* optimize digestAtRelease */ |
421 | 0 | } |
422 | | /* store authValue */ |
423 | 0 | if (rc == 0) { |
424 | 0 | rc = TPM_Secret_Store(sbuffer, tpm_nv_data_sensitive->authValue); |
425 | 0 | } |
426 | | /* is the nvIndex GPIO space */ |
427 | 0 | if (rc == 0) { |
428 | 0 | rc = TPM_NVDataSensitive_IsGPIO(&isGPIO, tpm_nv_data_sensitive->pubInfo.nvIndex); |
429 | 0 | } |
430 | | /* store data */ |
431 | 0 | if ((rc == 0) && !isGPIO) { |
432 | 0 | rc = TPM_Sbuffer_Append(sbuffer, tpm_nv_data_sensitive->data, |
433 | 0 | tpm_nv_data_sensitive->pubInfo.dataSize); |
434 | 0 | } |
435 | 0 | return rc; |
436 | 0 | } |
437 | | |
438 | | /* TPM_NVDataSensitive_Delete() |
439 | | |
440 | | No-OP if the parameter is NULL, else: |
441 | | frees memory allocated for the object |
442 | | sets pointers to NULL |
443 | | calls TPM_NVDataSensitive_Init to set members back to default values |
444 | | The object itself is not freed |
445 | | */ |
446 | | |
447 | | void TPM_NVDataSensitive_Delete(TPM_NV_DATA_SENSITIVE *tpm_nv_data_sensitive) |
448 | 0 | { |
449 | 0 | printf(" TPM_NVDataSensitive_Delete:\n"); |
450 | 0 | if (tpm_nv_data_sensitive != NULL) { |
451 | | /* zero any secrets in NV index data */ |
452 | 0 | if (tpm_nv_data_sensitive->data != NULL) { |
453 | 0 | memset(tpm_nv_data_sensitive->data, 0xff, tpm_nv_data_sensitive->pubInfo.dataSize); |
454 | 0 | } |
455 | 0 | TPM_NVDataPublic_Delete(&(tpm_nv_data_sensitive->pubInfo)); |
456 | 0 | TPM_Secret_Delete(tpm_nv_data_sensitive->authValue); |
457 | 0 | free(tpm_nv_data_sensitive->data); |
458 | 0 | TPM_NVDataSensitive_Init(tpm_nv_data_sensitive); |
459 | 0 | } |
460 | 0 | return; |
461 | 0 | } |
462 | | |
463 | | /* TPM_NVDataSensitive_IsValidIndex() determines if 'nvIndex' is permissible for an NV defined space |
464 | | TPM_NV_DATA_SENSITIVE structure. |
465 | | |
466 | | Some values have special meaning, so they are allowed for the TPM_NV_DefineSpace command but will |
467 | | not actually define a space. |
468 | | */ |
469 | | |
470 | | TPM_RESULT TPM_NVDataSensitive_IsValidIndex(TPM_NV_INDEX nvIndex) |
471 | 0 | { |
472 | 0 | TPM_RESULT rc = 0; |
473 | 0 | TPM_BOOL isGPIO; |
474 | |
|
475 | 0 | printf(" TPM_NVDataSensitive_IsValidIndex: nvIndex %08x\n", nvIndex); |
476 | 0 | if (rc == 0) { |
477 | 0 | if ((nvIndex == TPM_NV_INDEX_LOCK) || |
478 | 0 | (nvIndex == TPM_NV_INDEX0) || |
479 | 0 | (nvIndex == TPM_NV_INDEX_DIR)) { |
480 | 0 | printf("TPM_NVDataSensitive_IsValidIndex: Error, illegal special index\n"); |
481 | 0 | rc = TPM_BADINDEX; |
482 | 0 | } |
483 | 0 | } |
484 | 0 | if (rc == 0) { |
485 | 0 | if ((nvIndex & TPM_NV_INDEX_RESVD) != 0) { |
486 | 0 | printf("TPM_NVDataSensitive_IsValidIndex: Error, illegal reserved index\n"); |
487 | 0 | rc = TPM_BADINDEX; |
488 | 0 | } |
489 | 0 | } |
490 | 0 | if (rc == 0) { |
491 | 0 | rc = TPM_NVDataSensitive_IsValidPlatformIndex(nvIndex); |
492 | 0 | } |
493 | | /* The GPIO range validity is platform dependent */ |
494 | 0 | if (rc == 0) { |
495 | 0 | rc = TPM_NVDataSensitive_IsGPIO(&isGPIO, nvIndex); |
496 | 0 | } |
497 | 0 | return rc; |
498 | 0 | } |
499 | | |
500 | | /* TPM_NVDataSensitive_IsGPIO() determines if 'nvIndex' is in the GPIO range and is valid. |
501 | | |
502 | | Returns: |
503 | | |
504 | | TPM_SUCCESS , FALSE if 'nvIndex' is not in the GPIO range |
505 | | TPM_SUCCESS , TRUE if 'nvIndex' is in the GPIO range and the platform allows GPIO defined space |
506 | | TPM_BADINDEX, FALSE if 'nvIndex' is in the GPIO range and the platform does not allow GPIO |
507 | | defined space |
508 | | */ |
509 | | |
510 | | TPM_RESULT TPM_NVDataSensitive_IsGPIO(TPM_BOOL *isGPIO, TPM_NV_INDEX nvIndex) |
511 | 0 | { |
512 | 0 | TPM_RESULT rc = 0; |
513 | |
|
514 | 0 | printf(" TPM_NVDataSensitive_IsGPIO: nvIndex %08x\n", nvIndex); |
515 | 0 | *isGPIO = FALSE; |
516 | 0 | #if defined TPM_PCCLIENT |
517 | 0 | if (rc == 0) { |
518 | | /* GPIO space allowed for PC Client */ |
519 | 0 | if ((nvIndex >= TPM_NV_INDEX_GPIO_START) && |
520 | 0 | (nvIndex <= TPM_NV_INDEX_GPIO_END)) { |
521 | 0 | printf(" TPM_NVDataSensitive_IsGPIO: nvIndex is GPIO space\n"); |
522 | 0 | *isGPIO = TRUE; |
523 | 0 | } |
524 | 0 | } |
525 | | /* #elif */ |
526 | | #else |
527 | | if (rc == 0) { |
528 | | /* GPIO space cannot be defined in platforms with no GPIO */ |
529 | | if ((nvIndex >= TPM_NV_INDEX_GPIO_START) && |
530 | | (nvIndex <= TPM_NV_INDEX_GPIO_END)) { |
531 | | printf("TPM_NVDataSensitive_IsGPIO: Error, illegal index\n"); |
532 | | rc = TPM_BADINDEX; |
533 | | } |
534 | | } |
535 | | #endif |
536 | 0 | return rc; |
537 | 0 | } |
538 | | |
539 | | TPM_RESULT TPM_NVDataSensitive_IsValidPlatformIndex(TPM_NV_INDEX nvIndex) |
540 | 0 | { |
541 | 0 | TPM_RESULT rc = 0; |
542 | |
|
543 | 0 | printf(" TPM_NVDataSensitive_IsValidPlatformIndex: nvIndex %08x\n", nvIndex); |
544 | | #ifndef TPM_PCCLIENT |
545 | | if (rc == 0) { |
546 | | if (((nvIndex & TPM_NV_INDEX_PURVIEW_MASK) >> TPM_NV_INDEX_PURVIEW_BIT) == TPM_PC) { |
547 | | printf(" TPM_NVDataSensitive_IsValidPlatformIndex: Error, PC Client index\n"); |
548 | | rc = TPM_BADINDEX; |
549 | | } |
550 | | } |
551 | | #endif |
552 | 0 | return rc; |
553 | 0 | } |
554 | | |
555 | | /* |
556 | | NV Index Entries |
557 | | |
558 | | This handles the in-memory copy of NV defined space |
559 | | */ |
560 | | |
561 | | /* |
562 | | TPM_NVIndexEntries_Init() initializes the TPM_NV_INDEX_ENTRIES array |
563 | | */ |
564 | | |
565 | | void TPM_NVIndexEntries_Init(TPM_NV_INDEX_ENTRIES *tpm_nv_index_entries) |
566 | 0 | { |
567 | 0 | printf(" TPM_NVIndexEntries_Init:\n"); |
568 | 0 | tpm_nv_index_entries->nvIndexCount = 0; |
569 | 0 | tpm_nv_index_entries->tpm_nvindex_entry = NULL; |
570 | 0 | return; |
571 | 0 | } |
572 | | |
573 | | /* |
574 | | TPM_NVIndexEntries_Delete() iterates through the entire TPM_NV_INDEX_ENTRIES array, deleting any |
575 | | used entries. |
576 | | |
577 | | It then frees and reinitializes the array. |
578 | | */ |
579 | | |
580 | | |
581 | | void TPM_NVIndexEntries_Delete(TPM_NV_INDEX_ENTRIES *tpm_nv_index_entries) |
582 | 0 | { |
583 | 0 | size_t i; |
584 | |
|
585 | 0 | printf(" TPM_NVIndexEntries_Delete: Deleting from %u slots\n", |
586 | 0 | tpm_nv_index_entries->nvIndexCount); |
587 | | /* free the entries */ |
588 | 0 | for (i = 0 ; i < tpm_nv_index_entries->nvIndexCount ; i++) { |
589 | 0 | TPM_NVDataSensitive_Delete(&(tpm_nv_index_entries->tpm_nvindex_entry[i])); |
590 | 0 | } |
591 | | /* free the array */ |
592 | 0 | free(tpm_nv_index_entries->tpm_nvindex_entry); |
593 | 0 | TPM_NVIndexEntries_Init(tpm_nv_index_entries); |
594 | 0 | return; |
595 | 0 | } |
596 | | |
597 | | /* TPM_NVIndexEntries_Trace() traces the TPM_NV_INDEX_ENTRIES array. |
598 | | |
599 | | Edit and call as required for debugging. |
600 | | */ |
601 | | |
602 | | void TPM_NVIndexEntries_Trace(TPM_NV_INDEX_ENTRIES *tpm_nv_index_entries) |
603 | 0 | { |
604 | 0 | uint32_t i; |
605 | 0 | TPM_NV_DATA_SENSITIVE *tpm_nv_data_sensitive; |
606 | | |
607 | 0 | printf("\tTPM_NVIndexEntries_Trace: %u slots\n", tpm_nv_index_entries->nvIndexCount); |
608 | 0 | for (i = 0 ; i < tpm_nv_index_entries->nvIndexCount ; i++) { |
609 | 0 | tpm_nv_data_sensitive = &(tpm_nv_index_entries->tpm_nvindex_entry[i]); |
610 | 0 | printf("\tTPM_NVIndexEntries_Trace: TPM_NV_DATA_SENSITIVE.data %p\n", |
611 | 0 | tpm_nv_data_sensitive->data); |
612 | 0 | } |
613 | 0 | return; |
614 | 0 | } |
615 | | |
616 | | /* |
617 | | TPM_NVIndexEntries_Load() loads the TPM_NV_INDEX_ENTRIES array from a stream. |
618 | | |
619 | | The first data in the stream must be a uint32_t count of the number of entries to follow. |
620 | | */ |
621 | | |
622 | | TPM_RESULT TPM_NVIndexEntries_Load(TPM_NV_INDEX_ENTRIES *tpm_nv_index_entries, |
623 | | unsigned char **stream, |
624 | | uint32_t *stream_size) |
625 | 0 | { |
626 | 0 | TPM_RESULT rc = 0; |
627 | 0 | uint32_t i; |
628 | 0 | TPM_TAG nvEntriesVersion; |
629 | |
|
630 | 0 | printf(" TPM_NVIndexEntries_Load:\n"); |
631 | | /* get the NV entries version number */ |
632 | 0 | if (rc == 0) { |
633 | 0 | rc = TPM_Load16(&nvEntriesVersion, stream, stream_size); |
634 | 0 | } |
635 | | /* check tag */ |
636 | 0 | if (rc == 0) { |
637 | 0 | switch (nvEntriesVersion) { |
638 | 0 | case TPM_TAG_NVSTATE_NV_V1: |
639 | 0 | case TPM_TAG_NVSTATE_NV_V2: |
640 | 0 | break; |
641 | 0 | default: |
642 | 0 | printf("TPM_NVIndexEntries_Load: Error (fatal), version %04x unsupported\n", |
643 | 0 | nvEntriesVersion); |
644 | 0 | rc = TPM_FAIL; |
645 | 0 | break; |
646 | 0 | } |
647 | 0 | } |
648 | | /* nvIndexCount */ |
649 | 0 | if (rc == 0) { |
650 | 0 | rc = TPM_Load32(&(tpm_nv_index_entries->nvIndexCount), stream, stream_size); |
651 | 0 | } |
652 | | /* allocate memory for the array, nvIndexCount TPM_NV_DATA_SENSITIVE structures */ |
653 | 0 | if ((rc == 0) && (tpm_nv_index_entries->nvIndexCount > 0)) { |
654 | 0 | printf(" TPM_NVIndexEntries_Load: Loading %u slots\n", tpm_nv_index_entries->nvIndexCount); |
655 | 0 | rc = TPM_Malloc((unsigned char **)&(tpm_nv_index_entries->tpm_nvindex_entry), |
656 | 0 | sizeof(TPM_NV_DATA_SENSITIVE) * tpm_nv_index_entries->nvIndexCount); |
657 | 0 | } |
658 | | /* immediately after allocating, initialize so that _Delete is safe even on a _Load error */ |
659 | 0 | for (i = 0 ; (rc == 0) && (i < tpm_nv_index_entries->nvIndexCount) ; i++) { |
660 | 0 | TPM_NVDataSensitive_Init(&(tpm_nv_index_entries->tpm_nvindex_entry[i])); |
661 | 0 | } |
662 | | /* tpm_nvindex_entry array */ |
663 | 0 | for (i = 0 ; (rc == 0) && (i < tpm_nv_index_entries->nvIndexCount) ; i++) { |
664 | 0 | printf(" TPM_NVIndexEntries_Load: Loading slot %u\n", i); |
665 | 0 | if (rc == 0) { |
666 | 0 | rc = TPM_NVDataSensitive_Load(&(tpm_nv_index_entries->tpm_nvindex_entry[i]), |
667 | 0 | nvEntriesVersion, stream, stream_size); |
668 | 0 | } |
669 | | /* should never load an unused entry */ |
670 | 0 | if (rc == 0) { |
671 | 0 | printf(" TPM_NVIndexEntries_Load: Loaded NV index %08x\n", |
672 | 0 | tpm_nv_index_entries->tpm_nvindex_entry[i].pubInfo.nvIndex); |
673 | 0 | if (tpm_nv_index_entries->tpm_nvindex_entry[i].pubInfo.nvIndex == TPM_NV_INDEX_LOCK) { |
674 | 0 | printf("TPM_NVIndexEntries_Load: Error (fatal) Entry %u bad NV index %08x\n", |
675 | 0 | i, tpm_nv_index_entries->tpm_nvindex_entry[i].pubInfo.nvIndex); |
676 | 0 | rc = TPM_FAIL; |
677 | 0 | } |
678 | 0 | } |
679 | 0 | } |
680 | 0 | return rc; |
681 | 0 | } |
682 | | |
683 | | /* |
684 | | TPM_NVIndexEntries_Store() serializes the TPM_NV_INDEX_ENTRIES array into a stream. Only used |
685 | | entries are serialized. |
686 | | |
687 | | The first data in the stream is the used count, obtained by iterating through the array. |
688 | | */ |
689 | | |
690 | | TPM_RESULT TPM_NVIndexEntries_Store(TPM_STORE_BUFFER *sbuffer, |
691 | | TPM_NV_INDEX_ENTRIES *tpm_nv_index_entries) |
692 | 0 | { |
693 | 0 | TPM_RESULT rc = 0; |
694 | 0 | uint32_t count; /* number of used entries to store */ |
695 | 0 | size_t i; |
696 | | |
697 | 0 | printf(" TPM_NVIndexEntries_Store: Storing from %u slots\n", |
698 | 0 | tpm_nv_index_entries->nvIndexCount); |
699 | | /* append the NV entries version number to the stream */ |
700 | 0 | if (rc == 0) { |
701 | 0 | rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_NVSTATE_NV_V2); |
702 | 0 | } |
703 | | /* count the number of used entries */ |
704 | 0 | if (rc == 0) { |
705 | 0 | rc = TPM_NVIndexEntries_GetUsedCount(&count, tpm_nv_index_entries); |
706 | 0 | } |
707 | | /* store the actual used count, not the number of array entries */ |
708 | 0 | if (rc == 0) { |
709 | 0 | rc = TPM_Sbuffer_Append32(sbuffer, count); |
710 | 0 | } |
711 | | /* tpm_nvindex_entry array */ |
712 | 0 | for (i = 0 ; (rc == 0) && (i < tpm_nv_index_entries->nvIndexCount) ; i++) { |
713 | | /* if the entry is used */ |
714 | 0 | if (tpm_nv_index_entries->tpm_nvindex_entry[i].pubInfo.nvIndex != TPM_NV_INDEX_LOCK) { |
715 | 0 | printf(" TPM_NVIndexEntries_Store: Storing slot %lu NV index %08x\n", |
716 | 0 | (unsigned long)i, tpm_nv_index_entries->tpm_nvindex_entry[i].pubInfo.nvIndex); |
717 | 0 | rc = TPM_NVDataSensitive_Store(sbuffer, &(tpm_nv_index_entries->tpm_nvindex_entry[i])); |
718 | 0 | } |
719 | 0 | else { |
720 | 0 | printf(" TPM_NVIndexEntries_Store: Skipping unused slot %lu\n", (unsigned long)i); |
721 | 0 | } |
722 | 0 | } |
723 | 0 | return rc; |
724 | 0 | } |
725 | | |
726 | | /* TPM_NVIndexEntries_StClear() steps through each entry in the NV TPM_NV_INDEX_ENTRIES array, |
727 | | setting the volatile flags to FALSE. |
728 | | */ |
729 | | |
730 | | void TPM_NVIndexEntries_StClear(TPM_NV_INDEX_ENTRIES *tpm_nv_index_entries) |
731 | 0 | { |
732 | 0 | size_t i; |
733 | |
|
734 | 0 | printf(" TPM_NVIndexEntries_StClear: Clearing %u slots\n", tpm_nv_index_entries->nvIndexCount); |
735 | | /* bReadSTClear and bWriteSTClear are volatile, in that they are set FALSE at |
736 | | TPM_Startup(ST_Clear) */ |
737 | 0 | for (i = 0 ; i < tpm_nv_index_entries->nvIndexCount ; i++) { |
738 | 0 | tpm_nv_index_entries->tpm_nvindex_entry[i].pubInfo.bReadSTClear = FALSE; |
739 | 0 | tpm_nv_index_entries->tpm_nvindex_entry[i].pubInfo.bWriteSTClear = FALSE; |
740 | 0 | } |
741 | 0 | return; |
742 | 0 | } |
743 | | |
744 | | /* TPM_NVIndexEntries_LoadVolatile() deserializes the stream into the volatile members of the |
745 | | TPM_NV_INDEX_ENTRIES array. |
746 | | */ |
747 | | |
748 | | TPM_RESULT TPM_NVIndexEntries_LoadVolatile(TPM_NV_INDEX_ENTRIES *tpm_nv_index_entries, |
749 | | unsigned char **stream, |
750 | | uint32_t *stream_size) |
751 | 0 | { |
752 | 0 | TPM_RESULT rc = 0; |
753 | 0 | uint32_t usedCount; |
754 | 0 | uint32_t entryIndex; |
755 | 0 | TPM_NV_DATA_PUBLIC *tpm_nv_data_public; |
756 | |
|
757 | 0 | printf(" TPM_NVIndexEntries_LoadVolatile:\n"); |
758 | | /* check tag */ |
759 | 0 | if (rc == 0) { |
760 | 0 | rc = TPM_CheckTag(TPM_TAG_NV_INDEX_ENTRIES_VOLATILE_V1, stream, stream_size); |
761 | 0 | } |
762 | | /* Get the number of used slots. This should be equal to the total number of slots. */ |
763 | 0 | if (rc == 0) { |
764 | 0 | rc = TPM_Load32(&usedCount, stream, stream_size); |
765 | 0 | } |
766 | 0 | if (rc == 0) { |
767 | 0 | printf(" TPM_NVIndexEntries_LoadVolatile: usedCount %u\n", usedCount); |
768 | 0 | if (usedCount != tpm_nv_index_entries->nvIndexCount) { |
769 | 0 | printf("TPM_NVIndexEntries_LoadVolatile: Error (fatal), " |
770 | 0 | "usedCount %u does not equal slot count %u\n", |
771 | 0 | usedCount, tpm_nv_index_entries->nvIndexCount); |
772 | 0 | rc = TPM_FAIL; |
773 | 0 | } |
774 | 0 | } |
775 | | /* deserialize the stream into the TPM_NV_INDEX_ENTRIES array */ |
776 | 0 | for (entryIndex = 0 ; |
777 | 0 | (rc == 0) && (entryIndex < tpm_nv_index_entries->nvIndexCount) ; |
778 | 0 | entryIndex++) { |
779 | |
|
780 | 0 | tpm_nv_data_public = &(tpm_nv_index_entries->tpm_nvindex_entry[entryIndex].pubInfo); |
781 | 0 | printf(" TPM_NVIndexEntries_LoadVolatile: Loading index %08x\n", |
782 | 0 | tpm_nv_data_public->nvIndex); |
783 | | /* load bReadSTClear */ |
784 | 0 | if (rc == 0) { |
785 | 0 | rc = TPM_LoadBool(&(tpm_nv_data_public->bReadSTClear), stream, stream_size); |
786 | 0 | } |
787 | | /* load bWriteSTClear */ |
788 | 0 | if (rc == 0) { |
789 | 0 | rc = TPM_LoadBool(&(tpm_nv_data_public->bWriteSTClear), stream, stream_size); |
790 | 0 | } |
791 | 0 | } |
792 | 0 | return rc; |
793 | 0 | } |
794 | | |
795 | | /* TPM_NVIndexEntries_StoreVolatile() serializes the volatile members of the |
796 | | TPM_NV_INDEX_ENTRIES array into the TPM_STORE_BUFFER. |
797 | | */ |
798 | | |
799 | | TPM_RESULT TPM_NVIndexEntries_StoreVolatile(TPM_STORE_BUFFER *sbuffer, |
800 | | TPM_NV_INDEX_ENTRIES *tpm_nv_index_entries) |
801 | 0 | { |
802 | 0 | TPM_RESULT rc = 0; |
803 | 0 | uint32_t usedCount; |
804 | 0 | uint32_t entryIndex; |
805 | 0 | TPM_NV_DATA_PUBLIC *tpm_nv_data_public; |
806 | | |
807 | 0 | printf(" TPM_NVIndexEntries_StoreVolatile: %u slots\n", tpm_nv_index_entries->nvIndexCount); |
808 | | /* store tag */ |
809 | 0 | if (rc == 0) { |
810 | 0 | rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_NV_INDEX_ENTRIES_VOLATILE_V1); |
811 | 0 | } |
812 | | /* Get the number of used slots. If indexes were deleted since the last TPM_Init, there can be |
813 | | some unused slots. */ |
814 | 0 | if (rc == 0) { |
815 | 0 | rc = TPM_NVIndexEntries_GetUsedCount(&usedCount, tpm_nv_index_entries); |
816 | 0 | } |
817 | | /* store usedCount */ |
818 | 0 | if (rc == 0) { |
819 | 0 | printf(" TPM_NVIndexEntries_StoreVolatile: usedCount %u\n", usedCount); |
820 | 0 | rc = TPM_Sbuffer_Append32(sbuffer, usedCount); |
821 | 0 | } |
822 | | /* save entries into the array */ |
823 | 0 | for (entryIndex = 0 ; |
824 | 0 | (rc == 0) && (entryIndex < tpm_nv_index_entries->nvIndexCount) ; |
825 | 0 | entryIndex++) { |
826 | | /* Only save used slots. During a rollback, slots are deleted and recreated. At that time, |
827 | | unused slots will be reclaimed. */ |
828 | 0 | if (tpm_nv_index_entries->tpm_nvindex_entry[entryIndex].pubInfo.nvIndex != |
829 | 0 | TPM_NV_INDEX_LOCK) { |
830 | |
|
831 | 0 | tpm_nv_data_public = &(tpm_nv_index_entries->tpm_nvindex_entry[entryIndex].pubInfo); |
832 | 0 | printf(" TPM_NVIndexEntries_StoreVolatile: Storing index %08x\n", |
833 | 0 | tpm_nv_data_public->nvIndex); |
834 | | /* store bReadSTClear */ |
835 | 0 | if (rc == 0) { |
836 | 0 | rc = TPM_Sbuffer_Append(sbuffer, |
837 | 0 | &(tpm_nv_data_public->bReadSTClear), sizeof(TPM_BOOL)); |
838 | 0 | } |
839 | | /* store bWriteSTClear */ |
840 | 0 | if (rc == 0) { |
841 | 0 | rc = TPM_Sbuffer_Append(sbuffer, |
842 | 0 | &(tpm_nv_data_public->bWriteSTClear), sizeof(TPM_BOOL)); |
843 | 0 | } |
844 | 0 | } |
845 | 0 | } |
846 | 0 | return rc; |
847 | 0 | } |
848 | | |
849 | | /* TPM_NVIndexEntries_GetVolatile() saves an array of the NV defined space volatile flags. |
850 | | |
851 | | The array is used during a rollback, since the volatile flags are not stored in NVRAM |
852 | | */ |
853 | | |
854 | | TPM_RESULT TPM_NVIndexEntries_GetVolatile(TPM_NV_DATA_ST **tpm_nv_data_st, /* freed by caller */ |
855 | | TPM_NV_INDEX_ENTRIES *tpm_nv_index_entries) |
856 | 0 | { |
857 | 0 | TPM_RESULT rc = 0; |
858 | 0 | uint32_t usedCount; |
859 | 0 | uint32_t entryIndex; |
860 | 0 | uint32_t usedIndex; |
861 | |
|
862 | 0 | printf(" TPM_NVIndexEntries_GetVolatile: %u slots\n", tpm_nv_index_entries->nvIndexCount); |
863 | | /* Get the number of used slots. If indexes were deleted since the last TPM_Init, there can be |
864 | | some unused slots. */ |
865 | 0 | if (rc == 0) { |
866 | 0 | rc = TPM_NVIndexEntries_GetUsedCount(&usedCount, tpm_nv_index_entries); |
867 | 0 | } |
868 | | /* allocate memory for the array, nvIndexCount TPM_NV_DATA_SENSITIVE structures */ |
869 | 0 | if ((rc == 0) && (usedCount > 0)) { |
870 | 0 | printf(" TPM_NVIndexEntries_GetVolatile: Aloocating for %u used slots\n", usedCount); |
871 | 0 | rc = TPM_Malloc((unsigned char **)tpm_nv_data_st, |
872 | 0 | sizeof(TPM_NV_DATA_ST) * usedCount); |
873 | 0 | } |
874 | | /* save entries into the array */ |
875 | 0 | for (entryIndex = 0 , usedIndex = 0 ; |
876 | 0 | (rc == 0) && (entryIndex < tpm_nv_index_entries->nvIndexCount) && (usedCount > 0) ; |
877 | 0 | entryIndex++) { |
878 | | /* Only save used slots. During a rollback, slots are deleted and recreated. At that time, |
879 | | unused slots will be reclaimed. */ |
880 | 0 | if (tpm_nv_index_entries->tpm_nvindex_entry[entryIndex].pubInfo.nvIndex != |
881 | 0 | TPM_NV_INDEX_LOCK) { |
882 | |
|
883 | 0 | printf(" TPM_NVIndexEntries_GetVolatile: Saving slot %u at used %u NV index %08x\n", |
884 | 0 | entryIndex, usedIndex, |
885 | 0 | tpm_nv_index_entries->tpm_nvindex_entry[entryIndex].pubInfo.nvIndex); |
886 | | |
887 | 0 | printf(" TPM_NVIndexEntries_GetVolatile: bReadSTClear %u bWriteSTClear %u\n", |
888 | 0 | tpm_nv_index_entries->tpm_nvindex_entry[entryIndex].pubInfo.bReadSTClear, |
889 | 0 | tpm_nv_index_entries->tpm_nvindex_entry[entryIndex].pubInfo.bWriteSTClear); |
890 | 0 | (*tpm_nv_data_st)[usedIndex].nvIndex = |
891 | 0 | tpm_nv_index_entries->tpm_nvindex_entry[entryIndex].pubInfo.nvIndex; |
892 | 0 | (*tpm_nv_data_st)[usedIndex].bReadSTClear = |
893 | 0 | tpm_nv_index_entries->tpm_nvindex_entry[entryIndex].pubInfo.bReadSTClear; |
894 | 0 | (*tpm_nv_data_st)[usedIndex].bWriteSTClear = |
895 | 0 | tpm_nv_index_entries->tpm_nvindex_entry[entryIndex].pubInfo.bWriteSTClear; |
896 | 0 | usedIndex++; |
897 | 0 | } |
898 | 0 | } |
899 | 0 | return rc; |
900 | 0 | } |
901 | | |
902 | | /* TPM_NVIndexEntries_SetVolatile() restores an array of the NV defined space volatile flags. |
903 | | |
904 | | The array is used during a rollback, since the volatile flags are not stored in NVRAM |
905 | | */ |
906 | | |
907 | | TPM_RESULT TPM_NVIndexEntries_SetVolatile(TPM_NV_DATA_ST *tpm_nv_data_st, |
908 | | TPM_NV_INDEX_ENTRIES *tpm_nv_index_entries) |
909 | 0 | { |
910 | 0 | TPM_RESULT rc = 0; |
911 | 0 | uint32_t usedCount; |
912 | 0 | uint32_t i; |
913 | |
|
914 | 0 | printf(" TPM_NVIndexEntries_SetVolatile: %u slots\n", tpm_nv_index_entries->nvIndexCount); |
915 | | /* Get the number of used slots. This should be equal to the total number of slots. */ |
916 | 0 | if (rc == 0) { |
917 | 0 | rc = TPM_NVIndexEntries_GetUsedCount(&usedCount, tpm_nv_index_entries); |
918 | 0 | } |
919 | 0 | if (rc == 0) { |
920 | 0 | if (usedCount != tpm_nv_index_entries->nvIndexCount) { |
921 | 0 | printf("TPM_NVIndexEntries_SetVolatile: Error (fatal), " |
922 | 0 | "usedCount %u does not equal slot count %u\n", |
923 | 0 | usedCount, tpm_nv_index_entries->nvIndexCount); |
924 | 0 | rc = TPM_FAIL; |
925 | 0 | } |
926 | 0 | } |
927 | | /* if the used count is non-zero, the volatile array should not be NULL */ |
928 | 0 | if (rc == 0) { |
929 | 0 | if ((usedCount > 0) && (tpm_nv_data_st == NULL)) { |
930 | 0 | printf("TPM_NVIndexEntries_SetVolatile: Error (fatal), " |
931 | 0 | "usedCount %u unconsistant with volatile array NULL\n", usedCount); |
932 | 0 | rc = TPM_FAIL; |
933 | 0 | } |
934 | 0 | } |
935 | | /* copy entries into the array */ |
936 | 0 | for (i = 0 ; (rc == 0) && (i < tpm_nv_index_entries->nvIndexCount) ; i++) { |
937 | 0 | printf(" TPM_NVIndexEntries_SetVolatile: slot %u index %08x\n", |
938 | 0 | i, tpm_nv_index_entries->tpm_nvindex_entry[i].pubInfo.nvIndex); |
939 | | /* sanity check on a mismatch of entries between the save and restore */ |
940 | 0 | if (tpm_nv_index_entries->tpm_nvindex_entry[i].pubInfo.nvIndex != |
941 | 0 | tpm_nv_data_st[i].nvIndex) { |
942 | |
|
943 | 0 | printf("TPM_NVIndexEntries_SetVolatile: Error (fatal), " |
944 | 0 | "mismatch NV entry %08x, saved %08x\n", |
945 | 0 | tpm_nv_index_entries->tpm_nvindex_entry[i].pubInfo.nvIndex, |
946 | 0 | tpm_nv_data_st[i].nvIndex); |
947 | 0 | rc = TPM_FAIL; |
948 | 0 | } |
949 | | /* restore entries from the array */ |
950 | 0 | else { |
951 | 0 | printf(" TPM_NVIndexEntries_SetVolatile: bReadSTClear %u bWriteSTClear %u\n", |
952 | 0 | tpm_nv_data_st[i].bReadSTClear, tpm_nv_data_st[i].bWriteSTClear); |
953 | 0 | tpm_nv_index_entries->tpm_nvindex_entry[i].pubInfo.bReadSTClear = |
954 | 0 | tpm_nv_data_st[i].bReadSTClear; |
955 | 0 | tpm_nv_index_entries->tpm_nvindex_entry[i].pubInfo.bWriteSTClear = |
956 | 0 | tpm_nv_data_st[i].bWriteSTClear; |
957 | 0 | } |
958 | 0 | } |
959 | 0 | return rc; |
960 | 0 | } |
961 | | |
962 | | /* TPM_NVIndexEntries_GetFreeEntry() gets a free entry in the TPM_NV_INDEX_ENTRIES array. |
963 | | |
964 | | If a free entry exists, it it returned. It should already be initialized. |
965 | | |
966 | | If a free entry does not exist, it it created and initialized. |
967 | | |
968 | | If a slot cannot be created, tpm_nv_data_sensitive returns NULL, so a subsequent free is safe. |
969 | | */ |
970 | | |
971 | | TPM_RESULT TPM_NVIndexEntries_GetFreeEntry(TPM_NV_DATA_SENSITIVE **tpm_nv_data_sensitive, |
972 | | TPM_NV_INDEX_ENTRIES *tpm_nv_index_entries) |
973 | 0 | { |
974 | 0 | TPM_RESULT rc = 0; |
975 | 0 | TPM_BOOL done = FALSE; |
976 | 0 | size_t i; |
977 | |
|
978 | 0 | printf(" TPM_NVIndexEntries_GetFreeEntry: Searching %u slots\n", |
979 | 0 | tpm_nv_index_entries->nvIndexCount); |
980 | | /* for debug - trace the entire TPM_NV_INDEX_ENTRIES array */ |
981 | 0 | for (i = 0 ; i < tpm_nv_index_entries->nvIndexCount ; i++) { |
982 | 0 | *tpm_nv_data_sensitive = &(tpm_nv_index_entries->tpm_nvindex_entry[i]); |
983 | 0 | printf(" TPM_NVIndexEntries_GetFreeEntry: slot %lu entry %08x\n", |
984 | 0 | (unsigned long)i, (*tpm_nv_data_sensitive)->pubInfo.nvIndex); |
985 | 0 | } |
986 | | /* search the existing array for a free entry */ |
987 | 0 | for (i = 0 ; (rc == 0) && (i < tpm_nv_index_entries->nvIndexCount) && !done ; i++) { |
988 | 0 | *tpm_nv_data_sensitive = &(tpm_nv_index_entries->tpm_nvindex_entry[i]); |
989 | | /* if the entry is not used */ |
990 | 0 | if ((*tpm_nv_data_sensitive)->pubInfo.nvIndex == TPM_NV_INDEX_LOCK) { |
991 | 0 | printf(" TPM_NVIndexEntries_GetFreeEntry: Found free slot %lu\n", (unsigned long)i); |
992 | 0 | done = TRUE; |
993 | 0 | } |
994 | 0 | } |
995 | | /* need to expand the array */ |
996 | 0 | if ((rc == 0) && !done) { |
997 | 0 | *tpm_nv_data_sensitive = NULL; |
998 | 0 | rc = TPM_Realloc((unsigned char **)&(tpm_nv_index_entries->tpm_nvindex_entry), |
999 | 0 | sizeof(TPM_NV_DATA_SENSITIVE) * (i + 1)); |
1000 | 0 | } |
1001 | | /* initialize the new entry in the array */ |
1002 | 0 | if ((rc == 0) && !done) { |
1003 | 0 | printf(" TPM_NVIndexEntries_GetFreeEntry: Created new slot at index %lu\n", |
1004 | 0 | (unsigned long)i); |
1005 | 0 | *tpm_nv_data_sensitive = &(tpm_nv_index_entries->tpm_nvindex_entry[i]); |
1006 | 0 | TPM_NVDataSensitive_Init(*tpm_nv_data_sensitive); |
1007 | 0 | tpm_nv_index_entries->nvIndexCount++; |
1008 | 0 | } |
1009 | 0 | return rc; |
1010 | 0 | } |
1011 | | |
1012 | | /* TPM_NVIndexEntries_GetEntry() gets the TPM_NV_DATA_SENSITIVE entry corresponding to nvIndex. |
1013 | | |
1014 | | Returns TPM_BADINDEX on non-existent nvIndex |
1015 | | */ |
1016 | | |
1017 | | TPM_RESULT TPM_NVIndexEntries_GetEntry(TPM_NV_DATA_SENSITIVE **tpm_nv_data_sensitive, |
1018 | | TPM_NV_INDEX_ENTRIES *tpm_nv_index_entries, |
1019 | | TPM_NV_INDEX nvIndex) |
1020 | 0 | { |
1021 | 0 | TPM_RESULT rc = 0; |
1022 | 0 | size_t i; |
1023 | 0 | TPM_BOOL found; |
1024 | | |
1025 | 0 | printf(" TPM_NVIndexEntries_GetEntry: Getting NV index %08x in %u slots\n", |
1026 | 0 | nvIndex, tpm_nv_index_entries->nvIndexCount); |
1027 | | /* for debug tracing */ |
1028 | 0 | for (i = 0 ; i < tpm_nv_index_entries->nvIndexCount ; i++) { |
1029 | 0 | *tpm_nv_data_sensitive = &(tpm_nv_index_entries->tpm_nvindex_entry[i]); |
1030 | 0 | printf(" TPM_NVIndexEntries_GetEntry: slot %lu entry %08x\n", |
1031 | 0 | (unsigned long)i, (*tpm_nv_data_sensitive)->pubInfo.nvIndex); |
1032 | 0 | } |
1033 | | /* check for the special index that indicates an empty entry */ |
1034 | 0 | if (rc == 0) { |
1035 | 0 | if (nvIndex == TPM_NV_INDEX_LOCK) { |
1036 | 0 | rc = TPM_BADINDEX; |
1037 | 0 | } |
1038 | 0 | } |
1039 | 0 | for (i = 0 , found = FALSE ; |
1040 | 0 | (rc == 0) && (i < tpm_nv_index_entries->nvIndexCount) && !found ; |
1041 | 0 | i++) { |
1042 | |
|
1043 | 0 | *tpm_nv_data_sensitive = &(tpm_nv_index_entries->tpm_nvindex_entry[i]); |
1044 | 0 | if ((*tpm_nv_data_sensitive)->pubInfo.nvIndex == nvIndex) { |
1045 | 0 | printf(" TPM_NVIndexEntries_GetEntry: Found NV index at slot %lu\n", (unsigned long)i); |
1046 | 0 | printf(" TPM_NVIndexEntries_GetEntry: permission %08x dataSize %u\n", |
1047 | 0 | (*tpm_nv_data_sensitive)->pubInfo.permission.attributes, |
1048 | 0 | (*tpm_nv_data_sensitive)->pubInfo.dataSize); |
1049 | 0 | printf(" TPM_NVIndexEntries_GetEntry: " |
1050 | 0 | "bReadSTClear %02x bWriteSTClear %02x bWriteDefine %02x\n", |
1051 | 0 | (*tpm_nv_data_sensitive)->pubInfo.bReadSTClear, |
1052 | 0 | (*tpm_nv_data_sensitive)->pubInfo.bWriteSTClear, |
1053 | 0 | (*tpm_nv_data_sensitive)->pubInfo.bWriteDefine); |
1054 | 0 | found = TRUE; |
1055 | 0 | } |
1056 | 0 | } |
1057 | 0 | if (rc == 0) { |
1058 | 0 | if (!found) { |
1059 | 0 | printf(" TPM_NVIndexEntries_GetEntry: NV index not found\n"); |
1060 | 0 | rc = TPM_BADINDEX; |
1061 | 0 | } |
1062 | 0 | } |
1063 | 0 | return rc; |
1064 | 0 | } |
1065 | | |
1066 | | /* TPM_NVIndexEntries_GetUsedCount() returns the number of used entries in the TPM_NV_INDEX_ENTRIES |
1067 | | array. |
1068 | | |
1069 | | At startup, all entries will be used. If an NV index is deleted, the entryis marked unused, but |
1070 | | the TPM_NV_INDEX_ENTRIES space is not reclaimed until the next startup. |
1071 | | */ |
1072 | | |
1073 | | TPM_RESULT TPM_NVIndexEntries_GetUsedCount(uint32_t *count, |
1074 | | TPM_NV_INDEX_ENTRIES *tpm_nv_index_entries) |
1075 | 0 | { |
1076 | 0 | TPM_RESULT rc = 0; |
1077 | 0 | size_t i; |
1078 | | |
1079 | 0 | *count = 0; |
1080 | 0 | for (i = 0 ; (rc == 0) && (i < tpm_nv_index_entries->nvIndexCount) ; i++) { |
1081 | | /* if the entry is used */ |
1082 | 0 | if (tpm_nv_index_entries->tpm_nvindex_entry[i].pubInfo.nvIndex != TPM_NV_INDEX_LOCK) { |
1083 | 0 | (*count)++; |
1084 | 0 | } |
1085 | 0 | } |
1086 | 0 | printf(" TPM_NVIndexEntries_GetUsedCount: Used count %d in %u slots\n", |
1087 | 0 | *count, tpm_nv_index_entries->nvIndexCount); |
1088 | 0 | return rc; |
1089 | 0 | } |
1090 | | |
1091 | | /* TPM_NVIndexEntries_GetNVList() serializes a list of the used NV indexes into the |
1092 | | TPM_STORE_BUFFER |
1093 | | */ |
1094 | | |
1095 | | TPM_RESULT TPM_NVIndexEntries_GetNVList(TPM_STORE_BUFFER *sbuffer, |
1096 | | TPM_NV_INDEX_ENTRIES *tpm_nv_index_entries) |
1097 | 0 | { |
1098 | 0 | TPM_RESULT rc = 0; |
1099 | 0 | size_t i; |
1100 | |
|
1101 | 0 | printf(" TPM_NVIndexEntries_GetNVList: Creating list from %u slots\n", |
1102 | 0 | tpm_nv_index_entries->nvIndexCount); |
1103 | | |
1104 | 0 | for (i = 0 ; (rc == 0) && (i < tpm_nv_index_entries->nvIndexCount) ; i++) { |
1105 | | /* if the entry is used */ |
1106 | 0 | if (tpm_nv_index_entries->tpm_nvindex_entry[i].pubInfo.nvIndex != TPM_NV_INDEX_LOCK) { |
1107 | 0 | rc = TPM_Sbuffer_Append32(sbuffer, |
1108 | 0 | tpm_nv_index_entries->tpm_nvindex_entry[i].pubInfo.nvIndex); |
1109 | 0 | } |
1110 | 0 | } |
1111 | 0 | return rc; |
1112 | 0 | } |
1113 | | |
1114 | | /* TPM_NVIndexEntries_GetUsedSpace() gets the NV space consumed by NV defined space indexes. |
1115 | | |
1116 | | It does it inefficiently but reliably by serializing the structure with the same function used |
1117 | | when writing to NV storage. |
1118 | | */ |
1119 | | |
1120 | | TPM_RESULT TPM_NVIndexEntries_GetUsedSpace(uint32_t *usedSpace, |
1121 | | TPM_NV_INDEX_ENTRIES *tpm_nv_index_entries) |
1122 | 0 | { |
1123 | 0 | TPM_RESULT rc = 0; |
1124 | 0 | TPM_STORE_BUFFER sbuffer; |
1125 | 0 | const unsigned char *buffer; |
1126 | | |
1127 | 0 | printf(" TPM_NVIndexEntries_GetUsedSpace:\n"); |
1128 | 0 | TPM_Sbuffer_Init(&sbuffer); /* freed @1 */ |
1129 | | /* serialize NV defined space */ |
1130 | 0 | if (rc == 0) { |
1131 | 0 | rc = TPM_NVIndexEntries_Store(&sbuffer, tpm_nv_index_entries); |
1132 | 0 | } |
1133 | | /* get the serialized buffer and its length */ |
1134 | 0 | if (rc == 0) { |
1135 | 0 | TPM_Sbuffer_Get(&sbuffer, &buffer, usedSpace); |
1136 | 0 | printf(" TPM_NVIndexEntries_GetUsedSpace: Used space %u\n", *usedSpace); |
1137 | 0 | } |
1138 | 0 | TPM_Sbuffer_Delete(&sbuffer); /* @1 */ |
1139 | 0 | return rc; |
1140 | 0 | } |
1141 | | |
1142 | | /* TPM_NVIndexEntries_GetFreeSpace() gets the total free NV defined space. |
1143 | | |
1144 | | When defining an index, not all can be used for data, as some is consumed by metadata such as |
1145 | | authorization and the index number. |
1146 | | */ |
1147 | | |
1148 | | TPM_RESULT TPM_NVIndexEntries_GetFreeSpace(uint32_t *freeSpace, |
1149 | | TPM_NV_INDEX_ENTRIES *tpm_nv_index_entries) |
1150 | 0 | { |
1151 | 0 | TPM_RESULT rc = 0; |
1152 | 0 | uint32_t usedSpace; |
1153 | |
|
1154 | 0 | printf(" TPM_NVIndexEntries_GetFreeSpace:\n"); |
1155 | | /* get the used space */ |
1156 | 0 | if (rc == 0) { |
1157 | 0 | rc = TPM_NVIndexEntries_GetUsedSpace(&usedSpace, tpm_nv_index_entries); |
1158 | 0 | } |
1159 | | /* sanity check */ |
1160 | 0 | if (rc == 0) { |
1161 | 0 | if (usedSpace > TPM_MAX_NV_DEFINED_SIZE) { |
1162 | 0 | printf("TPM_NVIndexEntries_GetFreeSpace: used %u greater than max %u\n", |
1163 | 0 | usedSpace, TPM_MAX_NV_DEFINED_SIZE); |
1164 | 0 | rc = TPM_NOSPACE; |
1165 | 0 | } |
1166 | 0 | } |
1167 | | /* calculate the free space */ |
1168 | 0 | if (rc == 0) { |
1169 | 0 | *freeSpace = TPM_MAX_NV_DEFINED_SIZE - usedSpace; |
1170 | 0 | printf(" TPM_NVIndexEntries_GetFreeSpace: Free space %u\n", *freeSpace); |
1171 | 0 | } |
1172 | 0 | return rc; |
1173 | 0 | } |
1174 | | |
1175 | | /* TPM_OwnerClear: rev 99 |
1176 | | 12. The TPM MUST deallocate all defined NV storage areas where |
1177 | | a. TPM_NV_PER_OWNERWRITE is TRUE if nvIndex does not have the "D" bit set |
1178 | | b. TPM_NV_PER_OWNERREAD is TRUE if nvIndex does not have the "D" bit set |
1179 | | c. The TPM MUST NOT deallocate any other currently defined NV storage areas. |
1180 | | |
1181 | | TPM_RevokeTrust: a. NV items with the pubInfo -> nvIndex D value set MUST be deleted. This |
1182 | | changes the TPM_OwnerClear handling of the same NV areas |
1183 | | |
1184 | | If deleteAllNvram is TRUE, all NVRAM is deleted. If it is FALSE, indexes with the D bit set are |
1185 | | not cleared. |
1186 | | |
1187 | | The write to NV space is done bu the caller. |
1188 | | */ |
1189 | | |
1190 | | TPM_RESULT TPM_NVIndexEntries_DeleteOwnerAuthorized(TPM_NV_INDEX_ENTRIES *tpm_nv_index_entries, |
1191 | | TPM_BOOL deleteAllNvram) |
1192 | 0 | { |
1193 | 0 | TPM_RESULT rc = 0; |
1194 | 0 | size_t i; |
1195 | 0 | TPM_NV_DATA_SENSITIVE *tpm_nv_data_sensitive; /* an entry in the array */ |
1196 | | |
1197 | 0 | printf(" TPM_NVIndexEntries_DeleteOwnerAuthorized: Deleting from %u slots\n", |
1198 | 0 | tpm_nv_index_entries->nvIndexCount); |
1199 | 0 | for (i = 0 ; i < tpm_nv_index_entries->nvIndexCount ; i++) { |
1200 | | /* get an entry in the array */ |
1201 | 0 | tpm_nv_data_sensitive = &(tpm_nv_index_entries->tpm_nvindex_entry[i]); |
1202 | | |
1203 | | /* if the index is in use */ |
1204 | 0 | if (tpm_nv_data_sensitive->pubInfo.nvIndex != TPM_NV_INDEX_LOCK) { |
1205 | | /* if TPM_NV_PER_OWNERWRITE or TPM_NV_PER_OWNERREAD and nvIndex does not have the "D" |
1206 | | bit set */ |
1207 | 0 | if ((tpm_nv_data_sensitive->pubInfo.permission.attributes & TPM_NV_PER_OWNERWRITE) || |
1208 | 0 | (tpm_nv_data_sensitive->pubInfo.permission.attributes & TPM_NV_PER_OWNERREAD)) { |
1209 | 0 | if (!(tpm_nv_data_sensitive->pubInfo.nvIndex & TPM_NV_INDEX_D_BIT) || |
1210 | 0 | deleteAllNvram) { |
1211 | | /* delete the index */ |
1212 | 0 | printf(" TPM_NVIndexEntries_DeleteOwnerAuthorized: Deleting NV index %08x\n", |
1213 | 0 | tpm_nv_data_sensitive->pubInfo.nvIndex); |
1214 | 0 | TPM_NVDataSensitive_Delete(tpm_nv_data_sensitive); |
1215 | 0 | } |
1216 | 0 | } |
1217 | 0 | } |
1218 | 0 | } |
1219 | 0 | return rc; |
1220 | 0 | } |
1221 | | |
1222 | | /* TPM_NVIndexEntries_GetDataPublic() returns the TPM_NV_DATA_PUBLIC corresponding to the nvIndex |
1223 | | */ |
1224 | | |
1225 | | TPM_RESULT TPM_NVIndexEntries_GetDataPublic(TPM_NV_DATA_PUBLIC **tpm_nv_data_public, |
1226 | | TPM_NV_INDEX_ENTRIES *tpm_nv_index_entries, |
1227 | | TPM_NV_INDEX nvIndex) |
1228 | 0 | { |
1229 | 0 | TPM_RESULT rc = 0; |
1230 | 0 | TPM_NV_DATA_SENSITIVE *tpm_nv_data_sensitive; |
1231 | | |
1232 | 0 | printf(" TPM_NVIndexEntries_GetDataPublic: Getting data at NV index %08x\n", nvIndex); |
1233 | 0 | if (rc == 0) { |
1234 | 0 | rc = TPM_NVIndexEntries_GetEntry(&tpm_nv_data_sensitive, |
1235 | 0 | tpm_nv_index_entries, |
1236 | 0 | nvIndex); |
1237 | 0 | } |
1238 | 0 | if (rc == 0) { |
1239 | 0 | *tpm_nv_data_public = &(tpm_nv_data_sensitive->pubInfo); |
1240 | 0 | } |
1241 | 0 | return rc; |
1242 | 0 | } |
1243 | | |
1244 | | /* |
1245 | | Command Processing Functions |
1246 | | */ |
1247 | | |
1248 | | /* 20.4 TPM_NV_ReadValue rev 114 |
1249 | | |
1250 | | Read a value from the NV store. This command uses optional owner authorization. |
1251 | | |
1252 | | Action 1 indicates that if the NV area is not locked then reading of the NV area continues |
1253 | | without ANY authorization. This is intentional, and allows a platform manufacturer to set the NV |
1254 | | areas, read them back, and then lock them all without having to install a TPM owner. |
1255 | | */ |
1256 | | |
1257 | | TPM_RESULT TPM_Process_NVReadValue(tpm_state_t *tpm_state, |
1258 | | TPM_STORE_BUFFER *response, |
1259 | | TPM_TAG tag, |
1260 | | uint32_t paramSize, |
1261 | | TPM_COMMAND_CODE ordinal, |
1262 | | unsigned char *command, |
1263 | | TPM_TRANSPORT_INTERNAL *transportInternal) |
1264 | 0 | { |
1265 | 0 | TPM_RESULT rcf = 0; /* fatal error precluding response */ |
1266 | 0 | TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ |
1267 | | |
1268 | | /* input parameters */ |
1269 | 0 | TPM_NV_INDEX nvIndex; /* The index of the area to set */ |
1270 | 0 | uint32_t offset = 0; /* The offset into the area */ |
1271 | 0 | uint32_t dataSize = 0; /* The size of the data area */ |
1272 | 0 | TPM_AUTHHANDLE authHandle; /* The authorization handle used for TPM Owner |
1273 | | authorization */ |
1274 | 0 | TPM_NONCE nonceOdd; /* Nonce generated by caller */ |
1275 | 0 | TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the authorization |
1276 | | handle */ |
1277 | 0 | TPM_AUTHDATA ownerAuth; /* HMAC key: TPM Owner authorization */ |
1278 | | |
1279 | | /* processing parameters */ |
1280 | 0 | unsigned char * inParamStart; /* starting point of inParam's */ |
1281 | 0 | unsigned char * inParamEnd; /* ending point of inParam's */ |
1282 | 0 | TPM_DIGEST inParamDigest; |
1283 | 0 | TPM_BOOL auditStatus; /* audit the ordinal */ |
1284 | 0 | TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ |
1285 | 0 | TPM_BOOL authHandleValid = FALSE; |
1286 | 0 | TPM_SECRET *hmacKey; |
1287 | 0 | TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ |
1288 | 0 | TPM_BOOL ignore_auth = FALSE; |
1289 | 0 | TPM_BOOL dir = FALSE; |
1290 | 0 | TPM_BOOL physicalPresence; |
1291 | 0 | TPM_BOOL isGPIO = FALSE; |
1292 | 0 | BYTE *gpioData = NULL; |
1293 | 0 | TPM_NV_DATA_SENSITIVE *d1NvdataSensitive = NULL; |
1294 | 0 | uint32_t s1Last; |
1295 | | |
1296 | | /* output parameters */ |
1297 | 0 | uint32_t outParamStart; /* starting point of outParam's */ |
1298 | 0 | uint32_t outParamEnd; /* ending point of outParam's */ |
1299 | 0 | TPM_DIGEST outParamDigest; |
1300 | 0 | TPM_SIZED_BUFFER data; /* The data to set the area to */ |
1301 | |
|
1302 | 0 | printf("TPM_Process_NVReadValue: Ordinal Entry\n"); |
1303 | 0 | TPM_SizedBuffer_Init(&data); /* freed @1 */ |
1304 | | /* |
1305 | | get inputs |
1306 | | */ |
1307 | | /* save the starting point of inParam's for authorization and auditing */ |
1308 | 0 | inParamStart = command; |
1309 | | /* get nvIndex parameter */ |
1310 | 0 | if (returnCode == TPM_SUCCESS) { |
1311 | 0 | returnCode = TPM_Load32(&nvIndex, &command, ¶mSize); |
1312 | 0 | } |
1313 | | /* get offset parameter */ |
1314 | 0 | if (returnCode == TPM_SUCCESS) { |
1315 | 0 | returnCode = TPM_Load32(&offset, &command, ¶mSize); |
1316 | 0 | } |
1317 | | /* get dataSize parameter */ |
1318 | 0 | if (returnCode == TPM_SUCCESS) { |
1319 | 0 | returnCode = TPM_Load32(&dataSize, &command, ¶mSize); |
1320 | 0 | } |
1321 | | /* save the ending point of inParam's for authorization and auditing */ |
1322 | 0 | inParamEnd = command; |
1323 | | /* digest the input parameters */ |
1324 | 0 | if (returnCode == TPM_SUCCESS) { |
1325 | 0 | returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ |
1326 | 0 | &auditStatus, /* output */ |
1327 | 0 | &transportEncrypt, /* output */ |
1328 | 0 | tpm_state, |
1329 | 0 | tag, |
1330 | 0 | ordinal, |
1331 | 0 | inParamStart, |
1332 | 0 | inParamEnd, |
1333 | 0 | transportInternal); |
1334 | 0 | } |
1335 | | /* check state */ |
1336 | 0 | if (returnCode == TPM_SUCCESS) { |
1337 | 0 | returnCode = TPM_CheckState(tpm_state, tag, (TPM_CHECK_NOT_SHUTDOWN | |
1338 | 0 | TPM_CHECK_NO_LOCKOUT | |
1339 | 0 | TPM_CHECK_NV_NOAUTH)); |
1340 | 0 | } |
1341 | | /* check tag */ |
1342 | 0 | if (returnCode == TPM_SUCCESS) { |
1343 | 0 | returnCode = TPM_CheckRequestTag10(tag); |
1344 | 0 | } |
1345 | | /* get the optional 'below the line' authorization parameters */ |
1346 | 0 | if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { |
1347 | 0 | returnCode = TPM_AuthParams_Get(&authHandle, |
1348 | 0 | &authHandleValid, |
1349 | 0 | nonceOdd, |
1350 | 0 | &continueAuthSession, |
1351 | 0 | ownerAuth, |
1352 | 0 | &command, ¶mSize); |
1353 | 0 | } |
1354 | 0 | if (returnCode == TPM_SUCCESS) { |
1355 | 0 | if (paramSize != 0) { |
1356 | 0 | printf("TPM_Process_NVReadValue: Error, command has %u extra bytes\n", |
1357 | 0 | paramSize); |
1358 | 0 | returnCode = TPM_BAD_PARAM_SIZE; |
1359 | 0 | } |
1360 | 0 | } |
1361 | | /* do not terminate sessions if the command did not parse correctly */ |
1362 | 0 | if (returnCode != TPM_SUCCESS) { |
1363 | 0 | authHandleValid = FALSE; |
1364 | 0 | } |
1365 | | /* |
1366 | | Processing |
1367 | | */ |
1368 | | /* 1. If TPM_PERMANENT_FLAGS -> nvLocked is FALSE then all authorization checks are |
1369 | | ignored */ |
1370 | | /* a. Ignored checks include physical presence, owner authorization, PCR, bReadSTClear, |
1371 | | locality, TPM_NV_PER_OWNERREAD, disabled and deactivated */ |
1372 | | /* b. TPM_NV_PER_AUTHREAD is not ignored. */ |
1373 | | /* c. If ownerAuth is present, the TPM MAY check the authorization HMAC. */ |
1374 | 0 | if (returnCode == TPM_SUCCESS) { |
1375 | 0 | printf("TPM_Process_NVReadValue: index %08x offset %u dataSize %u\n", |
1376 | 0 | nvIndex, offset, dataSize); |
1377 | 0 | if (!(tpm_state->tpm_permanent_flags.nvLocked)) { |
1378 | 0 | printf("TPM_Process_NVReadValue: nvLocked FALSE, ignoring authorization\n"); |
1379 | 0 | ignore_auth = TRUE; |
1380 | 0 | } |
1381 | | /* determine whether the nvIndex is legal GPIO space */ |
1382 | 0 | if (returnCode == 0) { |
1383 | 0 | returnCode = TPM_NVDataSensitive_IsGPIO(&isGPIO, nvIndex); |
1384 | 0 | } |
1385 | 0 | } |
1386 | | /* 2. Set D1 a TPM_NV_DATA_AREA structure to the area pointed to by nvIndex, if not found |
1387 | | return TPM_BADINDEX */ |
1388 | 0 | if (returnCode == TPM_SUCCESS) { |
1389 | | /* a. If nvIndex = TPM_NV_INDEX_DIR, set D1 to TPM_PERMANENT_DATA -> authDir[0] */ |
1390 | 0 | if (nvIndex == TPM_NV_INDEX_DIR) { |
1391 | 0 | printf("TPM_Process_NVReadValue: Reading DIR\n"); |
1392 | 0 | dir = TRUE; |
1393 | 0 | } |
1394 | 0 | else { |
1395 | 0 | printf("TPM_Process_NVReadValue: Loading data from NVRAM\n"); |
1396 | 0 | returnCode = TPM_NVIndexEntries_GetEntry(&d1NvdataSensitive, |
1397 | 0 | &(tpm_state->tpm_nv_index_entries), |
1398 | 0 | nvIndex); |
1399 | 0 | if (returnCode != 0) { |
1400 | 0 | printf("TPM_Process_NVReadValue: Error, NV index %08x not found\n", nvIndex); |
1401 | 0 | } |
1402 | 0 | } |
1403 | 0 | } |
1404 | | /* Do not check permission for DIR, DIR is no-auth */ |
1405 | 0 | if ((returnCode == TPM_SUCCESS) && !dir) { |
1406 | | /* 3. If TPM_PERMANENT_FLAGS -> nvLocked is TRUE */ |
1407 | 0 | if (tpm_state->tpm_permanent_flags.nvLocked) { |
1408 | | /* a. If D1 -> permission -> TPM_NV_PER_OWNERREAD is TRUE */ |
1409 | 0 | if (d1NvdataSensitive->pubInfo.permission.attributes & TPM_NV_PER_OWNERREAD) { |
1410 | | /* i. If TPM_PERMANENT_FLAGS -> disable is TRUE, return TPM_DISABLED */ |
1411 | 0 | if (tpm_state->tpm_permanent_flags.disable) { |
1412 | 0 | printf("TPM_Process_NVReadValue: Error, disabled\n"); |
1413 | 0 | return TPM_DISABLED; |
1414 | 0 | } |
1415 | | /* ii. If TPM_STCLEAR_FLAGS -> deactivated is TRUE, return TPM_DEACTIVATED */ |
1416 | 0 | else if (tpm_state->tpm_stclear_flags.deactivated) { |
1417 | 0 | printf("TPM_Process_NVReadValue: Error, deactivated\n"); |
1418 | 0 | return TPM_DEACTIVATED;; |
1419 | 0 | } |
1420 | 0 | } |
1421 | | /* NOTE: Intel software requires NV access disabled and deactivated */ |
1422 | | /* b. If D1 -> permission -> TPM_NV_PER_OWNERREAD is FALSE */ |
1423 | | /* i. If TPM_PERMANENT_FLAGS -> disable is TRUE, the TPM MAY return TPM_DISABLED */ |
1424 | | /* ii. If TPM_STCLEAR_FLAGS -> deactivated is TRUE, the TPM MAY return |
1425 | | TPM_DEACTIVATED */ |
1426 | 0 | } |
1427 | 0 | } |
1428 | | /* 4. If tag = TPM_TAG_RQU_AUTH1_COMMAND then */ |
1429 | | /* NOTE: This is optional if ignore_auth is TRUE */ |
1430 | 0 | if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND) && !dir) { |
1431 | | /* a. If D1 -> TPM_NV_PER_OWNERREAD is FALSE return TPM_AUTH_CONFLICT */ |
1432 | 0 | if (!(d1NvdataSensitive->pubInfo.permission.attributes & TPM_NV_PER_OWNERREAD)) { |
1433 | 0 | printf("TPM_Process_NVReadValue: Error, " |
1434 | 0 | "owner authorization conflict, attributes %08x\n", |
1435 | 0 | d1NvdataSensitive->pubInfo.permission.attributes); |
1436 | 0 | returnCode = TPM_AUTH_CONFLICT; |
1437 | 0 | } |
1438 | 0 | } |
1439 | | /* b. Validate command and parameters using TPM Owners authorization on error return |
1440 | | TPM_AUTHFAIL */ |
1441 | 0 | if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { |
1442 | 0 | returnCode = TPM_AuthSessions_GetData(&auth_session_data, |
1443 | 0 | &hmacKey, |
1444 | 0 | tpm_state, |
1445 | 0 | authHandle, |
1446 | 0 | TPM_PID_NONE, |
1447 | 0 | TPM_ET_OWNER, |
1448 | 0 | ordinal, |
1449 | 0 | NULL, |
1450 | 0 | &(tpm_state->tpm_permanent_data.ownerAuth), /* OIAP */ |
1451 | 0 | tpm_state->tpm_permanent_data.ownerAuth); /* OSAP */ |
1452 | 0 | } |
1453 | 0 | if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND) && !ignore_auth) { |
1454 | 0 | returnCode = TPM_Authdata_Check(tpm_state, |
1455 | 0 | *hmacKey, /* HMAC key */ |
1456 | 0 | inParamDigest, |
1457 | 0 | auth_session_data, /* authorization session */ |
1458 | 0 | nonceOdd, /* Nonce generated by system |
1459 | | associated with authHandle */ |
1460 | 0 | continueAuthSession, |
1461 | 0 | ownerAuth); /* Authorization digest for input */ |
1462 | 0 | } |
1463 | | /* 5. Else */ |
1464 | 0 | if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_COMMAND) && !dir) { |
1465 | | /* a. If D1 -> TPM_NV_PER_AUTHREAD is TRUE return TPM_AUTH_CONFLICT */ |
1466 | 0 | if (d1NvdataSensitive->pubInfo.permission.attributes & TPM_NV_PER_AUTHREAD) { |
1467 | 0 | printf("TPM_Process_NVReadValue: Error, authorization conflict TPM_NV_PER_AUTHREAD\n"); |
1468 | 0 | returnCode = TPM_AUTH_CONFLICT; |
1469 | 0 | } |
1470 | 0 | } |
1471 | | /* b. If D1 -> TPM_NV_PER_OWNERREAD is TRUE return TPM_AUTH_CONFLICT */ |
1472 | 0 | if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_COMMAND) && !ignore_auth && !dir) { |
1473 | 0 | if (d1NvdataSensitive->pubInfo.permission.attributes & TPM_NV_PER_OWNERREAD) { |
1474 | 0 | printf("TPM_Process_NVReadValue: Error, authorization conflict TPM_NV_PER_OWNERREAD\n"); |
1475 | 0 | returnCode = TPM_AUTH_CONFLICT; |
1476 | 0 | } |
1477 | 0 | } |
1478 | | /* 6. Check that D1 -> pcrInfoRead -> localityAtRelease for TPM_STANY_DATA -> localityModifier |
1479 | | is TRUE */ |
1480 | | /* a. For example if TPM_STANY_DATA -> localityModifier was 2 then D1 -> pcrInfo -> |
1481 | | localityAtRelease -> TPM_LOC_TWO would have to be TRUE */ |
1482 | | /* b. On error return TPM_BAD_LOCALITY */ |
1483 | | /* NOTE Done by TPM_PCRInfoShort_CheckDigest() */ |
1484 | | /* 7. If D1 -> attributes specifies TPM_NV_PER_PPREAD then validate physical presence is |
1485 | | asserted if not return TPM_BAD_PRESENCE */ |
1486 | 0 | if ((returnCode == TPM_SUCCESS) && !ignore_auth && !dir) { |
1487 | 0 | if (d1NvdataSensitive->pubInfo.permission.attributes & TPM_NV_PER_PPREAD) { |
1488 | 0 | if (returnCode == TPM_SUCCESS) { |
1489 | 0 | returnCode = TPM_Global_GetPhysicalPresence(&physicalPresence, tpm_state); |
1490 | 0 | } |
1491 | 0 | if (returnCode == TPM_SUCCESS) { |
1492 | 0 | if (!physicalPresence) { |
1493 | 0 | printf("TPM_Process_NVReadValue: Error, physicalPresence is FALSE\n"); |
1494 | 0 | returnCode = TPM_BAD_PRESENCE; |
1495 | 0 | } |
1496 | 0 | } |
1497 | 0 | } |
1498 | 0 | } |
1499 | 0 | if ((returnCode == TPM_SUCCESS) && !ignore_auth && !dir) { |
1500 | | /* 8. If D1 -> TPM_NV_PER_READ_STCLEAR then */ |
1501 | 0 | if ((d1NvdataSensitive->pubInfo.permission.attributes & TPM_NV_PER_READ_STCLEAR) && |
1502 | | /* a. If D1 -> bReadSTClear is TRUE return TPM_DISABLED_CMD */ |
1503 | 0 | (d1NvdataSensitive->pubInfo.bReadSTClear)) { |
1504 | 0 | printf("TPM_Process_NVReadValue: Error, area locked by bReadSTClear\n"); |
1505 | 0 | returnCode = TPM_DISABLED_CMD; |
1506 | 0 | } |
1507 | 0 | } |
1508 | | /* 9. If D1 -> pcrInfoRead -> pcrSelection specifies a selection of PCR */ |
1509 | | /* a. Create P1 a composite hash of the PCR specified by D1 -> pcrInfoRead */ |
1510 | | /* b. Compare P1 to D1 -> pcrInfoRead -> digestAtRelease return TPM_WRONGPCRVAL on |
1511 | | mismatch */ |
1512 | 0 | if ((returnCode == TPM_SUCCESS) && !ignore_auth && !dir) { |
1513 | 0 | returnCode = TPM_PCRInfoShort_CheckDigest(&(d1NvdataSensitive->pubInfo.pcrInfoRead), |
1514 | 0 | tpm_state->tpm_stclear_data.PCRS, |
1515 | 0 | tpm_state->tpm_stany_flags.localityModifier); |
1516 | 0 | } |
1517 | 0 | if (returnCode == TPM_SUCCESS && !dir) { |
1518 | | /* 10. If dataSize is 0 then */ |
1519 | 0 | if (dataSize == 0) { |
1520 | 0 | printf("TPM_Process_NVReadValue: dataSize 0, setting bReadSTClear\n"); |
1521 | | /* a. Set D1 -> bReadSTClear to TRUE */ |
1522 | 0 | d1NvdataSensitive->pubInfo.bReadSTClear = TRUE; |
1523 | | /* b. Set data to NULL (output parameter dataSize to 0) */ |
1524 | | /* NOTE Done by TPM_SizedBuffer_Init */ |
1525 | 0 | } |
1526 | | /* 11. Else (if dataSize is not 0) */ |
1527 | 0 | else { |
1528 | 0 | if (returnCode == TPM_SUCCESS) { |
1529 | | /* a. Set S1 to offset + dataSize */ |
1530 | 0 | s1Last = offset + dataSize; /* set to last data point */ |
1531 | | /* b. If S1 > D1 -> dataSize return TPM_NOSPACE */ |
1532 | 0 | if (s1Last > d1NvdataSensitive->pubInfo.dataSize) { |
1533 | 0 | printf("TPM_Process_NVReadValue: Error, NVRAM dataSize %u\n", |
1534 | 0 | d1NvdataSensitive->pubInfo.dataSize); |
1535 | 0 | returnCode = TPM_NOSPACE; |
1536 | 0 | } |
1537 | 0 | } |
1538 | | /* c. Set data to area pointed to by offset */ |
1539 | 0 | if ((returnCode == TPM_SUCCESS) && !isGPIO) { |
1540 | 0 | TPM_PrintFourLimit("TPM_Process_NVReadValue: read data", |
1541 | 0 | d1NvdataSensitive->data + offset, dataSize); |
1542 | 0 | returnCode = TPM_SizedBuffer_Set(&data, |
1543 | 0 | dataSize, d1NvdataSensitive->data + offset); |
1544 | 0 | } |
1545 | | /* GPIO */ |
1546 | 0 | if ((returnCode == TPM_SUCCESS) && isGPIO) { |
1547 | 0 | returnCode = TPM_Malloc(&gpioData, dataSize); /* freed @2 */ |
1548 | 0 | } |
1549 | 0 | if ((returnCode == TPM_SUCCESS) && isGPIO) { |
1550 | 0 | printf("TPM_Process_NVReadValue: Reading GPIO\n"); |
1551 | 0 | returnCode = TPM_IO_GPIO_Read(nvIndex, |
1552 | 0 | dataSize, |
1553 | 0 | gpioData, |
1554 | 0 | tpm_state->tpm_number); |
1555 | 0 | } |
1556 | 0 | if ((returnCode == TPM_SUCCESS) && isGPIO) { |
1557 | 0 | returnCode = TPM_SizedBuffer_Set(&data, |
1558 | 0 | dataSize, gpioData); |
1559 | 0 | } |
1560 | 0 | } |
1561 | 0 | } |
1562 | | /* DIR read */ |
1563 | 0 | if (returnCode == TPM_SUCCESS && dir) { |
1564 | | /* DIR is hard coded as a TPM_DIRVALUE array */ |
1565 | 0 | if (returnCode == TPM_SUCCESS) { |
1566 | 0 | s1Last = offset + dataSize; /* set to last data point */ |
1567 | 0 | if (s1Last > TPM_DIGEST_SIZE) { |
1568 | 0 | printf("TPM_Process_NVReadValue: Error, NVRAM dataSize %u too small\n", |
1569 | 0 | TPM_DIGEST_SIZE); |
1570 | 0 | returnCode = TPM_NOSPACE; |
1571 | 0 | } |
1572 | 0 | } |
1573 | | /* i.This includes partial reads of TPM_NV_INDEX_DIR. */ |
1574 | 0 | if (returnCode == TPM_SUCCESS) { |
1575 | 0 | printf("TPM_Process_NVReadValue: Copying data\n"); |
1576 | 0 | returnCode = TPM_SizedBuffer_Set(&data, dataSize, |
1577 | 0 | tpm_state->tpm_permanent_data.authDIR + offset); |
1578 | 0 | } |
1579 | 0 | } |
1580 | | /* |
1581 | | response |
1582 | | */ |
1583 | | /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ |
1584 | 0 | if (rcf == 0) { |
1585 | 0 | printf("TPM_Process_NVReadValue: Ordinal returnCode %08x %u\n", |
1586 | 0 | returnCode, returnCode); |
1587 | 0 | rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); |
1588 | 0 | } |
1589 | | /* success response, append the rest of the parameters. */ |
1590 | 0 | if (rcf == 0) { |
1591 | 0 | if (returnCode == TPM_SUCCESS) { |
1592 | | /* checkpoint the beginning of the outParam's */ |
1593 | 0 | outParamStart = response->buffer_current - response->buffer; |
1594 | | /* return data */ |
1595 | 0 | returnCode = TPM_SizedBuffer_Store(response, &data); |
1596 | | /* checkpoint the end of the outParam's */ |
1597 | 0 | outParamEnd = response->buffer_current - response->buffer; |
1598 | 0 | } |
1599 | | /* digest the above the line output parameters */ |
1600 | 0 | if (returnCode == TPM_SUCCESS) { |
1601 | 0 | returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ |
1602 | 0 | auditStatus, /* input audit status */ |
1603 | 0 | transportEncrypt, |
1604 | 0 | tag, |
1605 | 0 | returnCode, |
1606 | 0 | ordinal, /* command ordinal */ |
1607 | 0 | response->buffer + outParamStart, /* start */ |
1608 | 0 | outParamEnd - outParamStart); /* length */ |
1609 | 0 | } |
1610 | | /* calculate and set the below the line parameters */ |
1611 | 0 | if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { |
1612 | 0 | returnCode = TPM_AuthParams_Set(response, |
1613 | 0 | *hmacKey, /* owner HMAC key */ |
1614 | 0 | auth_session_data, |
1615 | 0 | outParamDigest, |
1616 | 0 | nonceOdd, |
1617 | 0 | continueAuthSession); |
1618 | 0 | } |
1619 | | /* audit if required */ |
1620 | 0 | if ((returnCode == TPM_SUCCESS) && auditStatus) { |
1621 | 0 | returnCode = TPM_ProcessAudit(tpm_state, |
1622 | 0 | transportEncrypt, |
1623 | 0 | inParamDigest, |
1624 | 0 | outParamDigest, |
1625 | 0 | ordinal); |
1626 | 0 | } |
1627 | | /* adjust the initial response */ |
1628 | 0 | rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); |
1629 | 0 | } |
1630 | | /* if there was an error, or continueAuthSession is FALSE, terminate the session */ |
1631 | 0 | if (((rcf != 0) || |
1632 | 0 | ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || |
1633 | 0 | !continueAuthSession) && |
1634 | 0 | authHandleValid) { |
1635 | 0 | TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); |
1636 | 0 | } |
1637 | | /* |
1638 | | cleanup |
1639 | | */ |
1640 | 0 | TPM_SizedBuffer_Delete(&data); /* @1 */ |
1641 | 0 | free(gpioData); /* @2 */ |
1642 | 0 | return rcf; |
1643 | 0 | } |
1644 | | |
1645 | | /* 20.5 TPM_NV_ReadValueAuth rev 87 |
1646 | | |
1647 | | This command requires that the read be authorized by a value set with the blob. |
1648 | | */ |
1649 | | |
1650 | | TPM_RESULT TPM_Process_NVReadValueAuth(tpm_state_t *tpm_state, |
1651 | | TPM_STORE_BUFFER *response, |
1652 | | TPM_TAG tag, |
1653 | | uint32_t paramSize, |
1654 | | TPM_COMMAND_CODE ordinal, |
1655 | | unsigned char *command, |
1656 | | TPM_TRANSPORT_INTERNAL *transportInternal) |
1657 | 0 | { |
1658 | 0 | TPM_RESULT rcf = 0; /* fatal error precluding response */ |
1659 | 0 | TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ |
1660 | | |
1661 | | /* input parameters */ |
1662 | 0 | TPM_NV_INDEX nvIndex; /* The index of the area to set */ |
1663 | 0 | uint32_t offset = 0; /* The offset from the data area */ |
1664 | 0 | uint32_t dataSize = 0; /* The size of the data area */ |
1665 | 0 | TPM_AUTHHANDLE authHandle; /* The auth handle for the NV element authorization */ |
1666 | 0 | TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ |
1667 | 0 | TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the authorization |
1668 | | handle */ |
1669 | 0 | TPM_AUTHDATA authHmac; /* HMAC key: nv element authorization */ |
1670 | | |
1671 | | /* processing parameters */ |
1672 | 0 | unsigned char * inParamStart; /* starting point of inParam's */ |
1673 | 0 | unsigned char * inParamEnd; /* ending point of inParam's */ |
1674 | 0 | TPM_DIGEST inParamDigest; |
1675 | 0 | TPM_BOOL auditStatus; /* audit the ordinal */ |
1676 | 0 | TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ |
1677 | 0 | TPM_BOOL authHandleValid = FALSE; |
1678 | 0 | TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ |
1679 | 0 | TPM_SECRET *hmacKey; |
1680 | 0 | TPM_NV_DATA_SENSITIVE *d1NvdataSensitive; |
1681 | 0 | uint32_t s1Last; |
1682 | 0 | TPM_BOOL physicalPresence; |
1683 | 0 | TPM_BOOL isGPIO; |
1684 | 0 | BYTE *gpioData = NULL; |
1685 | | |
1686 | | /* output parameters */ |
1687 | 0 | uint32_t outParamStart; /* starting point of outParam's */ |
1688 | 0 | uint32_t outParamEnd; /* ending point of outParam's */ |
1689 | 0 | TPM_DIGEST outParamDigest; |
1690 | 0 | TPM_SIZED_BUFFER data; /* The data */ |
1691 | |
|
1692 | 0 | printf("TPM_Process_NVReadValueAuth: Ordinal Entry\n"); |
1693 | 0 | TPM_SizedBuffer_Init(&data); /* freed @1 */ |
1694 | | /* |
1695 | | get inputs |
1696 | | */ |
1697 | | /* save the starting point of inParam's for authorization and auditing */ |
1698 | 0 | inParamStart = command; |
1699 | | /* get nvIndex parameter */ |
1700 | 0 | if (returnCode == TPM_SUCCESS) { |
1701 | 0 | returnCode = TPM_Load32(&nvIndex, &command, ¶mSize); |
1702 | 0 | } |
1703 | | /* get offset parameter */ |
1704 | 0 | if (returnCode == TPM_SUCCESS) { |
1705 | 0 | returnCode = TPM_Load32(&offset, &command, ¶mSize); |
1706 | 0 | } |
1707 | | /* get dataSize parameter */ |
1708 | 0 | if (returnCode == TPM_SUCCESS) { |
1709 | 0 | returnCode = TPM_Load32(&dataSize, &command, ¶mSize); |
1710 | 0 | } |
1711 | | /* save the ending point of inParam's for authorization and auditing */ |
1712 | 0 | inParamEnd = command; |
1713 | | /* digest the input parameters */ |
1714 | 0 | if (returnCode == TPM_SUCCESS) { |
1715 | 0 | returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ |
1716 | 0 | &auditStatus, /* output */ |
1717 | 0 | &transportEncrypt, /* output */ |
1718 | 0 | tpm_state, |
1719 | 0 | tag, |
1720 | 0 | ordinal, |
1721 | 0 | inParamStart, |
1722 | 0 | inParamEnd, |
1723 | 0 | transportInternal); |
1724 | 0 | } |
1725 | | /* check state */ |
1726 | 0 | if (returnCode == TPM_SUCCESS) { |
1727 | 0 | returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL); |
1728 | 0 | } |
1729 | | /* check tag */ |
1730 | 0 | if (returnCode == TPM_SUCCESS) { |
1731 | 0 | returnCode = TPM_CheckRequestTag1(tag); |
1732 | 0 | } |
1733 | | /* get the 'below the line' authorization parameters */ |
1734 | 0 | if (returnCode == TPM_SUCCESS) { |
1735 | 0 | returnCode = TPM_AuthParams_Get(&authHandle, |
1736 | 0 | &authHandleValid, |
1737 | 0 | nonceOdd, |
1738 | 0 | &continueAuthSession, |
1739 | 0 | authHmac, |
1740 | 0 | &command, ¶mSize); |
1741 | 0 | } |
1742 | 0 | if (returnCode == TPM_SUCCESS) { |
1743 | 0 | if (paramSize != 0) { |
1744 | 0 | printf("TPM_Process_NVReadValueAuth: Error, command has %u extra bytes\n", |
1745 | 0 | paramSize); |
1746 | 0 | returnCode = TPM_BAD_PARAM_SIZE; |
1747 | 0 | } |
1748 | 0 | } |
1749 | | /* do not terminate sessions if the command did not parse correctly */ |
1750 | 0 | if (returnCode != TPM_SUCCESS) { |
1751 | 0 | authHandleValid = FALSE; |
1752 | 0 | } |
1753 | | /* |
1754 | | Processing |
1755 | | */ |
1756 | | /* determine whether the nvIndex is legal GPIO space */ |
1757 | 0 | if (returnCode == 0) { |
1758 | 0 | returnCode = TPM_NVDataSensitive_IsGPIO(&isGPIO, nvIndex); |
1759 | 0 | } |
1760 | | /* 1. Locate and set D1 to the TPM_NV_DATA_AREA that corresponds to nvIndex, on error return |
1761 | | TPM_BAD_INDEX */ |
1762 | 0 | if (returnCode == TPM_SUCCESS) { |
1763 | 0 | printf("TPM_Process_NVReadValueAuth: index %08x offset %u dataSize %u\n", |
1764 | 0 | nvIndex, offset, dataSize); |
1765 | 0 | printf("TPM_Process_NVReadValueAuth: Loading data from NVRAM\n"); |
1766 | 0 | returnCode = TPM_NVIndexEntries_GetEntry(&d1NvdataSensitive, |
1767 | 0 | &(tpm_state->tpm_nv_index_entries), |
1768 | 0 | nvIndex); |
1769 | 0 | if (returnCode != 0) { |
1770 | 0 | printf("TPM_Process_NVReadValueAuth: Error, NV index %08x not found\n", nvIndex); |
1771 | 0 | } |
1772 | 0 | } |
1773 | | /* 2. If D1 -> TPM_NV_PER_AUTHREAD is FALSE return TPM_AUTH_CONFLICT */ |
1774 | 0 | if (returnCode == TPM_SUCCESS) { |
1775 | 0 | if (!(d1NvdataSensitive->pubInfo.permission.attributes & TPM_NV_PER_AUTHREAD)) { |
1776 | 0 | printf("TPM_Process_NVReadValueAuth: Error, authorization conflict\n"); |
1777 | 0 | returnCode = TPM_AUTH_CONFLICT; |
1778 | 0 | } |
1779 | 0 | } |
1780 | | /* 3. Validate authHmac using D1 -> authValue on error return TPM_AUTHFAIL */ |
1781 | 0 | if (returnCode == TPM_SUCCESS) { |
1782 | 0 | returnCode = TPM_AuthSessions_GetData(&auth_session_data, |
1783 | 0 | &hmacKey, |
1784 | 0 | tpm_state, |
1785 | 0 | authHandle, |
1786 | 0 | TPM_PID_NONE, |
1787 | 0 | TPM_ET_NV, |
1788 | 0 | ordinal, |
1789 | 0 | NULL, |
1790 | 0 | &(d1NvdataSensitive->authValue), /* OIAP */ |
1791 | 0 | d1NvdataSensitive->digest); /* OSAP */ |
1792 | 0 | } |
1793 | 0 | if (returnCode == TPM_SUCCESS) { |
1794 | 0 | returnCode = TPM_Authdata_Check(tpm_state, |
1795 | 0 | *hmacKey, /* HMAC key */ |
1796 | 0 | inParamDigest, |
1797 | 0 | auth_session_data, /* authorization session */ |
1798 | 0 | nonceOdd, /* Nonce generated by system |
1799 | | associated with authHandle */ |
1800 | 0 | continueAuthSession, |
1801 | 0 | authHmac); /* Authorization digest for input */ |
1802 | 0 | } |
1803 | | /* 4. If D1 -> attributes specifies TPM_NV_PER_PPREAD then validate physical presence is |
1804 | | asserted if not return TPM_BAD_PRESENCE */ |
1805 | 0 | if (returnCode == TPM_SUCCESS) { |
1806 | 0 | if (d1NvdataSensitive->pubInfo.permission.attributes & TPM_NV_PER_PPREAD) { |
1807 | 0 | if (returnCode == TPM_SUCCESS) { |
1808 | 0 | returnCode = TPM_Global_GetPhysicalPresence(&physicalPresence, tpm_state); |
1809 | 0 | } |
1810 | 0 | if (returnCode == TPM_SUCCESS) { |
1811 | 0 | if (!physicalPresence) { |
1812 | 0 | printf("TPM_Process_NVReadValueAuth: Error, physicalPresence is FALSE\n"); |
1813 | 0 | returnCode = TPM_BAD_PRESENCE; |
1814 | 0 | } |
1815 | 0 | } |
1816 | 0 | } |
1817 | 0 | } |
1818 | | /* 5. Check that D1 -> pcrInfoRead -> localityAtRelease for TPM_STANY_DATA -> localityModifier |
1819 | | is TRUE */ |
1820 | | /* a. For example if TPM_STANY_DATA -> localityModifier was 2 then D1 -> pcrInfo -> |
1821 | | localityAtRelease -> TPM_LOC_TWO would have to be TRUE */ |
1822 | | /* b. On error return TPM_BAD_LOCALITY */ |
1823 | | /* 6. If D1 -> pcrInfoRead -> pcrSelection specifies a selection of PCR */ |
1824 | | /* a. Create P1 a composite hash of the PCR specified by D1 -> pcrInfoRead */ |
1825 | | /* b. Compare P1 to D1 -> pcrInfoRead -> digestAtRelease return TPM_WRONGPCRVAL on |
1826 | | mismatch */ |
1827 | 0 | if (returnCode == TPM_SUCCESS) { |
1828 | 0 | returnCode = TPM_PCRInfoShort_CheckDigest(&(d1NvdataSensitive->pubInfo.pcrInfoRead), |
1829 | 0 | tpm_state->tpm_stclear_data.PCRS, |
1830 | 0 | tpm_state->tpm_stany_flags.localityModifier); |
1831 | 0 | } |
1832 | 0 | if (returnCode == TPM_SUCCESS) { |
1833 | | /* 7. If D1 specifies TPM_NV_PER_READ_STCLEAR then */ |
1834 | 0 | if ((d1NvdataSensitive->pubInfo.permission.attributes & TPM_NV_PER_READ_STCLEAR) && |
1835 | | /* a. If D1 -> bReadSTClear is TRUE return TPM_DISABLED_CMD */ |
1836 | 0 | (d1NvdataSensitive->pubInfo.bReadSTClear)) { |
1837 | 0 | printf("TPM_Process_NVReadValueAuth: Error, area locked by bReadSTClear\n"); |
1838 | 0 | returnCode = TPM_DISABLED_CMD; |
1839 | 0 | } |
1840 | 0 | } |
1841 | 0 | if (returnCode == TPM_SUCCESS) { |
1842 | | /* 8. If dataSize is 0 then */ |
1843 | 0 | if (dataSize == 0) { |
1844 | 0 | printf("TPM_Process_NVReadValueAuth: dataSize 0, setting bReadSTClear\n"); |
1845 | | /* a. Set D1 -> bReadSTClear to TRUE */ |
1846 | 0 | d1NvdataSensitive->pubInfo.bReadSTClear = TRUE; |
1847 | | /* b. Set data to NULL */ |
1848 | | /* NOTE Done by TPM_SizedBuffer_Init */ |
1849 | 0 | } |
1850 | | /* 9. Else (if dataSize is not 0) */ |
1851 | 0 | else { |
1852 | 0 | if (returnCode == TPM_SUCCESS) { |
1853 | | /* a. Set S1 to offset + dataSize */ |
1854 | 0 | s1Last = offset + dataSize; /* set to last data point */ |
1855 | | /* b. If S1 > D1 -> dataSize return TPM_NOSPACE */ |
1856 | 0 | if (s1Last > d1NvdataSensitive->pubInfo.dataSize) { |
1857 | 0 | printf("TPM_Process_NVReadValueAuth: Error, NVRAM dataSize %u too small\n", |
1858 | 0 | d1NvdataSensitive->pubInfo.dataSize); |
1859 | 0 | returnCode = TPM_NOSPACE; |
1860 | 0 | } |
1861 | 0 | } |
1862 | | /* c. Set data to area pointed to by offset */ |
1863 | 0 | if ((returnCode == TPM_SUCCESS) && !isGPIO) { |
1864 | 0 | TPM_PrintFourLimit("TPM_Process_NVReadValueAuth: read data", |
1865 | 0 | d1NvdataSensitive->data + offset, dataSize); |
1866 | 0 | returnCode = TPM_SizedBuffer_Set(&data, dataSize, d1NvdataSensitive->data + offset); |
1867 | 0 | } |
1868 | | /* GPIO */ |
1869 | 0 | if ((returnCode == TPM_SUCCESS) && isGPIO) { |
1870 | 0 | returnCode = TPM_Malloc(&gpioData, dataSize); /* freed @2 */ |
1871 | 0 | } |
1872 | 0 | if ((returnCode == TPM_SUCCESS) && isGPIO) { |
1873 | 0 | printf("TPM_Process_NVReadValueAuth: Reading GPIO\n"); |
1874 | 0 | returnCode = TPM_IO_GPIO_Read(nvIndex, |
1875 | 0 | dataSize, |
1876 | 0 | gpioData, |
1877 | 0 | tpm_state->tpm_number); |
1878 | 0 | } |
1879 | 0 | if ((returnCode == TPM_SUCCESS) && isGPIO) { |
1880 | 0 | returnCode = TPM_SizedBuffer_Set(&data, |
1881 | 0 | dataSize, gpioData); |
1882 | 0 | } |
1883 | 0 | } |
1884 | 0 | } |
1885 | | /* |
1886 | | response |
1887 | | */ |
1888 | | /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ |
1889 | 0 | if (rcf == 0) { |
1890 | 0 | printf("TPM_Process_NVReadValueAuth: Ordinal returnCode %08x %u\n", |
1891 | 0 | returnCode, returnCode); |
1892 | 0 | rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); |
1893 | 0 | } |
1894 | | /* success response, append the rest of the parameters. */ |
1895 | 0 | if (rcf == 0) { |
1896 | 0 | if (returnCode == TPM_SUCCESS) { |
1897 | | /* checkpoint the beginning of the outParam's */ |
1898 | 0 | outParamStart = response->buffer_current - response->buffer; |
1899 | | /* return data */ |
1900 | 0 | returnCode = TPM_SizedBuffer_Store(response, &data); |
1901 | | /* checkpoint the end of the outParam's */ |
1902 | 0 | outParamEnd = response->buffer_current - response->buffer; |
1903 | 0 | } |
1904 | | /* digest the above the line output parameters */ |
1905 | 0 | if (returnCode == TPM_SUCCESS) { |
1906 | 0 | returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ |
1907 | 0 | auditStatus, /* input audit status */ |
1908 | 0 | transportEncrypt, |
1909 | 0 | tag, |
1910 | 0 | returnCode, |
1911 | 0 | ordinal, /* command ordinal */ |
1912 | 0 | response->buffer + outParamStart, /* start */ |
1913 | 0 | outParamEnd - outParamStart); /* length */ |
1914 | 0 | } |
1915 | | /* calculate and set the below the line parameters */ |
1916 | 0 | if (returnCode == TPM_SUCCESS) { |
1917 | 0 | returnCode = TPM_AuthParams_Set(response, |
1918 | 0 | *hmacKey, /* HMAC key */ |
1919 | 0 | auth_session_data, |
1920 | 0 | outParamDigest, |
1921 | 0 | nonceOdd, |
1922 | 0 | continueAuthSession); |
1923 | 0 | } |
1924 | | /* audit if required */ |
1925 | 0 | if ((returnCode == TPM_SUCCESS) && auditStatus) { |
1926 | 0 | returnCode = TPM_ProcessAudit(tpm_state, |
1927 | 0 | transportEncrypt, |
1928 | 0 | inParamDigest, |
1929 | 0 | outParamDigest, |
1930 | 0 | ordinal); |
1931 | 0 | } |
1932 | | /* adjust the initial response */ |
1933 | 0 | rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); |
1934 | 0 | } |
1935 | | /* if there was an error, or continueAuthSession is FALSE, terminate the session */ |
1936 | 0 | if (((rcf != 0) || |
1937 | 0 | ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || |
1938 | 0 | !continueAuthSession) && |
1939 | 0 | authHandleValid) { |
1940 | 0 | TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); |
1941 | 0 | } |
1942 | | /* |
1943 | | cleanup |
1944 | | */ |
1945 | 0 | TPM_SizedBuffer_Delete(&data); /* @1 */ |
1946 | 0 | return rcf; |
1947 | 0 | } |
1948 | | |
1949 | | /* 20.2 TPM_NV_WriteValue rev 117 |
1950 | | |
1951 | | This command writes the value to a defined area. The write can be TPM Owner authorized or |
1952 | | unauthorized and protected by other attributes and will work when no TPM Owner is present. |
1953 | | |
1954 | | The action setting bGlobalLock to TRUE is intentionally before the action checking the |
1955 | | owner authorization. This allows code (e.g., a BIOS) to lock NVRAM without knowing the |
1956 | | owner authorization. |
1957 | | |
1958 | | The DIR (TPM_NV_INDEX_DIR) has the attributes TPM_NV_PER_OWNERWRITE and TPM_NV_WRITEALL. |
1959 | | |
1960 | | FIXME: A simpler way to do DIR might be to create the DIR as NV defined space at first |
1961 | | initialization and remove the special casing here. |
1962 | | */ |
1963 | | |
1964 | | TPM_RESULT TPM_Process_NVWriteValue(tpm_state_t *tpm_state, |
1965 | | TPM_STORE_BUFFER *response, |
1966 | | TPM_TAG tag, |
1967 | | uint32_t paramSize, |
1968 | | TPM_COMMAND_CODE ordinal, |
1969 | | unsigned char *command, |
1970 | | TPM_TRANSPORT_INTERNAL *transportInternal) |
1971 | 0 | { |
1972 | 0 | TPM_RESULT rcf = 0; /* fatal error precluding response */ |
1973 | 0 | TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ |
1974 | 0 | int irc; |
1975 | | |
1976 | | /* input parameters */ |
1977 | 0 | TPM_NV_INDEX nvIndex; /* The index of the area to set */ |
1978 | 0 | uint32_t offset = 0; /* The offset into the NV Area */ |
1979 | 0 | TPM_SIZED_BUFFER data; /* The data to set the area to */ |
1980 | 0 | TPM_AUTHHANDLE authHandle; /* The authorization handle used for TPM Owner */ |
1981 | 0 | TPM_NONCE nonceOdd; /* Nonce generated by caller */ |
1982 | 0 | TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the authorization |
1983 | | handle */ |
1984 | 0 | TPM_AUTHDATA ownerAuth; /* The authorization digest HMAC key: TPM Owner auth */ |
1985 | | |
1986 | | /* processing parameters */ |
1987 | 0 | unsigned char * inParamStart; /* starting point of inParam's */ |
1988 | 0 | unsigned char * inParamEnd; /* ending point of inParam's */ |
1989 | 0 | TPM_DIGEST inParamDigest; |
1990 | 0 | TPM_BOOL auditStatus; /* audit the ordinal */ |
1991 | 0 | TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ |
1992 | 0 | TPM_BOOL authHandleValid = FALSE; |
1993 | 0 | TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ |
1994 | 0 | TPM_SECRET *hmacKey = NULL; |
1995 | 0 | TPM_BOOL ignore_auth = FALSE; |
1996 | 0 | TPM_BOOL index0 = FALSE; |
1997 | 0 | TPM_BOOL done = FALSE; |
1998 | 0 | TPM_BOOL dir = FALSE; |
1999 | 0 | TPM_BOOL writeAllNV = FALSE; /* flag to write back NV */ |
2000 | 0 | TPM_NV_DATA_SENSITIVE *d1NvdataSensitive = NULL; |
2001 | 0 | uint32_t s1Last; |
2002 | 0 | TPM_BOOL physicalPresence; |
2003 | 0 | TPM_BOOL isGPIO = FALSE; |
2004 | 0 | uint32_t nv1 = tpm_state->tpm_permanent_data.noOwnerNVWrite; |
2005 | | /* temp for noOwnerNVWrite, initialize to |
2006 | | silence compiler */ |
2007 | 0 | TPM_BOOL nv1Incremented = FALSE; /* flag that nv1 was incremented */ |
2008 | | |
2009 | | /* output parameters */ |
2010 | 0 | uint32_t outParamStart; /* starting point of outParam's */ |
2011 | 0 | uint32_t outParamEnd; /* ending point of outParam's */ |
2012 | 0 | TPM_DIGEST outParamDigest; |
2013 | |
|
2014 | 0 | printf("TPM_Process_NVWriteValue: Ordinal Entry\n"); |
2015 | 0 | TPM_SizedBuffer_Init(&data); /* freed @1 */ |
2016 | | /* |
2017 | | get inputs |
2018 | | */ |
2019 | | /* save the starting point of inParam's for authorization and auditing */ |
2020 | 0 | inParamStart = command; |
2021 | | /* get nvIndex parameter */ |
2022 | 0 | if (returnCode == TPM_SUCCESS) { |
2023 | 0 | returnCode = TPM_Load32(&nvIndex, &command, ¶mSize); |
2024 | 0 | } |
2025 | 0 | if (returnCode == TPM_SUCCESS) { |
2026 | 0 | returnCode = TPM_Load32(&offset, &command, ¶mSize); |
2027 | 0 | } |
2028 | 0 | if (returnCode == TPM_SUCCESS) { |
2029 | 0 | returnCode = TPM_SizedBuffer_Load(&data, &command, ¶mSize); |
2030 | 0 | } |
2031 | | /* save the ending point of inParam's for authorization and auditing */ |
2032 | 0 | inParamEnd = command; |
2033 | | /* digest the input parameters */ |
2034 | 0 | if (returnCode == TPM_SUCCESS) { |
2035 | 0 | returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ |
2036 | 0 | &auditStatus, /* output */ |
2037 | 0 | &transportEncrypt, /* output */ |
2038 | 0 | tpm_state, |
2039 | 0 | tag, |
2040 | 0 | ordinal, |
2041 | 0 | inParamStart, |
2042 | 0 | inParamEnd, |
2043 | 0 | transportInternal); |
2044 | 0 | } |
2045 | | /* check state */ |
2046 | 0 | if (returnCode == TPM_SUCCESS) { |
2047 | 0 | returnCode = TPM_CheckState(tpm_state, tag, (TPM_CHECK_NOT_SHUTDOWN | |
2048 | 0 | TPM_CHECK_NO_LOCKOUT | |
2049 | 0 | TPM_CHECK_NV_NOAUTH)); |
2050 | 0 | } |
2051 | | /* check tag */ |
2052 | 0 | if (returnCode == TPM_SUCCESS) { |
2053 | 0 | returnCode = TPM_CheckRequestTag10(tag); |
2054 | 0 | } |
2055 | | /* get the optional 'below the line' authorization parameters */ |
2056 | 0 | if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { |
2057 | 0 | returnCode = TPM_AuthParams_Get(&authHandle, |
2058 | 0 | &authHandleValid, |
2059 | 0 | nonceOdd, |
2060 | 0 | &continueAuthSession, |
2061 | 0 | ownerAuth, |
2062 | 0 | &command, ¶mSize); |
2063 | 0 | } |
2064 | 0 | if (returnCode == TPM_SUCCESS) { |
2065 | 0 | if (paramSize != 0) { |
2066 | 0 | printf("TPM_Process_NVWriteValue: Error, command has %u extra bytes\n", |
2067 | 0 | paramSize); |
2068 | 0 | returnCode = TPM_BAD_PARAM_SIZE; |
2069 | 0 | } |
2070 | 0 | } |
2071 | | /* do not terminate sessions if the command did not parse correctly */ |
2072 | 0 | if (returnCode != TPM_SUCCESS) { |
2073 | 0 | authHandleValid = FALSE; |
2074 | 0 | } |
2075 | | /* |
2076 | | Processing |
2077 | | */ |
2078 | 0 | if (returnCode == TPM_SUCCESS) { |
2079 | 0 | printf("TPM_Process_NVWriteValue: index %08x offset %u dataSize %u\n", |
2080 | 0 | nvIndex, offset, data.size); |
2081 | 0 | TPM_PrintFourLimit("TPM_Process_NVWriteValue: data", data.buffer, data.size); |
2082 | | /* 1. If TPM_PERMANENT_FLAGS -> nvLocked is FALSE then all authorization checks except for |
2083 | | the max NV writes are ignored */ |
2084 | | /* a. Ignored checks include physical presence, owner authorization, TPM_NV_PER_OWNERWRITE, |
2085 | | PCR, bWriteDefine, bGlobalLock, bWriteSTClear, locality, disabled and deactivated */ |
2086 | | /* b. TPM_NV_PER_AUTHWRITE is not ignored. */ |
2087 | | /* a.If ownerAuth is present, the TPM MAY check the authorization HMAC. */ |
2088 | 0 | if (!(tpm_state->tpm_permanent_flags.nvLocked)) { |
2089 | 0 | printf("TPM_Process_NVWriteValue: nvLocked FALSE, ignoring authorization\n"); |
2090 | 0 | ignore_auth = TRUE; |
2091 | 0 | } |
2092 | 0 | if (nvIndex == TPM_NV_INDEX0) { |
2093 | 0 | index0 = TRUE; |
2094 | 0 | } |
2095 | | /* determine whether the nvIndex is legal GPIO space */ |
2096 | 0 | if (returnCode == 0) { |
2097 | 0 | returnCode = TPM_NVDataSensitive_IsGPIO(&isGPIO, nvIndex); |
2098 | 0 | } |
2099 | 0 | } |
2100 | | /* 2. Locate and set D1 to the TPM_NV_DATA_AREA that corresponds to nvIndex, return TPM_BADINDEX |
2101 | | on error */ |
2102 | 0 | if ((returnCode == TPM_SUCCESS) && !index0) { |
2103 | | /* a. If nvIndex = TPM_NV_INDEX_DIR, set D1 to TPM_PERMANENT_DATA -> authDir[0] */ |
2104 | 0 | if (nvIndex == TPM_NV_INDEX_DIR) { |
2105 | 0 | printf("TPM_Process_NVWriteValue: Writing DIR\n"); |
2106 | 0 | dir = TRUE; |
2107 | 0 | } |
2108 | 0 | else { |
2109 | 0 | printf("TPM_Process_NVWriteValue: Loading data space from NVRAM\n"); |
2110 | 0 | returnCode = TPM_NVIndexEntries_GetEntry(&d1NvdataSensitive, |
2111 | 0 | &(tpm_state->tpm_nv_index_entries), |
2112 | 0 | nvIndex); |
2113 | 0 | if (returnCode != 0) { |
2114 | 0 | printf("TPM_Process_NVWriteValue: Error, NV index %08x not found\n", nvIndex); |
2115 | 0 | } |
2116 | 0 | } |
2117 | 0 | } |
2118 | 0 | if ((returnCode == TPM_SUCCESS) && !index0) { |
2119 | | /* 3. If TPM_PERMANENT_FLAGS -> nvLocked is TRUE */ |
2120 | 0 | if (tpm_state->tpm_permanent_flags.nvLocked) { |
2121 | | /* a. If D1 -> permission -> TPM_NV_PER_OWNERWRITE is TRUE */ |
2122 | 0 | if (dir || /* DIR always has TPM_NV_PER_OWNERWRITE */ |
2123 | 0 | (d1NvdataSensitive->pubInfo.permission.attributes & TPM_NV_PER_OWNERWRITE)) { |
2124 | | /* i. If TPM_PERMANENT_FLAGS -> disable is TRUE, return TPM_DISABLED */ |
2125 | 0 | if (tpm_state->tpm_permanent_flags.disable) { |
2126 | 0 | printf("TPM_Process_NVWriteValue: Error, disabled\n"); |
2127 | 0 | return TPM_DISABLED; |
2128 | 0 | } |
2129 | | /* ii.If TPM_STCLEAR_FLAGS -> deactivated is TRUE, return TPM_DEACTIVATED */ |
2130 | 0 | else if (tpm_state->tpm_stclear_flags.deactivated) { |
2131 | 0 | printf("TPM_Process_NVWriteValue: Error, deactivated\n"); |
2132 | 0 | return TPM_DEACTIVATED;; |
2133 | 0 | } |
2134 | 0 | } |
2135 | | /* NOTE: Intel software requires NV access disabled and deactivated */ |
2136 | | /* b. If D1 -> permission -> TPM_NV_PER_OWNERWRITE is FALSE */ |
2137 | | /* i. If TPM_PERMANENT_FLAGS -> disable is TRUE, the TPM MAY return TPM_DISABLED */ |
2138 | | /* ii. If TPM_STCLEAR_FLAGS -> deactivated is TRUE, the TPM MAY return |
2139 | | TPM_DEACTIVATED */ |
2140 | 0 | } |
2141 | 0 | } |
2142 | | /* 4. If tag = TPM_TAG_RQU_AUTH1_COMMAND then */ |
2143 | 0 | if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND) && !dir && !index0) { |
2144 | | /* a. If D1 -> permission -> TPM_NV_PER_OWNERWRITE is FALSE return TPM_AUTH_CONFLICT */ |
2145 | | /* i. This check is ignored if nvIndex is TPM_NV_INDEX0. */ |
2146 | 0 | if (!(d1NvdataSensitive->pubInfo.permission.attributes & TPM_NV_PER_OWNERWRITE)) { |
2147 | 0 | printf("TPM_Process_NVWriteValue: Error, owner authorization conflict\n"); |
2148 | 0 | returnCode = TPM_AUTH_CONFLICT; |
2149 | 0 | } |
2150 | 0 | } |
2151 | | /* b. Validate command and parameters using ownerAuth HMAC with TPM Owner authentication as the |
2152 | | secret, return TPM_AUTHFAIL on error */ |
2153 | 0 | if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { |
2154 | 0 | returnCode = TPM_AuthSessions_GetData(&auth_session_data, |
2155 | 0 | &hmacKey, |
2156 | 0 | tpm_state, |
2157 | 0 | authHandle, |
2158 | 0 | TPM_PID_NONE, |
2159 | 0 | TPM_ET_OWNER, |
2160 | 0 | ordinal, |
2161 | 0 | NULL, |
2162 | 0 | &(tpm_state->tpm_permanent_data.ownerAuth), /* OIAP */ |
2163 | 0 | tpm_state->tpm_permanent_data.ownerAuth); /* OSAP */ |
2164 | 0 | } |
2165 | | /* NOTE: This is optional if ignore_auth is TRUE */ |
2166 | 0 | if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { |
2167 | 0 | returnCode = TPM_Authdata_Check(tpm_state, |
2168 | 0 | *hmacKey, /* HMAC key */ |
2169 | 0 | inParamDigest, |
2170 | 0 | auth_session_data, /* authorization session */ |
2171 | 0 | nonceOdd, /* Nonce generated by system |
2172 | | associated with authHandle */ |
2173 | 0 | continueAuthSession, |
2174 | 0 | ownerAuth); /* Authorization digest for input */ |
2175 | 0 | } |
2176 | | /* 5. Else */ |
2177 | 0 | if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_COMMAND) && !ignore_auth && !index0) { |
2178 | | /* a. If D1 -> permission -> TPM_NV_PER_OWNERWRITE is TRUE return TPM_AUTH_CONFLICT */ |
2179 | 0 | if (dir || /* DIR always has TPM_NV_PER_OWNERWRITE */ |
2180 | 0 | (d1NvdataSensitive->pubInfo.permission.attributes & TPM_NV_PER_OWNERWRITE)) { |
2181 | 0 | printf("TPM_Process_NVWriteValue: Error, no owner authorization conflict\n"); |
2182 | 0 | returnCode = TPM_AUTH_CONFLICT; |
2183 | 0 | } |
2184 | 0 | } |
2185 | 0 | if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_COMMAND) && !index0) { |
2186 | | /* b. If no TPM Owner validate max NV writes without an owner */ |
2187 | | /* i. Set NV1 to TPM_PERMANENT_DATA -> noOwnerNVWrite */ |
2188 | 0 | nv1 = tpm_state->tpm_permanent_data.noOwnerNVWrite; |
2189 | | /* ii. Increment NV1 by 1 */ |
2190 | 0 | nv1++; |
2191 | | /* iii. If NV1 > TPM_MAX_NV_WRITE_NOOWNER return TPM_MAXNVWRITES */ |
2192 | 0 | if (nv1 > TPM_MAX_NV_WRITE_NOOWNER) { |
2193 | 0 | printf("TPM_Process_NVWriteValue: Error, max NV writes %d w/o owner reached\n", |
2194 | 0 | tpm_state->tpm_permanent_data.noOwnerNVWrite); |
2195 | 0 | returnCode = TPM_MAXNVWRITES; |
2196 | 0 | } |
2197 | | /* iv. Set NV1_INCREMENTED to TRUE */ |
2198 | 0 | else { |
2199 | 0 | nv1Incremented = TRUE; |
2200 | 0 | } |
2201 | 0 | } |
2202 | 0 | if (returnCode == TPM_SUCCESS) { |
2203 | | /* 6. If nvIndex = 0 then */ |
2204 | 0 | if (nvIndex == 0) { |
2205 | | /* a. If dataSize is not 0, the TPM MAY return TPM_BADINDEX. */ |
2206 | 0 | if (data.size != 0) { |
2207 | 0 | printf("TPM_Process_NVWriteValue: Error, index 0 size %u\n", data.size); |
2208 | 0 | returnCode = TPM_BADINDEX; |
2209 | 0 | } |
2210 | 0 | else { |
2211 | | /* b. Set TPM_STCLEAR_FLAGS -> bGlobalLock to TRUE */ |
2212 | 0 | printf("TPM_Process_NVWriteValue: nvIndex 0, setting bGlobalLock\n"); |
2213 | 0 | tpm_state->tpm_stclear_flags.bGlobalLock = TRUE; |
2214 | | /* c. Return TPM_SUCCESS */ |
2215 | 0 | done = TRUE; |
2216 | 0 | } |
2217 | 0 | } |
2218 | 0 | } |
2219 | | /* 7. If D1 -> permission -> TPM_NV_PER_AUTHWRITE is TRUE return TPM_AUTH_CONFLICT */ |
2220 | 0 | if ((returnCode == TPM_SUCCESS) && !done && !dir) { |
2221 | 0 | if (d1NvdataSensitive->pubInfo.permission.attributes & TPM_NV_PER_AUTHWRITE) { |
2222 | 0 | printf("TPM_Process_NVWriteValue: Error, authorization conflict, attributes %08x \n", |
2223 | 0 | d1NvdataSensitive->pubInfo.permission.attributes); |
2224 | 0 | returnCode = TPM_AUTH_CONFLICT; |
2225 | 0 | } |
2226 | 0 | } |
2227 | | /* 8. Check that D1 -> pcrInfoWrite -> localityAtRelease for TPM_STANY_DATA -> localityModifier |
2228 | | is TRUE */ |
2229 | | /* a. For example if TPM_STANY_DATA -> localityModifier was 2 then D1 -> pcrInfo -> |
2230 | | localityAtRelease -> TPM_LOC_TWO would have to be TRUE */ |
2231 | | /* b. On error return TPM_BAD_LOCALITY */ |
2232 | | /* NOTE Done by TPM_PCRInfoShort_CheckDigest() */ |
2233 | | /* 9. If D1 -> attributes specifies TPM_NV_PER_PPWRITE then validate physical presence is |
2234 | | asserted if not return TPM_BAD_PRESENCE */ |
2235 | 0 | if ((returnCode == TPM_SUCCESS) && !done && !ignore_auth && !dir) { |
2236 | 0 | if (d1NvdataSensitive->pubInfo.permission.attributes & TPM_NV_PER_PPWRITE) { |
2237 | 0 | if (returnCode == TPM_SUCCESS) { |
2238 | 0 | returnCode = TPM_Global_GetPhysicalPresence(&physicalPresence, tpm_state); |
2239 | 0 | } |
2240 | 0 | if (returnCode == TPM_SUCCESS) { |
2241 | 0 | if (!physicalPresence) { |
2242 | 0 | printf("TPM_Process_NVWriteValue: Error, physicalPresence is FALSE\n"); |
2243 | 0 | returnCode = TPM_BAD_PRESENCE; |
2244 | 0 | } |
2245 | 0 | } |
2246 | 0 | } |
2247 | 0 | } |
2248 | 0 | if ((returnCode == TPM_SUCCESS) && !done && !ignore_auth && !dir) { |
2249 | | /* 10. If D1 -> attributes specifies TPM_NV_PER_WRITEDEFINE */ |
2250 | 0 | if ((d1NvdataSensitive->pubInfo.permission.attributes & TPM_NV_PER_WRITEDEFINE) && |
2251 | | /* a. If D1 -> bWriteDefine is TRUE return TPM_AREA_LOCKED */ |
2252 | 0 | (d1NvdataSensitive->pubInfo.bWriteDefine)) { |
2253 | 0 | printf("TPM_Process_NVWriteValue: Error, area locked by bWriteDefine\n"); |
2254 | 0 | returnCode = TPM_AREA_LOCKED; |
2255 | 0 | } |
2256 | 0 | } |
2257 | 0 | if ((returnCode == TPM_SUCCESS) && !done && !ignore_auth && !dir) { |
2258 | | /* 11. If D1 -> attributes specifies TPM_NV_PER_GLOBALLOCK */ |
2259 | 0 | if ((d1NvdataSensitive->pubInfo.permission.attributes & TPM_NV_PER_GLOBALLOCK) && |
2260 | | /* a. If TPM_STCLEAR_FLAGS -> bGlobalLock is TRUE return TPM_AREA_LOCKED */ |
2261 | 0 | (tpm_state->tpm_stclear_flags.bGlobalLock)) { |
2262 | 0 | printf("TPM_Process_NVWriteValue: Error, area locked by bGlobalLock\n"); |
2263 | 0 | returnCode = TPM_AREA_LOCKED; |
2264 | 0 | } |
2265 | 0 | } |
2266 | 0 | if ((returnCode == TPM_SUCCESS) && !done && !ignore_auth && !dir) { |
2267 | | /* 12. If D1 -> attributes specifies TPM_NV_PER_WRITE_STCLEAR */ |
2268 | 0 | if ((d1NvdataSensitive->pubInfo.permission.attributes & TPM_NV_PER_WRITE_STCLEAR) && |
2269 | | /* a. If D1 ->bWriteSTClear is TRUE return TPM_AREA_LOCKED */ |
2270 | 0 | (d1NvdataSensitive->pubInfo.bWriteSTClear)) { |
2271 | 0 | printf("TPM_Process_NVWriteValue: Error, area locked by bWriteSTClear\n"); |
2272 | 0 | returnCode = TPM_AREA_LOCKED; |
2273 | 0 | } |
2274 | 0 | } |
2275 | | /* 13. If D1 -> pcrInfoWrite -> pcrSelection specifies a selection of PCR */ |
2276 | | /* a. Create P1 a composite hash of the PCR specified by D1 -> pcrInfoWrite */ |
2277 | | /* b. Compare P1 to D1 -> pcrInfoWrite -> digestAtRelease return TPM_WRONGPCRVAL on mismatch |
2278 | | */ |
2279 | 0 | if ((returnCode == TPM_SUCCESS) && !done && !ignore_auth && !dir) { |
2280 | 0 | returnCode = TPM_PCRInfoShort_CheckDigest(&(d1NvdataSensitive->pubInfo.pcrInfoWrite), |
2281 | 0 | tpm_state->tpm_stclear_data.PCRS, |
2282 | 0 | tpm_state->tpm_stany_flags.localityModifier); |
2283 | 0 | } |
2284 | 0 | if ((returnCode == TPM_SUCCESS) && !done && !dir) { |
2285 | | /* 14. If dataSize = 0 then */ |
2286 | 0 | if (data.size == 0) { |
2287 | 0 | printf("TPM_Process_NVWriteValue: dataSize 0, setting bWriteSTClear, bWriteDefine\n"); |
2288 | | /* a. Set D1 -> bWriteSTClear to TRUE */ |
2289 | 0 | d1NvdataSensitive->pubInfo.bWriteSTClear = TRUE; |
2290 | | /* b. Set D1 -> bWriteDefine */ |
2291 | 0 | if (!d1NvdataSensitive->pubInfo.bWriteDefine) { /* save wearout, only write if |
2292 | | FALSE */ |
2293 | 0 | d1NvdataSensitive->pubInfo.bWriteDefine = TRUE; |
2294 | | /* must write TPM_PERMANENT_DATA back to NVRAM, set this flag after structure is |
2295 | | written */ |
2296 | 0 | writeAllNV = TRUE; |
2297 | 0 | } |
2298 | 0 | } |
2299 | | /* 15. Else (if dataSize is not 0) */ |
2300 | 0 | else { |
2301 | 0 | if (returnCode == TPM_SUCCESS) { |
2302 | | /* a. Set S1 to offset + dataSize */ |
2303 | 0 | s1Last = offset + data.size; /* set to last data point */ |
2304 | | /* b. If S1 > D1 -> dataSize return TPM_NOSPACE */ |
2305 | 0 | if (s1Last > d1NvdataSensitive->pubInfo.dataSize) { |
2306 | 0 | printf("TPM_Process_NVWriteValue: Error, NVRAM dataSize %u too small\n", |
2307 | 0 | d1NvdataSensitive->pubInfo.dataSize); |
2308 | 0 | returnCode = TPM_NOSPACE; |
2309 | 0 | } |
2310 | 0 | } |
2311 | 0 | if (returnCode == TPM_SUCCESS) { |
2312 | | /* c. If D1 -> attributes specifies TPM_NV_PER_WRITEALL */ |
2313 | 0 | if ((d1NvdataSensitive->pubInfo.permission.attributes & TPM_NV_PER_WRITEALL) && |
2314 | | /* i. If dataSize != D1 -> dataSize return TPM_NOT_FULLWRITE */ |
2315 | 0 | (data.size != d1NvdataSensitive->pubInfo.dataSize)) { |
2316 | 0 | printf("TPM_Process_NVWriteValue: Error, Must write full %u\n", |
2317 | 0 | d1NvdataSensitive->pubInfo.dataSize); |
2318 | 0 | returnCode = TPM_NOT_FULLWRITE; |
2319 | 0 | } |
2320 | 0 | } |
2321 | 0 | if (returnCode == TPM_SUCCESS) { |
2322 | | /* not GPIO */ |
2323 | 0 | if (!isGPIO) { |
2324 | | /* wearout optimization, don't write if the data is the same */ |
2325 | 0 | irc = memcmp((d1NvdataSensitive->data) + offset, data.buffer, data.size); |
2326 | 0 | if (irc != 0) { |
2327 | 0 | printf("TPM_Process_NVWriteValue: Copying data\n"); |
2328 | | /* d. Write the new value into the NV storage area */ |
2329 | 0 | memcpy((d1NvdataSensitive->data) + offset, data.buffer, data.size); |
2330 | | /* must write TPM_PERMANENT_DATA back to NVRAM, set this flag after |
2331 | | structure is written */ |
2332 | 0 | writeAllNV = TRUE; |
2333 | 0 | } |
2334 | 0 | else { |
2335 | 0 | printf("TPM_Process_NVWriteValue: Same data, no copy\n"); |
2336 | 0 | } |
2337 | 0 | } |
2338 | | /* GPIO */ |
2339 | 0 | else { |
2340 | 0 | printf("TPM_Process_NVWriteValue: Writing GPIO\n"); |
2341 | 0 | returnCode = TPM_IO_GPIO_Write(nvIndex, |
2342 | 0 | data.size, |
2343 | 0 | data.buffer, |
2344 | 0 | tpm_state->tpm_number); |
2345 | 0 | } |
2346 | 0 | } |
2347 | 0 | } |
2348 | 0 | } |
2349 | | /* DIR write */ |
2350 | 0 | if ((returnCode == TPM_SUCCESS) && !done && dir) { |
2351 | | /* For TPM_NV_INDEX_DIR, the ordinal MUST NOT set an error code for the "if dataSize = 0" |
2352 | | action. However, the flags set in this case are not applicable to the DIR. */ |
2353 | 0 | if (data.size != 0) { |
2354 | | /* DIR is hard coded as a TPM_DIRVALUE array, TPM_NV_WRITEALL is implied */ |
2355 | 0 | if (returnCode == TPM_SUCCESS) { |
2356 | 0 | if ((offset != 0) || (data.size != TPM_DIGEST_SIZE)) { |
2357 | 0 | printf("TPM_Process_NVWriteValue: Error, Must write full DIR %u\n", |
2358 | 0 | TPM_DIGEST_SIZE); |
2359 | 0 | returnCode = TPM_NOT_FULLWRITE; |
2360 | 0 | } |
2361 | 0 | } |
2362 | 0 | if (returnCode == TPM_SUCCESS) { |
2363 | 0 | printf("TPM_Process_NVWriteValue: Copying data\n"); |
2364 | 0 | memcpy(tpm_state->tpm_permanent_data.authDIR, data.buffer, TPM_DIGEST_SIZE); |
2365 | 0 | writeAllNV = TRUE; |
2366 | 0 | } |
2367 | 0 | } |
2368 | 0 | } |
2369 | 0 | if ((returnCode == TPM_SUCCESS) && !done && !dir) { |
2370 | | /* 16. Set D1 -> bReadSTClear to FALSE (unlocked by a successful write) */ |
2371 | 0 | d1NvdataSensitive->pubInfo.bReadSTClear = FALSE; |
2372 | 0 | } |
2373 | | /* 15.d Write the new value into the NV storage area */ |
2374 | 0 | if (writeAllNV) { |
2375 | 0 | printf("TPM_Process_NVWriteValue: Writing data to NVRAM\n"); |
2376 | | /* NOTE Don't do this step until just before the serialization */ |
2377 | | /* e. If NV1_INCREMENTED is TRUE */ |
2378 | 0 | if (nv1Incremented) { |
2379 | | /* i. Set TPM_PERMANENT_DATA -> noOwnerNVWrite to NV1 */ |
2380 | 0 | tpm_state->tpm_permanent_data.noOwnerNVWrite = nv1; |
2381 | 0 | } |
2382 | 0 | } |
2383 | 0 | returnCode = TPM_PermanentAll_NVStore(tpm_state, |
2384 | 0 | writeAllNV, |
2385 | 0 | returnCode); |
2386 | | /* |
2387 | | response |
2388 | | */ |
2389 | | /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ |
2390 | 0 | if (rcf == 0) { |
2391 | 0 | printf("TPM_Process_NVWriteValue: Ordinal returnCode %08x %u\n", |
2392 | 0 | returnCode, returnCode); |
2393 | 0 | rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); |
2394 | 0 | } |
2395 | | /* success response, append the rest of the parameters. */ |
2396 | 0 | if (rcf == 0) { |
2397 | 0 | if (returnCode == TPM_SUCCESS) { |
2398 | | /* checkpoint the beginning of the outParam's */ |
2399 | 0 | outParamStart = response->buffer_current - response->buffer; |
2400 | | /* checkpoint the end of the outParam's */ |
2401 | 0 | outParamEnd = response->buffer_current - response->buffer; |
2402 | 0 | } |
2403 | | /* digest the above the line output parameters */ |
2404 | 0 | if (returnCode == TPM_SUCCESS) { |
2405 | 0 | returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ |
2406 | 0 | auditStatus, /* input audit status */ |
2407 | 0 | transportEncrypt, |
2408 | 0 | tag, |
2409 | 0 | returnCode, |
2410 | 0 | ordinal, /* command ordinal */ |
2411 | 0 | response->buffer + outParamStart, /* start */ |
2412 | 0 | outParamEnd - outParamStart); /* length */ |
2413 | 0 | } |
2414 | | /* calculate and set the below the line parameters */ |
2415 | 0 | if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { |
2416 | 0 | returnCode = TPM_AuthParams_Set(response, |
2417 | 0 | *hmacKey, /* owner HMAC key */ |
2418 | 0 | auth_session_data, |
2419 | 0 | outParamDigest, |
2420 | 0 | nonceOdd, |
2421 | 0 | continueAuthSession); |
2422 | 0 | } |
2423 | | /* audit if required */ |
2424 | 0 | if ((returnCode == TPM_SUCCESS) && auditStatus) { |
2425 | 0 | returnCode = TPM_ProcessAudit(tpm_state, |
2426 | 0 | transportEncrypt, |
2427 | 0 | inParamDigest, |
2428 | 0 | outParamDigest, |
2429 | 0 | ordinal); |
2430 | 0 | } |
2431 | | /* adjust the initial response */ |
2432 | 0 | rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); |
2433 | 0 | } |
2434 | | /* if there was an error, or continueAuthSession is FALSE, terminate the session */ |
2435 | 0 | if (((rcf != 0) || |
2436 | 0 | ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || |
2437 | 0 | !continueAuthSession) && |
2438 | 0 | authHandleValid) { |
2439 | 0 | TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); |
2440 | 0 | } |
2441 | | /* |
2442 | | cleanup |
2443 | | */ |
2444 | 0 | TPM_SizedBuffer_Delete(&data); /* @1 */ |
2445 | 0 | return rcf; |
2446 | 0 | } |
2447 | | |
2448 | | /* 20.3 TPM_NV_WriteValueAuth rev 87 |
2449 | | |
2450 | | This command writes to a previously defined area. The area must require authorization to |
2451 | | write. This command is for using when authorization other than the owner authorization is to be |
2452 | | used. Otherwise, you should use TPM_NV_WriteValue |
2453 | | */ |
2454 | | |
2455 | | TPM_RESULT TPM_Process_NVWriteValueAuth(tpm_state_t *tpm_state, |
2456 | | TPM_STORE_BUFFER *response, |
2457 | | TPM_TAG tag, |
2458 | | uint32_t paramSize, |
2459 | | TPM_COMMAND_CODE ordinal, |
2460 | | unsigned char *command, |
2461 | | TPM_TRANSPORT_INTERNAL *transportInternal) |
2462 | 0 | { |
2463 | 0 | TPM_RESULT rcf = 0; /* fatal error precluding response */ |
2464 | 0 | TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ |
2465 | 0 | int irc; |
2466 | | |
2467 | | /* input parameters */ |
2468 | 0 | TPM_NV_INDEX nvIndex; /* The index of the area to set */ |
2469 | 0 | uint32_t offset = 0; /* The offset into the chunk */ |
2470 | 0 | TPM_SIZED_BUFFER data; /* The data to set the area to */ |
2471 | 0 | TPM_AUTHHANDLE authHandle; /* The authorization handle used for NV element |
2472 | | authorization */ |
2473 | 0 | TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ |
2474 | 0 | TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the authorization |
2475 | | handle */ |
2476 | 0 | TPM_AUTHDATA authValue; /* HMAC key: NV element auth value */ |
2477 | | |
2478 | | /* processing parameters */ |
2479 | 0 | unsigned char * inParamStart; /* starting point of inParam's */ |
2480 | 0 | unsigned char * inParamEnd; /* ending point of inParam's */ |
2481 | 0 | TPM_DIGEST inParamDigest; |
2482 | 0 | TPM_BOOL auditStatus = FALSE; /* audit the ordinal */ |
2483 | 0 | TPM_BOOL transportEncrypt = FALSE; /* wrapped in encrypted transport |
2484 | | session */ |
2485 | 0 | TPM_BOOL authHandleValid = FALSE; |
2486 | 0 | TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ |
2487 | 0 | TPM_SECRET *hmacKey = NULL; |
2488 | 0 | TPM_NV_DATA_SENSITIVE *d1NvdataSensitive; |
2489 | 0 | uint32_t s1Last; |
2490 | 0 | TPM_BOOL writeAllNV = FALSE; /* flag to write back NV */ |
2491 | 0 | TPM_BOOL physicalPresence; |
2492 | 0 | TPM_BOOL isGPIO; |
2493 | | |
2494 | | /* output parameters */ |
2495 | 0 | uint32_t outParamStart; /* starting point of outParam's */ |
2496 | 0 | uint32_t outParamEnd; /* ending point of outParam's */ |
2497 | 0 | TPM_DIGEST outParamDigest; |
2498 | |
|
2499 | 0 | printf("TPM_Process_NVWriteValueAuth: Ordinal Entry\n"); |
2500 | 0 | TPM_SizedBuffer_Init(&data); /* freed @1 */ |
2501 | | /* |
2502 | | get inputs |
2503 | | */ |
2504 | | /* save the starting point of inParam's for authorization and auditing */ |
2505 | 0 | inParamStart = command; |
2506 | | /* get nvIndex parameter */ |
2507 | 0 | if (returnCode == TPM_SUCCESS) { |
2508 | 0 | returnCode = TPM_Load32(&nvIndex, &command, ¶mSize); |
2509 | 0 | } |
2510 | | /* get offset parameter */ |
2511 | 0 | if (returnCode == TPM_SUCCESS) { |
2512 | 0 | returnCode = TPM_Load32(&offset, &command, ¶mSize); |
2513 | 0 | } |
2514 | | /* get data parameter */ |
2515 | 0 | if (returnCode == TPM_SUCCESS) { |
2516 | 0 | returnCode = TPM_SizedBuffer_Load(&data, &command, ¶mSize); |
2517 | 0 | } |
2518 | | /* save the ending point of inParam's for authorization and auditing */ |
2519 | 0 | inParamEnd = command; |
2520 | | /* digest the input parameters */ |
2521 | 0 | if (returnCode == TPM_SUCCESS) { |
2522 | 0 | returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ |
2523 | 0 | &auditStatus, /* output */ |
2524 | 0 | &transportEncrypt, /* output */ |
2525 | 0 | tpm_state, |
2526 | 0 | tag, |
2527 | 0 | ordinal, |
2528 | 0 | inParamStart, |
2529 | 0 | inParamEnd, |
2530 | 0 | transportInternal); |
2531 | 0 | } |
2532 | | /* check state */ |
2533 | 0 | if (returnCode == TPM_SUCCESS) { |
2534 | 0 | returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL); |
2535 | 0 | } |
2536 | | /* check tag */ |
2537 | 0 | if (returnCode == TPM_SUCCESS) { |
2538 | 0 | returnCode = TPM_CheckRequestTag1(tag); |
2539 | 0 | } |
2540 | | /* get the 'below the line' authorization parameters */ |
2541 | 0 | if (returnCode == TPM_SUCCESS) { |
2542 | 0 | returnCode = TPM_AuthParams_Get(&authHandle, |
2543 | 0 | &authHandleValid, |
2544 | 0 | nonceOdd, |
2545 | 0 | &continueAuthSession, |
2546 | 0 | authValue, |
2547 | 0 | &command, ¶mSize); |
2548 | 0 | } |
2549 | 0 | if (returnCode == TPM_SUCCESS) { |
2550 | 0 | if (paramSize != 0) { |
2551 | 0 | printf("TPM_Process_NVWriteValueAuth: Error, command has %u extra bytes\n", |
2552 | 0 | paramSize); |
2553 | 0 | returnCode = TPM_BAD_PARAM_SIZE; |
2554 | 0 | } |
2555 | 0 | } |
2556 | | /* do not terminate sessions if the command did not parse correctly */ |
2557 | 0 | if (returnCode != TPM_SUCCESS) { |
2558 | 0 | authHandleValid = FALSE; |
2559 | 0 | } |
2560 | | /* |
2561 | | Processing |
2562 | | */ |
2563 | | /* determine whether the nvIndex is legal GPIO space */ |
2564 | 0 | if (returnCode == 0) { |
2565 | 0 | returnCode = TPM_NVDataSensitive_IsGPIO(&isGPIO, nvIndex); |
2566 | 0 | } |
2567 | | /* 1. Locate and set D1 to the TPM_NV_DATA_AREA that corresponds to nvIndex, return TPM_BADINDEX |
2568 | | on error */ |
2569 | 0 | if (returnCode == TPM_SUCCESS) { |
2570 | 0 | printf("TPM_Process_NVWriteValueAuth: index %08x offset %u dataSize %u\n", |
2571 | 0 | nvIndex, offset, data.size); |
2572 | 0 | TPM_PrintFourLimit("TPM_Process_NVWriteValueAuth: data", data.buffer, data.size); |
2573 | 0 | printf("TPM_Process_NVWriteValueAuth: Loading data from NVRAM\n"); |
2574 | 0 | returnCode = TPM_NVIndexEntries_GetEntry(&d1NvdataSensitive, |
2575 | 0 | &(tpm_state->tpm_nv_index_entries), |
2576 | 0 | nvIndex); |
2577 | 0 | if (returnCode != 0) { |
2578 | 0 | printf("TPM_Process_NVWriteValueAuth: Error, NV index %08x not found\n", nvIndex); |
2579 | 0 | } |
2580 | 0 | } |
2581 | | /* 2. If D1 -> attributes does not specify TPM_NV_PER_AUTHWRITE then return TPM_AUTH_CONFLICT */ |
2582 | 0 | if (returnCode == TPM_SUCCESS) { |
2583 | 0 | if (!(d1NvdataSensitive->pubInfo.permission.attributes & TPM_NV_PER_AUTHWRITE)) { |
2584 | 0 | printf("TPM_Process_NVWriteValueAuth: Error, authorization conflict\n"); |
2585 | 0 | returnCode = TPM_AUTH_CONFLICT; |
2586 | 0 | } |
2587 | 0 | } |
2588 | | /* 3. Validate authValue using D1 -> authValue, return TPM_AUTHFAIL on error */ |
2589 | 0 | if (returnCode == TPM_SUCCESS) { |
2590 | 0 | returnCode = TPM_AuthSessions_GetData(&auth_session_data, |
2591 | 0 | &hmacKey, |
2592 | 0 | tpm_state, |
2593 | 0 | authHandle, |
2594 | 0 | TPM_PID_NONE, |
2595 | 0 | TPM_ET_NV, |
2596 | 0 | ordinal, |
2597 | 0 | NULL, |
2598 | 0 | &(d1NvdataSensitive->authValue), /* OIAP */ |
2599 | 0 | d1NvdataSensitive->digest); /* OSAP */ |
2600 | 0 | } |
2601 | 0 | if (returnCode == TPM_SUCCESS) { |
2602 | 0 | returnCode = TPM_Authdata_Check(tpm_state, |
2603 | 0 | *hmacKey, /* HMAC key */ |
2604 | 0 | inParamDigest, |
2605 | 0 | auth_session_data, /* authorization session */ |
2606 | 0 | nonceOdd, /* Nonce generated by system |
2607 | | associated with authHandle */ |
2608 | 0 | continueAuthSession, |
2609 | 0 | authValue); /* Authorization digest for input */ |
2610 | 0 | } |
2611 | | /* 4. Check that D1 -> pcrInfoWrite -> localityAtRelease for TPM_STANY_DATA -> localityModifier |
2612 | | is TRUE */ |
2613 | | /* a. For example if TPM_STANY_DATA -> localityModifier was 2 then D1 -> pcrInfo -> |
2614 | | localityAtRelease -> TPM_LOC_TWO would have to be TRUE */ |
2615 | | /* b. On error return TPM_BAD_LOCALITY */ |
2616 | | /* NOTE Done by TPM_PCRInfoShort_CheckDigest() */ |
2617 | | /* 5. If D1 -> attributes specifies TPM_NV_PER_PPWRITE then validate physical presence is |
2618 | | asserted if not return TPM_BAD_PRESENCE */ |
2619 | 0 | if (returnCode == TPM_SUCCESS) { |
2620 | 0 | if (d1NvdataSensitive->pubInfo.permission.attributes & TPM_NV_PER_PPWRITE) { |
2621 | 0 | if (returnCode == TPM_SUCCESS) { |
2622 | 0 | returnCode = TPM_Global_GetPhysicalPresence(&physicalPresence, tpm_state); |
2623 | 0 | } |
2624 | 0 | if (returnCode == TPM_SUCCESS) { |
2625 | 0 | if (!physicalPresence) { |
2626 | 0 | printf("TPM_Process_NVWriteValueAuth: Error, physicalPresence is FALSE\n"); |
2627 | 0 | returnCode = TPM_BAD_PRESENCE; |
2628 | 0 | } |
2629 | 0 | } |
2630 | 0 | } |
2631 | 0 | } |
2632 | | /* 6. If D1 -> pcrInfoWrite -> pcrSelection specifies a selection of PCR */ |
2633 | | /* a. Create P1 a composite hash of the PCR specified by D1 -> pcrInfoWrite */ |
2634 | | /* b. Compare P1 to digestAtRelease return TPM_WRONGPCRVAL on mismatch */ |
2635 | 0 | if (returnCode == TPM_SUCCESS) { |
2636 | 0 | returnCode = TPM_PCRInfoShort_CheckDigest(&(d1NvdataSensitive->pubInfo.pcrInfoWrite), |
2637 | 0 | tpm_state->tpm_stclear_data.PCRS, |
2638 | 0 | tpm_state->tpm_stany_flags.localityModifier); |
2639 | 0 | } |
2640 | 0 | if (returnCode == TPM_SUCCESS) { |
2641 | | /* 7. If D1 -> attributes specifies TPM_NV_PER_WRITEDEFINE */ |
2642 | 0 | if ((d1NvdataSensitive->pubInfo.permission.attributes & TPM_NV_PER_WRITEDEFINE) && |
2643 | | /* a. If D1 -> bWriteDefine is TRUE return TPM_AREA_LOCKED */ |
2644 | 0 | (d1NvdataSensitive->pubInfo.bWriteDefine)) { |
2645 | 0 | printf("TPM_Process_NVWriteValueAuth: Error, area locked by bWriteDefine\n"); |
2646 | 0 | returnCode = TPM_AREA_LOCKED; |
2647 | 0 | } |
2648 | 0 | } |
2649 | 0 | if (returnCode == TPM_SUCCESS) { |
2650 | | /* 8. If D1 -> attributes specifies TPM_NV_PER_GLOBALLOCK */ |
2651 | 0 | if ((d1NvdataSensitive->pubInfo.permission.attributes & TPM_NV_PER_GLOBALLOCK) && |
2652 | | /* a. If TPM_STCLEAR_FLAGS -> bGlobalLock is TRUE return TPM_AREA_LOCKED */ |
2653 | 0 | (tpm_state->tpm_stclear_flags.bGlobalLock)) { |
2654 | 0 | printf("TPM_Process_NVWriteValueAuth: Error, area locked by bGlobalLock\n"); |
2655 | 0 | returnCode = TPM_AREA_LOCKED; |
2656 | 0 | } |
2657 | 0 | } |
2658 | 0 | if (returnCode == TPM_SUCCESS) { |
2659 | | /* 9. If D1 -> attributes specifies TPM_NV_PER_WRITE_STCLEAR */ |
2660 | 0 | if ((d1NvdataSensitive->pubInfo.permission.attributes & TPM_NV_PER_WRITE_STCLEAR) && |
2661 | | /* a. If D1 -> bWriteSTClear is TRUE return TPM_AREA_LOCKED */ |
2662 | 0 | (d1NvdataSensitive->pubInfo.bWriteSTClear)) { |
2663 | 0 | printf("TPM_Process_NVWriteValueAuth: Error, area locked by bWriteSTClear\n"); |
2664 | 0 | returnCode = TPM_AREA_LOCKED; |
2665 | 0 | } |
2666 | 0 | } |
2667 | 0 | if (returnCode == TPM_SUCCESS) { |
2668 | | /* 10. If dataSize = 0 then */ |
2669 | 0 | if (data.size == 0) { |
2670 | 0 | printf("TPM_Process_NVWriteValueAuth: " |
2671 | 0 | "dataSize 0, setting bWriteSTClear, bWriteDefine\n"); |
2672 | | /* a. Set D1 -> bWriteSTClear to TRUE */ |
2673 | 0 | d1NvdataSensitive->pubInfo.bWriteSTClear = TRUE; |
2674 | | /* b. Set D1 -> bWriteDefine to TRUE */ |
2675 | 0 | if (!d1NvdataSensitive->pubInfo.bWriteDefine) { /* save wearout, only write if |
2676 | | FALSE */ |
2677 | 0 | d1NvdataSensitive->pubInfo.bWriteDefine = TRUE; |
2678 | | /* must write TPM_PERMANENT_DATA back to NVRAM, set this flag after structure is |
2679 | | written */ |
2680 | 0 | writeAllNV = TRUE; |
2681 | 0 | } |
2682 | 0 | } |
2683 | | /* 11. Else (if dataSize is not 0) */ |
2684 | 0 | else { |
2685 | 0 | if (returnCode == TPM_SUCCESS) { |
2686 | | /* a. Set S1 to offset + dataSize */ |
2687 | 0 | s1Last = offset + data.size; /* set to last data point */ |
2688 | | /* b. If S1 > D1 -> dataSize return TPM_NOSPACE */ |
2689 | 0 | if (s1Last > d1NvdataSensitive->pubInfo.dataSize) { |
2690 | 0 | printf("TPM_Process_NVWriteValueAuth: Error, NVRAM dataSize %u\n", |
2691 | 0 | d1NvdataSensitive->pubInfo.dataSize); |
2692 | 0 | returnCode = TPM_NOSPACE; |
2693 | 0 | } |
2694 | 0 | } |
2695 | 0 | if (returnCode == TPM_SUCCESS) { |
2696 | | /* c. If D1 -> attributes specifies TPM_PER_WRITEALL */ |
2697 | 0 | if ((d1NvdataSensitive->pubInfo.permission.attributes & TPM_NV_PER_WRITEALL) && |
2698 | | /* i. If dataSize != D1 -> dataSize return TPM_NOT_FULLWRITE */ |
2699 | 0 | (data.size != d1NvdataSensitive->pubInfo.dataSize)) { |
2700 | 0 | printf("TPM_Process_NVWriteValueAuth: Error, Must write all %u\n", |
2701 | 0 | d1NvdataSensitive->pubInfo.dataSize); |
2702 | 0 | returnCode = TPM_NOT_FULLWRITE; |
2703 | 0 | } |
2704 | 0 | } |
2705 | 0 | if (returnCode == TPM_SUCCESS) { |
2706 | | /* not GPIO */ |
2707 | 0 | if (!isGPIO) { |
2708 | | /* wearout optimization, don't write if the data is the same */ |
2709 | 0 | irc = memcmp((d1NvdataSensitive->data) + offset, data.buffer, data.size); |
2710 | 0 | if (irc != 0) { |
2711 | | /* d. Write the new value into the NV storage area */ |
2712 | 0 | printf("TPM_Process_NVWriteValueAuth: Copying data\n"); |
2713 | 0 | memcpy((d1NvdataSensitive->data) + offset, data.buffer, data.size); |
2714 | | /* must write TPM_PERMANENT_DATA back to NVRAM, set this flag after |
2715 | | structure is written */ |
2716 | 0 | writeAllNV = TRUE; |
2717 | 0 | } |
2718 | 0 | else { |
2719 | 0 | printf("TPM_Process_NVWriteValueAuth: Same data, no copy\n"); |
2720 | 0 | } |
2721 | 0 | } |
2722 | | /* GPIO */ |
2723 | 0 | else { |
2724 | 0 | printf("TPM_Process_NVWriteValueAuth: Writing GPIO\n"); |
2725 | 0 | returnCode = TPM_IO_GPIO_Write(nvIndex, |
2726 | 0 | data.size, |
2727 | 0 | data.buffer, |
2728 | 0 | tpm_state->tpm_number); |
2729 | 0 | } |
2730 | 0 | } |
2731 | 0 | } |
2732 | 0 | } |
2733 | | /* 12. Set D1 -> bReadSTClear to FALSE */ |
2734 | 0 | if (returnCode == TPM_SUCCESS) { |
2735 | 0 | d1NvdataSensitive->pubInfo.bReadSTClear = FALSE; |
2736 | 0 | printf("TPM_Process_NVWriteValueAuth: Writing data to NVRAM\n"); |
2737 | 0 | } |
2738 | | /* write back TPM_PERMANENT_DATA if required */ |
2739 | 0 | returnCode = TPM_PermanentAll_NVStore(tpm_state, |
2740 | 0 | writeAllNV, |
2741 | 0 | returnCode); |
2742 | | /* |
2743 | | response |
2744 | | */ |
2745 | | /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ |
2746 | 0 | if (rcf == 0) { |
2747 | 0 | printf("TPM_Process_NVWriteValueAuth: Ordinal returnCode %08x %u\n", |
2748 | 0 | returnCode, returnCode); |
2749 | 0 | rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); |
2750 | 0 | } |
2751 | | /* success response, append the rest of the parameters. */ |
2752 | 0 | if (rcf == 0) { |
2753 | 0 | if (returnCode == TPM_SUCCESS) { |
2754 | | /* checkpoint the beginning of the outParam's */ |
2755 | 0 | outParamStart = response->buffer_current - response->buffer; |
2756 | | /* checkpoint the end of the outParam's */ |
2757 | 0 | outParamEnd = response->buffer_current - response->buffer; |
2758 | 0 | } |
2759 | | /* digest the above the line output parameters */ |
2760 | 0 | if (returnCode == TPM_SUCCESS) { |
2761 | 0 | returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ |
2762 | 0 | auditStatus, /* input audit status */ |
2763 | 0 | transportEncrypt, |
2764 | 0 | tag, |
2765 | 0 | returnCode, |
2766 | 0 | ordinal, /* command ordinal */ |
2767 | 0 | response->buffer + outParamStart, /* start */ |
2768 | 0 | outParamEnd - outParamStart); /* length */ |
2769 | 0 | } |
2770 | | /* calculate and set the below the line parameters */ |
2771 | 0 | if (returnCode == TPM_SUCCESS) { |
2772 | 0 | returnCode = TPM_AuthParams_Set(response, |
2773 | 0 | *hmacKey, /* HMAC key */ |
2774 | 0 | auth_session_data, |
2775 | 0 | outParamDigest, |
2776 | 0 | nonceOdd, |
2777 | 0 | continueAuthSession); |
2778 | 0 | } |
2779 | | /* audit if required */ |
2780 | 0 | if ((returnCode == TPM_SUCCESS) && auditStatus) { |
2781 | 0 | returnCode = TPM_ProcessAudit(tpm_state, |
2782 | 0 | transportEncrypt, |
2783 | 0 | inParamDigest, |
2784 | 0 | outParamDigest, |
2785 | 0 | ordinal); |
2786 | 0 | } |
2787 | | /* adjust the initial response */ |
2788 | 0 | rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); |
2789 | 0 | } |
2790 | | /* if there was an error, or continueAuthSession is FALSE, terminate the session */ |
2791 | 0 | if (((rcf != 0) || |
2792 | 0 | ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || |
2793 | 0 | !continueAuthSession) && |
2794 | 0 | authHandleValid) { |
2795 | 0 | TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); |
2796 | 0 | } |
2797 | | /* |
2798 | | cleanup |
2799 | | */ |
2800 | 0 | TPM_SizedBuffer_Delete(&data); /* @1 */ |
2801 | 0 | return rcf; |
2802 | 0 | } |
2803 | | |
2804 | | /* 20.1 TPM_NV_DefineSpace rev 109 |
2805 | | |
2806 | | This establishes the space necessary for the indicated index. The definition will include the |
2807 | | access requirements for writing and reading the area. |
2808 | | |
2809 | | Previously defined space at the index and new size is non-zero (and space is available, |
2810 | | etc.) -> redefine the index |
2811 | | |
2812 | | No previous space at the index and new size is non-zero (and space is available, etc.)-> |
2813 | | define the index |
2814 | | |
2815 | | Previously defined space at the index and new size is 0 -> delete the index |
2816 | | |
2817 | | No previous space at the index and new size is 0 -> error |
2818 | | |
2819 | | The space definition size does not include the area needed to manage the space. |
2820 | | |
2821 | | Setting TPM_PERMANENT_FLAGS -> nvLocked TRUE when it is already TRUE is not an error. |
2822 | | |
2823 | | For the case where pubInfo -> dataSize is 0, pubInfo -> pcrInfoRead and pubInfo -> pcrInfoWrite |
2824 | | are not used. However, since the general principle is to validate parameters before changing |
2825 | | state, the TPM SHOULD parse pubInfo completely before invalidating the data area. |
2826 | | */ |
2827 | | |
2828 | | TPM_RESULT TPM_Process_NVDefineSpace(tpm_state_t *tpm_state, |
2829 | | TPM_STORE_BUFFER *response, |
2830 | | TPM_TAG tag, |
2831 | | uint32_t paramSize, |
2832 | | TPM_COMMAND_CODE ordinal, |
2833 | | unsigned char *command, |
2834 | | TPM_TRANSPORT_INTERNAL *transportInternal) |
2835 | 0 | { |
2836 | 0 | TPM_RESULT rcf = 0; /* fatal error precluding response */ |
2837 | 0 | TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ |
2838 | | |
2839 | | /* input parameters */ |
2840 | 0 | TPM_NV_INDEX newNVIndex = TPM_NV_INDEX_LOCK; /* from input TPM_NV_DATA_PUBLIC, initialize |
2841 | | to silence compiler */ |
2842 | 0 | TPM_ENCAUTH encAuth; /* The encrypted AuthData, only valid if the attributes |
2843 | | require subsequent authorization */ |
2844 | 0 | TPM_AUTHHANDLE authHandle; /* The authorization session handle used for ownerAuth */ |
2845 | 0 | TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ |
2846 | 0 | TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the authorization |
2847 | | session handle */ |
2848 | 0 | TPM_AUTHDATA ownerAuth; /* The authorization session digest HMAC key: ownerAuth */ |
2849 | | |
2850 | | /* processing parameters */ |
2851 | 0 | unsigned char * inParamStart; /* starting point of inParam's */ |
2852 | 0 | unsigned char * inParamEnd; /* ending point of inParam's */ |
2853 | 0 | TPM_DIGEST inParamDigest; |
2854 | 0 | TPM_BOOL auditStatus; /* audit the ordinal */ |
2855 | 0 | TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ |
2856 | 0 | TPM_BOOL authHandleValid = FALSE; |
2857 | 0 | TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ |
2858 | 0 | TPM_SECRET *hmacKey = NULL; |
2859 | 0 | TPM_BOOL ignore_auth = FALSE; |
2860 | 0 | TPM_BOOL writeAllNV = FALSE; /* flag to write back NV */ |
2861 | 0 | TPM_BOOL done = FALSE; /* processing is done */ |
2862 | 0 | TPM_DIGEST a1Auth; |
2863 | 0 | TPM_NV_DATA_SENSITIVE *d1_old; /* possibly old data */ |
2864 | 0 | TPM_NV_DATA_SENSITIVE *d1_new = NULL; /* new data */ |
2865 | 0 | TPM_NV_DATA_PUBLIC *pubInfo = NULL; /* new, initialize to silence |
2866 | | compiler */ |
2867 | 0 | uint32_t freeSpace; /* free space after allocating new |
2868 | | index */ |
2869 | 0 | TPM_BOOL writeLocalities = FALSE; |
2870 | 0 | TPM_BOOL physicalPresence; |
2871 | 0 | TPM_BOOL foundOld = TRUE; /* index already exists, initialize |
2872 | | to silence compiler */ |
2873 | 0 | uint32_t nv1 = tpm_state->tpm_permanent_data.noOwnerNVWrite; |
2874 | | /* temp for noOwnerNVWrite, initialize to silence |
2875 | | compiler */ |
2876 | 0 | TPM_BOOL nv1Incremented = FALSE; /* flag that nv1 was incremented */ |
2877 | | |
2878 | | /* output parameters */ |
2879 | 0 | uint32_t outParamStart; /* starting point of outParam's */ |
2880 | 0 | uint32_t outParamEnd; /* ending point of outParam's */ |
2881 | 0 | TPM_DIGEST outParamDigest; |
2882 | |
|
2883 | 0 | printf("TPM_Process_NVDefineSpace: Ordinal Entry\n"); |
2884 | | /* This design gets a slot in the TPM_NV_INDEX_ENTRIES array, either an existing empty one or a |
2885 | | newly re'allocated one. The incoming parameters are deserialized directly into the slot. |
2886 | | |
2887 | | On success, the slot remains. On failure, the slot is deleted. There is no need to remove |
2888 | | the slot from the array. It can remain for the next call. |
2889 | | */ |
2890 | | /* |
2891 | | get inputs |
2892 | | */ |
2893 | | /* save the starting point of inParam's for authorization and auditing */ |
2894 | 0 | inParamStart = command; |
2895 | | /* get or create a free index in the TPM_NV_INDEX_ENTRIES array */ |
2896 | 0 | if (returnCode == TPM_SUCCESS) { |
2897 | 0 | returnCode = TPM_NVIndexEntries_GetFreeEntry(&d1_new, &(tpm_state->tpm_nv_index_entries)); |
2898 | 0 | } |
2899 | 0 | if (returnCode == TPM_SUCCESS) { |
2900 | 0 | if (d1_new == NULL) { // -fanalyzer |
2901 | 0 | returnCode = TPM_FAIL; |
2902 | 0 | } |
2903 | 0 | } |
2904 | | /* get pubInfo parameter */ |
2905 | 0 | if (returnCode == TPM_SUCCESS) { |
2906 | 0 | pubInfo = &(d1_new->pubInfo); /* pubInfo is an input parameter */ |
2907 | 0 | returnCode = TPM_NVDataPublic_Load(pubInfo, |
2908 | 0 | &command, ¶mSize, |
2909 | 0 | FALSE); /* not optimized for digestAtRelease */ |
2910 | | /* The NV index cannot be immediately deserialized in the slot, or the function will think |
2911 | | that the index already exists. Therefore, the nvIndex parameter is saved and temporarily |
2912 | | set to empty until the old slot is deleted. */ |
2913 | 0 | newNVIndex = pubInfo->nvIndex; /* save the possibly new index */ |
2914 | 0 | pubInfo->nvIndex = TPM_NV_INDEX_LOCK; /* temporarily mark unused */ |
2915 | 0 | } |
2916 | 0 | if (returnCode == TPM_SUCCESS) { |
2917 | 0 | printf("TPM_Process_NVDefineSpace: index %08x permission %08x dataSize %08x\n", |
2918 | 0 | newNVIndex, pubInfo->permission.attributes, pubInfo->dataSize); |
2919 | 0 | TPM_PCRInfo_Trace("TPM_Process_NVDefineSpace: pcrInfoRead", |
2920 | 0 | pubInfo->pcrInfoRead.pcrSelection, |
2921 | 0 | pubInfo->pcrInfoRead.digestAtRelease); |
2922 | 0 | TPM_PCRInfo_Trace("TPM_Process_NVDefineSpace: pcrInfoWrite", |
2923 | 0 | pubInfo->pcrInfoWrite.pcrSelection, |
2924 | 0 | pubInfo->pcrInfoWrite.digestAtRelease); |
2925 | | /* get encAuth parameter */ |
2926 | 0 | returnCode = TPM_Secret_Load(encAuth, &command, ¶mSize); |
2927 | 0 | } |
2928 | | /* save the ending point of inParam's for authorization and auditing */ |
2929 | 0 | inParamEnd = command; |
2930 | | /* digest the input parameters */ |
2931 | 0 | if (returnCode == TPM_SUCCESS) { |
2932 | 0 | returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ |
2933 | 0 | &auditStatus, /* output */ |
2934 | 0 | &transportEncrypt, /* output */ |
2935 | 0 | tpm_state, |
2936 | 0 | tag, |
2937 | 0 | ordinal, |
2938 | 0 | inParamStart, |
2939 | 0 | inParamEnd, |
2940 | 0 | transportInternal); |
2941 | 0 | } |
2942 | | /* check state */ |
2943 | 0 | if (returnCode == TPM_SUCCESS) { |
2944 | 0 | returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALLOW_NO_OWNER | TPM_CHECK_NV_NOAUTH); |
2945 | 0 | } |
2946 | | /* check tag */ |
2947 | 0 | if (returnCode == TPM_SUCCESS) { |
2948 | 0 | returnCode = TPM_CheckRequestTag10(tag); |
2949 | 0 | } |
2950 | | /* get the optional 'below the line' authorization parameters */ |
2951 | 0 | if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { |
2952 | 0 | returnCode = TPM_AuthParams_Get(&authHandle, |
2953 | 0 | &authHandleValid, |
2954 | 0 | nonceOdd, |
2955 | 0 | &continueAuthSession, |
2956 | 0 | ownerAuth, |
2957 | 0 | &command, ¶mSize); |
2958 | 0 | } |
2959 | 0 | if (returnCode == TPM_SUCCESS) { |
2960 | 0 | if (paramSize != 0) { |
2961 | 0 | printf("TPM_Process_NVDefineSpace: Error, command has %u extra bytes\n", |
2962 | 0 | paramSize); |
2963 | 0 | returnCode = TPM_BAD_PARAM_SIZE; |
2964 | 0 | } |
2965 | 0 | } |
2966 | | /* do not terminate sessions if the command did not parse correctly */ |
2967 | 0 | if (returnCode != TPM_SUCCESS) { |
2968 | 0 | authHandleValid = FALSE; |
2969 | 0 | } |
2970 | | /* |
2971 | | Processing |
2972 | | */ |
2973 | | /* 1. If pubInfo -> nvIndex == TPM_NV_INDEX_LOCK and tag = TPM_TAG_RQU_COMMAND */ |
2974 | 0 | if ((returnCode == TPM_SUCCESS) && |
2975 | 0 | (newNVIndex == TPM_NV_INDEX_LOCK) && |
2976 | 0 | (tag == TPM_TAG_RQU_COMMAND)) { |
2977 | | /* a. If pubInfo -> dataSize is not 0, the command MAY return TPM_BADINDEX. */ |
2978 | 0 | if (pubInfo->dataSize != 0) { |
2979 | 0 | printf("TPM_Process_NVDefineSpace: Error, TPM_NV_INDEX_LOCK dataSize %u\n", |
2980 | 0 | pubInfo->dataSize); |
2981 | 0 | returnCode = TPM_BADINDEX; |
2982 | 0 | } |
2983 | 0 | else { |
2984 | | /* b. Set TPM_PERMANENT_FLAGS -> nvLocked to TRUE */ |
2985 | | /* writeAllNV set to TRUE if nvLocked is being set, not if already set */ |
2986 | 0 | printf("TPM_Process_NVDefineSpace: Setting nvLocked\n"); |
2987 | 0 | TPM_SetCapability_Flag(&writeAllNV, /* altered */ |
2988 | 0 | &(tpm_state->tpm_permanent_flags.nvLocked ), /* flag */ |
2989 | 0 | TRUE); /* value */ |
2990 | 0 | } |
2991 | | /* c. Return TPM_SUCCESS */ |
2992 | 0 | done = TRUE; |
2993 | 0 | } |
2994 | | /* 2. If TPM_PERMANENT_FLAGS -> nvLocked is FALSE then all authorization checks except for the |
2995 | | Max NV writes are ignored */ |
2996 | | /* a. Ignored checks include physical presence, owner authorization, 'D' bit check, bGlobalLock, |
2997 | | no authorization with a TPM owner present, bWriteSTClear, the check that pubInfo -> dataSize |
2998 | | is 0 in Action 5.c. (the no-authorization case), disabled and deactivated. */ |
2999 | | /* NOTE: The disabled and deactivated flags are conditionally checked by TPM_CheckState() using |
3000 | | the TPM_CHECK_NV_NOAUTH flag */ |
3001 | | /* ii. The check that pubInfo -> dataSize is 0 is still enforced in Action 6.f. (returning after |
3002 | | deleting a previously defined storage area) and Action 9.f. (not allowing a space of size 0 |
3003 | | to be defined). */ |
3004 | | /* i.If ownerAuth is present, the TPM MAY check the authorization HMAC. */ |
3005 | 0 | if (returnCode == TPM_SUCCESS) { |
3006 | 0 | if (!(tpm_state->tpm_permanent_flags.nvLocked)) { |
3007 | 0 | printf("TPM_Process_NVDefineSpace: nvLocked FALSE, ignoring authorization\n"); |
3008 | 0 | ignore_auth = TRUE; |
3009 | 0 | } |
3010 | 0 | } |
3011 | | /* b.The check for pubInfo -> nvIndex == 0 in Action 3. is not ignored. */ |
3012 | 0 | if ((returnCode == TPM_SUCCESS) && !done) { |
3013 | 0 | if (newNVIndex == TPM_NV_INDEX0) { |
3014 | 0 | printf("TPM_Process_NVDefineSpace: Error, bad index %08x\n", newNVIndex); |
3015 | 0 | returnCode = TPM_BADINDEX; |
3016 | 0 | } |
3017 | 0 | } |
3018 | | /* 3. If pubInfo -> nvIndex has the D bit (bit 28) set to a 1 or pubInfo -> nvIndex == 0 then */ |
3019 | 0 | if ((returnCode == TPM_SUCCESS) && !done && !ignore_auth) { |
3020 | | /* b. The D bit specifies an index value that is set in manufacturing and can never be |
3021 | | deleted or added to the TPM */ |
3022 | 0 | if (newNVIndex & TPM_NV_INDEX_D_BIT) { |
3023 | | /* c. Index value of 0 is reserved and cannot be defined */ |
3024 | | /* a. Return TPM_BADINDEX */ |
3025 | 0 | printf("TPM_Process_NVDefineSpace: Error, bad index %08x\n", newNVIndex); |
3026 | 0 | returnCode = TPM_BADINDEX; |
3027 | 0 | } |
3028 | 0 | } |
3029 | | /* 4. If tag = TPM_TAG_RQU_AUTH1_COMMAND then */ |
3030 | | /* b. authHandle session type MUST be OSAP */ |
3031 | | /* must get the HMAC key for the response even if ignore_auth is TRUE */ |
3032 | 0 | if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { |
3033 | 0 | returnCode = TPM_AuthSessions_GetData(&auth_session_data, |
3034 | 0 | &hmacKey, |
3035 | 0 | tpm_state, |
3036 | 0 | authHandle, |
3037 | 0 | TPM_PID_OSAP, |
3038 | 0 | TPM_ET_OWNER, |
3039 | 0 | ordinal, |
3040 | 0 | NULL, |
3041 | 0 | NULL, |
3042 | 0 | tpm_state->tpm_permanent_data.ownerAuth); |
3043 | 0 | } |
3044 | | /* a. The TPM MUST validate the command and parameters using the TPM Owner authentication and |
3045 | | ownerAuth, on error return TPM_AUTHFAIL */ |
3046 | | /* NOTE: This is optional if ignore_auth is TRUE */ |
3047 | 0 | if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND) && !done) { |
3048 | 0 | returnCode = TPM_Authdata_Check(tpm_state, |
3049 | 0 | *hmacKey, /* HMAC key */ |
3050 | 0 | inParamDigest, |
3051 | 0 | auth_session_data, /* authorization session */ |
3052 | 0 | nonceOdd, /* Nonce generated by system |
3053 | | associated with authHandle */ |
3054 | 0 | continueAuthSession, |
3055 | 0 | ownerAuth); /* Authorization digest for input */ |
3056 | 0 | } |
3057 | | /* c. Create A1 by decrypting encAuth according to the ADIP indicated by authHandle. */ |
3058 | 0 | if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND) && !done) { |
3059 | 0 | returnCode = TPM_AuthSessionData_Decrypt(a1Auth, |
3060 | 0 | NULL, |
3061 | 0 | encAuth, |
3062 | 0 | auth_session_data, |
3063 | 0 | NULL, |
3064 | 0 | NULL, |
3065 | 0 | FALSE); /* even and odd */ |
3066 | 0 | } |
3067 | | /* 5. else (not auth1) */ |
3068 | | /* a. Validate the assertion of physical presence. Return TPM_BAD_PRESENCE on error. */ |
3069 | 0 | if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_COMMAND) && !done && !ignore_auth) { |
3070 | 0 | if (returnCode == TPM_SUCCESS) { |
3071 | 0 | returnCode = TPM_Global_GetPhysicalPresence(&physicalPresence, tpm_state); |
3072 | 0 | } |
3073 | 0 | if (returnCode == TPM_SUCCESS) { |
3074 | 0 | if (!physicalPresence) { |
3075 | 0 | printf("TPM_Process_NVDefineSpace: Error, physicalPresence is FALSE\n"); |
3076 | 0 | returnCode = TPM_BAD_PRESENCE; |
3077 | 0 | } |
3078 | 0 | } |
3079 | 0 | } |
3080 | | /* b. If TPM Owner is present then return TPM_OWNER_SET. */ |
3081 | 0 | if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_COMMAND) && !done && !ignore_auth) { |
3082 | 0 | if (tpm_state->tpm_permanent_data.ownerInstalled) { |
3083 | 0 | printf("TPM_Process_NVDefineSpace: Error, no authorization, but owner installed\n"); |
3084 | 0 | returnCode = TPM_OWNER_SET; |
3085 | 0 | } |
3086 | 0 | } |
3087 | | /* c. If pubInfo -> dataSize is 0 then return TPM_BAD_DATASIZE. Setting the size to 0 represents |
3088 | | an attempt to delete the value without TPM Owner authentication. */ |
3089 | 0 | if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_COMMAND) && !done && !ignore_auth) { |
3090 | 0 | if (pubInfo->dataSize == 0) { |
3091 | 0 | printf("TPM_Process_NVDefineSpace: Error, no owner authorization and dataSize 0\n"); |
3092 | 0 | returnCode = TPM_BAD_DATASIZE; |
3093 | 0 | } |
3094 | 0 | } |
3095 | | /* d. Validate max NV writes without an owner */ |
3096 | 0 | if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_COMMAND) && !done) { |
3097 | | /* i. Set NV1 to TPM_PERMANENT_DATA -> noOwnerNVWrite */ |
3098 | 0 | nv1 = tpm_state->tpm_permanent_data.noOwnerNVWrite; |
3099 | | /* ii. Increment NV1 by 1 */ |
3100 | 0 | nv1++; |
3101 | | /* iii. If NV1 > TPM_MAX_NV_WRITE_NOOWNER return TPM_MAXNVWRITES */ |
3102 | 0 | if (nv1 > TPM_MAX_NV_WRITE_NOOWNER) { |
3103 | 0 | printf("TPM_Process_NVDefineSpace: Error, max NV writes %d w/o owner reached\n", |
3104 | 0 | tpm_state->tpm_permanent_data.noOwnerNVWrite); |
3105 | 0 | returnCode = TPM_MAXNVWRITES; |
3106 | 0 | } |
3107 | 0 | else { |
3108 | | /* iv. Set NV1_INCREMENTED to TRUE */ |
3109 | 0 | nv1Incremented = TRUE; |
3110 | 0 | } |
3111 | 0 | } |
3112 | | /* e. Set A1 to encAuth. There is no nonce or authorization to create the encryption string, |
3113 | | hence the AuthData value is passed in the clear */ |
3114 | 0 | if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_COMMAND) && !done) { |
3115 | 0 | TPM_Digest_Copy(a1Auth, encAuth); |
3116 | 0 | } |
3117 | | /* 6. If pubInfo -> nvIndex points to a valid previously defined storage area then */ |
3118 | | /* 6.a. Map D1 a TPM_NV_DATA_SENSITIVE to the storage area */ |
3119 | 0 | if ((returnCode == TPM_SUCCESS) && !done) { |
3120 | 0 | printf("TPM_Process_NVDefineSpace: Loading existing NV index %08x\n", newNVIndex); |
3121 | 0 | returnCode = TPM_NVIndexEntries_GetEntry(&d1_old, |
3122 | 0 | &(tpm_state->tpm_nv_index_entries), |
3123 | 0 | newNVIndex); |
3124 | 0 | if (returnCode == TPM_SUCCESS) { |
3125 | 0 | printf("TPM_Process_NVDefineSpace: NV index %08x exists\n", newNVIndex); |
3126 | 0 | foundOld = TRUE; |
3127 | 0 | } |
3128 | 0 | else if (returnCode == TPM_BADINDEX) { |
3129 | 0 | returnCode = TPM_SUCCESS; /* non-existent index is not an error */ |
3130 | 0 | foundOld = FALSE; |
3131 | 0 | printf("TPM_Process_NVDefineSpace: Index %08x is new\n", newNVIndex); |
3132 | 0 | } |
3133 | 0 | } |
3134 | 0 | if ((returnCode == TPM_SUCCESS) && !done && !ignore_auth && foundOld) { |
3135 | | /* 6.b. If D1 -> attributes specifies TPM_NV_PER_GLOBALLOCK then */ |
3136 | 0 | if (d1_old->pubInfo.permission.attributes & TPM_NV_PER_GLOBALLOCK) { |
3137 | | /* i. If TPM_STCLEAR_FLAGS -> bGlobalLock is TRUE then return TPM_AREA_LOCKED */ |
3138 | 0 | if (tpm_state->tpm_stclear_flags.bGlobalLock) { |
3139 | 0 | printf("TPM_Process_NVDefineSpace: Error, index %08x (bGlobalLock) locked\n", |
3140 | 0 | newNVIndex); |
3141 | 0 | returnCode = TPM_AREA_LOCKED; |
3142 | 0 | } |
3143 | 0 | } |
3144 | 0 | } |
3145 | 0 | if ((returnCode == TPM_SUCCESS) && !done && !ignore_auth && foundOld) { |
3146 | | /* 6.c. If D1 -> attributes specifies TPM_NV_PER_WRITE_STCLEAR */ |
3147 | 0 | if (d1_old->pubInfo.permission.attributes & TPM_NV_PER_WRITE_STCLEAR) { |
3148 | | /* i. If D1 -> pubInfo -> bWriteSTClear is TRUE then return TPM_AREA_LOCKED */ |
3149 | 0 | if (d1_old->pubInfo.bWriteSTClear) { |
3150 | 0 | printf("TPM_Process_NVDefineSpace: Error, area locked by bWriteSTClear\n"); |
3151 | 0 | returnCode = TPM_AREA_LOCKED; |
3152 | 0 | } |
3153 | 0 | } |
3154 | 0 | } |
3155 | | /* NOTE Changed the Action order. Must terminate auth sessions while the old index digest |
3156 | | still exists. |
3157 | | */ |
3158 | | /* 6.f. The TPM invalidates authorization sessions */ |
3159 | | /* i. MUST invalidate all authorization sessions associated with D1 */ |
3160 | | /* ii. MAY invalidate any other authorization session */ |
3161 | 0 | if ((returnCode == TPM_SUCCESS) && !done && foundOld) { |
3162 | 0 | TPM_AuthSessions_TerminateEntity(&continueAuthSession, |
3163 | 0 | authHandle, |
3164 | 0 | tpm_state->tpm_stclear_data.authSessions, |
3165 | 0 | TPM_ET_NV, |
3166 | 0 | &(d1_old->digest)); |
3167 | 0 | } |
3168 | 0 | if ((returnCode == TPM_SUCCESS) && !done && foundOld) { |
3169 | | /* 6.d. Invalidate the data area currently pointed to by D1 and ensure that if the area is |
3170 | | reallocated no residual information is left */ |
3171 | 0 | printf("TPM_Process_NVDefineSpace: Deleting index %08x\n", newNVIndex); |
3172 | 0 | TPM_NVDataSensitive_Delete(d1_old); |
3173 | | /* must write deleted space back to NVRAM */ |
3174 | 0 | writeAllNV = TRUE; |
3175 | | /* 6.e. If NV1_INCREMENTED is TRUE */ |
3176 | | /* i. Set TPM_PERMANENT_DATA -> noOwnerNVWrite to NV1 */ |
3177 | | /* NOTE Don't do this step until just before the serialization */ |
3178 | 0 | } |
3179 | | /* g. If pubInfo -> dataSize is 0 then return TPM_SUCCESS */ |
3180 | 0 | if ((returnCode == TPM_SUCCESS) && !done && foundOld) { |
3181 | 0 | if (pubInfo->dataSize == 0) { |
3182 | 0 | printf("TPM_Process_NVDefineSpace: Size 0, done\n"); |
3183 | 0 | done = TRUE; |
3184 | 0 | } |
3185 | 0 | } |
3186 | | /* 7. Parse pubInfo -> pcrInfoRead */ |
3187 | | /* a. Validate pcrInfoRead structure on error return TPM_INVALID_STRUCTURE */ |
3188 | | /* i. Validation includes proper PCR selections and locality selections */ |
3189 | | /* NOTE: Done by TPM_NVDataPublic_Load() */ |
3190 | | /* 8. Parse pubInfo -> pcrInfoWrite */ |
3191 | | /* a. Validate pcrInfoWrite structure on error return TPM_INVALID_STRUCTURE */ |
3192 | | /* i. Validation includes proper PCR selections and locality selections */ |
3193 | | /* NOTE: Done by TPM_NVDataPublic_Load() */ |
3194 | 0 | if ((returnCode == TPM_SUCCESS) && !done) { |
3195 | | /* b. If pcrInfoWrite -> localityAtRelease disallows some localities */ |
3196 | 0 | if (pubInfo->pcrInfoRead.localityAtRelease != TPM_LOC_ALL) { |
3197 | | /* i. Set writeLocalities to TRUE */ |
3198 | 0 | writeLocalities = TRUE; |
3199 | 0 | } |
3200 | | /* c. Else */ |
3201 | 0 | else { |
3202 | | /* i. Set writeLocalities to FALSE */ |
3203 | 0 | writeLocalities = FALSE; |
3204 | 0 | } |
3205 | 0 | } |
3206 | | /* 9. Validate that the attributes are consistent */ |
3207 | | /* a. The TPM SHALL ignore the bReadSTClear, bWriteSTClear and bWriteDefine attributes during |
3208 | | the execution of this command */ |
3209 | | /* b. If TPM_NV_PER_OWNERWRITE is TRUE and TPM_NV_PER_AUTHWRITE is TRUE return TPM_AUTH_CONFLICT |
3210 | | */ |
3211 | 0 | if ((returnCode == TPM_SUCCESS) && !done) { |
3212 | 0 | if ((pubInfo->permission.attributes & TPM_NV_PER_OWNERWRITE) && |
3213 | 0 | (pubInfo->permission.attributes & TPM_NV_PER_AUTHWRITE)) { |
3214 | 0 | printf("TPM_Process_NVDefineSpace: Error, write authorization conflict\n"); |
3215 | 0 | returnCode = TPM_AUTH_CONFLICT; |
3216 | 0 | } |
3217 | 0 | } |
3218 | | /* c. If TPM_NV_PER_OWNERREAD is TRUE and TPM_NV_PER_AUTHREAD is TRUE return TPM_AUTH_CONFLICT |
3219 | | */ |
3220 | 0 | if ((returnCode == TPM_SUCCESS) && !done) { |
3221 | 0 | if ((pubInfo->permission.attributes & TPM_NV_PER_OWNERREAD) && |
3222 | 0 | (pubInfo->permission.attributes & TPM_NV_PER_AUTHREAD)) { |
3223 | 0 | printf("TPM_Process_NVDefineSpace: Error, read authorization conflict\n"); |
3224 | 0 | returnCode = TPM_AUTH_CONFLICT; |
3225 | 0 | } |
3226 | 0 | } |
3227 | | /* d. If TPM_NV_PER_OWNERWRITE and TPM_NV_PER_AUTHWRITE and TPM_NV_PER_WRITEDEFINE and |
3228 | | TPM_NV_PER_PPWRITE and writeLocalities are all FALSE */ |
3229 | 0 | if ((returnCode == TPM_SUCCESS) && !done) { |
3230 | 0 | if (!(pubInfo->permission.attributes & TPM_NV_PER_OWNERWRITE) && |
3231 | 0 | !(pubInfo->permission.attributes & TPM_NV_PER_AUTHWRITE) && |
3232 | 0 | !(pubInfo->permission.attributes & TPM_NV_PER_WRITEDEFINE) && |
3233 | 0 | !(pubInfo->permission.attributes & TPM_NV_PER_PPWRITE) && |
3234 | 0 | !writeLocalities) { |
3235 | | /* i. Return TPM_PER_NOWRITE */ |
3236 | 0 | printf("TPM_Process_NVDefineSpace: Error, no write\n"); |
3237 | 0 | returnCode = TPM_PER_NOWRITE; |
3238 | 0 | } |
3239 | 0 | } |
3240 | | /* e. Validate pubInfo -> nvIndex */ |
3241 | | /* i. Make sure that the index is applicable for this TPM return TPM_BADINDEX on error */ |
3242 | 0 | if ((returnCode == TPM_SUCCESS) && !done) { |
3243 | 0 | returnCode = TPM_NVDataSensitive_IsValidIndex(newNVIndex); |
3244 | 0 | } |
3245 | | /* f. If dataSize is 0 return TPM_BAD_PARAM_SIZE */ |
3246 | 0 | if ((returnCode == TPM_SUCCESS) && !done) { |
3247 | 0 | if (pubInfo->dataSize == 0) { |
3248 | 0 | printf("TPM_Process_NVDefineSpace: Error, New index data size is zero\n"); |
3249 | 0 | returnCode = TPM_BAD_PARAM_SIZE; |
3250 | 0 | } |
3251 | 0 | } |
3252 | | /* 10. Create D1 a TPM_NV_DATA_SENSITIVE structure */ |
3253 | | /* NOTE Created and initialized d1_new directly in the TPM_NV_INDEX_ENTRIES array */ |
3254 | | /* a. Set D1 -> pubInfo to pubInfo */ |
3255 | | /* NOTE deserialized in place */ |
3256 | 0 | if ((returnCode == TPM_SUCCESS) && !done) { |
3257 | | /* b. Set D1 -> authValue to A1 */ |
3258 | 0 | TPM_Digest_Copy(d1_new->authValue, a1Auth); |
3259 | | /* c. Set D1 -> pubInfo -> bReadSTClear to FALSE */ |
3260 | | /* d. Set D1 -> pubInfo -> bWriteSTClear to FALSE */ |
3261 | | /* e. Set D1 -> pubInfo -> bWriteDefine to FALSE */ |
3262 | 0 | pubInfo->bReadSTClear = FALSE; |
3263 | 0 | pubInfo->bWriteSTClear = FALSE; |
3264 | 0 | pubInfo->bWriteDefine = FALSE; |
3265 | 0 | } |
3266 | 0 | if ((returnCode == TPM_SUCCESS) && !done) { |
3267 | | /* assign the empty slot to the index now so it will be counted as used space during the |
3268 | | serialization. */ |
3269 | 0 | pubInfo->nvIndex = newNVIndex; |
3270 | | /* 12.a. Reserve NV space for pubInfo -> dataSize |
3271 | | |
3272 | | NOTE: Action is out or order. Must allocate data space now so that the serialization |
3273 | | inherent in TPM_NVIndexEntries_GetFreeSpace() is valid |
3274 | | */ |
3275 | 0 | returnCode = TPM_Malloc(&(d1_new->data), pubInfo->dataSize); |
3276 | 0 | } |
3277 | | /* 11. Validate that sufficient NV is available to store D1 and pubInfo -> dataSize bytes of |
3278 | | data*/ |
3279 | | /* a. return TPM_NOSPACE if pubInfo -> dataSize is not available in the TPM */ |
3280 | 0 | if ((returnCode == TPM_SUCCESS) && !done) { |
3281 | 0 | printf("TPM_Process_NVDefineSpace: Allocated %u data bytes at %p\n", |
3282 | 0 | pubInfo->dataSize, d1_new->data); |
3283 | 0 | printf("TPM_Process_NVDefineSpace: Checking for %u bytes free space\n", pubInfo->dataSize); |
3284 | 0 | returnCode = TPM_NVIndexEntries_GetFreeSpace(&freeSpace, |
3285 | 0 | &(tpm_state->tpm_nv_index_entries)); |
3286 | 0 | if (returnCode != TPM_SUCCESS) { |
3287 | 0 | printf("TPM_Process_NVDefineSpace: Error: No space\n"); |
3288 | 0 | } |
3289 | 0 | } |
3290 | | /* if there is no free space, free the NV index in-memory structure. This implicitly removes |
3291 | | the entry from tpm_nv_index_entries. If pubInfo -> nvIndex is TPM_NV_INDEX_TRIAL, the entry |
3292 | | should also be removed. */ |
3293 | 0 | if ((returnCode != TPM_SUCCESS) || |
3294 | 0 | (newNVIndex == TPM_NV_INDEX_TRIAL)) { |
3295 | 0 | if (newNVIndex == TPM_NV_INDEX_TRIAL) { |
3296 | 0 | printf("TPM_Process_NVDefineSpace: nvIndex is TPM_NV_INDEX_TRIAL, done\n"); |
3297 | | /* don't actually write, just return success or failure */ |
3298 | 0 | done = TRUE; |
3299 | 0 | } |
3300 | 0 | TPM_NVDataSensitive_Delete(d1_new); |
3301 | 0 | } |
3302 | | /* 12. If pubInfo -> nvIndex is not TPM_NV_INDEX_TRIAL */ |
3303 | 0 | if ((returnCode == TPM_SUCCESS) && !done) { |
3304 | 0 | printf("TPM_Process_NVDefineSpace: Creating index %08x\n", newNVIndex); |
3305 | | /* b. Set all bytes in the newly defined area to 0xFF */ |
3306 | 0 | memset(d1_new->data, 0xff, pubInfo->dataSize); |
3307 | | /* must write newly defined space back to NVRAM */ |
3308 | 0 | writeAllNV = TRUE; |
3309 | 0 | } |
3310 | 0 | if (returnCode == TPM_SUCCESS) { |
3311 | | /* c. If NV1_INCREMENTED is TRUE */ |
3312 | 0 | if (nv1Incremented) { |
3313 | | /* i. Set TPM_PERMANENT_DATA -> noOwnerNVWrite to NV1 */ |
3314 | 0 | tpm_state->tpm_permanent_data.noOwnerNVWrite = nv1; |
3315 | 0 | } |
3316 | | /* 13. Ignore continueAuthSession on input and set to FALSE on output */ |
3317 | 0 | continueAuthSession = FALSE; |
3318 | 0 | } |
3319 | | /* write the file to NVRAM */ |
3320 | | /* write back TPM_PERMANENT_DATA and TPM_PERMANENT_FLAGS if required */ |
3321 | 0 | returnCode = TPM_PermanentAll_NVStore(tpm_state, |
3322 | 0 | writeAllNV, |
3323 | 0 | returnCode); |
3324 | | /* |
3325 | | response |
3326 | | */ |
3327 | | /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ |
3328 | 0 | if (rcf == 0) { |
3329 | 0 | printf("TPM_Process_NVDefineSpace: Ordinal returnCode %08x %u\n", |
3330 | 0 | returnCode, returnCode); |
3331 | 0 | rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); |
3332 | 0 | } |
3333 | | /* success response, append the rest of the parameters. */ |
3334 | 0 | if (rcf == 0) { |
3335 | 0 | if (returnCode == TPM_SUCCESS) { |
3336 | | /* checkpoint the beginning of the outParam's */ |
3337 | 0 | outParamStart = response->buffer_current - response->buffer; |
3338 | | /* checkpoint the end of the outParam's */ |
3339 | 0 | outParamEnd = response->buffer_current - response->buffer; |
3340 | 0 | } |
3341 | | /* digest the above the line output parameters */ |
3342 | 0 | if (returnCode == TPM_SUCCESS) { |
3343 | 0 | returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ |
3344 | 0 | auditStatus, /* input audit status */ |
3345 | 0 | transportEncrypt, |
3346 | 0 | tag, |
3347 | 0 | returnCode, |
3348 | 0 | ordinal, /* command ordinal */ |
3349 | 0 | response->buffer + outParamStart, /* start */ |
3350 | 0 | outParamEnd - outParamStart); /* length */ |
3351 | 0 | } |
3352 | | /* calculate and set the below the line parameters */ |
3353 | 0 | if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { |
3354 | 0 | returnCode = TPM_AuthParams_Set(response, |
3355 | 0 | *hmacKey, /* owner HMAC key */ |
3356 | 0 | auth_session_data, |
3357 | 0 | outParamDigest, |
3358 | 0 | nonceOdd, |
3359 | 0 | continueAuthSession); |
3360 | 0 | } |
3361 | | /* audit if required */ |
3362 | 0 | if ((returnCode == TPM_SUCCESS) && auditStatus) { |
3363 | 0 | returnCode = TPM_ProcessAudit(tpm_state, |
3364 | 0 | transportEncrypt, |
3365 | 0 | inParamDigest, |
3366 | 0 | outParamDigest, |
3367 | 0 | ordinal); |
3368 | 0 | } |
3369 | | /* adjust the initial response */ |
3370 | 0 | rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); |
3371 | 0 | } |
3372 | | /* if there was an error, or continueAuthSession is FALSE, terminate the session */ |
3373 | 0 | if (((rcf != 0) || |
3374 | 0 | ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || |
3375 | 0 | !continueAuthSession) && |
3376 | 0 | authHandleValid) { |
3377 | 0 | TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); |
3378 | 0 | } |
3379 | | /* |
3380 | | cleanup |
3381 | | */ |
3382 | 0 | return rcf; |
3383 | 0 | } |
3384 | | |
3385 | | /* 27.3 DIR commands rev 87 |
3386 | | |
3387 | | The DIR commands are replaced by the NV storage commands. |
3388 | | |
3389 | | The DIR [0] in 1.1 is now TPM_PERMANENT_DATA -> authDIR[0] and is always available for the TPM to |
3390 | | use. It is accessed by DIR commands using dirIndex 0 and by NV commands using nvIndex |
3391 | | TPM_NV_INDEX_DIR. |
3392 | | |
3393 | | If the TPM vendor supports additional DIR registers, the TPM vendor may return errors or provide |
3394 | | vendor specific mappings for those DIR registers to NV storage locations. |
3395 | | |
3396 | | 1. A dirIndex value of 0 MUST corresponds to an NV storage nvIndex value TPM_NV_INDEX_DIR. |
3397 | | |
3398 | | 2. The TPM vendor MAY return errors or MAY provide vendor specific mappings for DIR dirIndex |
3399 | | values greater than 0 to NV storage locations. |
3400 | | */ |
3401 | | |
3402 | | /* 27.3.1 TPM_DirWriteAuth rev 87 |
3403 | | |
3404 | | The TPM_DirWriteAuth operation provides write access to the Data Integrity Registers. DIRs are |
3405 | | non-volatile memory registers held in a TPM-shielded location. Owner authentication is required |
3406 | | to authorize this action. |
3407 | | |
3408 | | Access is also provided through the NV commands with nvIndex TPM_NV_INDEX_DIR. Owner |
3409 | | authorization is not required when nvLocked is FALSE. |
3410 | | |
3411 | | Version 1.2 requires only one DIR. If the DIR named does not exist, the TPM_DirWriteAuth |
3412 | | operation returns TPM_BADINDEX. |
3413 | | */ |
3414 | | |
3415 | | TPM_RESULT TPM_Process_DirWriteAuth(tpm_state_t *tpm_state, |
3416 | | TPM_STORE_BUFFER *response, |
3417 | | TPM_TAG tag, |
3418 | | uint32_t paramSize, |
3419 | | TPM_COMMAND_CODE ordinal, |
3420 | | unsigned char *command, |
3421 | | TPM_TRANSPORT_INTERNAL *transportInternal) |
3422 | 0 | { |
3423 | 0 | TPM_RESULT rcf = 0; /* fatal error precluding response */ |
3424 | 0 | TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ |
3425 | | |
3426 | | /* input parameters */ |
3427 | 0 | TPM_DIRINDEX dirIndex; /* Index of the DIR */ |
3428 | 0 | TPM_DIRVALUE newContents; /* New value to be stored in named DIR */ |
3429 | 0 | TPM_AUTHHANDLE authHandle; /* The authorization session handle used for command. */ |
3430 | 0 | TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ |
3431 | 0 | TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the authorization |
3432 | | session handle */ |
3433 | 0 | TPM_AUTHDATA ownerAuth; /* The authorization session digest for inputs. HMAC key: |
3434 | | ownerAuth. */ |
3435 | | |
3436 | | /* processing parameters */ |
3437 | 0 | unsigned char * inParamStart; /* starting point of inParam's */ |
3438 | 0 | unsigned char * inParamEnd; /* ending point of inParam's */ |
3439 | 0 | TPM_DIGEST inParamDigest; |
3440 | 0 | TPM_BOOL auditStatus; /* audit the ordinal */ |
3441 | 0 | TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ |
3442 | 0 | TPM_BOOL authHandleValid = FALSE; |
3443 | 0 | TPM_SECRET *hmacKey; |
3444 | 0 | TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ |
3445 | | |
3446 | | /* output parameters */ |
3447 | 0 | uint32_t outParamStart; /* starting point of outParam's */ |
3448 | 0 | uint32_t outParamEnd; /* ending point of outParam's */ |
3449 | 0 | TPM_DIGEST outParamDigest; |
3450 | |
|
3451 | 0 | printf("TPM_Process_DirWriteAuth: Ordinal Entry\n"); |
3452 | | /* |
3453 | | get inputs |
3454 | | */ |
3455 | | /* save the starting point of inParam's for authorization and auditing */ |
3456 | 0 | inParamStart = command; |
3457 | | /* get dirIndex parameter */ |
3458 | 0 | if (returnCode == TPM_SUCCESS) { |
3459 | 0 | returnCode = TPM_Load32(&dirIndex, &command, ¶mSize); |
3460 | 0 | } |
3461 | | /* get newContents parameter */ |
3462 | 0 | if (returnCode == TPM_SUCCESS) { |
3463 | 0 | printf("TPM_Process_DirWriteAuth: dirIndex %08x\n", dirIndex); |
3464 | 0 | returnCode = TPM_Digest_Load(newContents, &command, ¶mSize); |
3465 | 0 | } |
3466 | 0 | if (returnCode == TPM_SUCCESS) { |
3467 | 0 | TPM_PrintFour("TPM_Process_DirWriteAuth: newContents", newContents); |
3468 | 0 | } |
3469 | | /* save the ending point of inParam's for authorization and auditing */ |
3470 | 0 | inParamEnd = command; |
3471 | | /* digest the input parameters */ |
3472 | 0 | if (returnCode == TPM_SUCCESS) { |
3473 | 0 | returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ |
3474 | 0 | &auditStatus, /* output */ |
3475 | 0 | &transportEncrypt, /* output */ |
3476 | 0 | tpm_state, |
3477 | 0 | tag, |
3478 | 0 | ordinal, |
3479 | 0 | inParamStart, |
3480 | 0 | inParamEnd, |
3481 | 0 | transportInternal); |
3482 | 0 | } |
3483 | | /* check state */ |
3484 | 0 | if (returnCode == TPM_SUCCESS) { |
3485 | 0 | returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALLOW_NO_OWNER); |
3486 | 0 | } |
3487 | | /* check tag */ |
3488 | 0 | if (returnCode == TPM_SUCCESS) { |
3489 | 0 | returnCode = TPM_CheckRequestTag1(tag); |
3490 | 0 | } |
3491 | | /* get the 'below the line' authorization parameters */ |
3492 | 0 | if (returnCode == TPM_SUCCESS) { |
3493 | 0 | returnCode = TPM_AuthParams_Get(&authHandle, |
3494 | 0 | &authHandleValid, |
3495 | 0 | nonceOdd, |
3496 | 0 | &continueAuthSession, |
3497 | 0 | ownerAuth, |
3498 | 0 | &command, ¶mSize); |
3499 | 0 | } |
3500 | 0 | if (returnCode == TPM_SUCCESS) { |
3501 | 0 | if (paramSize != 0) { |
3502 | 0 | printf("TPM_Process_DirWriteAuth: Error, command has %u extra bytes\n", |
3503 | 0 | paramSize); |
3504 | 0 | returnCode = TPM_BAD_PARAM_SIZE; |
3505 | 0 | } |
3506 | 0 | } |
3507 | | /* do not terminate sessions if the command did not parse correctly */ |
3508 | 0 | if (returnCode != TPM_SUCCESS) { |
3509 | 0 | authHandleValid = FALSE; |
3510 | 0 | } |
3511 | | /* |
3512 | | Processing |
3513 | | */ |
3514 | | /* 1. Validate that authHandle contains a TPM Owner AuthData to execute the TPM_DirWriteAuth |
3515 | | command */ |
3516 | 0 | if (returnCode == TPM_SUCCESS) { |
3517 | 0 | returnCode = TPM_AuthSessions_GetData(&auth_session_data, |
3518 | 0 | &hmacKey, |
3519 | 0 | tpm_state, |
3520 | 0 | authHandle, |
3521 | 0 | TPM_PID_NONE, |
3522 | 0 | TPM_ET_OWNER, |
3523 | 0 | ordinal, |
3524 | 0 | NULL, |
3525 | 0 | &(tpm_state->tpm_permanent_data.ownerAuth), /* OIAP */ |
3526 | 0 | tpm_state->tpm_permanent_data.ownerAuth); /* OSAP */ |
3527 | 0 | } |
3528 | 0 | if (returnCode == TPM_SUCCESS) { |
3529 | 0 | returnCode = TPM_Authdata_Check(tpm_state, |
3530 | 0 | *hmacKey, /* HMAC key */ |
3531 | 0 | inParamDigest, |
3532 | 0 | auth_session_data, /* authorization session */ |
3533 | 0 | nonceOdd, /* Nonce generated by system |
3534 | | associated with authHandle */ |
3535 | 0 | continueAuthSession, |
3536 | 0 | ownerAuth); /* Authorization digest for input */ |
3537 | 0 | } |
3538 | | /* 2. Validate that dirIndex points to a valid DIR on this TPM */ |
3539 | 0 | if (returnCode == TPM_SUCCESS) { |
3540 | 0 | if (dirIndex != 0) { /* only one TPM_PERMANENT_DATA -> authDIR */ |
3541 | 0 | printf("TPM_Process_DirWriteAuth: Error, Invalid index %08x\n", dirIndex); |
3542 | 0 | returnCode = TPM_BADINDEX; |
3543 | 0 | } |
3544 | 0 | } |
3545 | | /* 3. Write newContents into the DIR pointed to by dirIndex */ |
3546 | 0 | if (returnCode == TPM_SUCCESS) { |
3547 | 0 | printf("TPM_Process_DirWriteAuth: Writing data\n"); |
3548 | 0 | TPM_Digest_Copy(tpm_state->tpm_permanent_data.authDIR, newContents); |
3549 | | /* write back TPM_PERMANENT_DATA */ |
3550 | 0 | returnCode = TPM_PermanentAll_NVStore(tpm_state, |
3551 | 0 | TRUE, |
3552 | 0 | returnCode); |
3553 | 0 | } |
3554 | | /* |
3555 | | response |
3556 | | */ |
3557 | | /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ |
3558 | 0 | if (rcf == 0) { |
3559 | 0 | printf("TPM_Process_DirWriteAuth: Ordinal returnCode %08x %u\n", |
3560 | 0 | returnCode, returnCode); |
3561 | 0 | rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); |
3562 | 0 | } |
3563 | | /* success response, append the rest of the parameters. */ |
3564 | 0 | if (rcf == 0) { |
3565 | 0 | if (returnCode == TPM_SUCCESS) { |
3566 | | /* checkpoint the beginning of the outParam's */ |
3567 | 0 | outParamStart = response->buffer_current - response->buffer; |
3568 | | /* checkpoint the end of the outParam's */ |
3569 | 0 | outParamEnd = response->buffer_current - response->buffer; |
3570 | 0 | } |
3571 | | /* digest the above the line output parameters */ |
3572 | 0 | if (returnCode == TPM_SUCCESS) { |
3573 | 0 | returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ |
3574 | 0 | auditStatus, /* input audit status */ |
3575 | 0 | transportEncrypt, |
3576 | 0 | tag, |
3577 | 0 | returnCode, |
3578 | 0 | ordinal, /* command ordinal */ |
3579 | 0 | response->buffer + outParamStart, /* start */ |
3580 | 0 | outParamEnd - outParamStart); /* length */ |
3581 | 0 | } |
3582 | | /* calculate and set the below the line parameters */ |
3583 | 0 | if (returnCode == TPM_SUCCESS) { |
3584 | 0 | returnCode = TPM_AuthParams_Set(response, |
3585 | 0 | *hmacKey, /* owner HMAC key */ |
3586 | 0 | auth_session_data, |
3587 | 0 | outParamDigest, |
3588 | 0 | nonceOdd, |
3589 | 0 | continueAuthSession); |
3590 | 0 | } |
3591 | | /* audit if required */ |
3592 | 0 | if ((returnCode == TPM_SUCCESS) && auditStatus) { |
3593 | 0 | returnCode = TPM_ProcessAudit(tpm_state, |
3594 | 0 | transportEncrypt, |
3595 | 0 | inParamDigest, |
3596 | 0 | outParamDigest, |
3597 | 0 | ordinal); |
3598 | 0 | } |
3599 | | /* adjust the initial response */ |
3600 | 0 | rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); |
3601 | 0 | } |
3602 | | /* if there was an error, or continueAuthSession is FALSE, terminate the session */ |
3603 | 0 | if (((rcf != 0) || |
3604 | 0 | ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || |
3605 | 0 | !continueAuthSession) && |
3606 | 0 | authHandleValid) { |
3607 | 0 | TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); |
3608 | 0 | } |
3609 | | /* |
3610 | | cleanup |
3611 | | */ |
3612 | 0 | return rcf; |
3613 | 0 | } |
3614 | | |
3615 | | /* 27.3.2 TPM_DirRead rev 87 |
3616 | | |
3617 | | The TPM_DirRead operation provides read access to the DIRs. No authentication is required to |
3618 | | perform this action because typically no cryptographically useful AuthData is available early in |
3619 | | boot. TSS implementors may choose to provide other means of authorizing this action. Version 1.2 |
3620 | | requires only one DIR. If the DIR named does not exist, the TPM_DirRead operation returns |
3621 | | TPM_BADINDEX. |
3622 | | */ |
3623 | | |
3624 | | TPM_RESULT TPM_Process_DirRead(tpm_state_t *tpm_state, |
3625 | | TPM_STORE_BUFFER *response, |
3626 | | TPM_TAG tag, |
3627 | | uint32_t paramSize, |
3628 | | TPM_COMMAND_CODE ordinal, |
3629 | | unsigned char *command, |
3630 | | TPM_TRANSPORT_INTERNAL *transportInternal) |
3631 | 0 | { |
3632 | 0 | TPM_RESULT rcf = 0; /* fatal error precluding response */ |
3633 | 0 | TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ |
3634 | | |
3635 | | /* input parameters */ |
3636 | 0 | TPM_DIRINDEX dirIndex; /* Index of the DIR to be read */ |
3637 | | |
3638 | | /* processing parameters */ |
3639 | 0 | unsigned char * inParamStart; /* starting point of inParam's */ |
3640 | 0 | unsigned char * inParamEnd; /* ending point of inParam's */ |
3641 | 0 | TPM_DIGEST inParamDigest; |
3642 | 0 | TPM_BOOL auditStatus; /* audit the ordinal */ |
3643 | 0 | TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ |
3644 | | |
3645 | | /* output parameters */ |
3646 | 0 | uint32_t outParamStart; /* starting point of outParam's */ |
3647 | 0 | uint32_t outParamEnd; /* ending point of outParam's */ |
3648 | 0 | TPM_DIGEST outParamDigest; |
3649 | |
|
3650 | 0 | printf("TPM_Process_DirRead: Ordinal Entry\n"); |
3651 | | /* |
3652 | | get inputs |
3653 | | */ |
3654 | | /* save the starting point of inParam's for authorization and auditing */ |
3655 | 0 | inParamStart = command; |
3656 | | /* get dirIndex parameter */ |
3657 | 0 | if (returnCode == TPM_SUCCESS) { |
3658 | 0 | returnCode = TPM_Load32(&dirIndex, &command, ¶mSize); |
3659 | 0 | } |
3660 | 0 | if (returnCode == TPM_SUCCESS) { |
3661 | 0 | printf("TPM_Process_DirRead: dirIndex %08x\n", dirIndex); |
3662 | 0 | } |
3663 | | /* save the ending point of inParam's for authorization and auditing */ |
3664 | 0 | inParamEnd = command; |
3665 | | /* digest the input parameters */ |
3666 | 0 | if (returnCode == TPM_SUCCESS) { |
3667 | 0 | returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ |
3668 | 0 | &auditStatus, /* output */ |
3669 | 0 | &transportEncrypt, /* output */ |
3670 | 0 | tpm_state, |
3671 | 0 | tag, |
3672 | 0 | ordinal, |
3673 | 0 | inParamStart, |
3674 | 0 | inParamEnd, |
3675 | 0 | transportInternal); |
3676 | 0 | } |
3677 | | /* check state */ |
3678 | 0 | if (returnCode == TPM_SUCCESS) { |
3679 | 0 | returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALLOW_NO_OWNER); |
3680 | 0 | } |
3681 | | /* check tag */ |
3682 | 0 | if (returnCode == TPM_SUCCESS) { |
3683 | 0 | returnCode = TPM_CheckRequestTag0(tag); |
3684 | 0 | } |
3685 | 0 | if (returnCode == TPM_SUCCESS) { |
3686 | 0 | if (paramSize != 0) { |
3687 | 0 | printf("TPM_Process_DirRead: Error, command has %u extra bytes\n", |
3688 | 0 | paramSize); |
3689 | 0 | returnCode = TPM_BAD_PARAM_SIZE; |
3690 | 0 | } |
3691 | 0 | } |
3692 | | /* |
3693 | | Processing |
3694 | | */ |
3695 | | /* 1. Validate that dirIndex points to a valid DIR on this TPM */ |
3696 | 0 | if (returnCode == TPM_SUCCESS) { |
3697 | 0 | if (dirIndex != 0) { /* only one TPM_PERMANENT_DATA -> authDIR */ |
3698 | 0 | printf("TPM_Process_DirRead: Error, Invalid index %08x\n", dirIndex); |
3699 | 0 | returnCode = TPM_BADINDEX; |
3700 | 0 | } |
3701 | 0 | } |
3702 | | /* 2. Return the contents of the DIR in dirContents */ |
3703 | 0 | if (returnCode == TPM_SUCCESS) { |
3704 | 0 | printf("TPM_Process_DirRead: Reading data\n"); |
3705 | 0 | TPM_PrintFour("TPM_Process_DirRead:", tpm_state->tpm_permanent_data.authDIR); |
3706 | 0 | } |
3707 | | /* |
3708 | | response |
3709 | | */ |
3710 | | /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ |
3711 | 0 | if (rcf == 0) { |
3712 | 0 | printf("TPM_Process_DirRead: Ordinal returnCode %08x %u\n", |
3713 | 0 | returnCode, returnCode); |
3714 | 0 | rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); |
3715 | 0 | } |
3716 | | /* success response, append the rest of the parameters. */ |
3717 | 0 | if (rcf == 0) { |
3718 | 0 | if (returnCode == TPM_SUCCESS) { |
3719 | | /* checkpoint the beginning of the outParam's */ |
3720 | 0 | outParamStart = response->buffer_current - response->buffer; |
3721 | | /* append dirContents */ |
3722 | 0 | returnCode = TPM_Digest_Store(response, tpm_state->tpm_permanent_data.authDIR); |
3723 | | /* checkpoint the end of the outParam's */ |
3724 | 0 | outParamEnd = response->buffer_current - response->buffer; |
3725 | 0 | } |
3726 | | /* digest the above the line output parameters */ |
3727 | 0 | if (returnCode == TPM_SUCCESS) { |
3728 | 0 | returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ |
3729 | 0 | auditStatus, /* input audit status */ |
3730 | 0 | transportEncrypt, |
3731 | 0 | tag, |
3732 | 0 | returnCode, |
3733 | 0 | ordinal, /* command ordinal */ |
3734 | 0 | response->buffer + outParamStart, /* start */ |
3735 | 0 | outParamEnd - outParamStart); /* length */ |
3736 | 0 | } |
3737 | | /* audit if required */ |
3738 | 0 | if ((returnCode == TPM_SUCCESS) && auditStatus) { |
3739 | 0 | returnCode = TPM_ProcessAudit(tpm_state, |
3740 | 0 | transportEncrypt, |
3741 | 0 | inParamDigest, |
3742 | 0 | outParamDigest, |
3743 | 0 | ordinal); |
3744 | 0 | } |
3745 | | /* adjust the initial response */ |
3746 | 0 | rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); |
3747 | 0 | } |
3748 | | /* |
3749 | | cleanup |
3750 | | */ |
3751 | 0 | return rcf; |
3752 | 0 | } |