Coverage Report

Created: 2025-07-18 06:04

/src/tpm2/Object_spt.c
Line
Count
Source (jump to first uncovered line)
1
// This file was extracted from the TCG Published
2
// Trusted Platform Module Library
3
// Part 4: Supporting Routines
4
// Family "2.0"
5
// Level 00 Revision 01.16
6
// October 30, 2014
7
8
#include "InternalRoutines.h"
9
#include "Object_spt_fp.h"
10
#include "Platform.h"
11
//
12
//
13
//
14
//          Local Functions
15
//
16
//          EqualCryptSet()
17
//
18
//     Check if the crypto sets in two public areas are equal
19
//
20
//     Error Returns                     Meaning
21
//
22
//     TPM_RC_ASYMMETRIC                 mismatched parameters
23
//     TPM_RC_HASH                       mismatched name algorithm
24
//     TPM_RC_TYPE                       mismatched type
25
//
26
static TPM_RC
27
EqualCryptSet(
28
   TPMT_PUBLIC         *publicArea1,        // IN: public area 1
29
   TPMT_PUBLIC         *publicArea2         // IN: public area 2
30
   )
31
0
{
32
0
   UINT16                   size1;
33
0
   UINT16                   size2;
34
0
   BYTE                     params1[sizeof(TPMU_PUBLIC_PARMS)];
35
0
   BYTE                     params2[sizeof(TPMU_PUBLIC_PARMS)];
36
0
   BYTE                     *buffer;
37
0
   INT32                    bufferSize;
38
   // Compare name hash
39
0
   if(publicArea1->nameAlg != publicArea2->nameAlg)
40
0
       return TPM_RC_HASH;
41
   // Compare algorithm
42
0
   if(publicArea1->type != publicArea2->type)
43
0
       return TPM_RC_TYPE;
44
   // TPMU_PUBLIC_PARMS field should be identical
45
0
   buffer = params1;
46
0
   bufferSize = sizeof(TPMU_PUBLIC_PARMS);
47
0
   size1 = TPMU_PUBLIC_PARMS_Marshal(&publicArea1->parameters, &buffer,
48
0
                                     &bufferSize, publicArea1->type);
49
0
   buffer = params2;
50
0
   bufferSize = sizeof(TPMU_PUBLIC_PARMS);
51
0
   size2 = TPMU_PUBLIC_PARMS_Marshal(&publicArea2->parameters, &buffer,
52
0
                                     &bufferSize, publicArea2->type);
53
0
   if(size1 != size2 || !MemoryEqual(params1, params2, size1))
54
0
       return TPM_RC_ASYMMETRIC;
55
0
   return TPM_RC_SUCCESS;
56
0
}
57
//
58
//
59
//          GetIV2BSize()
60
//
61
//     Get the size of TPM2B_IV in canonical form that will be append to the start of the sensitive data. It
62
//     includes both size of size field and size of iv data
63
//
64
//     Return Value                      Meaning
65
//
66
static UINT16
67
GetIV2BSize(
68
   TPM_HANDLE            protectorHandle           // IN: the protector handle
69
   )
70
0
{
71
0
   OBJECT                   *protector = NULL; // Pointer to the protector object
72
0
   TPM_ALG_ID               symAlg;
73
//
74
0
   UINT16                    keyBits;
75
   // Determine the symmetric algorithm and size of key
76
0
   if(protectorHandle == TPM_RH_NULL)
77
0
   {
78
       // Use the context encryption algorithm and key size
79
0
       symAlg = CONTEXT_ENCRYPT_ALG;
80
0
       keyBits = CONTEXT_ENCRYPT_KEY_BITS;
81
0
   }
82
0
   else
83
0
   {
84
0
       protector = ObjectGet(protectorHandle);
85
0
       symAlg = protector->publicArea.parameters.asymDetail.symmetric.algorithm;
86
0
       keyBits= protector->publicArea.parameters.asymDetail.symmetric.keyBits.sym;
87
0
   }
88
   // The IV size is a UINT16 size field plus the block size of the symmetric
89
   // algorithm
90
0
   return sizeof(UINT16) + CryptGetSymmetricBlockSize(symAlg, keyBits);
91
0
}
92
//
93
//
94
//         ComputeProtectionKeyParms()
95
//
96
//     This function retrieves the symmetric protection key parameters for the sensitive data The parameters
97
//     retrieved from this function include encryption algorithm, key size in bit, and a TPM2B_SYM_KEY
98
//     containing the key material as well as the key size in bytes This function is used for any action that
99
//     requires encrypting or decrypting of the sensitive area of an object or a credential blob
100
//
101
static void
102
ComputeProtectionKeyParms(
103
   TPM_HANDLE          protectorHandle,       //   IN: the protector handle
104
   TPM_ALG_ID          hashAlg,               //   IN: hash algorithm for KDFa
105
   TPM2B_NAME         *name,                  //   IN: name of the object
106
   TPM2B_SEED         *seedIn,                //   IN: optional seed for duplication blob.
107
                                              //       For non duplication blob, this
108
                                              //       parameter should be NULL
109
   TPM_ALG_ID         *symAlg,                //   OUT: the symmetric algorithm
110
   UINT16             *keyBits,               //   OUT: the symmetric key size in bits
111
   TPM2B_SYM_KEY      *symKey                 //   OUT: the symmetric key
112
   )
113
0
{
114
0
   TPM2B_SEED                *seed = NULL;
115
0
   OBJECT                    *protector = NULL; // Pointer to the protector
116
   // Determine the algorithms for the KDF and the encryption/decryption
117
   // For TPM_RH_NULL, using context settings
118
0
   if(protectorHandle == TPM_RH_NULL)
119
0
   {
120
       // Use the context encryption algorithm and key size
121
0
       *symAlg = CONTEXT_ENCRYPT_ALG;
122
0
       symKey->t.size = CONTEXT_ENCRYPT_KEY_BYTES;
123
0
       *keyBits = CONTEXT_ENCRYPT_KEY_BITS;
124
0
   }
125
0
   else
126
0
   {
127
0
       TPMT_SYM_DEF_OBJECT *symDef;
128
0
       protector = ObjectGet(protectorHandle);
129
0
       symDef = &protector->publicArea.parameters.asymDetail.symmetric;
130
0
       *symAlg = symDef->algorithm;
131
0
       *keyBits= symDef->keyBits.sym;
132
0
       symKey->t.size = (*keyBits + 7) / 8;
133
0
   }
134
   // Get seed for KDF
135
0
   seed = GetSeedForKDF(protectorHandle, seedIn);
136
   // KDFa to generate symmetric key and IV value
137
0
   KDFa(hashAlg, (TPM2B *)seed, "STORAGE", (TPM2B *)name, NULL,
138
0
        symKey->t.size * 8, symKey->t.buffer, NULL);
139
0
   return;
140
0
}
141
//
142
//
143
//           ComputeOuterIntegrity()
144
//
145
//      The sensitive area parameter is a buffer that holds a space for the integrity value and the marshaled
146
//      sensitive area. The caller should skip over the area set aside for the integrity value and compute the hash
147
//      of the remainder of the object. The size field of sensitive is in unmarshaled form and the sensitive area
148
//      contents is an array of bytes.
149
//
150
static void
151
ComputeOuterIntegrity(
152
   TPM2B_NAME          *name,                   //   IN: the name of the object
153
   TPM_HANDLE           protectorHandle,        //   IN: The handle of the object that
154
                                                //       provides protection. For object, it
155
                                                //       is parent handle. For credential, it
156
                                                //       is the handle of encrypt object. For
157
                                                //       a Temporary Object, it is TPM_RH_NULL
158
   TPMI_ALG_HASH        hashAlg,                //   IN: algorithm to use for integrity
159
   TPM2B_SEED          *seedIn,                 //   IN: an external seed may be provided for
160
                                                //       duplication blob. For non duplication
161
                                                //       blob, this parameter should be NULL
162
   UINT32               sensitiveSize,          //   IN: size of the marshaled sensitive data
163
   BYTE                *sensitiveData,          //   IN: sensitive area
164
   TPM2B_DIGEST        *integrity               //   OUT: integrity
165
   )
166
0
{
167
0
   HMAC_STATE               hmacState;
168
0
   TPM2B_DIGEST             hmacKey;
169
0
   TPM2B_SEED               *seed = NULL;
170
   // Get seed for KDF
171
0
   seed = GetSeedForKDF(protectorHandle, seedIn);
172
   // Determine the HMAC key bits
173
0
   hmacKey.t.size = CryptGetHashDigestSize(hashAlg);
174
   // KDFa to generate HMAC key
175
0
   KDFa(hashAlg, (TPM2B *)seed, "INTEGRITY", NULL, NULL,
176
0
        hmacKey.t.size * 8, hmacKey.t.buffer, NULL);
177
   // Start HMAC and get the size of the digest which will become the integrity
178
0
   integrity->t.size = CryptStartHMAC2B(hashAlg, &hmacKey.b, &hmacState);
179
   // Adding the marshaled sensitive area to the integrity value
180
0
   CryptUpdateDigest(&hmacState, sensitiveSize, sensitiveData);
181
   // Adding name
182
0
   CryptUpdateDigest2B(&hmacState, (TPM2B *)name);
183
   // Compute HMAC
184
0
   CryptCompleteHMAC2B(&hmacState, &integrity->b);
185
0
   return;
186
0
}
187
//
188
//
189
//           ComputeInnerIntegrity()
190
//
191
//      This function computes the integrity of an inner wrap
192
//
193
static void
194
ComputeInnerIntegrity(
195
    TPM_ALG_ID           hashAlg,           //   IN: hash algorithm for inner wrap
196
    TPM2B_NAME          *name,              //   IN: the name of the object
197
    UINT16               dataSize,          //   IN: the size of sensitive data
198
    BYTE                *sensitiveData,     //   IN: sensitive data
199
    TPM2B_DIGEST        *integrity          //   OUT: inner integrity
200
    )
201
0
{
202
0
    HASH_STATE          hashState;
203
    // Start hash and get the size of the digest which will become the integrity
204
0
    integrity->t.size = CryptStartHash(hashAlg, &hashState);
205
    // Adding the marshaled sensitive area to the integrity value
206
0
    CryptUpdateDigest(&hashState, dataSize, sensitiveData);
207
    // Adding name
208
0
    CryptUpdateDigest2B(&hashState, &name->b);
209
    // Compute hash
210
0
    CryptCompleteHash2B(&hashState, &integrity->b);
211
0
    return;
212
0
}
213
//
214
//
215
//           ProduceInnerIntegrity()
216
//
217
//      This function produces an inner integrity for regular private, credential or duplication blob It requires the
218
//      sensitive data being marshaled to the innerBuffer, with the leading bytes reserved for integrity hash. It
219
//      assume the sensitive data starts at address (innerBuffer + integrity size). This function integrity at the
220
//      beginning of the inner buffer It returns the total size of buffer with the inner wrap
221
//
222
static UINT16
223
ProduceInnerIntegrity(
224
    TPM2B_NAME          *name,              //   IN: the name of the object
225
    TPM_ALG_ID           hashAlg,           //   IN: hash algorithm for inner wrap
226
    UINT16               dataSize,          //   IN: the size of sensitive data, excluding the
227
                                            //       leading integrity buffer size
228
    BYTE                *innerBuffer        //   IN/OUT: inner buffer with sensitive data in
229
                                            //       it. At input, the leading bytes of this
230
                                            //       buffer is reserved for integrity
231
    )
232
0
{
233
0
    BYTE                     *sensitiveData; // pointer to the sensitive data
234
0
    TPM2B_DIGEST             integrity;
235
0
    UINT16                   integritySize;
236
0
    BYTE                     *buffer;             // Auxiliary buffer pointer
237
0
    INT32                    bufferSize;
238
    // sensitiveData points to the beginning of sensitive data in innerBuffer
239
0
    integritySize = sizeof(UINT16) + CryptGetHashDigestSize(hashAlg);
240
0
    sensitiveData = innerBuffer + integritySize;
241
0
    ComputeInnerIntegrity(hashAlg, name, dataSize, sensitiveData, &integrity);
242
    // Add integrity at the beginning of inner buffer
243
0
    buffer = innerBuffer;
244
0
    bufferSize = sizeof(TPM2B_DIGEST);
245
0
    TPM2B_DIGEST_Marshal(&integrity, &buffer, &bufferSize);
246
0
    return dataSize + integritySize;
247
0
}
248
//
249
//
250
//           CheckInnerIntegrity()
251
//
252
//      This function check integrity of inner blob
253
//
254
//      Error Returns                     Meaning
255
//
256
//      TPM_RC_INTEGRITY                  if the outer blob integrity is bad
257
//      unmarshal errors                  unmarshal errors while unmarshaling integrity
258
//
259
static TPM_RC
260
CheckInnerIntegrity(
261
    TPM2B_NAME          *name,                //   IN: the name of the object
262
    TPM_ALG_ID           hashAlg,             //   IN: hash algorithm for inner wrap
263
    UINT16               dataSize,            //   IN: the size of sensitive data, including the
264
                                              //       leading integrity buffer size
265
    BYTE                *innerBuffer          //   IN/OUT: inner buffer with sensitive data in
266
                                              //       it
267
    )
268
0
{
269
0
    TPM_RC              result;
270
0
    TPM2B_DIGEST        integrity;
271
0
    TPM2B_DIGEST        integrityToCompare;
272
0
    BYTE                *buffer;                          // Auxiliary buffer pointer
273
0
    INT32               size;
274
    // Unmarshal integrity
275
0
    buffer = innerBuffer;
276
0
    size = (INT32) dataSize;
277
0
    result = TPM2B_DIGEST_Unmarshal(&integrity, &buffer, &size);
278
0
    if(result == TPM_RC_SUCCESS)
279
0
    {
280
        // Compute integrity to compare
281
0
        ComputeInnerIntegrity(hashAlg, name, (UINT16) size, buffer,
282
0
                              &integrityToCompare);
283
         // Compare outer blob integrity
284
0
         if(!Memory2BEqual(&integrity.b, &integrityToCompare.b))
285
0
             result = TPM_RC_INTEGRITY;
286
0
    }
287
0
    return result;
288
0
}
289
//
290
//
291
//           Public Functions
292
//
293
//           AreAttributesForParent()
294
//
295
//      This function is called by create, load, and import functions.
296
//
297
//      Return Value                      Meaning
298
//
299
//      TRUE                              properties are those of a parent
300
//      FALSE                             properties are not those of a parent
301
//
302
BOOL
303
AreAttributesForParent(
304
   OBJECT             *parentObject        // IN: parent handle
305
   )
306
0
{
307
   // This function is only called when a parent is needed. Any
308
   // time a "parent" is used, it must be authorized. When
309
   // the authorization is checked, both the public and sensitive
310
   // areas must be loaded. Just make sure...
311
0
   pAssert(parentObject->attributes.publicOnly == CLEAR);
312
0
   if(ObjectDataIsStorage(&parentObject->publicArea))
313
0
       return TRUE;
314
0
   else
315
0
       return FALSE;
316
0
}
317
//
318
//
319
//          SchemeChecks()
320
//
321
//      This function validates the schemes in the public area of an object. This function is called by
322
//      TPM2_LoadExternal() and PublicAttributesValidation().
323
//
324
//      Error Returns                   Meaning
325
//
326
//      TPM_RC_ASYMMETRIC               non-duplicable storage key and its parent have different public
327
//                                      parameters
328
//      TPM_RC_ATTRIBUTES               attempt to inject sensitive data for an asymmetric key; or attempt to
329
//                                      create a symmetric cipher key that is not a decryption key
330
//      TPM_RC_HASH                     non-duplicable storage key and its parent have different name
331
//                                      algorithm
332
//      TPM_RC_KDF                      incorrect KDF specified for decrypting keyed hash object
333
//      TPM_RC_KEY                      invalid key size values in an asymmetric key public area
334
//      TPM_RC_SCHEME                   inconsistent attributes decrypt, sign, restricted and key's scheme ID;
335
//                                      or hash algorithm is inconsistent with the scheme ID for keyed hash
336
//                                      object
337
//      TPM_RC_SYMMETRIC                a storage key with no symmetric algorithm specified; or non-storage
338
//                                      key with symmetric algorithm different from TPM_ALG_NULL
339
//      TPM_RC_TYPE                     unexpected object type; or non-duplicable storage key and its parent
340
//                                      have different types
341
//
342
TPM_RC
343
SchemeChecks(
344
   BOOL                load,               // IN: TRUE if load checks, FALSE if
345
                                           //     TPM2_Create()
346
   TPMI_DH_OBJECT      parentHandle,       // IN: input parent handle
347
   TPMT_PUBLIC        *publicArea          // IN: public area of the object
348
   )
349
58
{
350
   // Checks for an asymmetric key
351
58
   if(CryptIsAsymAlgorithm(publicArea->type))
352
58
   {
353
58
       TPMT_ASYM_SCHEME        *keyScheme;
354
58
       keyScheme = &publicArea->parameters.asymDetail.scheme;
355
         // An asymmetric key can't be injected
356
         // This is only checked when creating an object
357
58
         if(!load && (publicArea->objectAttributes.sensitiveDataOrigin == CLEAR))
358
0
             return TPM_RC_ATTRIBUTES;
359
58
         if(load && !CryptAreKeySizesConsistent(publicArea))
360
1
             return TPM_RC_KEY;
361
         // Keys that are both signing and decrypting must have TPM_ALG_NULL
362
         // for scheme
363
57
         if(     publicArea->objectAttributes.sign == SET
364
57
             && publicArea->objectAttributes.decrypt == SET
365
57
             && keyScheme->scheme != TPM_ALG_NULL)
366
0
              return TPM_RC_SCHEME;
367
         // A restrict sign key must have a non-NULL scheme
368
57
         if(     publicArea->objectAttributes.restricted == SET
369
57
             && publicArea->objectAttributes.sign == SET
370
57
             && keyScheme->scheme == TPM_ALG_NULL)
371
0
             return TPM_RC_SCHEME;
372
         // Keys must have a valid sign or decrypt scheme, or a TPM_ALG_NULL
373
         // scheme
374
         // NOTE: The unmarshaling for a public area will unmarshal based on the
375
         // object type. If the type is an RSA key, then only RSA schemes will be
376
         // allowed because a TPMI_ALG_RSA_SCHEME will be unmarshaled and it
377
         // consists only of those algorithms that are allowed with an RSA key.
378
         // This means that there is no need to again make sure that the algorithm
379
         // is compatible with the object type.
380
57
         if(    keyScheme->scheme != TPM_ALG_NULL
381
57
             && (    (    publicArea->objectAttributes.sign == SET
382
54
                       && !CryptIsSignScheme(keyScheme->scheme)
383
54
                     )
384
54
                  || (    publicArea->objectAttributes.decrypt == SET
385
54
                       && !CryptIsDecryptScheme(keyScheme->scheme)
386
54
                     )
387
54
                )
388
57
           )
389
0
              return TPM_RC_SCHEME;
390
       // Special checks for an ECC key
391
57
#ifdef TPM_ALG_ECC
392
57
       if(publicArea->type == TPM_ALG_ECC)
393
6
       {
394
6
           TPM_ECC_CURVE        curveID = publicArea->parameters.eccDetail.curveID;
395
6
           const TPMT_ECC_SCHEME *curveScheme = CryptGetCurveSignScheme(curveID);
396
           // The curveId must be valid or the unmarshaling is busted.
397
6
           pAssert(curveScheme != NULL);
398
             // If the curveID requires a specific scheme, then the key must select
399
             // the same scheme
400
6
             if(curveScheme->scheme != TPM_ALG_NULL)
401
0
             {
402
0
                 if(keyScheme->scheme != curveScheme->scheme)
403
0
                      return TPM_RC_SCHEME;
404
                 // The scheme can allow any hash, or not...
405
0
                 if(    curveScheme->details.anySig.hashAlg != TPM_ALG_NULL
406
0
                     && (   keyScheme->details.anySig.hashAlg
407
0
                         != curveScheme->details.anySig.hashAlg
408
0
                        )
409
0
                   )
410
0
                      return TPM_RC_SCHEME;
411
0
             }
412
             // For now, the KDF must be TPM_ALG_NULL
413
6
             if(publicArea->parameters.eccDetail.kdf.scheme != TPM_ALG_NULL)
414
0
                 return TPM_RC_KDF;
415
6
         }
416
57
#endif
417
         // Checks for a storage key (restricted + decryption)
418
57
         if(   publicArea->objectAttributes.restricted == SET
419
57
              && publicArea->objectAttributes.decrypt == SET)
420
0
        {
421
              // A storage key must have a valid protection key
422
0
              if(    publicArea->parameters.asymDetail.symmetric.algorithm
423
0
                  == TPM_ALG_NULL)
424
0
                   return TPM_RC_SYMMETRIC;
425
              // A storage key must have a null scheme
426
0
              if(publicArea->parameters.asymDetail.scheme.scheme != TPM_ALG_NULL)
427
0
                  return TPM_RC_SCHEME;
428
              // A storage key must match its parent algorithms unless
429
              // it is duplicable or a primary (including Temporary Primary Objects)
430
0
              if(    HandleGetType(parentHandle) != TPM_HT_PERMANENT
431
0
                  && publicArea->objectAttributes.fixedParent == SET
432
0
                )
433
0
              {
434
                   // If the object to be created is a storage key, and is fixedParent,
435
                   // its crypto set has to match its parent's crypto set. TPM_RC_TYPE,
436
                   // TPM_RC_HASH or TPM_RC_ASYMMETRIC may be returned at this point
437
0
                   return EqualCryptSet(publicArea,
438
0
                                        &(ObjectGet(parentHandle)->publicArea));
439
0
              }
440
0
        }
441
57
        else
442
57
        {
443
              // Non-storage keys must have TPM_ALG_NULL for the symmetric algorithm
444
57
              if(    publicArea->parameters.asymDetail.symmetric.algorithm
445
57
                  != TPM_ALG_NULL)
446
0
                   return TPM_RC_SYMMETRIC;
447
57
       }// End of asymmetric decryption key checks
448
57
   } // End of asymmetric checks
449
   // Check for bit attributes
450
0
   else if(publicArea->type == TPM_ALG_KEYEDHASH)
451
0
   {
452
0
       TPMT_KEYEDHASH_SCHEME    *scheme
453
0
           = &publicArea->parameters.keyedHashDetail.scheme;
454
       // If both sign and decrypt are set the scheme must be TPM_ALG_NULL
455
       // and the scheme selected when the key is used.
456
       // If neither sign nor decrypt is set, the scheme must be TPM_ALG_NULL
457
       // because this is a data object.
458
0
       if(      publicArea->objectAttributes.sign
459
0
           == publicArea->objectAttributes.decrypt)
460
0
       {
461
0
           if(scheme->scheme != TPM_ALG_NULL)
462
0
                return TPM_RC_SCHEME;
463
0
           return TPM_RC_SUCCESS;
464
0
       }
465
       // If this is a decryption key, make sure that is is XOR and that there
466
       // is a KDF
467
0
       else if(publicArea->objectAttributes.decrypt)
468
0
       {
469
0
           if(    scheme->scheme != TPM_ALG_XOR
470
0
               || scheme->details.xor_.hashAlg == TPM_ALG_NULL)
471
0
                return TPM_RC_SCHEME;
472
0
           if(scheme->details.xor_.kdf == TPM_ALG_NULL)
473
0
                return TPM_RC_KDF;
474
0
           return TPM_RC_SUCCESS;
475
0
        }
476
        // only supported signing scheme for keyedHash object is HMAC
477
0
        if(    scheme->scheme != TPM_ALG_HMAC
478
0
            || scheme->details.hmac.hashAlg == TPM_ALG_NULL)
479
0
             return TPM_RC_SCHEME;
480
         // end of the checks for keyedHash
481
0
         return TPM_RC_SUCCESS;
482
0
   }
483
0
   else if (publicArea->type == TPM_ALG_SYMCIPHER)
484
0
   {
485
       // Must be a decrypting key and may not be a signing key
486
0
       if(    publicArea->objectAttributes.decrypt == CLEAR
487
0
           || publicArea->objectAttributes.sign == SET
488
0
         )
489
0
            return TPM_RC_ATTRIBUTES;
490
0
   }
491
0
   else
492
0
       return TPM_RC_TYPE;
493
57
   return TPM_RC_SUCCESS;
494
58
}
495
//
496
//
497
//          PublicAttributesValidation()
498
//
499
//      This function validates the values in the public area of an object. This function is called by
500
//      TPM2_Create(), TPM2_Load(), and TPM2_CreatePrimary()
501
//
502
//      Error Returns                     Meaning
503
//
504
//      TPM_RC_ASYMMETRIC                 non-duplicable storage key and its parent have different public
505
//                                        parameters
506
//      TPM_RC_ATTRIBUTES                 fixedTPM, fixedParent, or encryptedDuplication attributes are
507
//                                        inconsistent between themselves or with those of the parent object;
508
//                                        inconsistent restricted, decrypt and sign attributes; attempt to inject
509
//                                        sensitive data for an asymmetric key; attempt to create a symmetric
510
//                                        cipher key that is not a decryption key
511
//      TPM_RC_HASH                       non-duplicable storage key and its parent have different name
512
//                                        algorithm
513
//      TPM_RC_KDF                        incorrect KDF specified for decrypting keyed hash object
514
//      TPM_RC_KEY                        invalid key size values in an asymmetric key public area
515
//      TPM_RC_SCHEME                     inconsistent attributes decrypt, sign, restricted and key's scheme ID;
516
//                                        or hash algorithm is inconsistent with the scheme ID for keyed hash
517
//                                        object
518
//      TPM_RC_SIZE                       authPolicy size does not match digest size of the name algorithm in
519
//                                        publicArea
520
//      TPM_RC_SYMMETRIC                  a storage key with no symmetric algorithm specified; or non-storage
521
//                                        key with symmetric algorithm different from TPM_ALG_NULL
522
//      TPM_RC_TYPE                       unexpected object type; or non-duplicable storage key and its parent
523
//                                        have different types
524
//
525
TPM_RC
526
PublicAttributesValidation(
527
   BOOL                load,                 // IN: TRUE if load checks, FALSE if
528
                                             //     TPM2_Create()
529
   TPMI_DH_OBJECT      parentHandle,         // IN: input parent handle
530
   TPMT_PUBLIC        *publicArea            // IN: public area of the object
531
   )
532
3
{
533
3
   OBJECT                  *parentObject = NULL;
534
3
   if(HandleGetType(parentHandle) != TPM_HT_PERMANENT)
535
0
       parentObject = ObjectGet(parentHandle);
536
3
    if (publicArea->nameAlg == TPM_ALG_NULL)
537
0
        return TPM_RC_HASH;
538
    // Check authPolicy digest consistency
539
3
    if(   publicArea->authPolicy.t.size != 0
540
3
       && (    publicArea->authPolicy.t.size
541
0
            != CryptGetHashDigestSize(publicArea->nameAlg)
542
0
          )
543
3
      )
544
0
        return TPM_RC_SIZE;
545
    // If the parent is fixedTPM (including a Primary Object) the object must have
546
    // the same value for fixedTPM and fixedParent
547
3
    if(     parentObject == NULL
548
3
        || parentObject->publicArea.objectAttributes.fixedTPM == SET)
549
3
    {
550
3
        if(    publicArea->objectAttributes.fixedParent
551
3
            != publicArea->objectAttributes.fixedTPM
552
3
          )
553
0
             return TPM_RC_ATTRIBUTES;
554
3
    }
555
0
    else
556
        // The parent is not fixedTPM so the object can't be fixedTPM
557
0
        if(publicArea->objectAttributes.fixedTPM == SET)
558
0
             return TPM_RC_ATTRIBUTES;
559
    // A restricted object cannot be both sign and decrypt and it can't be neither
560
    // sign nor decrypt
561
3
    if (    publicArea->objectAttributes.restricted == SET
562
3
         && (    publicArea->objectAttributes.decrypt
563
0
              == publicArea->objectAttributes.sign)
564
3
       )
565
0
         return TPM_RC_ATTRIBUTES;
566
    // A fixedTPM object can not have encryptedDuplication bit SET
567
3
    if(    publicArea->objectAttributes.fixedTPM == SET
568
3
        && publicArea->objectAttributes.encryptedDuplication == SET)
569
0
        return TPM_RC_ATTRIBUTES;
570
    // If a parent object has fixedTPM CLEAR, the child must have the
571
    // same encryptedDuplication value as its parent.
572
    // Primary objects are considered to have a fixedTPM parent (the seeds).
573
3
   if(       (   parentObject != NULL
574
3
              && parentObject->publicArea.objectAttributes.fixedTPM == CLEAR)
575
       // Get here if parent is not fixed TPM
576
3
       && (     publicArea->objectAttributes.encryptedDuplication
577
0
             != parentObject->publicArea.objectAttributes.encryptedDuplication
578
0
           )
579
3
      )
580
0
        return TPM_RC_ATTRIBUTES;
581
3
   return SchemeChecks(load, parentHandle, publicArea);
582
3
}
583
//
584
//
585
//            FillInCreationData()
586
//
587
//      Fill in creation data for an object.
588
//
589
void
590
FillInCreationData(
591
    TPMI_DH_OBJECT                     parentHandle,    //   IN: handle of parent
592
    TPMI_ALG_HASH                      nameHashAlg,     //   IN: name hash algorithm
593
    TPML_PCR_SELECTION                *creationPCR,     //   IN: PCR selection
594
    TPM2B_DATA                        *outsideData,     //   IN: outside data
595
    TPM2B_CREATION_DATA               *outCreation,     //   OUT: creation data for output
596
    TPM2B_DIGEST                      *creationDigest   //   OUT: creation digest
597
//
598
   )
599
3
{
600
3
   BYTE                     creationBuffer[sizeof(TPMS_CREATION_DATA)];
601
3
   BYTE                    *buffer;
602
3
   INT32                    bufferSize;
603
3
   HASH_STATE               hashState;
604
   // Fill in TPMS_CREATION_DATA in outCreation
605
   // Compute PCR digest
606
3
   PCRComputeCurrentDigest(nameHashAlg, creationPCR,
607
3
                           &outCreation->t.creationData.pcrDigest);
608
   // Put back PCR selection list
609
3
   outCreation->t.creationData.pcrSelect = *creationPCR;
610
   // Get locality
611
3
   outCreation->t.creationData.locality
612
3
       = LocalityGetAttributes(_plat__LocalityGet());
613
3
   outCreation->t.creationData.parentNameAlg = TPM_ALG_NULL;
614
   // If the parent is is either a primary seed or TPM_ALG_NULL, then the Name
615
   // and QN of the parent are the parent's handle.
616
3
   if(HandleGetType(parentHandle) == TPM_HT_PERMANENT)
617
3
   {
618
3
       BYTE         *buffer = &outCreation->t.creationData.parentName.t.name[0];
619
3
       INT32         bufferSize = sizeof(TPM_HANDLE);
620
3
       outCreation->t.creationData.parentName.t.size =
621
3
            TPM_HANDLE_Marshal(&parentHandle, &buffer, &bufferSize);
622
         // Parent qualified name of a Temporary Object is the same as parent's
623
         // name
624
3
         MemoryCopy2B(&outCreation->t.creationData.parentQualifiedName.b,
625
3
                      &outCreation->t.creationData.parentName.b,
626
3
                     sizeof(outCreation->t.creationData.parentQualifiedName.t.name));
627
3
   }
628
0
   else           // Regular object
629
0
   {
630
0
       OBJECT              *parentObject = ObjectGet(parentHandle);
631
         // Set name algorithm
632
0
         outCreation->t.creationData.parentNameAlg =
633
0
             parentObject->publicArea.nameAlg;
634
         // Copy parent name
635
0
         outCreation->t.creationData.parentName = parentObject->name;
636
         // Copy parent qualified name
637
0
         outCreation->t.creationData.parentQualifiedName =
638
0
             parentObject->qualifiedName;
639
0
   }
640
   // Copy outside information
641
3
   outCreation->t.creationData.outsideInfo = *outsideData;
642
   // Marshal creation data to canonical form
643
3
   buffer = creationBuffer;
644
3
   bufferSize = sizeof(TPMS_CREATION_DATA);
645
3
   outCreation->t.size = TPMS_CREATION_DATA_Marshal(&outCreation->t.creationData,
646
3
                         &buffer, &bufferSize);
647
   // Compute hash for creation field in public template
648
3
   creationDigest->t.size = CryptStartHash(nameHashAlg, &hashState);
649
3
   CryptUpdateDigest(&hashState, outCreation->t.size, creationBuffer);
650
3
   CryptCompleteHash2B(&hashState, &creationDigest->b);
651
3
   return;
652
3
}
653
//           GetSeedForKDF()
654
//
655
//      Get a seed for KDF. The KDF for encryption and HMAC key use the same seed. It returns a pointer to
656
//      the seed
657
//
658
TPM2B_SEED*
659
GetSeedForKDF(
660
    TPM_HANDLE           protectorHandle,          // IN: the protector handle
661
    TPM2B_SEED          *seedIn                    // IN: the optional input seed
662
    )
663
0
{
664
0
    OBJECT                   *protector = NULL; // Pointer to the protector
665
    // Get seed for encryption key. Use input seed if provided.
666
    // Otherwise, using protector object's seedValue. TPM_RH_NULL is the only
667
    // exception that we may not have a loaded object as protector. In such a
668
    // case, use nullProof as seed.
669
0
    if(seedIn != NULL)
670
0
    {
671
0
        return seedIn;
672
0
    }
673
0
    else
674
0
    {
675
0
        if(protectorHandle == TPM_RH_NULL)
676
0
        {
677
0
             return (TPM2B_SEED *) &gr.nullProof;
678
0
        }
679
0
        else
680
0
        {
681
0
             protector = ObjectGet(protectorHandle);
682
0
             return (TPM2B_SEED *) &protector->sensitive.seedValue;
683
0
        }
684
0
    }
685
0
}
686
//
687
//
688
//           ProduceOuterWrap()
689
//
690
//      This function produce outer wrap for a buffer containing the sensitive data. It requires the sensitive data
691
//      being marshaled to the outerBuffer, with the leading bytes reserved for integrity hash. If iv is used, iv
692
//      space should be reserved at the beginning of the buffer. It assumes the sensitive data starts at address
693
//      (outerBuffer + integrity size {+ iv size}). This function performs:
694
//      a) Add IV before sensitive area if required
695
//      b) encrypt sensitive data, if iv is required, encrypt by iv. otherwise, encrypted by a NULL iv
696
//      c) add HMAC integrity at the beginning of the buffer It returns the total size of blob with outer wrap
697
//
698
UINT16
699
ProduceOuterWrap(
700
    TPM_HANDLE           protector,          //   IN: The handle of the object that provides
701
                                             //       protection. For object, it is parent
702
                                             //       handle. For credential, it is the handle
703
                                             //       of encrypt object.
704
    TPM2B_NAME          *name,               //   IN: the name of the object
705
    TPM_ALG_ID           hashAlg,            //   IN: hash algorithm for outer wrap
706
    TPM2B_SEED          *seed,               //   IN: an external seed may be provided for
707
                                             //       duplication blob. For non duplication
708
                                             //       blob, this parameter should be NULL
709
    BOOL                 useIV,              //   IN: indicate if an IV is used
710
    UINT16               dataSize,           //   IN: the size of sensitive data, excluding the
711
                                             //       leading integrity buffer size or the
712
                                             //       optional iv size
713
    BYTE                *outerBuffer         //   IN/OUT: outer buffer with sensitive data in
714
                                       //     it
715
   )
716
0
{
717
0
   TPM_ALG_ID         symAlg;
718
0
   UINT16             keyBits;
719
0
   TPM2B_SYM_KEY      symKey;
720
0
   TPM2B_IV           ivRNG;           // IV from RNG
721
0
   TPM2B_IV           *iv = NULL;
722
0
   UINT16             ivSize = 0;      // size of iv area, including the size field
723
0
   BYTE               *sensitiveData; // pointer to the sensitive data
724
0
   TPM2B_DIGEST       integrity;
725
0
   UINT16             integritySize;
726
0
   BYTE               *buffer;         // Auxiliary buffer pointer
727
0
   INT32              bufferSize;
728
   // Compute the beginning of sensitive data. The outer integrity should
729
   // always exist if this function function is called to make an outer wrap
730
0
   integritySize = sizeof(UINT16) + CryptGetHashDigestSize(hashAlg);
731
0
   sensitiveData = outerBuffer + integritySize;
732
   // If iv is used, adjust the pointer of sensitive data and add iv before it
733
0
   if(useIV)
734
0
   {
735
0
       ivSize = GetIV2BSize(protector);
736
         // Generate IV from RNG. The iv data size should be the total IV area
737
         // size minus the size of size field
738
0
         ivRNG.t.size = ivSize - sizeof(UINT16);
739
0
         CryptGenerateRandom(ivRNG.t.size, ivRNG.t.buffer);
740
         // Marshal IV to buffer
741
0
         buffer = sensitiveData;
742
0
         bufferSize = sizeof(TPM2B_IV);
743
0
         TPM2B_IV_Marshal(&ivRNG, &buffer, &bufferSize);
744
         // adjust sensitive data starting after IV area
745
0
         sensitiveData += ivSize;
746
         // Use iv for encryption
747
0
         iv = &ivRNG;
748
0
   }
749
   // Compute symmetric key parameters for outer buffer encryption
750
0
   ComputeProtectionKeyParms(protector, hashAlg, name, seed,
751
0
                             &symAlg, &keyBits, &symKey);
752
   // Encrypt inner buffer in place
753
0
   CryptSymmetricEncrypt(sensitiveData, symAlg, keyBits,
754
0
                         TPM_ALG_CFB, symKey.t.buffer, iv, dataSize,
755
0
                         sensitiveData);
756
   // Compute outer integrity. Integrity computation includes the optional IV
757
   // area
758
0
   ComputeOuterIntegrity(name, protector, hashAlg, seed, dataSize + ivSize,
759
0
                         outerBuffer + integritySize, &integrity);
760
   // Add integrity at the beginning of outer buffer
761
0
   buffer = outerBuffer;
762
0
   bufferSize = sizeof(TPM2B_DIGEST);
763
0
   TPM2B_DIGEST_Marshal(&integrity, &buffer, &bufferSize);
764
   // return the total size in outer wrap
765
0
   return dataSize + integritySize + ivSize;
766
0
}
767
//
768
//
769
//
770
//           UnwrapOuter()
771
//
772
//      This function remove the outer wrap of a blob containing sensitive data This function performs:
773
//      a) check integrity of outer blob
774
//      b) decrypt outer blob
775
//
776
//      Error Returns                      Meaning
777
//
778
//      TPM_RC_INSUFFICIENT                error during sensitive data unmarshaling
779
//      TPM_RC_INTEGRITY                   sensitive data integrity is broken
780
//      TPM_RC_SIZE                        error during sensitive data unmarshaling
781
//      TPM_RC_VALUE                       IV size for CFB does not match the encryption algorithm block size
782
//
783
TPM_RC
784
UnwrapOuter(
785
   TPM_HANDLE           protector,             //   IN: The handle of the object that provides
786
                                               //       protection. For object, it is parent
787
                                               //       handle. For credential, it is the handle
788
                                               //       of encrypt object.
789
   TPM2B_NAME          *name,                  //   IN: the name of the object
790
   TPM_ALG_ID           hashAlg,               //   IN: hash algorithm for outer wrap
791
   TPM2B_SEED          *seed,                  //   IN: an external seed may be provided for
792
                                               //       duplication blob. For non duplication
793
                                               //       blob, this parameter should be NULL.
794
   BOOL                 useIV,                 //   IN: indicates if an IV is used
795
   UINT16               dataSize,              //   IN: size of sensitive data in outerBuffer,
796
                                               //       including the leading integrity buffer
797
                                               //       size, and an optional iv area
798
   BYTE                *outerBuffer            //   IN/OUT: sensitive data
799
   )
800
0
{
801
0
   TPM_RC              result;
802
0
   TPM_ALG_ID          symAlg = TPM_ALG_NULL;
803
0
   TPM2B_SYM_KEY       symKey;
804
0
   UINT16              keyBits = 0;
805
0
   TPM2B_IV            ivIn;               // input IV retrieved from input buffer
806
0
   TPM2B_IV            *iv = NULL;
807
0
   BYTE                *sensitiveData;               // pointer to the sensitive data
808
0
   TPM2B_DIGEST        integrityToCompare;
809
0
   TPM2B_DIGEST        integrity;
810
0
   INT32               size;
811
   // Unmarshal integrity
812
0
   sensitiveData = outerBuffer;
813
0
   size = (INT32) dataSize;
814
0
   result = TPM2B_DIGEST_Unmarshal(&integrity, &sensitiveData, &size);
815
0
   if(result == TPM_RC_SUCCESS)
816
0
   {
817
       // Compute integrity to compare
818
0
       ComputeOuterIntegrity(name, protector, hashAlg, seed,
819
0
                             (UINT16) size, sensitiveData,
820
0
                             &integrityToCompare);
821
         // Compare outer blob integrity
822
0
         if(!Memory2BEqual(&integrity.b, &integrityToCompare.b))
823
0
             return TPM_RC_INTEGRITY;
824
         // Get the symmetric algorithm parameters used for encryption
825
0
         ComputeProtectionKeyParms(protector, hashAlg, name, seed,
826
0
                                          &symAlg, &keyBits, &symKey);
827
         // Retrieve IV if it is used
828
0
         if(useIV)
829
0
         {
830
0
             result = TPM2B_IV_Unmarshal(&ivIn, &sensitiveData, &size);
831
0
             if(result == TPM_RC_SUCCESS)
832
0
             {
833
                 // The input iv size for CFB must match the encryption algorithm
834
                 // block size
835
0
                 if(ivIn.t.size != CryptGetSymmetricBlockSize(symAlg, keyBits))
836
0
                     result = TPM_RC_VALUE;
837
0
                 else
838
0
                     iv = &ivIn;
839
0
             }
840
0
         }
841
0
    }
842
    // If no errors, decrypt private in place
843
0
    if(result == TPM_RC_SUCCESS)
844
0
        CryptSymmetricDecrypt(sensitiveData, symAlg, keyBits,
845
0
                              TPM_ALG_CFB, symKey.t.buffer, iv,
846
0
                              (UINT16) size, sensitiveData);
847
0
    return result;
848
0
}
849
//
850
//
851
//           SensitiveToPrivate()
852
//
853
//      This function prepare the private blob for off the chip storage The operations in this function:
854
//      a) marshal TPM2B_SENSITIVE structure into the buffer of TPM2B_PRIVATE
855
//      b) apply encryption to the sensitive area.
856
//      c) apply outer integrity computation.
857
//
858
void
859
SensitiveToPrivate(
860
    TPMT_SENSITIVE      *sensitive,         //   IN: sensitive structure
861
    TPM2B_NAME          *name,              //   IN: the name of the object
862
    TPM_HANDLE           parentHandle,      //   IN: The parent's handle
863
    TPM_ALG_ID           nameAlg,           //   IN: hash algorithm in public area. This
864
                                            //       parameter is used when parentHandle is
865
                                            //       NULL, in which case the object is
866
                                            //       temporary.
867
    TPM2B_PRIVATE       *outPrivate         //   OUT: output private structure
868
    )
869
0
{
870
0
    BYTE                     *buffer;                  //   Auxiliary buffer pointer
871
0
    INT32                    bufferSize;
872
0
    BYTE                     *sensitiveData;           //   pointer to the sensitive data
873
0
    UINT16                   dataSize;                 //   data blob size
874
0
    TPMI_ALG_HASH            hashAlg;                  //   hash algorithm for integrity
875
0
    UINT16                   integritySize;
876
0
    UINT16                   ivSize;
877
0
    pAssert(name != NULL && name->t.size != 0);
878
    // Find the hash algorithm for integrity computation
879
0
    if(parentHandle == TPM_RH_NULL)
880
0
    {
881
        // For Temporary Object, using self name algorithm
882
0
        hashAlg = nameAlg;
883
0
    }
884
0
    else
885
0
   {
886
         // Otherwise, using parent's name algorithm
887
0
         hashAlg = ObjectGetNameAlg(parentHandle);
888
0
   }
889
   // Starting of sensitive data without wrappers
890
0
   sensitiveData = outPrivate->t.buffer;
891
   // Compute the integrity size
892
0
   integritySize = sizeof(UINT16) + CryptGetHashDigestSize(hashAlg);
893
   // Reserve space for integrity
894
0
   sensitiveData += integritySize;
895
   // Get iv size
896
0
   ivSize = GetIV2BSize(parentHandle);
897
   // Reserve space for iv
898
0
   sensitiveData += ivSize;
899
   // Marshal sensitive area, leaving the leading 2 bytes for size
900
0
   buffer = sensitiveData + sizeof(UINT16);
901
0
   bufferSize = sizeof(TPMT_SENSITIVE);
902
0
   dataSize = TPMT_SENSITIVE_Marshal(sensitive, &buffer, &bufferSize);
903
   // Adding size before the data area
904
0
   buffer = sensitiveData;
905
0
   bufferSize = sizeof(UINT16);
906
0
   UINT16_Marshal(&dataSize, &buffer, &bufferSize);
907
   // Adjust the dataSize to include the size field
908
0
   dataSize += sizeof(UINT16);
909
   // Adjust the pointer to inner buffer including the iv
910
0
   sensitiveData = outPrivate->t.buffer + ivSize;
911
   //Produce outer wrap, including encryption and HMAC
912
0
   outPrivate->t.size = ProduceOuterWrap(parentHandle, name, hashAlg, NULL,
913
0
                                         TRUE, dataSize, outPrivate->t.buffer);
914
0
   return;
915
0
}
916
//
917
//
918
//           PrivateToSensitive()
919
//
920
//      Unwrap a input private area. Check the integrity, decrypt and retrieve data to a sensitive structure. The
921
//      operations in this function:
922
//      a) check the integrity HMAC of the input private area
923
//      b) decrypt the private buffer
924
//      c) unmarshal TPMT_SENSITIVE structure into the buffer of TPMT_SENSITIVE
925
//
926
//      Error Returns                   Meaning
927
//
928
//      TPM_RC_INTEGRITY                if the private area integrity is bad
929
//      TPM_RC_SENSITIVE                unmarshal errors while unmarshaling TPMS_ENCRYPT from input
930
//                                      private
931
//      TPM_RC_VALUE                    outer wrapper does not have an iV of the correct size
932
//
933
TPM_RC
934
PrivateToSensitive(
935
   TPM2B_PRIVATE       *inPrivate,          // IN: input private structure
936
   TPM2B_NAME          *name,               // IN: the name of the object
937
   TPM_HANDLE          parentHandle,    // IN: The parent's handle
938
   TPM_ALG_ID          nameAlg,         // IN: hash algorithm in public area. It is
939
                                        //     passed separately because we only pass
940
                                        //     name, rather than the whole public area
941
                                        //     of the object. This parameter is used in
942
                                        //     the following two cases: 1. primary
943
                                        //     objects. 2. duplication blob with inner
944
                                        //     wrap. In other cases, this parameter
945
                                        //     will be ignored
946
   TPMT_SENSITIVE     *sensitive        // OUT: sensitive structure
947
   )
948
0
{
949
0
   TPM_RC             result;
950
0
   BYTE               *buffer;
951
0
   INT32              size;
952
0
   BYTE               *sensitiveData; // pointer to the sensitive data
953
0
   UINT16             dataSize;
954
0
   UINT16             dataSizeInput;
955
0
   TPMI_ALG_HASH      hashAlg;        // hash algorithm for integrity
956
0
   OBJECT             *parent = NULL;
957
0
   UINT16             integritySize;
958
0
   UINT16             ivSize;
959
   // Make sure that name is provided
960
0
   pAssert(name != NULL && name->t.size != 0);
961
   // Find the hash algorithm for integrity computation
962
0
   if(parentHandle == TPM_RH_NULL)
963
0
   {
964
       // For Temporary Object, using self name algorithm
965
0
       hashAlg = nameAlg;
966
0
   }
967
0
   else
968
0
   {
969
       // Otherwise, using parent's name algorithm
970
0
       hashAlg = ObjectGetNameAlg(parentHandle);
971
0
   }
972
   // unwrap outer
973
0
   result = UnwrapOuter(parentHandle, name, hashAlg, NULL, TRUE,
974
0
                        inPrivate->t.size, inPrivate->t.buffer);
975
0
   if(result != TPM_RC_SUCCESS)
976
0
       return result;
977
   // Compute the inner integrity size.
978
0
   integritySize = sizeof(UINT16) + CryptGetHashDigestSize(hashAlg);
979
   // Get iv size
980
0
   ivSize = GetIV2BSize(parentHandle);
981
   // The starting of sensitive data and data size without outer wrapper
982
0
   sensitiveData = inPrivate->t.buffer + integritySize + ivSize;
983
0
   dataSize = inPrivate->t.size - integritySize - ivSize;
984
   // Unmarshal input data size
985
0
   buffer = sensitiveData;
986
0
   size = (INT32) dataSize;
987
0
   result = UINT16_Unmarshal(&dataSizeInput, &buffer, &size);
988
0
   if(result == TPM_RC_SUCCESS)
989
0
   {
990
0
       if((dataSizeInput + sizeof(UINT16)) != dataSize)
991
0
            result = TPM_RC_SENSITIVE;
992
0
       else
993
0
       {
994
              // Unmarshal sensitive buffer to sensitive structure
995
0
              result = TPMT_SENSITIVE_Unmarshal(sensitive, &buffer, &size);
996
0
              if(result != TPM_RC_SUCCESS || size != 0)
997
0
              {
998
0
                  pAssert(    (parent == NULL)
999
0
                           || parent->publicArea.objectAttributes.fixedTPM == CLEAR);
1000
0
                  result = TPM_RC_SENSITIVE;
1001
0
              }
1002
0
              else
1003
0
              {
1004
                  // Always remove trailing zeros at load so that it is not necessary
1005
                  // to check
1006
                  // each time auth is checked.
1007
0
                  MemoryRemoveTrailingZeros(&(sensitive->authValue));
1008
0
              }
1009
0
        }
1010
0
    }
1011
0
    return result;
1012
0
}
1013
//
1014
//
1015
//          SensitiveToDuplicate()
1016
//
1017
//      This function prepare the duplication blob from the sensitive area. The operations in this function:
1018
//      a) marshal TPMT_SENSITIVE structure into the buffer of TPM2B_PRIVATE
1019
//      b) apply inner wrap to the sensitive area if required
1020
//      c) apply outer wrap if required
1021
//
1022
void
1023
SensitiveToDuplicate(
1024
    TPMT_SENSITIVE                *sensitive,          //   IN: sensitive structure
1025
    TPM2B_NAME                    *name,               //   IN: the name of the object
1026
    TPM_HANDLE                     parentHandle,       //   IN: The new parent's handle
1027
    TPM_ALG_ID                     nameAlg,            //   IN: hash algorithm in public area. It
1028
                                                       //       is passed separately because we
1029
                                                       //       only pass name, rather than the
1030
                                                       //       whole public area of the object.
1031
    TPM2B_SEED                    *seed,               //   IN: the external seed. If external
1032
                                                       //       seed is provided with size of 0,
1033
                                                       //       no outer wrap should be applied
1034
                                                       //       to duplication blob.
1035
    TPMT_SYM_DEF_OBJECT           *symDef,             //   IN: Symmetric key definition. If the
1036
                                                       //       symmetric key algorithm is NULL,
1037
                                                       //       no inner wrap should be applied.
1038
    TPM2B_DATA                    *innerSymKey,        //   IN/OUT: a symmetric key may be
1039
                                                       //       provided to encrypt the inner
1040
                                                       //       wrap of a duplication blob. May
1041
                                                       //       be generated here if needed.
1042
    TPM2B_PRIVATE                 *outPrivate          //   OUT: output private structure
1043
    )
1044
0
{
1045
0
    BYTE                *buffer;        // Auxiliary buffer pointer
1046
0
    INT32               bufferSize;
1047
0
    BYTE                *sensitiveData; // pointer to the sensitive data
1048
0
    TPMI_ALG_HASH       outerHash = TPM_ALG_NULL;// The hash algorithm for outer wrap
1049
0
    TPMI_ALG_HASH       innerHash = TPM_ALG_NULL;// The hash algorithm for inner wrap
1050
0
    UINT16              dataSize;       // data blob size
1051
0
    BOOL                doInnerWrap = FALSE;
1052
0
    BOOL                doOuterWrap = FALSE;
1053
    // Make sure that name is provided
1054
0
    pAssert(name != NULL && name->t.size != 0);
1055
    // Make sure symDef and innerSymKey are not NULL
1056
0
   pAssert(symDef != NULL && innerSymKey != NULL);
1057
   // Starting of sensitive data without wrappers
1058
0
   sensitiveData = outPrivate->t.buffer;
1059
   // Find out if inner wrap is required
1060
0
   if(symDef->algorithm != TPM_ALG_NULL)
1061
0
   {
1062
0
       doInnerWrap = TRUE;
1063
       // Use self nameAlg as inner hash algorithm
1064
0
       innerHash = nameAlg;
1065
       // Adjust sensitive data pointer
1066
0
       sensitiveData += sizeof(UINT16) + CryptGetHashDigestSize(innerHash);
1067
0
   }
1068
   // Find out if outer wrap is required
1069
0
   if(seed->t.size != 0)
1070
0
   {
1071
0
       doOuterWrap = TRUE;
1072
       // Use parent nameAlg as outer hash algorithm
1073
0
       outerHash = ObjectGetNameAlg(parentHandle);
1074
       // Adjust sensitive data pointer
1075
0
       sensitiveData += sizeof(UINT16) + CryptGetHashDigestSize(outerHash);
1076
0
   }
1077
   // Marshal sensitive area, leaving the leading 2 bytes for size
1078
0
   buffer = sensitiveData + sizeof(UINT16);
1079
0
   bufferSize = sizeof(TPMT_SENSITIVE);
1080
0
   dataSize = TPMT_SENSITIVE_Marshal(sensitive, &buffer, &bufferSize);
1081
   // Adding size before the data area
1082
0
   buffer = sensitiveData;
1083
0
   bufferSize = sizeof(UINT16);
1084
0
   UINT16_Marshal(&dataSize, &buffer, &bufferSize);
1085
   // Adjust the dataSize to include the size field
1086
0
   dataSize += sizeof(UINT16);
1087
   // Apply inner wrap for duplication blob. It includes both integrity and
1088
   // encryption
1089
0
   if(doInnerWrap)
1090
0
   {
1091
0
       BYTE             *innerBuffer = NULL;
1092
0
       BOOL             symKeyInput = TRUE;
1093
0
       innerBuffer = outPrivate->t.buffer;
1094
       // Skip outer integrity space
1095
0
       if(doOuterWrap)
1096
0
            innerBuffer += sizeof(UINT16) + CryptGetHashDigestSize(outerHash);
1097
0
       dataSize = ProduceInnerIntegrity(name, innerHash, dataSize,
1098
0
                                         innerBuffer);
1099
        // Generate inner encryption key if needed
1100
0
        if(innerSymKey->t.size == 0)
1101
0
        {
1102
0
            innerSymKey->t.size = (symDef->keyBits.sym + 7) / 8;
1103
0
            CryptGenerateRandom(innerSymKey->t.size, innerSymKey->t.buffer);
1104
             // TPM generates symmetric encryption.   Set the flag to FALSE
1105
0
             symKeyInput = FALSE;
1106
0
        }
1107
0
        else
1108
0
        {
1109
             // assume the input key size should matches the symmetric definition
1110
0
             pAssert(innerSymKey->t.size == (symDef->keyBits.sym + 7) / 8);
1111
0
        }
1112
        // Encrypt inner buffer in place
1113
0
          CryptSymmetricEncrypt(innerBuffer, symDef->algorithm,
1114
0
                                symDef->keyBits.sym, TPM_ALG_CFB,
1115
0
                                innerSymKey->t.buffer, NULL, dataSize,
1116
0
                                innerBuffer);
1117
          // If the symmetric encryption key is imported, clear the buffer for
1118
          // output
1119
0
          if(symKeyInput)
1120
0
              innerSymKey->t.size = 0;
1121
0
   }
1122
   // Apply outer wrap for duplication blob. It includes both integrity and
1123
   // encryption
1124
0
   if(doOuterWrap)
1125
0
   {
1126
0
       dataSize = ProduceOuterWrap(parentHandle, name, outerHash, seed, FALSE,
1127
0
                                   dataSize, outPrivate->t.buffer);
1128
0
   }
1129
   // Data size for output
1130
0
   outPrivate->t.size = dataSize;
1131
0
   return;
1132
0
}
1133
//
1134
//
1135
//           DuplicateToSensitive()
1136
//
1137
//       Unwrap a duplication blob. Check the integrity, decrypt and retrieve data to a sensitive structure. The
1138
//       operations in this function:
1139
//       a) check the integrity HMAC of the input private area
1140
//       b) decrypt the private buffer
1141
//       c) unmarshal TPMT_SENSITIVE structure into the buffer of TPMT_SENSITIVE
1142
//
1143
//       Error Returns                   Meaning
1144
//
1145
//       TPM_RC_INSUFFICIENT             unmarshaling sensitive data from inPrivate failed
1146
//       TPM_RC_INTEGRITY                inPrivate data integrity is broken
1147
//       TPM_RC_SIZE                     unmarshaling sensitive data from inPrivate failed
1148
//
1149
TPM_RC
1150
DuplicateToSensitive(
1151
   TPM2B_PRIVATE                 *inPrivate,           //   IN: input private structure
1152
   TPM2B_NAME                    *name,                //   IN: the name of the object
1153
   TPM_HANDLE                     parentHandle,        //   IN: The parent's handle
1154
   TPM_ALG_ID                     nameAlg,             //   IN: hash algorithm in public area.
1155
   TPM2B_SEED                    *seed,                //   IN: an external seed may be provided.
1156
                                                       //       If external seed is provided with
1157
                                                       //       size of 0, no outer wrap is
1158
                                                       //       applied
1159
   TPMT_SYM_DEF_OBJECT           *symDef,              //   IN: Symmetric key definition. If the
1160
                                                       //       symmetric key algorithm is NULL,
1161
                                                       //       no inner wrap is applied
1162
   TPM2B_DATA                    *innerSymKey,         //   IN: a symmetric key may be provided
1163
                                                       //       to decrypt the inner wrap of a
1164
                                                       //       duplication blob.
1165
   TPMT_SENSITIVE                *sensitive            //   OUT: sensitive structure
1166
   )
1167
0
{
1168
0
   TPM_RC              result;
1169
0
   BYTE               *buffer;
1170
0
   INT32              size;
1171
0
   BYTE               *sensitiveData; // pointer to the sensitive data
1172
0
   UINT16             dataSize;
1173
0
   UINT16             dataSizeInput;
1174
   // Make sure that name is provided
1175
0
   pAssert(name != NULL && name->t.size != 0);
1176
   // Make sure symDef and innerSymKey are not NULL
1177
0
   pAssert(symDef != NULL && innerSymKey != NULL);
1178
   // Starting of sensitive data
1179
0
   sensitiveData = inPrivate->t.buffer;
1180
0
   dataSize = inPrivate->t.size;
1181
   // Find out if outer wrap is applied
1182
0
   if(seed->t.size != 0)
1183
0
   {
1184
0
       TPMI_ALG_HASH   outerHash = TPM_ALG_NULL;
1185
        // Use parent nameAlg as outer hash algorithm
1186
0
        outerHash = ObjectGetNameAlg(parentHandle);
1187
0
        result = UnwrapOuter(parentHandle, name, outerHash, seed, FALSE,
1188
0
                             dataSize, sensitiveData);
1189
0
        if(result != TPM_RC_SUCCESS)
1190
0
            return result;
1191
        // Adjust sensitive data pointer and size
1192
0
        sensitiveData += sizeof(UINT16) + CryptGetHashDigestSize(outerHash);
1193
0
        dataSize -= sizeof(UINT16) + CryptGetHashDigestSize(outerHash);
1194
0
   }
1195
   // Find out if inner wrap is applied
1196
0
   if(symDef->algorithm != TPM_ALG_NULL)
1197
0
   {
1198
0
       TPMI_ALG_HASH   innerHash = TPM_ALG_NULL;
1199
        // assume the input key size should matches the symmetric definition
1200
0
        pAssert(innerSymKey->t.size == (symDef->keyBits.sym + 7) / 8);
1201
        // Decrypt inner buffer in place
1202
0
        CryptSymmetricDecrypt(sensitiveData, symDef->algorithm,
1203
0
                              symDef->keyBits.sym, TPM_ALG_CFB,
1204
0
                              innerSymKey->t.buffer, NULL, dataSize,
1205
0
                              sensitiveData);
1206
        // Use self nameAlg as inner hash algorithm
1207
0
        innerHash = nameAlg;
1208
        // Check inner integrity
1209
0
        result = CheckInnerIntegrity(name, innerHash, dataSize, sensitiveData);
1210
0
        if(result != TPM_RC_SUCCESS)
1211
0
            return result;
1212
        // Adjust sensitive data pointer and size
1213
0
        sensitiveData += sizeof(UINT16) + CryptGetHashDigestSize(innerHash);
1214
0
        dataSize -= sizeof(UINT16) + CryptGetHashDigestSize(innerHash);
1215
0
   }
1216
   // Unmarshal input data size
1217
0
   buffer = sensitiveData;
1218
0
   size = (INT32) dataSize;
1219
0
   result = UINT16_Unmarshal(&dataSizeInput, &buffer, &size);
1220
0
   if(result == TPM_RC_SUCCESS)
1221
0
   {
1222
0
       if((dataSizeInput + sizeof(UINT16)) != dataSize)
1223
0
              result = TPM_RC_SIZE;
1224
0
          else
1225
0
          {
1226
              // Unmarshal sensitive buffer to sensitive structure
1227
0
              result = TPMT_SENSITIVE_Unmarshal(sensitive, &buffer, &size);
1228
              // if the results is OK make sure that all the data was unmarshaled
1229
0
              if(result == TPM_RC_SUCCESS && size != 0)
1230
0
                  result = TPM_RC_SIZE;
1231
0
       }
1232
0
   }
1233
   // Always remove trailing zeros at load so that it is not necessary to check
1234
   // each time auth is checked.
1235
0
   if(result == TPM_RC_SUCCESS)
1236
0
       MemoryRemoveTrailingZeros(&(sensitive->authValue));
1237
0
   return result;
1238
0
}
1239
//
1240
//
1241
//           SecretToCredential()
1242
//
1243
//       This function prepare the credential blob from a secret (a TPM2B_DIGEST) The operations in this
1244
//       function:
1245
//       a) marshal TPM2B_DIGEST structure into the buffer of TPM2B_ID_OBJECT
1246
//       b) encrypt the private buffer, excluding the leading integrity HMAC area
1247
//       c) compute integrity HMAC and append to the beginning of the buffer.
1248
//       d) Set the total size of TPM2B_ID_OBJECT buffer
1249
//
1250
void
1251
SecretToCredential(
1252
   TPM2B_DIGEST              *secret,          //   IN: secret information
1253
   TPM2B_NAME                *name,            //   IN: the name of the object
1254
   TPM2B_SEED                *seed,            //   IN: an external seed.
1255
   TPM_HANDLE                 protector,       //   IN: The protector's handle
1256
   TPM2B_ID_OBJECT           *outIDObject      //   OUT: output credential
1257
   )
1258
0
{
1259
0
   BYTE                      *buffer;          //   Auxiliary buffer pointer
1260
0
   INT32                      bufferSize;
1261
0
   BYTE                      *sensitiveData;   //   pointer to the sensitive data
1262
0
   TPMI_ALG_HASH              outerHash;       //   The hash algorithm for outer wrap
1263
0
   UINT16                     dataSize;        //   data blob size
1264
0
   pAssert(secret != NULL && outIDObject != NULL);
1265
   // use protector's name algorithm as outer hash
1266
0
   outerHash = ObjectGetNameAlg(protector);
1267
   // Marshal secret area to credential buffer, leave space for integrity
1268
0
   sensitiveData = outIDObject->t.credential
1269
0
                   + sizeof(UINT16) + CryptGetHashDigestSize(outerHash);
1270
   // Marshal secret area
1271
0
   buffer = sensitiveData;
1272
0
   bufferSize = sizeof(TPM2B_DIGEST);
1273
0
   dataSize = TPM2B_DIGEST_Marshal(secret, &buffer, &bufferSize);
1274
   // Apply outer wrap
1275
0
   outIDObject->t.size = ProduceOuterWrap(protector,
1276
0
                                          name,
1277
0
                                          outerHash,
1278
0
                                          seed,
1279
0
                                          FALSE,
1280
0
                                          dataSize,
1281
0
                                          outIDObject->t.credential);
1282
0
   return;
1283
0
}
1284
//
1285
//
1286
//            CredentialToSecret()
1287
//
1288
//       Unwrap a credential. Check the integrity, decrypt and retrieve data to a TPM2B_DIGEST structure. The
1289
//       operations in this function:
1290
//       a) check the integrity HMAC of the input credential area
1291
//       b) decrypt the credential buffer
1292
//       c) unmarshal TPM2B_DIGEST structure into the buffer of TPM2B_DIGEST
1293
//
1294
//       Error Returns                      Meaning
1295
//
1296
//       TPM_RC_INSUFFICIENT                error during credential unmarshaling
1297
//       TPM_RC_INTEGRITY                   credential integrity is broken
1298
//       TPM_RC_SIZE                        error during credential unmarshaling
1299
//       TPM_RC_VALUE                       IV size does not match the encryption algorithm block size
1300
//
1301
TPM_RC
1302
CredentialToSecret(
1303
   TPM2B_ID_OBJECT          *inIDObject,             //   IN: input credential blob
1304
   TPM2B_NAME               *name,                   //   IN: the name of the object
1305
   TPM2B_SEED               *seed,                   //   IN: an external seed.
1306
   TPM_HANDLE                protector,              //   IN: The protector's handle
1307
   TPM2B_DIGEST             *secret                  //   OUT: secret information
1308
   )
1309
0
{
1310
0
   TPM_RC                           result;
1311
0
   BYTE                            *buffer;
1312
0
   INT32                            size;
1313
0
   TPMI_ALG_HASH                    outerHash;     // The hash algorithm for outer wrap
1314
0
   BYTE                            *sensitiveData; // pointer to the sensitive data
1315
0
   UINT16                           dataSize;
1316
   // use protector's name algorithm as outer hash
1317
0
   outerHash = ObjectGetNameAlg(protector);
1318
   // Unwrap outer, a TPM_RC_INTEGRITY error may be returned at this point
1319
0
   result = UnwrapOuter(protector, name, outerHash, seed, FALSE,
1320
0
                        inIDObject->t.size, inIDObject->t.credential);
1321
0
   if(result == TPM_RC_SUCCESS)
1322
0
   {
1323
       // Compute the beginning of sensitive data
1324
0
       sensitiveData = inIDObject->t.credential
1325
0
                       + sizeof(UINT16) + CryptGetHashDigestSize(outerHash);
1326
0
       dataSize = inIDObject->t.size
1327
0
                  - (sizeof(UINT16) + CryptGetHashDigestSize(outerHash));
1328
          // Unmarshal secret buffer to TPM2B_DIGEST structure
1329
0
          buffer = sensitiveData;
1330
0
          size = (INT32) dataSize;
1331
0
          result = TPM2B_DIGEST_Unmarshal(secret, &buffer, &size);
1332
          // If there were no other unmarshaling errors, make sure that the
1333
          // expected amount of data was recovered
1334
0
          if(result == TPM_RC_SUCCESS && size != 0)
1335
0
              return TPM_RC_SIZE;
1336
0
   }
1337
0
   return result;
1338
0
}