• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

stefanberger / libtpms / #2056

20 Jan 2026 10:12PM UTC coverage: 77.177% (-0.006%) from 77.183%
#2056

push

travis-ci

web-flow
Merge 26872a5bf into c2a8109f8

1063 of 1263 new or added lines in 88 files covered. (84.16%)

1810 existing lines in 64 files now uncovered.

36345 of 47093 relevant lines covered (77.18%)

125599.29 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

94.01
/src/tpm2/TPMCmd/tpm/src/command/Object/Object_spt.c
1
// SPDX-License-Identifier: BSD-2-Clause
2

3
//** Includes
4
#include "Tpm.h"
5
#include "Object_spt_fp.h"
6
#include "Marshal.h"
7

8
//** Local Functions
9

10
//*** GetIV2BSize()
11
// Get the size of TPM2B_IV in canonical form that will be append to the start of
12
// the sensitive data.  It includes both size of size field and size of iv data
13
static UINT16 GetIV2BSize(OBJECT* protector  // IN: the protector handle
1,156✔
14
)
15
{
16
    TPM_ALG_ID symAlg;
1,156✔
17
    UINT16     keyBits;
1,156✔
18

19
    // Determine the symmetric algorithm and size of key
20
    if(protector == NULL)
1,156✔
21
    {
22
        // Use the context encryption algorithm and key size
23
        symAlg  = CONTEXT_ENCRYPT_ALG;
24
        keyBits = CONTEXT_ENCRYPT_KEY_BITS;
25
    }
26
    else
27
    {
28
        symAlg  = protector->publicArea.parameters.asymDetail.symmetric.algorithm;
1,156✔
29
        keyBits = protector->publicArea.parameters.asymDetail.symmetric.keyBits.sym;
1,156✔
30
    }
31

32
    // The IV size is a UINT16 size field plus the block size of the symmetric
33
    // algorithm
34
    return sizeof(UINT16) + CryptGetSymmetricBlockSize(symAlg, keyBits);
1,156✔
35
}
36

37
//*** ComputeProtectionKeyParms()
38
// This function retrieves the symmetric protection key parameters for
39
// the sensitive data
40
// The parameters retrieved from this function include encryption algorithm,
41
// key size in bit, and a TPM2B_SYM_KEY containing the key material as well as
42
// the key size in bytes
43
// This function is used for any action that requires encrypting or decrypting of
44
// the sensitive area of an object or a credential blob
45
//
46
/*(See part 1 specification)
47
    KDF for generating the protection key material:
48
    KDFa(hashAlg, seed, "STORAGE", Name, NULL , bits)
49
where
50
    hashAlg     for a Primary Object, an algorithm chosen by the TPM vendor
51
                for derivations from Primary Seeds. For all other objects,
52
                the nameAlg of the object's parent.
53
    seed        for a Primary Object in the Platform Hierarchy, the PPS.
54
                For Primary Objects in either Storage or Endorsement Hierarchy,
55
                the SPS. For Temporary Objects, the context encryption seed.
56
                For all other objects, the symmetric seed value in the
57
                sensitive area of the object's parent.
58
    STORAGE     label to differentiate use of KDFa() (see 4.7)
59
    Name        the Name of the object being encrypted
60
    bits        the number of bits required for a  symmetric key and IV
61
*/
62
//  Return Type: void
63
static void ComputeProtectionKeyParms(
850✔
64
    OBJECT*    protector,    // IN: the protector object
65
    TPM_ALG_ID hashAlg,      // IN: hash algorithm for KDFa
66
    TPM2B*     name,         // IN: name of the object
67
    TPM2B*     seedIn,       // IN: optional seed for duplication blob.
68
                             //     For non duplication blob, this
69
                             //     parameter should be NULL
70
    TPM_ALG_ID*    symAlg,   // OUT: the symmetric algorithm
71
    UINT16*        keyBits,  // OUT: the symmetric key size in bits
72
    TPM2B_SYM_KEY* symKey    // OUT: the symmetric key
73
)
74
{
75
    const TPM2B* seed = seedIn;
850✔
76

77
    // Determine the algorithms for the KDF and the encryption/decryption
78
    // For TPM_RH_NULL, using context settings
79
    if(protector == NULL)
850✔
80
    {
81
        // Use the context encryption algorithm and key size
UNCOV
82
        *symAlg        = CONTEXT_ENCRYPT_ALG;
×
UNCOV
83
        symKey->t.size = CONTEXT_ENCRYPT_KEY_BYTES;
×
UNCOV
84
        *keyBits       = CONTEXT_ENCRYPT_KEY_BITS;
×
85
    }
86
    else
87
    {
88
        TPMT_SYM_DEF_OBJECT* symDef;
850✔
89
        symDef         = &protector->publicArea.parameters.asymDetail.symmetric;
850✔
90
        *symAlg        = symDef->algorithm;
850✔
91
        *keyBits       = symDef->keyBits.sym;
850✔
92
        symKey->t.size = (*keyBits + 7) / 8;
850✔
93
    }
94
    // Get seed for KDF
95
    if(seed == NULL)
850✔
96
        seed = GetSeedForKDF(protector);
780✔
97
    // KDFa to generate symmetric key and IV value
98
    CryptKDFa(hashAlg,
850✔
99
              seed,
100
              STORAGE_KEY,
101
              name,
102
              NULL,
103
              symKey->t.size * 8,
850✔
104
              symKey->t.buffer,
850✔
105
              NULL,
106
              FALSE);
107
    return;
850✔
108
}
109

110
//*** ComputeOuterIntegrity()
111
// The sensitive area parameter is a buffer that holds a space for
112
// the integrity value and the marshaled sensitive area. The caller should
113
// skip over the area set aside for the integrity value
114
// and compute the hash of the remainder of the object.
115
// The size field of sensitive is in unmarshaled form and the
116
// sensitive area contents is an array of bytes.
117
/*(See part 1 specification)
118
    KDFa(hashAlg, seed, "INTEGRITY", NULL, NULL , bits)   (38)
119
where
120
    hashAlg     for a Primary Object, the nameAlg of the object. For all other
121
                objects the nameAlg of the object's parent.
122
    seed        for a Primary Object in the Platform Hierarchy, the PPS. For
123
                Primary Objects in either Storage or Endorsement Hierarchy,
124
                the SPS. For a Temporary Object, the context encryption key.
125
                For all other objects, the symmetric seed value in the sensitive
126
                area of the object's parent.
127
    "INTEGRITY" a value used to differentiate the uses of the KDF.
128
    bits        the number of bits in the digest produced by hashAlg.
129
Key is then used in the integrity computation.
130
    HMACnameAlg(HMACkey, encSensitive || Name )
131
where
132
    HMACnameAlg()   the HMAC function using nameAlg of the object's parent
133
    HMACkey         value derived from the parent symmetric protection value
134
    encSensitive    symmetrically encrypted sensitive area
135
    Name            the Name of the object being protected
136
*/
137
//  Return Type: void
138
static void ComputeOuterIntegrity(
853✔
139
    TPM2B*  name,                 // IN: the name of the object
140
    OBJECT* protector,            // IN: the object that
141
                                  //     provides protection. For an object,
142
                                  //     it is a parent. For a credential, it
143
                                  //     is the encrypt object. For
144
                                  //     a Temporary Object, it is NULL
145
    TPMI_ALG_HASH hashAlg,        // IN: algorithm to use for integrity
146
    TPM2B*        seedIn,         // IN: an external seed may be provided for
147
                                  //     duplication blob. For non duplication
148
                                  //     blob, this parameter should be NULL
149
    UINT32        sensitiveSize,  // IN: size of the marshaled sensitive data
150
    BYTE*         sensitiveData,  // IN: sensitive area
151
    TPM2B_DIGEST* integrity       // OUT: integrity
152
)
153
{
154
    HMAC_STATE   hmacState;
853✔
155
    TPM2B_DIGEST hmacKey;
853✔
156
    const TPM2B* seed = seedIn;
853✔
157
    //
158
    // Get seed for KDF
159
    if(seed == NULL)
853✔
160
        seed = GetSeedForKDF(protector);
783✔
161
    // Determine the HMAC key bits
162
    hmacKey.t.size = CryptHashGetDigestSize(hashAlg);
853✔
163

164
    // KDFa to generate HMAC key
165
    CryptKDFa(hashAlg,
853✔
166
              seed,
167
              INTEGRITY_KEY,
168
              NULL,
169
              NULL,
170
              hmacKey.t.size * 8,
853✔
171
              hmacKey.t.buffer,
172
              NULL,
173
              FALSE);
174
    // Start HMAC and get the size of the digest which will become the integrity
175
    integrity->t.size = CryptHmacStart2B(&hmacState, hashAlg, &hmacKey.b);
853✔
176

177
    // Adding the marshaled sensitive area to the integrity value
178
    CryptDigestUpdate(&hmacState.hashState, sensitiveSize, sensitiveData);
853✔
179

180
    // Adding name
181
    CryptDigestUpdate2B(&hmacState.hashState, name);
853✔
182

183
    // Compute HMAC
184
    CryptHmacEnd2B(&hmacState, &integrity->b);
853✔
185

186
    return;
853✔
187
}
188

189
//*** ComputeInnerIntegrity()
190
// This function computes the integrity of an inner wrap
191
static void ComputeInnerIntegrity(
26✔
192
    TPM_ALG_ID    hashAlg,        // IN: hash algorithm for inner wrap
193
    TPM2B*        name,           // IN: the name of the object
194
    UINT16        dataSize,       // IN: the size of sensitive data
195
    BYTE*         sensitiveData,  // IN: sensitive data
196
    TPM2B_DIGEST* integrity       // OUT: inner integrity
197
)
198
{
199
    HASH_STATE hashState;
26✔
200
    //
201
    // Start hash and get the size of the digest which will become the integrity
202
    integrity->t.size = CryptHashStart(&hashState, hashAlg);
26✔
203

204
    // Adding the marshaled sensitive area to the integrity value
205
    CryptDigestUpdate(&hashState, dataSize, sensitiveData);
26✔
206

207
    // Adding name
208
    CryptDigestUpdate2B(&hashState, name);
26✔
209

210
    // Compute hash
211
    CryptHashEnd2B(&hashState, &integrity->b);
26✔
212

213
    return;
26✔
214
}
215

216
//*** ProduceInnerIntegrity()
217
// This function produces an inner integrity for regular private, credential or
218
// duplication blob
219
// It requires the sensitive data being marshaled to the innerBuffer, with the
220
// leading bytes reserved for integrity hash.  It assume the sensitive data
221
// starts at address (innerBuffer + integrity size).
222
// This function integrity at the beginning of the inner buffer
223
// It returns the total size of buffer with the inner wrap
224
static UINT16 ProduceInnerIntegrity(
13✔
225
    TPM2B*     name,      // IN: the name of the object
226
    TPM_ALG_ID hashAlg,   // IN: hash algorithm for inner wrap
227
    UINT16     dataSize,  // IN: the size of sensitive data, excluding the
228
                          //     leading integrity buffer size
229
    BYTE* innerBuffer     // IN/OUT: inner buffer with sensitive data in
230
                          //     it.  At input, the leading bytes of this
231
                          //     buffer is reserved for integrity
232
)
233
{
234
    BYTE*        sensitiveData;  // pointer to the sensitive data
13✔
235
    TPM2B_DIGEST integrity;
13✔
236
    UINT16       integritySize;
13✔
237
    BYTE*        buffer;  // Auxiliary buffer pointer
13✔
238
                          //
239
    // sensitiveData points to the beginning of sensitive data in innerBuffer
240
    integritySize = sizeof(UINT16) + CryptHashGetDigestSize(hashAlg);
13✔
241
    sensitiveData = innerBuffer + integritySize;
13✔
242

243
    ComputeInnerIntegrity(hashAlg, name, dataSize, sensitiveData, &integrity);
13✔
244

245
    // Add integrity at the beginning of inner buffer
246
    buffer = innerBuffer;
13✔
247
    TPM2B_DIGEST_Marshal(&integrity, &buffer, NULL);
13✔
248

249
    return dataSize + integritySize;
13✔
250
}
251

252
//*** CheckInnerIntegrity()
253
// This function check integrity of inner blob
254
//  Return Type: TPM_RC
255
//      TPM_RC_INTEGRITY        if the outer blob integrity is bad
256
//      unmarshal errors        unmarshal errors while unmarshaling integrity
257
static TPM_RC CheckInnerIntegrity(
13✔
258
    TPM2B*     name,      // IN: the name of the object
259
    TPM_ALG_ID hashAlg,   // IN: hash algorithm for inner wrap
260
    UINT16     dataSize,  // IN: the size of sensitive data, including the
261
                          //     leading integrity buffer size
262
    BYTE* innerBuffer     // IN/OUT: inner buffer with sensitive data in
263
                          //     it
264
)
265
{
266
    TPM_RC       result;
13✔
267
    TPM2B_DIGEST integrity;
13✔
268
    TPM2B_DIGEST integrityToCompare;
13✔
269
    BYTE*        buffer;  // Auxiliary buffer pointer
13✔
270
    INT32        size;
13✔
271
    //
272
    // Unmarshal integrity
273
    buffer = innerBuffer;
13✔
274
    size   = (INT32)dataSize;
13✔
275
    result = TPM2B_DIGEST_Unmarshal(&integrity, &buffer, &size);
13✔
276
    if(result == TPM_RC_SUCCESS)
13✔
277
    {
278
        // Compute integrity to compare
279
        ComputeInnerIntegrity(
13✔
280
            hashAlg, name, (UINT16)size, buffer, &integrityToCompare);
13✔
281
        // Compare outer blob integrity
282
        if(!MemoryEqual2B(&integrity.b, &integrityToCompare.b))
13✔
UNCOV
283
            result = TPM_RC_INTEGRITY;
×
284
    }
285
    return result;
13✔
286
}
287

288
//** Public Functions
289

290
//*** AdjustAuthSize()
291
// This function will validate that the input authValue is no larger than the
292
// digestSize for the nameAlg. It will then pad with zeros to the size of the
293
// digest.
294
BOOL AdjustAuthSize(TPM2B_AUTH*   auth,    // IN/OUT: value to adjust
968✔
295
                    TPMI_ALG_HASH nameAlg  // IN:
296
)
297
{
298
    UINT16 digestSize;
968✔
299
    //
300
    // If there is no nameAlg, then this is a LoadExternal and the authVale can
301
    // be any size up to the maximum allowed by the implementation
302
    digestSize = (nameAlg == TPM_ALG_NULL) ? sizeof(TPMU_HA)
968✔
303
                                           : CryptHashGetDigestSize(nameAlg);
968✔
304
    if(digestSize < MemoryRemoveTrailingZeros(auth))
968✔
305
        return FALSE;
306
    else if(digestSize > auth->t.size)
968✔
307
        MemoryPad2B(&auth->b, digestSize);
968✔
308
    auth->t.size = digestSize;
968✔
309

310
    return TRUE;
968✔
311
}
312

313
//*** AreAttributesForParent()
314
// This function is called by create, load, and import functions.
315
//
316
// Note: The 'isParent' attribute is SET when an object is loaded and it has
317
// attributes that are suitable for a parent object.
318
//  Return Type: BOOL
319
//      TRUE(1)         properties are those of a parent
320
//      FALSE(0)        properties are not those of a parent
321
BOOL ObjectIsParent(OBJECT* parentObject  // IN: parent handle
776✔
322
)
323
{
324
    return parentObject->attributes.isParent;
776✔
325
}
326

327
//*** CreateChecks()
328
// Attribute checks that are unique to creation.
329
// If parentObject is not NULL, then this function checks the object's
330
// attributes as an Ordinary or Derived Object with the given parent.
331
// If parentObject is NULL, and primaryHandle is not 0, then this function
332
// checks the object's attributes as a Primary Object in the given hierarchy.
333
// If parentObject is NULL, and primaryHandle is 0, then this function checks
334
// the object's attributes as an External Object.
335
//  Return Type: TPM_RC
336
//      TPM_RC_ATTRIBUTES   sensitiveDataOrigin is not consistent with the
337
//                          object type
338
//      other               returns from PublicAttributesValidation()
339
TPM_RC
340
CreateChecks(OBJECT*           parentObject,
991✔
341
             TPMI_RH_HIERARCHY primaryHierarchy,
342
             TPMT_PUBLIC*      publicArea,
343
             UINT16            sensitiveDataSize)
344
{
345
    TPMA_OBJECT attributes = publicArea->objectAttributes;
991✔
346
    TPM_RC      result     = TPM_RC_SUCCESS;
991✔
347
    //
348
    // If the caller indicates that they have provided the data, then make sure that
349
    // they have provided some data.
350
    if((!IS_ATTRIBUTE(attributes, TPMA_OBJECT, sensitiveDataOrigin))
991✔
351
       && (sensitiveDataSize == 0))
35✔
352
        return TPM_RCS_ATTRIBUTES;
353
    // For an ordinary object, data can only be provided when sensitiveDataOrigin
354
    // is CLEAR
355
    if((parentObject != NULL)
987✔
356
       && (IS_ATTRIBUTE(attributes, TPMA_OBJECT, sensitiveDataOrigin))
280✔
357
       && (sensitiveDataSize != 0))
257✔
358
        return TPM_RCS_ATTRIBUTES;
359
    switch(publicArea->type)
987✔
360
    {
361
        case TPM_ALG_KEYEDHASH:
62✔
362
            // if this is a data object (sign == decrypt == CLEAR) then the
363
            // TPM cannot be the data source.
364
            if(!IS_ATTRIBUTE(attributes, TPMA_OBJECT, sign)
62✔
365
               && !IS_ATTRIBUTE(attributes, TPMA_OBJECT, decrypt)
366
               && IS_ATTRIBUTE(attributes, TPMA_OBJECT, sensitiveDataOrigin))
62✔
UNCOV
367
                result = TPM_RC_ATTRIBUTES;
×
368
            // fall through to prevent a fixedTPM derivation parent
369
            // [[fallthrough]];
370
        /* fallthrough */                // libtpms added
371
        case TPM_ALG_SYMCIPHER:
372
            // A restricted key symmetric key (SYMCIPHER and KEYEDHASH)
373
            // must have sensitiveDataOrigin SET unless it has fixedParent and
374
            // fixedTPM CLEAR.
375
            if(IS_ATTRIBUTE(attributes, TPMA_OBJECT, restricted))
97✔
376
                if(!IS_ATTRIBUTE(attributes, TPMA_OBJECT, sensitiveDataOrigin))
15✔
UNCOV
377
                    if(IS_ATTRIBUTE(attributes, TPMA_OBJECT, fixedParent)
×
UNCOV
378
                       || IS_ATTRIBUTE(attributes, TPMA_OBJECT, fixedTPM))
×
379
                        result = TPM_RCS_ATTRIBUTES;
380
            break;
381
        default:  // Asymmetric keys cannot have the sensitive portion provided
890✔
382
            if(!IS_ATTRIBUTE(attributes, TPMA_OBJECT, sensitiveDataOrigin))
890✔
383
                result = TPM_RCS_ATTRIBUTES;
384
            break;
385
    }
386
    if(TPM_RC_SUCCESS == result)
97✔
387
    {
388
        result =
983✔
389
            PublicAttributesValidation(parentObject, primaryHierarchy, publicArea);
983✔
390
    }
391
    return result;
392
}
393

394
//*** SchemeChecks
395
// This function is called by TPM2_LoadExternal() and PublicAttributesValidation().
396
// This function validates the schemes in the public area of an object.
397
//  Return Type: TPM_RC
398
//      TPM_RC_HASH         non-duplicable storage key and its parent have different
399
//                          name algorithm
400
//      TPM_RC_KDF          incorrect KDF specified for decrypting keyed hash object
401
//      TPM_RC_KEY          invalid key size values in an asymmetric key public area
402
//      TPM_RCS_SCHEME       inconsistent attributes 'decrypt', 'sign', 'restricted'
403
//                          and key's scheme ID; or hash algorithm is inconsistent
404
//                          with the scheme ID for keyed hash object
405
//      TPM_RC_SYMMETRIC    a storage key with no symmetric algorithm specified; or
406
//                          non-storage key with symmetric algorithm different from
407
//                          TPM_ALG_NULL
408
TPM_RC
409
SchemeChecks(OBJECT*      parentObject,  // IN: parent (null if primary seed)
2,006✔
410
             TPMT_PUBLIC* publicArea     // IN: public area of the object
411
)
412
{
413
    TPMT_SYM_DEF_OBJECT* symAlgs    = NULL;
2,006✔
414
    TPM_ALG_ID           scheme     = TPM_ALG_NULL;
2,006✔
415
    TPMA_OBJECT          attributes = publicArea->objectAttributes;
2,006✔
416
    TPMU_PUBLIC_PARMS*   parms      = &publicArea->parameters;
2,006✔
417
    //
418
    switch(publicArea->type)
2,006✔
419
    {
420
        case TPM_ALG_SYMCIPHER:
47✔
421
            symAlgs = &parms->symDetail.sym;
47✔
422
            // If this is a decrypt key, then only the block cipher modes (not
423
            // SMAC) are valid. TPM_ALG_NULL is OK too. If this is a 'sign' key,
424
            // then any mode that got through the unmarshaling is OK.
425
            if(IS_ATTRIBUTE(attributes, TPMA_OBJECT, decrypt)
47✔
426
               && !CryptSymModeIsValid(symAlgs->mode.sym, TRUE))
47✔
427
                return TPM_RCS_SCHEME;
428
            break;
429
        case TPM_ALG_KEYEDHASH:
132✔
430
            scheme = parms->keyedHashDetail.scheme.scheme;
132✔
431
            // if both sign and decrypt
432
            if(IS_ATTRIBUTE(attributes, TPMA_OBJECT, sign)
132✔
433
               == IS_ATTRIBUTE(attributes, TPMA_OBJECT, decrypt))
132✔
434
            {
435
                // if both sign and decrypt are set or clear, then need
436
                // TPM_ALG_NULL as scheme
437
                if(scheme != TPM_ALG_NULL)
56✔
438
                    return TPM_RCS_SCHEME;
4✔
439
            }
440
            else if(
76✔
441
                IS_ATTRIBUTE(attributes, TPMA_OBJECT, sign) && scheme != TPM_ALG_HMAC)
64✔
442
                return TPM_RCS_SCHEME;
443
            else if(IS_ATTRIBUTE(attributes, TPMA_OBJECT, decrypt))
76✔
444
            {
445
                if(scheme != TPM_ALG_XOR)
12✔
446
                    return TPM_RCS_SCHEME;
447
                // If this is a derivation parent, then the KDF needs to be
448
                // SP800-108 for this implementation. This is the only derivation
449
                // supported by this implementation. Other implementations could
450
                // support additional schemes. There is no default.
451
                if(IS_ATTRIBUTE(attributes, TPMA_OBJECT, restricted))
8✔
452
                {
453
                    if(parms->keyedHashDetail.scheme.details.
8✔
454
                       xor_.kdf != TPM_ALG_KDF1_SP800_108)
8✔
455
                        return TPM_RCS_SCHEME;
456
                    // Must select a digest.
457
                    if(CryptHashGetDigestSize(
8✔
458
                           parms->keyedHashDetail.scheme.details.xor_.hashAlg)
8✔
459
                       == 0)
UNCOV
460
                        return TPM_RCS_HASH;
×
461
                }
462
            }
463
            break;
464
        default:  // handling for asymmetric
1,827✔
465
            scheme  = parms->asymDetail.scheme.scheme;
1,827✔
466
            symAlgs = &parms->asymDetail.symmetric;
1,827✔
467
            // if the key is both sign and decrypt, then the scheme must be
468
            // TPM_ALG_NULL because there is no way to specify both a sign and a
469
            // decrypt scheme in the key.
470
            if(IS_ATTRIBUTE(attributes, TPMA_OBJECT, sign)
1,827✔
471
               == IS_ATTRIBUTE(attributes, TPMA_OBJECT, decrypt))
1,827✔
472
            {
473
                // scheme must be TPM_ALG_NULL
474
                if(scheme != TPM_ALG_NULL)
226✔
475
                    return TPM_RCS_SCHEME;
476
            }
477
            else if(IS_ATTRIBUTE(attributes, TPMA_OBJECT, sign))
1,601✔
478
            {
479
                // If this is a signing key, see if it has a signing scheme
480
                if(CryptIsAsymSignScheme(publicArea->type, scheme))
841✔
481
                {
482
                    // if proper signing scheme then it needs a proper hash
483
                    if(parms->asymDetail.scheme.details.anySig.hashAlg
438✔
484
                       == TPM_ALG_NULL)
485
                        return TPM_RCS_SCHEME;
486
                }
487
                else
488
                {
489
                    // signing key that does not have a proper signing scheme.
490
                    // This is OK if the key is not restricted and its scheme
491
                    // is TPM_ALG_NULL
492
                    if(IS_ATTRIBUTE(attributes, TPMA_OBJECT, restricted)
403✔
493
                       || scheme != TPM_ALG_NULL)
395✔
494
                        return TPM_RCS_SCHEME;
495
                }
496
            }
497
            else if(IS_ATTRIBUTE(attributes, TPMA_OBJECT, decrypt))
760✔
498
            {
499
                if(IS_ATTRIBUTE(attributes, TPMA_OBJECT, restricted))
760✔
500
                {
501
                    // for a restricted decryption key (a parent), scheme
502
                    // is required to be TPM_ALG_NULL
503
                    if(scheme != TPM_ALG_NULL)
545✔
504
                        return TPM_RCS_SCHEME;
505
                }
506
                else
507
                {
508
                    // For an unrestricted decryption key, the scheme has to
509
                    // be a valid scheme or TPM_ALG_NULL
510
                    if(scheme != TPM_ALG_NULL
215✔
511
                       && !CryptIsAsymDecryptScheme(publicArea->type, scheme))
144✔
512
                        return TPM_RCS_SCHEME;
513
                }
514
            }
515
            if(!IS_ATTRIBUTE(attributes, TPMA_OBJECT, restricted)
1,775✔
516
               || !IS_ATTRIBUTE(attributes, TPMA_OBJECT, decrypt))
1,775✔
517
            {
518
                // For an asymmetric key that is not a parent, the symmetric
519
                // algorithms must be TPM_ALG_NULL
520
                if(symAlgs->algorithm != TPM_ALG_NULL)
1,242✔
521
                    return TPM_RCS_SYMMETRIC;
522
            }
523
            // Special checks for an ECC key
524
#if ALG_ECC
525
            if(publicArea->type == TPM_ALG_ECC)
1,771✔
526
            {
527
                TPM_ECC_CURVE          curveID;
620✔
528
                const TPMT_ECC_SCHEME* curveScheme;
620✔
529

530
                curveID     = publicArea->parameters.eccDetail.curveID;
620✔
531
                curveScheme = CryptGetCurveSignScheme(curveID);
620✔
532
                // The curveId must be valid or the unmarshaling is busted.
533
                pAssert_RC(curveScheme != NULL);
620✔
534

535
                // If the curveID requires a specific scheme, then the key must
536
                // select the same scheme
537
                if(curveScheme->scheme != TPM_ALG_NULL)
620✔
538
                {
UNCOV
539
                    TPMS_ECC_PARMS* ecc = &publicArea->parameters.eccDetail;
×
UNCOV
540
                    if(scheme != curveScheme->scheme)
×
541
                        return TPM_RCS_SCHEME;
542
                    // The scheme can allow any hash, or not...
UNCOV
543
                    if(curveScheme->details.anySig.hashAlg != TPM_ALG_NULL
×
UNCOV
544
                       && (ecc->scheme.details.anySig.hashAlg
×
545
                           != curveScheme->details.anySig.hashAlg))
546
                        return TPM_RCS_SCHEME;
547
                }
548
                // For now, the KDF must be TPM_ALG_NULL
549
                if(publicArea->parameters.eccDetail.kdf.scheme != TPM_ALG_NULL)
620✔
550
                    return TPM_RCS_KDF;
551
            }
552
#endif
553
            break;
554
    }
555
    // If this is a restricted decryption key with symmetric algorithms, then it
556
    // is an ordinary parent (not a derivation parent). It needs to specific
557
    // symmetric algorithms other than TPM_ALG_NULL
558
    if(symAlgs != NULL && IS_ATTRIBUTE(attributes, TPMA_OBJECT, restricted)
1,818✔
559
       && IS_ATTRIBUTE(attributes, TPMA_OBJECT, decrypt))
1,818✔
560
    {
561
        if(symAlgs->algorithm == TPM_ALG_NULL)
533✔
562
            return TPM_RCS_SYMMETRIC;
563
#if 0  //??
564
// This next check is under investigation. Need to see if it will break Windows
565
// before it is enabled. If it does not, then it should be default because a
566
// the mode used with a parent is always CFB and Part 2 indicates as much.
567
        if(symAlgs->mode.sym != TPM_ALG_CFB)
568
            return TPM_RCS_MODE;
569
#endif
570
        // If this parent is not duplicable, then the symmetric algorithms
571
        // (encryption and hash) must match those of its parent
572
        if(IS_ATTRIBUTE(attributes, TPMA_OBJECT, fixedParent)
533✔
573
           && (parentObject != NULL))
342✔
574
        {
575
            if(publicArea->nameAlg != parentObject->publicArea.nameAlg)
138✔
576
                return TPM_RCS_HASH;
577
            if(!MemoryEqual(symAlgs,
138✔
578
                            &parentObject->publicArea.parameters,
138✔
579
                            sizeof(TPMT_SYM_DEF_OBJECT)))
UNCOV
580
                return TPM_RCS_SYMMETRIC;
×
581
        }
582
    }
583
    return TPM_RC_SUCCESS;
584
}
585

586
//*** PublicAttributesValidation()
587
// This function validates the values in the public area of an object.
588
// This function is used in the processing of TPM2_Create, TPM2_CreatePrimary,
589
// TPM2_CreateLoaded(), TPM2_Load(),  TPM2_Import(), and TPM2_LoadExternal().
590
// For TPM2_Import() this is only used if the new parent has fixedTPM SET. For
591
// TPM2_LoadExternal(), this is not used for a public-only key
592
//  Return Type: TPM_RC
593
//      TPM_RC_ATTRIBUTES   'fixedTPM', 'fixedParent', or 'encryptedDuplication'
594
//                          attributes are inconsistent between themselves or with
595
//                          those of the parent object;
596
//                          inconsistent 'restricted', 'decrypt' and 'sign'
597
//                          attributes;
598
//                          attempt to inject sensitive data for an asymmetric key;
599
//                          attempt to create a symmetric cipher key that is not
600
//                          a decryption key
601
//      TPM_RC_HASH         nameAlg is TPM_ALG_NULL
602
//      TPM_RC_SIZE         'authPolicy' size does not match digest size of the name
603
//                          algorithm in 'publicArea'
604
//   other                  returns from SchemeChecks()
605
TPM_RC
606
PublicAttributesValidation(
1,863✔
607
    // IN: input parent object (if ordinary or derived object; NULL otherwise)
608
    OBJECT* parentObject,
609
    // IN: hierarchy (if primary object; 0 otherwise)
610
    TPMI_RH_HIERARCHY primaryHierarchy,
611
    // IN: public area of the object
612
    TPMT_PUBLIC* publicArea)
613
{
614
    TPMA_OBJECT attributes       = publicArea->objectAttributes;
1,863✔
615
    TPMA_OBJECT parentAttributes = TPMA_ZERO_INITIALIZER();
1,863✔
616

617
    if(parentObject != NULL)
1,863✔
618
        parentAttributes = parentObject->publicArea.objectAttributes;
697✔
619
    if(publicArea->nameAlg == TPM_ALG_NULL)
1,863✔
620
        return TPM_RCS_HASH;
621
    // If there is an authPolicy, it needs to be the size of the digest produced
622
    // by the nameAlg of the object
623
    if((publicArea->authPolicy.t.size != 0
1,863✔
624
        && (publicArea->authPolicy.t.size
371✔
625
            != CryptHashGetDigestSize(publicArea->nameAlg))))
371✔
626
        return TPM_RCS_SIZE;
627
    // If the parent is fixedTPM (including a Primary Object) the object must have
628
    // the same value for fixedTPM and fixedParent
629
    if(parentObject == NULL || IS_ATTRIBUTE(parentAttributes, TPMA_OBJECT, fixedTPM))
1,863✔
630
    {
631
        if(IS_ATTRIBUTE(attributes, TPMA_OBJECT, fixedParent)
1,861✔
632
           != IS_ATTRIBUTE(attributes, TPMA_OBJECT, fixedTPM))
1,861✔
633
            return TPM_RCS_ATTRIBUTES;
634
    }
635
    else
636
    {
637
        // The parent is not fixedTPM so the object can't be fixedTPM
638
        if(IS_ATTRIBUTE(attributes, TPMA_OBJECT, fixedTPM))
2✔
639
            return TPM_RCS_ATTRIBUTES;
640
    }
641
    // See if sign and decrypt are the same
642
    if(IS_ATTRIBUTE(attributes, TPMA_OBJECT, sign)
1,859✔
643
       == IS_ATTRIBUTE(attributes, TPMA_OBJECT, decrypt))
1,859✔
644
    {
645
        // a restricted key cannot have both SET or both CLEAR
646
        if(IS_ATTRIBUTE(attributes, TPMA_OBJECT, restricted))
281✔
647
            return TPM_RC_ATTRIBUTES;
648
        // only a data object may have both sign and decrypt CLEAR
649
        // BTW, since we know that decrypt==sign, no need to check both
650
        if(publicArea->type != TPM_ALG_KEYEDHASH
277✔
651
           && !IS_ATTRIBUTE(attributes, TPMA_OBJECT, sign))
221✔
652
            return TPM_RC_ATTRIBUTES;
653
    }
654
    // If the object can't be duplicated (directly or indirectly) then there
655
    // is no justification for having encryptedDuplication SET
656
    if(IS_ATTRIBUTE(attributes, TPMA_OBJECT, fixedTPM)
1,855✔
657
       && IS_ATTRIBUTE(attributes, TPMA_OBJECT, encryptedDuplication))
1,855✔
658
        return TPM_RCS_ATTRIBUTES;
659
    // If a parent object has fixedTPM CLEAR, the child must have the
660
    // same encryptedDuplication value as its parent.
661
    // Primary objects are considered to have a fixedTPM parent (the seeds).
662
    if(parentObject != NULL && !IS_ATTRIBUTE(parentAttributes, TPMA_OBJECT, fixedTPM))
1,850✔
663
    {
664
        if(IS_ATTRIBUTE(attributes, TPMA_OBJECT, encryptedDuplication)
2✔
665
           != IS_ATTRIBUTE(parentAttributes, TPMA_OBJECT, encryptedDuplication))
2✔
666
            return TPM_RCS_ATTRIBUTES;
667
    }
668
    // firmwareLimited/svnLimited can only be set if fixedTPM is also set.
669
    if((IS_ATTRIBUTE(attributes, TPMA_OBJECT, firmwareLimited)
1,850✔
670
        || IS_ATTRIBUTE(attributes, TPMA_OBJECT, svnLimited))
1,850✔
UNCOV
671
       && !IS_ATTRIBUTE(attributes, TPMA_OBJECT, fixedTPM))
×
672
    {
673
        return TPM_RCS_ATTRIBUTES;
674
    }
675

676
    // firmwareLimited/svnLimited also impose requirements on the parent key or
677
    // primary handle.
678
    if(IS_ATTRIBUTE(attributes, TPMA_OBJECT, firmwareLimited))
1,850✔
679
    {
680
#if FW_LIMITED_SUPPORT                        // libtpms added
681
        if(parentObject != NULL)
682
        {
683
            // For an ordinary object, firmwareLimited can only be set if its
684
            // parent is also firmwareLimited.
685
            if(!IS_ATTRIBUTE(parentAttributes, TPMA_OBJECT, firmwareLimited))
686
                return TPM_RCS_ATTRIBUTES;
687
        }
688
        else if(primaryHierarchy != 0)
689
        {
690
            // For a primary object, firmwareLimited can only be set if its
691
            // hierarchy is a firmware-limited hierarchy.
692
            if(!HierarchyIsFirmwareLimited(primaryHierarchy))
693
                return TPM_RCS_ATTRIBUTES;
694
        }
695
        else
696
        {
697
            return TPM_RCS_ATTRIBUTES;
698
        }
699
#else                                // libtpms added begin
700
            (void)primaryHierarchy;
701
        return TPM_RCS_ATTRIBUTES;
702
#endif                                // libtpms added end
703
    }
704
    if(IS_ATTRIBUTE(attributes, TPMA_OBJECT, svnLimited))
1,850✔
705
    {
706
#if SVN_LIMITED_SUPPORT                        // libtpms added
707
        if(parentObject != NULL)
708
        {
709
            // For an ordinary object, svnLimited can only be set if its
710
            // parent is also svnLimited.
711
            if(!IS_ATTRIBUTE(parentAttributes, TPMA_OBJECT, svnLimited))
712
                return TPM_RCS_ATTRIBUTES;
713
        }
714
        else if(primaryHierarchy != 0)
715
        {
716
            // For a primary object, svnLimited can only be set if its
717
            // hierarchy is an svn-limited hierarchy.
718
            if(!HierarchyIsSvnLimited(primaryHierarchy))
719
                return TPM_RCS_ATTRIBUTES;
720
        }
721
        else
722
        {
723
            return TPM_RCS_ATTRIBUTES;
724
        }
725
#else                                // libtpms added begin
726
            (void)primaryHierarchy;
727
        return TPM_RCS_ATTRIBUTES;
728
#endif                                // libtpms added end
729
    }
730

731
    // Special checks for derived objects
732
    if((parentObject != NULL) && (parentObject->attributes.derivation == SET))
1,850✔
733
    {
734
        // A derived object has the same settings for fixedTPM as its parent
735
        if(IS_ATTRIBUTE(attributes, TPMA_OBJECT, fixedTPM)
13✔
736
           != IS_ATTRIBUTE(parentAttributes, TPMA_OBJECT, fixedTPM))
13✔
737
            return TPM_RCS_ATTRIBUTES;
738
        // A derived object is required to be fixedParent
739
        if(!IS_ATTRIBUTE(attributes, TPMA_OBJECT, fixedParent))
13✔
740
            return TPM_RCS_ATTRIBUTES;
741
    }
742
    return SchemeChecks(parentObject, publicArea);
1,850✔
743
}
744

745
//*** FillInCreationData()
746
// Fill in creation data for an object.
747
//  Return Type: void
748
TPM_RC FillInCreationData(
901✔
749
    TPMI_DH_OBJECT       parentHandle,   // IN: handle of parent
750
    TPMI_ALG_HASH        nameHashAlg,    // IN: name hash algorithm
751
    TPML_PCR_SELECTION*  creationPCR,    // IN: PCR selection
752
    TPM2B_DATA*          outsideData,    // IN: outside data
753
    TPM2B_CREATION_DATA* outCreation,    // OUT: creation data for output
754
    TPM2B_DIGEST*        creationDigest  // OUT: creation digest
755
)
756
{
757
    BYTE       creationBuffer[sizeof(TPMS_CREATION_DATA)];
901✔
758
    BYTE*      buffer;
901✔
759
    HASH_STATE hashState;
901✔
760
    //
761
    // Fill in TPMS_CREATION_DATA in outCreation
762

763
    // Compute PCR digest
764
    TPM_RC result = PCRComputeCurrentDigest(
901✔
765
        nameHashAlg, creationPCR, &outCreation->creationData.pcrDigest);
766
    if(result != TPM_RC_SUCCESS)
901✔
767
        return result;
768

769
    // Put back PCR selection list
770
    outCreation->creationData.pcrSelect = *creationPCR;
901✔
771

772
    // Get locality
773
    outCreation->creationData.locality = LocalityGetAttributes(_plat__LocalityGet());
901✔
774
    outCreation->creationData.parentNameAlg = TPM_ALG_NULL;
901✔
775

776
    // If the parent is either a primary seed or TPM_ALG_NULL, then  the Name
777
    // and QN of the parent are the parent's handle.
778
    if(HandleGetType(parentHandle) == TPM_HT_PERMANENT)
901✔
779
    {
780
        buffer = &outCreation->creationData.parentName.t.name[0];
623✔
781
        outCreation->creationData.parentName.t.size =
1,246✔
782
            TPM_HANDLE_Marshal(&parentHandle, &buffer, NULL);
623✔
783
        // For a primary or temporary object, the parent name (a handle) and the
784
        // parent's QN are the same
785
        outCreation->creationData.parentQualifiedName =
623✔
786
            outCreation->creationData.parentName;
787
    }
788
    else  // Regular object
789
    {
790
        OBJECT* parentObject = HandleToObject(parentHandle);
278✔
791
        //
792
        // Set name algorithm
793
        outCreation->creationData.parentNameAlg = parentObject->publicArea.nameAlg;
278✔
794

795
        // Copy parent name
796
        outCreation->creationData.parentName = parentObject->name;
278✔
797

798
        // Copy parent qualified name
799
        outCreation->creationData.parentQualifiedName = parentObject->qualifiedName;
278✔
800
    }
801
    // Copy outside information
802
    outCreation->creationData.outsideInfo = *outsideData;
901✔
803

804
    // Marshal creation data to canonical form
805
    buffer = creationBuffer;
901✔
806
    outCreation->size =
1,802✔
807
        TPMS_CREATION_DATA_Marshal(&outCreation->creationData, &buffer, NULL);
901✔
808
    // Compute hash for creation field in public template
809
    creationDigest->t.size = CryptHashStart(&hashState, nameHashAlg);
901✔
810
    CryptDigestUpdate(&hashState, outCreation->size, creationBuffer);
901✔
811
    CryptHashEnd2B(&hashState, &creationDigest->b);
901✔
812

813
    return TPM_RC_SUCCESS;
901✔
814
}
815

816
//*** GetSeedForKDF()
817
// Get a seed for KDF.  The KDF for encryption and HMAC key use the same seed.
818
const TPM2B* GetSeedForKDF(OBJECT* protector  // IN: the protector handle
1,563✔
819
)
820
{
821
    // Get seed for encryption key.  Use input seed if provided.
822
    // Otherwise, using protector object's seedValue.  TPM_RH_NULL is the only
823
    // exception that we may not have a loaded object as protector.  In such a
824
    // case, use nullProof as seed.
825
    if(protector == NULL)
1,563✔
826
        return &gr.nullProof.b;
827
    else
828
        return &protector->sensitive.seedValue.b;
1,563✔
829
}
830

831
//*** ProduceOuterWrap()
832
// This function produce outer wrap for a buffer containing the sensitive data.
833
// It requires the sensitive data being marshaled to the outerBuffer, with the
834
// leading bytes reserved for integrity hash.  If iv is used, iv space should
835
// be reserved at the beginning of the buffer.  It assumes the sensitive data
836
// starts at address (outerBuffer + integrity size [+ iv size]).
837
// This function performs:
838
//  1. Add IV before sensitive area if required
839
//  2. encrypt sensitive data, if iv is required, encrypt by iv.  otherwise,
840
//     encrypted by a NULL iv
841
//  3. add HMAC integrity at the beginning of the buffer
842
// It returns the total size of blob with outer wrap
843
UINT16
844
ProduceOuterWrap(OBJECT* protector,   // IN: The handle of the object that provides
411✔
845
                                      //     protection.  For object, it is parent
846
                                      //     handle. For credential, it is the handle
847
                                      //     of encrypt object.
848
                 TPM2B*     name,     // IN: the name of the object
849
                 TPM_ALG_ID hashAlg,  // IN: hash algorithm for outer wrap
850
                 TPM2B*     seed,     // IN: an external seed may be provided for
851
                                      //     duplication blob. For non duplication
852
                                      //     blob, this parameter should be NULL
853
                 BOOL   useIV,        // IN: indicate if an IV is used
854
                 UINT16 dataSize,     // IN: the size of sensitive data, excluding the
855
                                      //     leading integrity buffer size or the
856
                                      //     optional iv size
857
                 BYTE* outerBuffer    // IN/OUT: outer buffer with sensitive data in
858
                                      //     it
859
)
860
{
861
    TPM_ALG_ID    symAlg;
411✔
862
    UINT16        keyBits;
411✔
863
    TPM2B_SYM_KEY symKey;
411✔
864
    TPM2B_IV      ivRNG;  // IV from RNG
411✔
865
    TPM2B_IV*     iv     = NULL;
411✔
866
    UINT16        ivSize = 0;     // size of iv area, including the size field
411✔
867
    BYTE*         sensitiveData;  // pointer to the sensitive data
411✔
868
    TPM2B_DIGEST  integrity;
411✔
869
    UINT16        integritySize;
411✔
870
    BYTE*         buffer;  // Auxiliary buffer pointer
411✔
871
                           //
872
    // Compute the beginning of sensitive data.  The outer integrity should
873
    // always exist if this function is called to make an outer wrap
874
    integritySize = sizeof(UINT16) + CryptHashGetDigestSize(hashAlg);
411✔
875
    sensitiveData = outerBuffer + integritySize;
411✔
876

877
    // If iv is used, adjust the pointer of sensitive data and add iv before it
878
    if(useIV)
411✔
879
    {
880
        ivSize = GetIV2BSize(protector);
376✔
881

882
        // Generate IV from RNG.  The iv data size should be the total IV area
883
        // size minus the size of size field
884
        ivRNG.t.size = ivSize - sizeof(UINT16);
376✔
885
        CryptRandomGenerate(ivRNG.t.size, ivRNG.t.buffer);
376✔
886

887
        // Marshal IV to buffer
888
        buffer = sensitiveData;
376✔
889
        TPM2B_IV_Marshal(&ivRNG, &buffer, NULL);
376✔
890

891
        // adjust sensitive data starting after IV area
892
        sensitiveData += ivSize;
376✔
893

894
        // Use iv for encryption
895
        iv = &ivRNG;
376✔
896
    }
897
    // Compute symmetric key parameters for outer buffer encryption
898
    ComputeProtectionKeyParms(
411✔
899
        protector, hashAlg, name, seed, &symAlg, &keyBits, &symKey);
900
    // Encrypt inner buffer in place
901
    CryptSymmetricEncrypt(sensitiveData,
411✔
902
                          symAlg,
903
                          keyBits,
904
                          symKey.t.buffer,
905
                          iv,
906
                          TPM_ALG_CFB,
907
                          dataSize,
908
                          sensitiveData);
909
    // Compute outer integrity.  Integrity computation includes the optional IV
910
    // area
911
    ComputeOuterIntegrity(name,
411✔
912
                          protector,
913
                          hashAlg,
914
                          seed,
915
                          dataSize + ivSize,
411✔
916
                          outerBuffer + integritySize,
917
                          &integrity);
918
    // Add integrity at the beginning of outer buffer
919
    buffer = outerBuffer;
411✔
920
    TPM2B_DIGEST_Marshal(&integrity, &buffer, NULL);
411✔
921

922
    // return the total size in outer wrap
923
    return dataSize + integritySize + ivSize;
411✔
924
}
925

926
//*** UnwrapOuter()
927
// This function remove the outer wrap of a blob containing sensitive data
928
// This function performs:
929
//  1. check integrity of outer blob
930
//  2. decrypt outer blob
931
//
932
//  Return Type: TPM_RC
933
//      TPM_RCS_INSUFFICIENT     error during sensitive data unmarshaling
934
//      TPM_RCS_INTEGRITY        sensitive data integrity is broken
935
//      TPM_RCS_SIZE             error during sensitive data unmarshaling
936
//      TPM_RCS_VALUE            IV size for CFB does not match the encryption
937
//                               algorithm block size
938
TPM_RC
939
UnwrapOuter(OBJECT* protector,   // IN: The object that provides
442✔
940
                                 //     protection.  For object, it is parent
941
                                 //     handle. For credential, it is the
942
                                 //     encrypt object.
943
            TPM2B*     name,     // IN: the name of the object
944
            TPM_ALG_ID hashAlg,  // IN: hash algorithm for outer wrap
945
            TPM2B*     seed,     // IN: an external seed may be provided for
946
                                 //     duplication blob. For non duplication
947
                                 //     blob, this parameter should be NULL.
948
            BOOL   useIV,        // IN: indicates if an IV is used
949
            UINT16 dataSize,     // IN: size of sensitive data in outerBuffer,
950
                                 //     including the leading integrity buffer
951
                                 //     size, and an optional iv area
952
            BYTE* outerBuffer    // IN/OUT: sensitive data
953
)
954
{
955
    TPM_RC        result;
442✔
956
    TPM_ALG_ID    symAlg = TPM_ALG_NULL;
442✔
957
    TPM2B_SYM_KEY symKey;
442✔
958
    UINT16        keyBits = 0;
442✔
959
    TPM2B_IV      ivIn;  // input IV retrieved from input buffer
442✔
960
    TPM2B_IV*     iv = NULL;
442✔
961
    BYTE*         sensitiveData;  // pointer to the sensitive data
442✔
962
    TPM2B_DIGEST  integrityToCompare;
442✔
963
    TPM2B_DIGEST  integrity;
442✔
964
    INT32         size;
442✔
965
    //
966
    // Unmarshal integrity
967
    sensitiveData = outerBuffer;
442✔
968
    size          = (INT32)dataSize;
442✔
969
    result        = TPM2B_DIGEST_Unmarshal(&integrity, &sensitiveData, &size);
442✔
970
    if(result == TPM_RC_SUCCESS)
442✔
971
    {
972
        // Compute integrity to compare
973
        ComputeOuterIntegrity(name,
442✔
974
                              protector,
975
                              hashAlg,
976
                              seed,
977
                              (UINT16)size,
442✔
978
                              sensitiveData,
979
                              &integrityToCompare);
980
        // Compare outer blob integrity
981
        if(!MemoryEqual2B(&integrity.b, &integrityToCompare.b))
442✔
982
            return TPM_RCS_INTEGRITY;
983
        // Get the symmetric algorithm parameters used for encryption
984
        ComputeProtectionKeyParms(
439✔
985
            protector, hashAlg, name, seed, &symAlg, &keyBits, &symKey);
986
        // Retrieve IV if it is used
987
        if(useIV)
439✔
988
        {
989
            result = TPM2B_IV_Unmarshal(&ivIn, &sensitiveData, &size);
404✔
990
            if(result == TPM_RC_SUCCESS)
404✔
991
            {
992
                // The input iv size for CFB must match the encryption algorithm
993
                // block size
994
                if(ivIn.t.size != CryptGetSymmetricBlockSize(symAlg, keyBits))
404✔
995
                    result = TPM_RC_VALUE;
996
                else
997
                    iv = &ivIn;
998
            }
999
        }
1000
    }
1001
    // If no errors, decrypt private in place. Since this function uses CFB,
1002
    // CryptSymmetricDecrypt() will not return any errors. It may fail but it will
1003
    // not return an error.
1004
    if(result == TPM_RC_SUCCESS)
439✔
1005
        CryptSymmetricDecrypt(sensitiveData,
439✔
1006
                              symAlg,
1007
                              keyBits,
1008
                              symKey.t.buffer,
1009
                              iv,
1010
                              TPM_ALG_CFB,
1011
                              (UINT16)size,
439✔
1012
                              sensitiveData);
1013
    return result;
1014
}
1015

1016
//*** MarshalSensitive()
1017
// This function is used to marshal a sensitive area. Among other things, it
1018
// adjusts the size of the authValue to be no smaller than the digest of
1019
// 'nameAlg'
1020
// Returns the size of the marshaled area.  0 indicates an error
1021
static UINT16 MarshalSensitive(
409✔
1022
    OBJECT*         parent LIBTPMS_ATTR_UNUSED,     // IN: the object parent (optional)
1023
    BYTE*           buffer,     // OUT: receiving buffer
1024
    TPMT_SENSITIVE* sensitive,  // IN: the sensitive area to marshal
1025
    TPMI_ALG_HASH   nameAlg     // IN:
1026
)
1027
{
1028
    BYTE* sizeField = buffer;  // saved so that size can be
409✔
1029
                               // marshaled after it is known
1030
    UINT16 retVal;
409✔
1031
    //
1032
    // Pad the authValue if needed
1033
    MemoryPad2B(&sensitive->authValue.b, CryptHashGetDigestSize(nameAlg));
409✔
1034
    buffer += 2;
409✔
1035

1036
#if !ALG_RSA
1037
    NOT_REFERENCED(parent);
1038
#endif
1039

1040
    // Marshal the structure
1041
#if 0 /* ALG_RSA */            // libtpms changed: We never set the RSA_prime_flag!
1042
    // If the sensitive size is the special case for a prime in the type
1043
    if((sensitive->sensitive.rsa.t.size & RSA_prime_flag) > 0)
1044
    {
1045
        pAssert_ZERO(sensitive->sensitiveType == ALG_RSA_VALUE);
1046
        UINT16 sizeSave = sensitive->sensitive.rsa.t.size;
1047
        //
1048
        // Turn off the flag that indicates that the sensitive->sensitive contains
1049
        // the CRT form of the exponent.
1050
        sensitive->sensitive.rsa.t.size &= ~(RSA_prime_flag);
1051
        // If the parent isn't fixedTPM, then truncate the sensitive data to be
1052
        // the size of the prime. Otherwise, leave it at the current size which
1053
        // is the full CRT size.
1054
        if(parent == NULL
1055
           || !IS_ATTRIBUTE(
1056
               parent->publicArea.objectAttributes, TPMA_OBJECT, fixedTPM))
1057
            sensitive->sensitive.rsa.t.size /= 5;
1058
        retVal = TPMT_SENSITIVE_Marshal(sensitive, &buffer, NULL);
1059
        // Restore the flag and the size.
1060
        sensitive->sensitive.rsa.t.size = sizeSave;
1061
    }
1062
    else
1063
#endif
1064
    {
1065
        retVal = TPMT_SENSITIVE_Marshal(sensitive, &buffer, NULL);
409✔
1066
    }
1067

1068
    // Marshal the size
1069
    retVal = (UINT16)(retVal + UINT16_Marshal(&retVal, &sizeField, NULL));
409✔
1070

1071
    return retVal;
409✔
1072
}
1073

1074
//*** SensitiveToPrivate()
1075
// This function prepare the private blob for off the chip storage
1076
// The operations in this function:
1077
//  1. marshal TPM2B_SENSITIVE structure into the buffer of TPM2B_PRIVATE
1078
//  2. apply encryption to the sensitive area.
1079
//  3. apply outer integrity computation.
1080
TPM_RC SensitiveToPrivate(
376✔
1081
    TPMT_SENSITIVE* sensitive,  // IN: sensitive structure
1082
    TPM2B_NAME*     name,       // IN: the name of the object
1083
    OBJECT*         parent,     // IN: The parent object
1084
    TPM_ALG_ID      nameAlg,    // IN: hash algorithm in public area.  This
1085
                                //     parameter is used when parentHandle is
1086
                                //     NULL, in which case the object is
1087
                                //     temporary.
1088
    TPM2B_PRIVATE* outPrivate   // OUT: output private structure
1089
)
1090
{
1091
    BYTE*         sensitiveData;  // pointer to the sensitive data
376✔
1092
    UINT16        dataSize;       // data blob size
376✔
1093
    TPMI_ALG_HASH hashAlg;        // hash algorithm for integrity
376✔
1094
    UINT16        integritySize;
376✔
1095
    UINT16        ivSize;
376✔
1096
    //
1097
    pAssert_RC(name != NULL && name->t.size != 0);
376✔
1098

1099
    // Find the hash algorithm for integrity computation
1100
    if(parent == NULL)
376✔
1101
    {
1102
        // For Temporary Object, using self name algorithm
1103
        hashAlg = nameAlg;
1104
    }
1105
    else
1106
    {
1107
        // Otherwise, using parent's name algorithm
1108
        hashAlg = parent->publicArea.nameAlg;
376✔
1109
    }
1110
    // Starting of sensitive data without wrappers
1111
    sensitiveData = outPrivate->t.buffer;
376✔
1112

1113
    // Compute the integrity size
1114
    integritySize = sizeof(UINT16) + CryptHashGetDigestSize(hashAlg);
376✔
1115

1116
    // Reserve space for integrity
1117
    sensitiveData += integritySize;
376✔
1118

1119
    // Get iv size
1120
    ivSize = GetIV2BSize(parent);
376✔
1121

1122
    // Reserve space for iv
1123
    sensitiveData += ivSize;
376✔
1124

1125
    // Marshal the sensitive area including authValue size adjustments.
1126
    dataSize = MarshalSensitive(parent, sensitiveData, sensitive, nameAlg);
376✔
1127
    pAssert_RC(dataSize != 0);  // 0 indicates a failure mode assertion
376✔
1128

1129
    //Produce outer wrap, including encryption and HMAC
1130
    outPrivate->t.size = ProduceOuterWrap(
376✔
1131
        parent, &name->b, hashAlg, NULL, TRUE, dataSize, outPrivate->t.buffer);
1132

1133
    return TPM_RC_SUCCESS;
376✔
1134
}
1135

1136
//*** PrivateToSensitive()
1137
// Unwrap an input private area; check the integrity; decrypt and retrieve data
1138
// to a sensitive structure.
1139
// The operations in this function:
1140
//  1. check the integrity HMAC of the input private area
1141
//  2. decrypt the private buffer
1142
//  3. unmarshal TPMT_SENSITIVE structure into the buffer of TPMT_SENSITIVE
1143
//
1144
//  Return Type: TPM_RC
1145
//      TPM_RCS_INTEGRITY       if the private area integrity is bad
1146
//      TPM_RC_SENSITIVE        unmarshal errors while unmarshaling TPMS_ENCRYPT
1147
//                              from input private
1148
//      TPM_RCS_SIZE            error during sensitive data unmarshaling
1149
//      TPM_RCS_VALUE           outer wrapper does not have an iV of the correct
1150
//                              size
1151
TPM_RC
1152
PrivateToSensitive(TPM2B*     inPrivate,  // IN: input private structure
407✔
1153
                   TPM2B*     name,       // IN: the name of the object
1154
                   OBJECT*    parent,     // IN: parent object
1155
                   TPM_ALG_ID nameAlg,    // IN: hash algorithm in public area.  It is
1156
                   //     passed separately because we only pass
1157
                   //     name, rather than the whole public area
1158
                   //     of the object.  This parameter is used in
1159
                   //     the following two cases: 1. primary
1160
                   //     objects. 2. duplication blob with inner
1161
                   //     wrap.  In other cases, this parameter
1162
                   //     will be ignored
1163
                   TPMT_SENSITIVE* sensitive  // OUT: sensitive structure
1164
)
1165
{
1166
    TPM_RC        result;
407✔
1167
    BYTE*         buffer;
407✔
1168
    INT32         size;
407✔
1169
    BYTE*         sensitiveData;  // pointer to the sensitive data
407✔
1170
    UINT16        dataSize;
407✔
1171
    UINT16        dataSizeInput;
407✔
1172
    TPMI_ALG_HASH hashAlg;  // hash algorithm for integrity
407✔
1173
    UINT16        integritySize;
407✔
1174
    UINT16        ivSize;
407✔
1175
    //
1176
    // Make sure that name is provided
1177
    pAssert_RC(name != NULL && name->size != 0);
407✔
1178

1179
    // Find the hash algorithm for integrity computation
1180
    // For Temporary Object (parent == NULL) use self name algorithm;
1181
    // Otherwise, using parent's name algorithm
1182
    hashAlg = (parent == NULL) ? nameAlg : parent->publicArea.nameAlg;
407✔
1183

1184
    // unwrap outer
1185
    result = UnwrapOuter(
814✔
1186
        parent, name, hashAlg, NULL, TRUE, inPrivate->size, inPrivate->buffer);
407✔
1187
    if(result != TPM_RC_SUCCESS)
407✔
1188
        return result;
1189
    // Compute the inner integrity size.
1190
    integritySize = sizeof(UINT16) + CryptHashGetDigestSize(hashAlg);
404✔
1191

1192
    // Get iv size
1193
    ivSize = GetIV2BSize(parent);
404✔
1194

1195
    // The starting of sensitive data and data size without outer wrapper
1196
    sensitiveData = inPrivate->buffer + integritySize + ivSize;
404✔
1197
    dataSize      = inPrivate->size - integritySize - ivSize;
404✔
1198

1199
    // Unmarshal input data size
1200
    buffer = sensitiveData;
404✔
1201
    size   = (INT32)dataSize;
404✔
1202
    result = UINT16_Unmarshal(&dataSizeInput, &buffer, &size);
404✔
1203
    if(result == TPM_RC_SUCCESS)
404✔
1204
    {
1205
        if((dataSizeInput + sizeof(UINT16)) != dataSize)
404✔
1206
            result = TPM_RC_SENSITIVE;
1207
        else
1208
        {
1209
            // Unmarshal sensitive buffer to sensitive structure
1210
            result = TPMT_SENSITIVE_Unmarshal(sensitive, &buffer, &size);
404✔
1211
            if(result != TPM_RC_SUCCESS || size != 0)
404✔
1212
            {
UNCOV
1213
                result = TPM_RC_SENSITIVE;
×
1214
            }
1215
        }
1216
    }
1217
    return result;
1218
}
1219

1220
//*** SensitiveToDuplicate()
1221
// This function prepare the duplication blob from the sensitive area.
1222
// The operations in this function:
1223
//  1. marshal TPMT_SENSITIVE structure into the buffer of TPM2B_PRIVATE
1224
//  2. apply inner wrap to the sensitive area if required
1225
//  3. apply outer wrap if required
1226
TPM_RC SensitiveToDuplicate(
33✔
1227
    TPMT_SENSITIVE* sensitive,    // IN: sensitive structure
1228
    TPM2B*          name,         // IN: the name of the object
1229
    OBJECT*         parent,       // IN: The new parent object
1230
    TPM_ALG_ID      nameAlg,      // IN: hash algorithm in public area. It
1231
                                  //     is passed separately because we
1232
                                  //     only pass name, rather than the
1233
                                  //     whole public area of the object.
1234
    TPM2B* seed,                  // IN: the external seed. If external
1235
                                  //     seed is provided with size of 0,
1236
                                  //     no outer wrap should be applied
1237
                                  //     to duplication blob.
1238
    TPMT_SYM_DEF_OBJECT* symDef,  // IN: Symmetric key definition. If the
1239
                                  //     symmetric key algorithm is NULL,
1240
                                  //     no inner wrap should be applied.
1241
    TPM2B_DATA* innerSymKey,      // IN/OUT: a symmetric key may be
1242
                                  //     provided to encrypt the inner
1243
                                  //     wrap of a duplication blob. May
1244
                                  //     be generated here if needed.
1245
    TPM2B_PRIVATE* outPrivate     // OUT: output private structure
1246
)
1247
{
1248
    BYTE*         sensitiveData;             // pointer to the sensitive data
33✔
1249
    TPMI_ALG_HASH outerHash = TPM_ALG_NULL;  // The hash algorithm for outer wrap
33✔
1250
    TPMI_ALG_HASH innerHash = TPM_ALG_NULL;  // The hash algorithm for inner wrap
33✔
1251
    UINT16        dataSize;                  // data blob size
33✔
1252
    BOOL          doInnerWrap = FALSE;
33✔
1253
    BOOL          doOuterWrap = FALSE;
33✔
1254
    //
1255
    // Make sure that name is provided
1256
    pAssert_RC(name != NULL && name->size != 0);
33✔
1257

1258
    // Make sure symDef and innerSymKey are not NULL
1259
    pAssert_RC(symDef != NULL && innerSymKey != NULL);
33✔
1260

1261
    // Starting of sensitive data without wrappers
1262
    sensitiveData = outPrivate->t.buffer;
33✔
1263

1264
    // Find out if inner wrap is required
1265
    if(symDef->algorithm != TPM_ALG_NULL)
33✔
1266
    {
1267
        doInnerWrap = TRUE;
13✔
1268

1269
        // Use self nameAlg as inner hash algorithm
1270
        innerHash = nameAlg;
13✔
1271

1272
        // Adjust sensitive data pointer
1273
        sensitiveData += sizeof(UINT16) + CryptHashGetDigestSize(innerHash);
13✔
1274
    }
1275
    // Find out if outer wrap is required
1276
    if(seed->size != 0)
33✔
1277
    {
1278
        doOuterWrap = TRUE;
33✔
1279

1280
        // Use parent nameAlg as outer hash algorithm
1281
        outerHash = parent->publicArea.nameAlg;
33✔
1282

1283
        // Adjust sensitive data pointer
1284
        sensitiveData += sizeof(UINT16) + CryptHashGetDigestSize(outerHash);
33✔
1285
    }
1286
    // Marshal sensitive area
1287
    dataSize = MarshalSensitive(NULL, sensitiveData, sensitive, nameAlg);
33✔
1288
    pAssert_RC(dataSize != 0);  // 0 indicates a failure mode assertion
33✔
1289

1290
    // Apply inner wrap for duplication blob.  It includes both integrity and
1291
    // encryption
1292
    if(doInnerWrap)
33✔
1293
    {
1294
        BYTE* innerBuffer = NULL;
13✔
1295
        BOOL  symKeyInput = TRUE;
13✔
1296
        innerBuffer       = outPrivate->t.buffer;
13✔
1297
        // Skip outer integrity space
1298
        if(doOuterWrap)
13✔
1299
            innerBuffer += sizeof(UINT16) + CryptHashGetDigestSize(outerHash);
13✔
1300
        dataSize = ProduceInnerIntegrity(name, innerHash, dataSize, innerBuffer);
13✔
1301
        // Generate inner encryption key if needed
1302
        if(innerSymKey->t.size == 0)
13✔
1303
        {
UNCOV
1304
            innerSymKey->t.size = (symDef->keyBits.sym + 7) / 8;
×
UNCOV
1305
            CryptRandomGenerate(innerSymKey->t.size, innerSymKey->t.buffer);
×
1306

1307
            // TPM generates symmetric encryption.  Set the flag to FALSE
UNCOV
1308
            symKeyInput = FALSE;
×
1309
        }
1310
        else
1311
        {
1312
            // assume the input key size should matches the symmetric definition
1313
            pAssert_RC(innerSymKey->t.size == (symDef->keyBits.sym + 7) / 8);
13✔
1314
        }
1315

1316
        // Encrypt inner buffer in place
1317
        VERIFY_RC(CryptSymmetricEncrypt(innerBuffer,
13✔
1318
                                        symDef->algorithm,
1319
                                        symDef->keyBits.sym,
1320
                                        innerSymKey->t.buffer,
1321
                                        NULL,
1322
                                        TPM_ALG_CFB,
1323
                                        dataSize,
1324
                                        innerBuffer));
1325

1326
        // If the symmetric encryption key is imported, clear the buffer for
1327
        // output
1328
        if(symKeyInput)
13✔
1329
            innerSymKey->t.size = 0;
13✔
1330
    }
1331
    // Apply outer wrap for duplication blob.  It includes both integrity and
1332
    // encryption
1333
    if(doOuterWrap)
33✔
1334
    {
1335
        dataSize = ProduceOuterWrap(
33✔
1336
            parent, name, outerHash, seed, FALSE, dataSize, outPrivate->t.buffer);
1337
    }
1338
    // Data size for output
1339
    outPrivate->t.size = dataSize;
33✔
1340

1341
    return TPM_RC_SUCCESS;
33✔
1342
}
1343

1344
//*** DuplicateToSensitive()
1345
// Unwrap a duplication blob.  Check the integrity, decrypt and retrieve data
1346
// to a sensitive structure.
1347
// The operations in this function:
1348
//  1. check the integrity HMAC of the input private area
1349
//  2. decrypt the private buffer
1350
//  3. unmarshal TPMT_SENSITIVE structure into the buffer of TPMT_SENSITIVE
1351
//
1352
//  Return Type: TPM_RC
1353
//      TPM_RC_INSUFFICIENT      unmarshaling sensitive data from 'inPrivate' failed
1354
//      TPM_RC_INTEGRITY         'inPrivate' data integrity is broken
1355
//      TPM_RC_SIZE              unmarshaling sensitive data from 'inPrivate' failed
1356
TPM_RC
1357
DuplicateToSensitive(
91✔
1358
    TPM2B*     inPrivate,         // IN: input private structure
1359
    TPM2B*     name,              // IN: the name of the object
1360
    OBJECT*    parent,            // IN: the parent
1361
    TPM_ALG_ID nameAlg,           // IN: hash algorithm in public area.
1362
    TPM2B*     seed,              // IN: an external seed may be provided.
1363
                                  //     If external seed is provided with
1364
                                  //     size of 0, no outer wrap is
1365
                                  //     applied
1366
    TPMT_SYM_DEF_OBJECT* symDef,  // IN: Symmetric key definition. If the
1367
                                  //     symmetric key algorithm is NULL,
1368
                                  //     no inner wrap is applied
1369
    TPM2B* innerSymKey,           // IN: a symmetric key may be provided
1370
                                  //     to decrypt the inner wrap of a
1371
                                  //     duplication blob.
1372
    TPMT_SENSITIVE* sensitive     // OUT: sensitive structure
1373
)
1374
{
1375
    TPM_RC result;
91✔
1376
    BYTE*  buffer;
91✔
1377
    INT32  size;
91✔
1378
    BYTE*  sensitiveData;  // pointer to the sensitive data
91✔
1379
    UINT16 dataSize;
91✔
1380
    UINT16 dataSizeInput;
91✔
1381
    //
1382
    // Make sure that name is provided
1383
    pAssert_RC(name != NULL && name->size != 0);
91✔
1384

1385
    // Make sure symDef and innerSymKey are not NULL
1386
    pAssert_RC(symDef != NULL && innerSymKey != NULL);
91✔
1387

1388
    // Starting of sensitive data
1389
    sensitiveData = inPrivate->buffer;
91✔
1390
    dataSize      = inPrivate->size;
91✔
1391

1392
    // Find out if outer wrap is applied
1393
    if(seed->size != 0)
91✔
1394
    {
1395
        // Use parent nameAlg as outer hash algorithm
1396
        TPMI_ALG_HASH outerHash = parent->publicArea.nameAlg;
33✔
1397

1398
        result                  = UnwrapOuter(
33✔
1399
            parent, name, outerHash, seed, FALSE, dataSize, sensitiveData);
1400
        if(result != TPM_RC_SUCCESS)
33✔
1401
            return result;
1402
        // Adjust sensitive data pointer and size
1403
        sensitiveData += sizeof(UINT16) + CryptHashGetDigestSize(outerHash);
33✔
1404
        dataSize -= sizeof(UINT16) + CryptHashGetDigestSize(outerHash);
33✔
1405
    }
1406
    // Find out if inner wrap is applied
1407
    if(symDef->algorithm != TPM_ALG_NULL)
91✔
1408
    {
1409
        // assume the input key size matches the symmetric definition
1410
        pAssert_RC(innerSymKey->size == (symDef->keyBits.sym + 7) / 8);
13✔
1411

1412
        // Decrypt inner buffer in place
1413
        CryptSymmetricDecrypt(sensitiveData,
13✔
1414
                              symDef->algorithm,
1415
                              symDef->keyBits.sym,
1416
                              innerSymKey->buffer,
13✔
1417
                              NULL,
1418
                              TPM_ALG_CFB,
1419
                              dataSize,
1420
                              sensitiveData);
1421
        // Check inner integrity
1422
        result = CheckInnerIntegrity(name, nameAlg, dataSize, sensitiveData);
13✔
1423
        if(result != TPM_RC_SUCCESS)
13✔
1424
            return result;
1425
        // Adjust sensitive data pointer and size
1426
        sensitiveData += sizeof(UINT16) + CryptHashGetDigestSize(nameAlg);
13✔
1427
        dataSize -= sizeof(UINT16) + CryptHashGetDigestSize(nameAlg);
13✔
1428
    }
1429
    // Unmarshal input data size
1430
    buffer = sensitiveData;
91✔
1431
    size   = (INT32)dataSize;
91✔
1432
    result = UINT16_Unmarshal(&dataSizeInput, &buffer, &size);
91✔
1433
    if(result == TPM_RC_SUCCESS)
91✔
1434
    {
1435
        if((dataSizeInput + sizeof(UINT16)) != dataSize)
91✔
1436
            result = TPM_RC_SIZE;
1437
        else
1438
        {
1439
            // Unmarshal sensitive buffer to sensitive structure
1440
            result = TPMT_SENSITIVE_Unmarshal(sensitive, &buffer, &size);
91✔
1441

1442
            // if the results is OK make sure that all the data was unmarshaled
1443
            if(result == TPM_RC_SUCCESS && size != 0)
91✔
UNCOV
1444
                result = TPM_RC_SIZE;
×
1445
        }
1446
    }
1447
    return result;
1448
}
1449

1450
//*** SecretToCredential()
1451
// This function prepare the credential blob from a secret (a TPM2B_DIGEST)
1452
// The operations in this function:
1453
//  1. marshal TPM2B_DIGEST structure into the buffer of TPM2B_ID_OBJECT
1454
//  2. encrypt the private buffer, excluding the leading integrity HMAC area
1455
//  3. compute integrity HMAC and append to the beginning of the buffer.
1456
//  4. Set the total size of TPM2B_ID_OBJECT buffer
1457
TPM_RC SecretToCredential(TPM2B_DIGEST*    secret,      // IN: secret information
1✔
1458
                          TPM2B*           name,        // IN: the name of the object
1459
                          TPM2B*           seed,        // IN: an external seed.
1460
                          OBJECT*          protector,   // IN: the protector
1461
                          TPM2B_ID_OBJECT* outIDObject  // OUT: output credential
1462
)
1463
{
1464
    BYTE*         buffer;         // Auxiliary buffer pointer
1✔
1465
    BYTE*         sensitiveData;  // pointer to the sensitive data
1✔
1466
    TPMI_ALG_HASH outerHash;      // The hash algorithm for outer wrap
1✔
1467
    UINT16        dataSize;       // data blob size
1✔
1468
                                  //
1469
    pAssert_RC(secret != NULL && outIDObject != NULL);
1✔
1470

1471
    // use protector's name algorithm as outer hash ????
1472
    outerHash = protector->publicArea.nameAlg;
1✔
1473

1474
    // Marshal secret area to credential buffer, leave space for integrity
1475
    sensitiveData = outIDObject->t.credential + sizeof(UINT16)
2✔
1476
                    + CryptHashGetDigestSize(outerHash);
1✔
1477
    // Marshal secret area
1478
    buffer   = sensitiveData;
1✔
1479
    dataSize = TPM2B_DIGEST_Marshal(secret, &buffer, NULL);
1✔
1480

1481
    // Apply outer wrap
1482
    outIDObject->t.size = ProduceOuterWrap(
1✔
1483
        protector, name, outerHash, seed, FALSE, dataSize, outIDObject->t.credential);
1484
    return TPM_RC_SUCCESS;
1✔
1485
}
1486

1487
//*** CredentialToSecret()
1488
// Unwrap a credential.  Check the integrity, decrypt and retrieve data
1489
// to a TPM2B_DIGEST structure.
1490
// The operations in this function:
1491
//  1. check the integrity HMAC of the input credential area
1492
//  2. decrypt the credential buffer
1493
//  3. unmarshal TPM2B_DIGEST structure into the buffer of TPM2B_DIGEST
1494
//
1495
//  Return Type: TPM_RC
1496
//      TPM_RC_INSUFFICIENT      error during credential unmarshaling
1497
//      TPM_RC_INTEGRITY         credential integrity is broken
1498
//      TPM_RC_SIZE              error during credential unmarshaling
1499
//      TPM_RC_VALUE             IV size does not match the encryption algorithm
1500
//                               block size
1501
TPM_RC
1502
CredentialToSecret(TPM2B*        inIDObject,  // IN: input credential blob
1✔
1503
                   TPM2B*        name,        // IN: the name of the object
1504
                   TPM2B*        seed,        // IN: an external seed.
1505
                   OBJECT*       protector,   // IN: the protector
1506
                   TPM2B_DIGEST* secret       // OUT: secret information
1507
)
1508
{
1509
    TPM_RC        result;
1✔
1510
    BYTE*         buffer;
1✔
1511
    INT32         size;
1✔
1512
    TPMI_ALG_HASH outerHash;      // The hash algorithm for outer wrap
1✔
1513
    BYTE*         sensitiveData;  // pointer to the sensitive data
1✔
1514
    UINT16        dataSize;
1✔
1515
    //
1516
    // use protector's name algorithm as outer hash
1517
    outerHash = protector->publicArea.nameAlg;
1✔
1518

1519
    // Unwrap outer, a TPM_RC_INTEGRITY error may be returned at this point
1520
    result = UnwrapOuter(protector,
2✔
1521
                         name,
1522
                         outerHash,
1523
                         seed,
1524
                         FALSE,
1525
                         inIDObject->size,
1✔
1526
                         inIDObject->buffer);
1✔
1527
    if(result == TPM_RC_SUCCESS)
1✔
1528
    {
1529
        // Compute the beginning of sensitive data
1530
        sensitiveData =
2✔
1531
            inIDObject->buffer + sizeof(UINT16) + CryptHashGetDigestSize(outerHash);
1✔
1532
        dataSize =
2✔
1533
            inIDObject->size - (sizeof(UINT16) + CryptHashGetDigestSize(outerHash));
1✔
1534
        // Unmarshal secret buffer to TPM2B_DIGEST structure
1535
        buffer = sensitiveData;
1✔
1536
        size   = (INT32)dataSize;
1✔
1537
        result = TPM2B_DIGEST_Unmarshal(secret, &buffer, &size);
1✔
1538

1539
        // If there were no other unmarshaling errors, make sure that the
1540
        // expected amount of data was recovered
1541
        if(result == TPM_RC_SUCCESS && size != 0)
1✔
UNCOV
1542
            return TPM_RC_SIZE;
×
1543
    }
1544
    return result;
1545
}
1546

1547
//*** MemoryRemoveTrailingZeros()
1548
// This function is used to adjust the length of an authorization value.
1549
// It adjusts the size of the TPM2B so that it does not include octets
1550
// at the end of the buffer that contain zero.
1551
// The function returns the number of non-zero octets in the buffer.
1552
UINT16
1553
MemoryRemoveTrailingZeros(TPM2B_AUTH* auth  // IN/OUT: value to adjust
14,595✔
1554
)
1555
{
1556
    while((auth->t.size > 0) && (auth->t.buffer[auth->t.size - 1] == 0))
90,807✔
1557
        auth->t.size--;
76,212✔
1558
    return auth->t.size;
14,595✔
1559
}
1560

1561
//*** SetLabelAndContext()
1562
// This function sets the label and context for a derived key. It is possible
1563
// that 'label' or 'context' can end up being an Empty Buffer.
1564
TPM_RC
1565
SetLabelAndContext(TPMS_DERIVE* labelContext,       // IN/OUT: the recovered label and
13✔
1566
                                                    //      context
1567
                   TPM2B_SENSITIVE_DATA* sensitive  // IN: the sensitive data
1568
)
1569
{
1570
    TPMS_DERIVE sensitiveValue;
13✔
1571
    TPM_RC      result;
13✔
1572
    INT32       size;
13✔
1573
    BYTE*       buff;
13✔
1574
    //
1575
    // Unmarshal a TPMS_DERIVE from the TPM2B_SENSITIVE_DATA buffer
1576
    // If there is something to unmarshal...
1577
    if(sensitive->t.size != 0)
13✔
1578
    {
UNCOV
1579
        size   = sensitive->t.size;
×
UNCOV
1580
        buff   = sensitive->t.buffer;
×
UNCOV
1581
        result = TPMS_DERIVE_Unmarshal(&sensitiveValue, &buff, &size);
×
UNCOV
1582
        if(result != TPM_RC_SUCCESS)
×
1583
            return result;
1584
        // If there was a label in the public area leave it there, otherwise, copy
1585
        // the new value
UNCOV
1586
        if(labelContext->label.t.size == 0)
×
UNCOV
1587
            MemoryCopy2B(&labelContext->label.b,
×
1588
                         &sensitiveValue.label.b,
1589
                         sizeof(labelContext->label.t.buffer));
1590
        // if there was a context string in publicArea, it overrides
UNCOV
1591
        if(labelContext->context.t.size == 0)
×
UNCOV
1592
            MemoryCopy2B(&labelContext->context.b,
×
1593
                         &sensitiveValue.context.b,
1594
                         sizeof(labelContext->label.t.buffer));
1595
    }
1596
    return TPM_RC_SUCCESS;
1597
}
1598

1599
//*** UnmarshalToPublic()
1600
// Support function to unmarshal the template. This is used because the
1601
// Input may be a TPMT_TEMPLATE and that structure does not have the same
1602
// size as a TPMT_PUBLIC because of the difference between the 'unique' and
1603
// 'seed' fields.
1604
// If 'derive' is not NULL, then the 'seed' field is assumed to contain
1605
// a 'label' and 'context' that are unmarshaled into 'derive'.
1606
TPM_RC
1607
UnmarshalToPublic(TPMT_PUBLIC*    tOut,  // OUT: output
58✔
1608
                  TPM2B_TEMPLATE* tIn,   // IN:
1609
                  BOOL derivation,       // IN: indicates if this is for a derivation
1610
                  TPMS_DERIVE* labelContext  // OUT: label and context if derivation
1611
)
1612
{
1613
    BYTE*  buffer = tIn->t.buffer;
58✔
1614
    INT32  size   = tIn->t.size;
58✔
1615
    TPM_RC result;
58✔
1616
    //
1617
    // make sure that tOut is zeroed so that there are no remnants from previous
1618
    // uses
1619
    MemorySet(tOut, 0, sizeof(TPMT_PUBLIC));
58✔
1620
    // Unmarshal the components of the TPMT_PUBLIC up to the unique field
1621
    result = TPMI_ALG_PUBLIC_Unmarshal(&tOut->type, &buffer, &size);
58✔
1622
    if(result != TPM_RC_SUCCESS)
58✔
1623
        return result;
1624
    result = TPMI_ALG_HASH_Unmarshal(&tOut->nameAlg, &buffer, &size, FALSE);
58✔
1625
    if(result != TPM_RC_SUCCESS)
58✔
1626
        return result;
1627
    result = TPMA_OBJECT_Unmarshal(&tOut->objectAttributes, &buffer, &size);
58✔
1628
    if(result != TPM_RC_SUCCESS)
58✔
1629
        return result;
1630
    result = TPM2B_DIGEST_Unmarshal(&tOut->authPolicy, &buffer, &size);
58✔
1631
    if(result != TPM_RC_SUCCESS)
58✔
1632
        return result;
1633
    result =
58✔
1634
        TPMU_PUBLIC_PARMS_Unmarshal(&tOut->parameters, &buffer, &size, tOut->type);
58✔
1635
    if(result != TPM_RC_SUCCESS)
58✔
1636
        return result;
1637
    // Now unmarshal a TPMS_DERIVE if this is for derivation
1638
    if(derivation)
58✔
1639
        result = TPMS_DERIVE_Unmarshal(labelContext, &buffer, &size);
13✔
1640
    else
1641
        // otherwise, unmarshal a TPMU_PUBLIC_ID
1642
        result = TPMU_PUBLIC_ID_Unmarshal(&tOut->unique, &buffer, &size, tOut->type);
45✔
1643
    // Make sure the template was used up
1644
    if((result == TPM_RC_SUCCESS) && (size != 0))
58✔
UNCOV
1645
        result = TPM_RC_SIZE;
×
1646
    return result;
1647
}
1648

1649
#if 0 /* libtpms added */
1650
//*** ObjectSetExternal()
1651
// Set the external attributes for an object.
1652
void ObjectSetExternal(OBJECT* object)
1653
{
1654
    object->attributes.external = SET;
1655
}
1656
#endif /* libtpms added */
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc