Coverage Report

Created: 2026-09-01 06:17

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