VirtualBox

source: vbox/trunk/src/libs/libtpms-0.9.0/src/tpm12/tpm_nvram.c@ 91612

最後變更 在這個檔案從91612是 91612,由 vboxsync 提交於 3 年 前

src/libs: Export libtpms-0.9.0, bugref:10078

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette