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

stefanberger / libtpms / #2022

23 Sep 2025 01:11PM UTC coverage: 77.227% (+0.009%) from 77.218%
#2022

push

travis-ci

web-flow
Merge a45c293de into 4504f47c6

36116 of 46766 relevant lines covered (77.23%)

125180.04 hits per line

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

94.01
/src/tpm2/Object_spt.c
1
/********************************************************************************/
2
/*                                                                                */
3
/*                            Object Command Support                                 */
4
/*                             Written by Ken Goldman                                */
5
/*                       IBM Thomas J. Watson Research Center                        */
6
/*                                                                                */
7
/*  Licenses and Notices                                                        */
8
/*                                                                                */
9
/*  1. Copyright Licenses:                                                        */
10
/*                                                                                */
11
/*  - Trusted Computing Group (TCG) grants to the user of the source code in        */
12
/*    this specification (the "Source Code") a worldwide, irrevocable,                 */
13
/*    nonexclusive, royalty free, copyright license to reproduce, create         */
14
/*    derivative works, distribute, display and perform the Source Code and        */
15
/*    derivative works thereof, and to grant others the rights granted herein.        */
16
/*                                                                                */
17
/*  - The TCG grants to the user of the other parts of the specification         */
18
/*    (other than the Source Code) the rights to reproduce, distribute,         */
19
/*    display, and perform the specification solely for the purpose of                 */
20
/*    developing products based on such documents.                                */
21
/*                                                                                */
22
/*  2. Source Code Distribution Conditions:                                        */
23
/*                                                                                */
24
/*  - Redistributions of Source Code must retain the above copyright licenses,         */
25
/*    this list of conditions and the following disclaimers.                        */
26
/*                                                                                */
27
/*  - Redistributions in binary form must reproduce the above copyright         */
28
/*    licenses, this list of conditions        and the following disclaimers in the         */
29
/*    documentation and/or other materials provided with the distribution.        */
30
/*                                                                                */
31
/*  3. Disclaimers:                                                                */
32
/*                                                                                */
33
/*  - THE COPYRIGHT LICENSES SET FORTH ABOVE DO NOT REPRESENT ANY FORM OF        */
34
/*  LICENSE OR WAIVER, EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE, WITH        */
35
/*  RESPECT TO PATENT RIGHTS HELD BY TCG MEMBERS (OR OTHER THIRD PARTIES)        */
36
/*  THAT MAY BE NECESSARY TO IMPLEMENT THIS SPECIFICATION OR OTHERWISE.                */
37
/*  Contact TCG Administration (admin@trustedcomputinggroup.org) for                 */
38
/*  information on specification licensing rights available through TCG         */
39
/*  membership agreements.                                                        */
40
/*                                                                                */
41
/*  - THIS SPECIFICATION IS PROVIDED "AS IS" WITH NO EXPRESS OR IMPLIED         */
42
/*    WARRANTIES WHATSOEVER, INCLUDING ANY WARRANTY OF MERCHANTABILITY OR         */
43
/*    FITNESS FOR A PARTICULAR PURPOSE, ACCURACY, COMPLETENESS, OR                 */
44
/*    NONINFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS, OR ANY WARRANTY                 */
45
/*    OTHERWISE ARISING OUT OF ANY PROPOSAL, SPECIFICATION OR SAMPLE.                */
46
/*                                                                                */
47
/*  - Without limitation, TCG and its members and licensors disclaim all         */
48
/*    liability, including liability for infringement of any proprietary         */
49
/*    rights, relating to use of information in this specification and to the        */
50
/*    implementation of this specification, and TCG disclaims all liability for        */
51
/*    cost of procurement of substitute goods or services, lost profits, loss         */
52
/*    of use, loss of data or any incidental, consequential, direct, indirect,         */
53
/*    or special damages, whether under contract, tort, warranty or otherwise,         */
54
/*    arising in any way out of use or reliance upon this specification or any         */
55
/*    information herein.                                                        */
56
/*                                                                                */
57
/*  (c) Copyright IBM Corp. and others, 2016 - 2023                                */
58
/*                                                                                */
59
/********************************************************************************/
60

61
//** Includes
62
#include "Tpm.h"
63
#include "Object_spt_fp.h"
64
#include "Marshal.h"
65
#include "TpmTypes.h"                // kgold
66

67
//** Local Functions
68

69
//*** GetIV2BSize()
70
// Get the size of TPM2B_IV in canonical form that will be append to the start of
71
// the sensitive data.  It includes both size of size field and size of iv data
72
static UINT16 GetIV2BSize(OBJECT* protector  // IN: the protector handle
1,156✔
73
)
74
{
75
    TPM_ALG_ID symAlg;
1,156✔
76
    UINT16     keyBits;
1,156✔
77

78
    // Determine the symmetric algorithm and size of key
79
    if(protector == NULL)
1,156✔
80
    {
81
        // Use the context encryption algorithm and key size
82
        symAlg  = CONTEXT_ENCRYPT_ALG;
83
        keyBits = CONTEXT_ENCRYPT_KEY_BITS;
84
    }
85
    else
86
    {
87
        symAlg  = protector->publicArea.parameters.asymDetail.symmetric.algorithm;
1,156✔
88
        keyBits = protector->publicArea.parameters.asymDetail.symmetric.keyBits.sym;
1,156✔
89
    }
90

91
    // The IV size is a UINT16 size field plus the block size of the symmetric
92
    // algorithm
93
    return sizeof(UINT16) + CryptGetSymmetricBlockSize(symAlg, keyBits);
1,156✔
94
}
95

96
//*** ComputeProtectionKeyParms()
97
// This function retrieves the symmetric protection key parameters for
98
// the sensitive data
99
// The parameters retrieved from this function include encryption algorithm,
100
// key size in bit, and a TPM2B_SYM_KEY containing the key material as well as
101
// the key size in bytes
102
// This function is used for any action that requires encrypting or decrypting of
103
// the sensitive area of an object or a credential blob
104
//
105
/*(See part 1 specification)
106
    KDF for generating the protection key material:
107
    KDFa(hashAlg, seed, "STORAGE", Name, NULL , bits)
108
where
109
    hashAlg     for a Primary Object, an algorithm chosen by the TPM vendor
110
                for derivations from Primary Seeds. For all other objects,
111
                the nameAlg of the object's parent.
112
    seed        for a Primary Object in the Platform Hierarchy, the PPS.
113
                For Primary Objects in either Storage or Endorsement Hierarchy,
114
                the SPS. For Temporary Objects, the context encryption seed.
115
                For all other objects, the symmetric seed value in the
116
                sensitive area of the object's parent.
117
    STORAGE     label to differentiate use of KDFa() (see 4.7)
118
    Name        the Name of the object being encrypted
119
    bits        the number of bits required for a  symmetric key and IV
120
*/
121
//  Return Type: void
122
static void ComputeProtectionKeyParms(
850✔
123
    OBJECT*    protector,    // IN: the protector object
124
    TPM_ALG_ID hashAlg,      // IN: hash algorithm for KDFa
125
    TPM2B*     name,         // IN: name of the object
126
    TPM2B*     seedIn,       // IN: optional seed for duplication blob.
127
                             //     For non duplication blob, this
128
                             //     parameter should be NULL
129
    TPM_ALG_ID*    symAlg,   // OUT: the symmetric algorithm
130
    UINT16*        keyBits,  // OUT: the symmetric key size in bits
131
    TPM2B_SYM_KEY* symKey    // OUT: the symmetric key
132
)
133
{
134
    const TPM2B* seed = seedIn;
850✔
135

136
    // Determine the algorithms for the KDF and the encryption/decryption
137
    // For TPM_RH_NULL, using context settings
138
    if(protector == NULL)
850✔
139
    {
140
        // Use the context encryption algorithm and key size
141
        *symAlg        = CONTEXT_ENCRYPT_ALG;
×
142
        symKey->t.size = CONTEXT_ENCRYPT_KEY_BYTES;
×
143
        *keyBits       = CONTEXT_ENCRYPT_KEY_BITS;
×
144
    }
145
    else
146
    {
147
        TPMT_SYM_DEF_OBJECT* symDef;
850✔
148
        symDef         = &protector->publicArea.parameters.asymDetail.symmetric;
850✔
149
        *symAlg        = symDef->algorithm;
850✔
150
        *keyBits       = symDef->keyBits.sym;
850✔
151
        symKey->t.size = (*keyBits + 7) / 8;
850✔
152
    }
153
    // Get seed for KDF
154
    if(seed == NULL)
850✔
155
        seed = GetSeedForKDF(protector);
780✔
156
    // KDFa to generate symmetric key and IV value
157
    CryptKDFa(hashAlg,
850✔
158
              seed,
159
              STORAGE_KEY,
160
              name,
161
              NULL,
162
              symKey->t.size * 8,
850✔
163
              symKey->t.buffer,
850✔
164
              NULL,
165
              FALSE);
166
    return;
850✔
167
}
168

169
//*** ComputeOuterIntegrity()
170
// The sensitive area parameter is a buffer that holds a space for
171
// the integrity value and the marshaled sensitive area. The caller should
172
// skip over the area set aside for the integrity value
173
// and compute the hash of the remainder of the object.
174
// The size field of sensitive is in unmarshaled form and the
175
// sensitive area contents is an array of bytes.
176
/*(See part 1 specification)
177
    KDFa(hashAlg, seed, "INTEGRITY", NULL, NULL , bits)   (38)
178
where
179
    hashAlg     for a Primary Object, the nameAlg of the object. For all other
180
                objects the nameAlg of the object's parent.
181
    seed        for a Primary Object in the Platform Hierarchy, the PPS. For
182
                Primary Objects in either Storage or Endorsement Hierarchy,
183
                the SPS. For a Temporary Object, the context encryption key.
184
                For all other objects, the symmetric seed value in the sensitive
185
                area of the object's parent.
186
    "INTEGRITY" a value used to differentiate the uses of the KDF.
187
    bits        the number of bits in the digest produced by hashAlg.
188
Key is then used in the integrity computation.
189
    HMACnameAlg(HMACkey, encSensitive || Name )
190
where
191
    HMACnameAlg()   the HMAC function using nameAlg of the object's parent
192
    HMACkey         value derived from the parent symmetric protection value
193
    encSensitive    symmetrically encrypted sensitive area
194
    Name            the Name of the object being protected
195
*/
196
//  Return Type: void
197
static void ComputeOuterIntegrity(
853✔
198
    TPM2B*  name,                 // IN: the name of the object
199
    OBJECT* protector,            // IN: the object that
200
                                  //     provides protection. For an object,
201
                                  //     it is a parent. For a credential, it
202
                                  //     is the encrypt object. For
203
                                  //     a Temporary Object, it is NULL
204
    TPMI_ALG_HASH hashAlg,        // IN: algorithm to use for integrity
205
    TPM2B*        seedIn,         // IN: an external seed may be provided for
206
                                  //     duplication blob. For non duplication
207
                                  //     blob, this parameter should be NULL
208
    UINT32        sensitiveSize,  // IN: size of the marshaled sensitive data
209
    BYTE*         sensitiveData,  // IN: sensitive area
210
    TPM2B_DIGEST* integrity       // OUT: integrity
211
)
212
{
213
    HMAC_STATE   hmacState;
853✔
214
    TPM2B_DIGEST hmacKey;
853✔
215
    const TPM2B* seed = seedIn;
853✔
216
    //
217
    // Get seed for KDF
218
    if(seed == NULL)
853✔
219
        seed = GetSeedForKDF(protector);
783✔
220
    // Determine the HMAC key bits
221
    hmacKey.t.size = CryptHashGetDigestSize(hashAlg);
853✔
222

223
    // KDFa to generate HMAC key
224
    CryptKDFa(hashAlg,
853✔
225
              seed,
226
              INTEGRITY_KEY,
227
              NULL,
228
              NULL,
229
              hmacKey.t.size * 8,
853✔
230
              hmacKey.t.buffer,
231
              NULL,
232
              FALSE);
233
    // Start HMAC and get the size of the digest which will become the integrity
234
    integrity->t.size = CryptHmacStart2B(&hmacState, hashAlg, &hmacKey.b);
853✔
235

236
    // Adding the marshaled sensitive area to the integrity value
237
    CryptDigestUpdate(&hmacState.hashState, sensitiveSize, sensitiveData);
853✔
238

239
    // Adding name
240
    CryptDigestUpdate2B(&hmacState.hashState, name);
853✔
241

242
    // Compute HMAC
243
    CryptHmacEnd2B(&hmacState, &integrity->b);
853✔
244

245
    return;
853✔
246
}
247

248
//*** ComputeInnerIntegrity()
249
// This function computes the integrity of an inner wrap
250
static void ComputeInnerIntegrity(
26✔
251
    TPM_ALG_ID    hashAlg,        // IN: hash algorithm for inner wrap
252
    TPM2B*        name,           // IN: the name of the object
253
    UINT16        dataSize,       // IN: the size of sensitive data
254
    BYTE*         sensitiveData,  // IN: sensitive data
255
    TPM2B_DIGEST* integrity       // OUT: inner integrity
256
)
257
{
258
    HASH_STATE hashState;
26✔
259
    //
260
    // Start hash and get the size of the digest which will become the integrity
261
    integrity->t.size = CryptHashStart(&hashState, hashAlg);
26✔
262

263
    // Adding the marshaled sensitive area to the integrity value
264
    CryptDigestUpdate(&hashState, dataSize, sensitiveData);
26✔
265

266
    // Adding name
267
    CryptDigestUpdate2B(&hashState, name);
26✔
268

269
    // Compute hash
270
    CryptHashEnd2B(&hashState, &integrity->b);
26✔
271

272
    return;
26✔
273
}
274

275
//*** ProduceInnerIntegrity()
276
// This function produces an inner integrity for regular private, credential or
277
// duplication blob
278
// It requires the sensitive data being marshaled to the innerBuffer, with the
279
// leading bytes reserved for integrity hash.  It assume the sensitive data
280
// starts at address (innerBuffer + integrity size).
281
// This function integrity at the beginning of the inner buffer
282
// It returns the total size of buffer with the inner wrap
283
static UINT16 ProduceInnerIntegrity(
13✔
284
    TPM2B*     name,      // IN: the name of the object
285
    TPM_ALG_ID hashAlg,   // IN: hash algorithm for inner wrap
286
    UINT16     dataSize,  // IN: the size of sensitive data, excluding the
287
                          //     leading integrity buffer size
288
    BYTE* innerBuffer     // IN/OUT: inner buffer with sensitive data in
289
                          //     it.  At input, the leading bytes of this
290
                          //     buffer is reserved for integrity
291
)
292
{
293
    BYTE*        sensitiveData;  // pointer to the sensitive data
13✔
294
    TPM2B_DIGEST integrity;
13✔
295
    UINT16       integritySize;
13✔
296
    BYTE*        buffer;  // Auxiliary buffer pointer
13✔
297
                          //
298
    // sensitiveData points to the beginning of sensitive data in innerBuffer
299
    integritySize = sizeof(UINT16) + CryptHashGetDigestSize(hashAlg);
13✔
300
    sensitiveData = innerBuffer + integritySize;
13✔
301

302
    ComputeInnerIntegrity(hashAlg, name, dataSize, sensitiveData, &integrity);
13✔
303

304
    // Add integrity at the beginning of inner buffer
305
    buffer = innerBuffer;
13✔
306
    TPM2B_DIGEST_Marshal(&integrity, &buffer, NULL);
13✔
307

308
    return dataSize + integritySize;
13✔
309
}
310

311
//*** CheckInnerIntegrity()
312
// This function check integrity of inner blob
313
//  Return Type: TPM_RC
314
//      TPM_RC_INTEGRITY        if the outer blob integrity is bad
315
//      unmarshal errors        unmarshal errors while unmarshaling integrity
316
static TPM_RC CheckInnerIntegrity(
13✔
317
    TPM2B*     name,      // IN: the name of the object
318
    TPM_ALG_ID hashAlg,   // IN: hash algorithm for inner wrap
319
    UINT16     dataSize,  // IN: the size of sensitive data, including the
320
                          //     leading integrity buffer size
321
    BYTE* innerBuffer     // IN/OUT: inner buffer with sensitive data in
322
                          //     it
323
)
324
{
325
    TPM_RC       result;
13✔
326
    TPM2B_DIGEST integrity;
13✔
327
    TPM2B_DIGEST integrityToCompare;
13✔
328
    BYTE*        buffer;  // Auxiliary buffer pointer
13✔
329
    INT32        size;
13✔
330
    //
331
    // Unmarshal integrity
332
    buffer = innerBuffer;
13✔
333
    size   = (INT32)dataSize;
13✔
334
    result = TPM2B_DIGEST_Unmarshal(&integrity, &buffer, &size);
13✔
335
    if(result == TPM_RC_SUCCESS)
13✔
336
    {
337
        // Compute integrity to compare
338
        ComputeInnerIntegrity(
13✔
339
            hashAlg, name, (UINT16)size, buffer, &integrityToCompare);
13✔
340
        // Compare outer blob integrity
341
        if(!MemoryEqual2B(&integrity.b, &integrityToCompare.b))
13✔
342
            result = TPM_RC_INTEGRITY;
×
343
    }
344
    return result;
13✔
345
}
346

347
//** Public Functions
348

349
//*** AdjustAuthSize()
350
// This function will validate that the input authValue is no larger than the
351
// digestSize for the nameAlg. It will then pad with zeros to the size of the
352
// digest.
353
BOOL AdjustAuthSize(TPM2B_AUTH*   auth,    // IN/OUT: value to adjust
968✔
354
                    TPMI_ALG_HASH nameAlg  // IN:
355
)
356
{
357
    UINT16 digestSize;
968✔
358
    //
359
    // If there is no nameAlg, then this is a LoadExternal and the authVale can
360
    // be any size up to the maximum allowed by the implementation
361
    digestSize = (nameAlg == TPM_ALG_NULL) ? sizeof(TPMU_HA)
968✔
362
                                           : CryptHashGetDigestSize(nameAlg);
968✔
363
    if(digestSize < MemoryRemoveTrailingZeros(auth))
968✔
364
        return FALSE;
365
    else if(digestSize > auth->t.size)
968✔
366
        MemoryPad2B(&auth->b, digestSize);
968✔
367
    auth->t.size = digestSize;
968✔
368

369
    return TRUE;
968✔
370
}
371

372
//*** AreAttributesForParent()
373
// This function is called by create, load, and import functions.
374
//
375
// Note: The 'isParent' attribute is SET when an object is loaded and it has
376
// attributes that are suitable for a parent object.
377
//  Return Type: BOOL
378
//      TRUE(1)         properties are those of a parent
379
//      FALSE(0)        properties are not those of a parent
380
BOOL ObjectIsParent(OBJECT* parentObject  // IN: parent handle
776✔
381
)
382
{
383
    return parentObject->attributes.isParent;
776✔
384
}
385

386
//*** CreateChecks()
387
// Attribute checks that are unique to creation.
388
// If parentObject is not NULL, then this function checks the object's
389
// attributes as an Ordinary or Derived Object with the given parent.
390
// If parentObject is NULL, and primaryHandle is not 0, then this function
391
// checks the object's attributes as a Primary Object in the given hierarchy.
392
// If parentObject is NULL, and primaryHandle is 0, then this function checks
393
// the object's attributes as an External Object.
394
//  Return Type: TPM_RC
395
//      TPM_RC_ATTRIBUTES   sensitiveDataOrigin is not consistent with the
396
//                          object type
397
//      other               returns from PublicAttributesValidation()
398
TPM_RC
399
CreateChecks(OBJECT*           parentObject,
991✔
400
             TPMI_RH_HIERARCHY primaryHierarchy,
401
             TPMT_PUBLIC*      publicArea,
402
             UINT16            sensitiveDataSize)
403
{
404
    TPMA_OBJECT attributes = publicArea->objectAttributes;
991✔
405
    TPM_RC      result     = TPM_RC_SUCCESS;
991✔
406
    //
407
    // If the caller indicates that they have provided the data, then make sure that
408
    // they have provided some data.
409
    if((!IS_ATTRIBUTE(attributes, TPMA_OBJECT, sensitiveDataOrigin))
991✔
410
       && (sensitiveDataSize == 0))
35✔
411
        return TPM_RCS_ATTRIBUTES;
412
    // For an ordinary object, data can only be provided when sensitiveDataOrigin
413
    // is CLEAR
414
    if((parentObject != NULL)
987✔
415
       && (IS_ATTRIBUTE(attributes, TPMA_OBJECT, sensitiveDataOrigin))
280✔
416
       && (sensitiveDataSize != 0))
257✔
417
        return TPM_RCS_ATTRIBUTES;
418
    switch(publicArea->type)
987✔
419
    {
420
        case TPM_ALG_KEYEDHASH:
62✔
421
            // if this is a data object (sign == decrypt == CLEAR) then the
422
            // TPM cannot be the data source.
423
            if(!IS_ATTRIBUTE(attributes, TPMA_OBJECT, sign)
62✔
424
               && !IS_ATTRIBUTE(attributes, TPMA_OBJECT, decrypt)
425
               && IS_ATTRIBUTE(attributes, TPMA_OBJECT, sensitiveDataOrigin))
62✔
426
                result = TPM_RC_ATTRIBUTES;
×
427
            // comment out the next line in order to prevent a fixedTPM derivation
428
            // parent
429
            //            break;
430
        /* fallthrough */                // libtpms added
431
        case TPM_ALG_SYMCIPHER:
432
            // A restricted key symmetric key (SYMCIPHER and KEYEDHASH)
433
            // must have sensitiveDataOrigin SET unless it has fixedParent and
434
            // fixedTPM CLEAR.
435
            if(IS_ATTRIBUTE(attributes, TPMA_OBJECT, restricted))
97✔
436
                if(!IS_ATTRIBUTE(attributes, TPMA_OBJECT, sensitiveDataOrigin))
15✔
437
                    if(IS_ATTRIBUTE(attributes, TPMA_OBJECT, fixedParent)
×
438
                       || IS_ATTRIBUTE(attributes, TPMA_OBJECT, fixedTPM))
×
439
                        result = TPM_RCS_ATTRIBUTES;
440
            break;
441
        default:  // Asymmetric keys cannot have the sensitive portion provided
890✔
442
            if(!IS_ATTRIBUTE(attributes, TPMA_OBJECT, sensitiveDataOrigin))
890✔
443
                result = TPM_RCS_ATTRIBUTES;
444
            break;
445
    }
446
    if(TPM_RC_SUCCESS == result)
97✔
447
    {
448
        result =
983✔
449
            PublicAttributesValidation(parentObject, primaryHierarchy, publicArea);
983✔
450
    }
451
    return result;
452
}
453

454
//*** SchemeChecks
455
// This function is called by TPM2_LoadExternal() and PublicAttributesValidation().
456
// This function validates the schemes in the public area of an object.
457
//  Return Type: TPM_RC
458
//      TPM_RC_HASH         non-duplicable storage key and its parent have different
459
//                          name algorithm
460
//      TPM_RC_KDF          incorrect KDF specified for decrypting keyed hash object
461
//      TPM_RC_KEY          invalid key size values in an asymmetric key public area
462
//      TPM_RCS_SCHEME       inconsistent attributes 'decrypt', 'sign', 'restricted'
463
//                          and key's scheme ID; or hash algorithm is inconsistent
464
//                          with the scheme ID for keyed hash object
465
//      TPM_RC_SYMMETRIC    a storage key with no symmetric algorithm specified; or
466
//                          non-storage key with symmetric algorithm different from
467
//                          TPM_ALG_NULL
468
TPM_RC
469
SchemeChecks(OBJECT*      parentObject,  // IN: parent (null if primary seed)
2,006✔
470
             TPMT_PUBLIC* publicArea     // IN: public area of the object
471
)
472
{
473
    TPMT_SYM_DEF_OBJECT* symAlgs    = NULL;
2,006✔
474
    TPM_ALG_ID           scheme     = TPM_ALG_NULL;
2,006✔
475
    TPMA_OBJECT          attributes = publicArea->objectAttributes;
2,006✔
476
    TPMU_PUBLIC_PARMS*   parms      = &publicArea->parameters;
2,006✔
477
    //
478
    switch(publicArea->type)
2,006✔
479
    {
480
        case TPM_ALG_SYMCIPHER:
47✔
481
            symAlgs = &parms->symDetail.sym;
47✔
482
            // If this is a decrypt key, then only the block cipher modes (not
483
            // SMAC) are valid. TPM_ALG_NULL is OK too. If this is a 'sign' key,
484
            // then any mode that got through the unmarshaling is OK.
485
            if(IS_ATTRIBUTE(attributes, TPMA_OBJECT, decrypt)
47✔
486
               && !CryptSymModeIsValid(symAlgs->mode.sym, TRUE))
47✔
487
                return TPM_RCS_SCHEME;
488
            break;
489
        case TPM_ALG_KEYEDHASH:
132✔
490
            scheme = parms->keyedHashDetail.scheme.scheme;
132✔
491
            // if both sign and decrypt
492
            if(IS_ATTRIBUTE(attributes, TPMA_OBJECT, sign)
132✔
493
               == IS_ATTRIBUTE(attributes, TPMA_OBJECT, decrypt))
132✔
494
            {
495
                // if both sign and decrypt are set or clear, then need
496
                // TPM_ALG_NULL as scheme
497
                if(scheme != TPM_ALG_NULL)
56✔
498
                    return TPM_RCS_SCHEME;
4✔
499
            }
500
            else if(
76✔
501
                IS_ATTRIBUTE(attributes, TPMA_OBJECT, sign) && scheme != TPM_ALG_HMAC)
64✔
502
                return TPM_RCS_SCHEME;
503
            else if(IS_ATTRIBUTE(attributes, TPMA_OBJECT, decrypt))
76✔
504
            {
505
                if(scheme != TPM_ALG_XOR)
12✔
506
                    return TPM_RCS_SCHEME;
507
                // If this is a derivation parent, then the KDF needs to be
508
                // SP800-108 for this implementation. This is the only derivation
509
                // supported by this implementation. Other implementations could
510
                // support additional schemes. There is no default.
511
                if(IS_ATTRIBUTE(attributes, TPMA_OBJECT, restricted))
8✔
512
                {
513
                    if(parms->keyedHashDetail.scheme.details.
8✔
514
                       xor.kdf != TPM_ALG_KDF1_SP800_108)
8✔
515
                        return TPM_RCS_SCHEME;
516
                    // Must select a digest.
517
                    if(CryptHashGetDigestSize(
8✔
518
                           parms->keyedHashDetail.scheme.details.xor.hashAlg)
8✔
519
                       == 0)
520
                        return TPM_RCS_HASH;
×
521
                }
522
            }
523
            break;
524
        default:  // handling for asymmetric
1,827✔
525
            scheme  = parms->asymDetail.scheme.scheme;
1,827✔
526
            symAlgs = &parms->asymDetail.symmetric;
1,827✔
527
            // if the key is both sign and decrypt, then the scheme must be
528
            // TPM_ALG_NULL because there is no way to specify both a sign and a
529
            // decrypt scheme in the key.
530
            if(IS_ATTRIBUTE(attributes, TPMA_OBJECT, sign)
1,827✔
531
               == IS_ATTRIBUTE(attributes, TPMA_OBJECT, decrypt))
1,827✔
532
            {
533
                // scheme must be TPM_ALG_NULL
534
                if(scheme != TPM_ALG_NULL)
226✔
535
                    return TPM_RCS_SCHEME;
536
            }
537
            else if(IS_ATTRIBUTE(attributes, TPMA_OBJECT, sign))
1,601✔
538
            {
539
                // If this is a signing key, see if it has a signing scheme
540
                if(CryptIsAsymSignScheme(publicArea->type, scheme))
841✔
541
                {
542
                    // if proper signing scheme then it needs a proper hash
543
                    if(parms->asymDetail.scheme.details.anySig.hashAlg
438✔
544
                       == TPM_ALG_NULL)
545
                        return TPM_RCS_SCHEME;
546
                }
547
                else
548
                {
549
                    // signing key that does not have a proper signing scheme.
550
                    // This is OK if the key is not restricted and its scheme
551
                    // is TPM_ALG_NULL
552
                    if(IS_ATTRIBUTE(attributes, TPMA_OBJECT, restricted)
403✔
553
                       || scheme != TPM_ALG_NULL)
395✔
554
                        return TPM_RCS_SCHEME;
555
                }
556
            }
557
            else if(IS_ATTRIBUTE(attributes, TPMA_OBJECT, decrypt))
760✔
558
            {
559
                if(IS_ATTRIBUTE(attributes, TPMA_OBJECT, restricted))
760✔
560
                {
561
                    // for a restricted decryption key (a parent), scheme
562
                    // is required to be TPM_ALG_NULL
563
                    if(scheme != TPM_ALG_NULL)
545✔
564
                        return TPM_RCS_SCHEME;
565
                }
566
                else
567
                {
568
                    // For an unrestricted decryption key, the scheme has to
569
                    // be a valid scheme or TPM_ALG_NULL
570
                    if(scheme != TPM_ALG_NULL
215✔
571
                       && !CryptIsAsymDecryptScheme(publicArea->type, scheme))
144✔
572
                        return TPM_RCS_SCHEME;
573
                }
574
            }
575
            if(!IS_ATTRIBUTE(attributes, TPMA_OBJECT, restricted)
1,775✔
576
               || !IS_ATTRIBUTE(attributes, TPMA_OBJECT, decrypt))
1,775✔
577
            {
578
                // For an asymmetric key that is not a parent, the symmetric
579
                // algorithms must be TPM_ALG_NULL
580
                if(symAlgs->algorithm != TPM_ALG_NULL)
1,242✔
581
                    return TPM_RCS_SYMMETRIC;
582
            }
583
            // Special checks for an ECC key
584
#if ALG_ECC
585
            if(publicArea->type == TPM_ALG_ECC)
1,771✔
586
            {
587
                TPM_ECC_CURVE          curveID;
620✔
588
                const TPMT_ECC_SCHEME* curveScheme;
620✔
589

590
                curveID     = publicArea->parameters.eccDetail.curveID;
620✔
591
                curveScheme = CryptGetCurveSignScheme(curveID);
620✔
592
                // The curveId must be valid or the unmarshaling is busted.
593
                pAssert(curveScheme != NULL);
620✔
594

595
                // If the curveID requires a specific scheme, then the key must
596
                // select the same scheme
597
                if(curveScheme->scheme != TPM_ALG_NULL)
620✔
598
                {
599
                    TPMS_ECC_PARMS* ecc = &publicArea->parameters.eccDetail;
×
600
                    if(scheme != curveScheme->scheme)
×
601
                        return TPM_RCS_SCHEME;
602
                    // The scheme can allow any hash, or not...
603
                    if(curveScheme->details.anySig.hashAlg != TPM_ALG_NULL
×
604
                       && (ecc->scheme.details.anySig.hashAlg
×
605
                           != curveScheme->details.anySig.hashAlg))
606
                        return TPM_RCS_SCHEME;
607
                }
608
                // For now, the KDF must be TPM_ALG_NULL
609
                if(publicArea->parameters.eccDetail.kdf.scheme != TPM_ALG_NULL)
620✔
610
                    return TPM_RCS_KDF;
611
            }
612
#endif
613
            break;
614
    }
615
    // If this is a restricted decryption key with symmetric algorithms, then it
616
    // is an ordinary parent (not a derivation parent). It needs to specific
617
    // symmetric algorithms other than TPM_ALG_NULL
618
    if(symAlgs != NULL && IS_ATTRIBUTE(attributes, TPMA_OBJECT, restricted)
1,818✔
619
       && IS_ATTRIBUTE(attributes, TPMA_OBJECT, decrypt))
1,818✔
620
    {
621
        if(symAlgs->algorithm == TPM_ALG_NULL)
533✔
622
            return TPM_RCS_SYMMETRIC;
623
#if 0  //??
624
// This next check is under investigation. Need to see if it will break Windows
625
// before it is enabled. If it does not, then it should be default because a
626
// the mode used with a parent is always CFB and Part 2 indicates as much.
627
        if(symAlgs->mode.sym != TPM_ALG_CFB)
628
            return TPM_RCS_MODE;
629
#endif
630
        // If this parent is not duplicable, then the symmetric algorithms
631
        // (encryption and hash) must match those of its parent
632
        if(IS_ATTRIBUTE(attributes, TPMA_OBJECT, fixedParent)
533✔
633
           && (parentObject != NULL))
342✔
634
        {
635
            if(publicArea->nameAlg != parentObject->publicArea.nameAlg)
138✔
636
                return TPM_RCS_HASH;
637
            if(!MemoryEqual(symAlgs,
138✔
638
                            &parentObject->publicArea.parameters,
138✔
639
                            sizeof(TPMT_SYM_DEF_OBJECT)))
640
                return TPM_RCS_SYMMETRIC;
×
641
        }
642
    }
643
    return TPM_RC_SUCCESS;
644
}
645

646
//*** PublicAttributesValidation()
647
// This function validates the values in the public area of an object.
648
// This function is used in the processing of TPM2_Create, TPM2_CreatePrimary,
649
// TPM2_CreateLoaded(), TPM2_Load(),  TPM2_Import(), and TPM2_LoadExternal().
650
// For TPM2_Import() this is only used if the new parent has fixedTPM SET. For
651
// TPM2_LoadExternal(), this is not used for a public-only key
652
//  Return Type: TPM_RC
653
//      TPM_RC_ATTRIBUTES   'fixedTPM', 'fixedParent', or 'encryptedDuplication'
654
//                          attributes are inconsistent between themselves or with
655
//                          those of the parent object;
656
//                          inconsistent 'restricted', 'decrypt' and 'sign'
657
//                          attributes;
658
//                          attempt to inject sensitive data for an asymmetric key;
659
//                          attempt to create a symmetric cipher key that is not
660
//                          a decryption key
661
//      TPM_RC_HASH         nameAlg is TPM_ALG_NULL
662
//      TPM_RC_SIZE         'authPolicy' size does not match digest size of the name
663
//                          algorithm in 'publicArea'
664
//   other                  returns from SchemeChecks()
665
TPM_RC
666
PublicAttributesValidation(
1,863✔
667
    // IN: input parent object (if ordinary or derived object; NULL otherwise)
668
    OBJECT* parentObject,
669
    // IN: hierarchy (if primary object; 0 otherwise)
670
    TPMI_RH_HIERARCHY primaryHierarchy,
671
    // IN: public area of the object
672
    TPMT_PUBLIC* publicArea)
673
{
674
    TPMA_OBJECT attributes       = publicArea->objectAttributes;
1,863✔
675
    TPMA_OBJECT parentAttributes = TPMA_ZERO_INITIALIZER();
1,863✔
676

677
    if(parentObject != NULL)
1,863✔
678
        parentAttributes = parentObject->publicArea.objectAttributes;
697✔
679
    if(publicArea->nameAlg == TPM_ALG_NULL)
1,863✔
680
        return TPM_RCS_HASH;
681
    // If there is an authPolicy, it needs to be the size of the digest produced
682
    // by the nameAlg of the object
683
    if((publicArea->authPolicy.t.size != 0
1,863✔
684
        && (publicArea->authPolicy.t.size
371✔
685
            != CryptHashGetDigestSize(publicArea->nameAlg))))
371✔
686
        return TPM_RCS_SIZE;
687
    // If the parent is fixedTPM (including a Primary Object) the object must have
688
    // the same value for fixedTPM and fixedParent
689
    if(parentObject == NULL || IS_ATTRIBUTE(parentAttributes, TPMA_OBJECT, fixedTPM))
1,863✔
690
    {
691
        if(IS_ATTRIBUTE(attributes, TPMA_OBJECT, fixedParent)
1,861✔
692
           != IS_ATTRIBUTE(attributes, TPMA_OBJECT, fixedTPM))
1,861✔
693
            return TPM_RCS_ATTRIBUTES;
694
    }
695
    else
696
    {
697
        // The parent is not fixedTPM so the object can't be fixedTPM
698
        if(IS_ATTRIBUTE(attributes, TPMA_OBJECT, fixedTPM))
2✔
699
            return TPM_RCS_ATTRIBUTES;
700
    }
701
    // See if sign and decrypt are the same
702
    if(IS_ATTRIBUTE(attributes, TPMA_OBJECT, sign)
1,859✔
703
       == IS_ATTRIBUTE(attributes, TPMA_OBJECT, decrypt))
1,859✔
704
    {
705
        // a restricted key cannot have both SET or both CLEAR
706
        if(IS_ATTRIBUTE(attributes, TPMA_OBJECT, restricted))
281✔
707
            return TPM_RC_ATTRIBUTES;
708
        // only a data object may have both sign and decrypt CLEAR
709
        // BTW, since we know that decrypt==sign, no need to check both
710
        if(publicArea->type != TPM_ALG_KEYEDHASH
277✔
711
           && !IS_ATTRIBUTE(attributes, TPMA_OBJECT, sign))
221✔
712
            return TPM_RC_ATTRIBUTES;
713
    }
714
    // If the object can't be duplicated (directly or indirectly) then there
715
    // is no justification for having encryptedDuplication SET
716
    if(IS_ATTRIBUTE(attributes, TPMA_OBJECT, fixedTPM)
1,855✔
717
       && IS_ATTRIBUTE(attributes, TPMA_OBJECT, encryptedDuplication))
1,855✔
718
        return TPM_RCS_ATTRIBUTES;
719
    // If a parent object has fixedTPM CLEAR, the child must have the
720
    // same encryptedDuplication value as its parent.
721
    // Primary objects are considered to have a fixedTPM parent (the seeds).
722
    if(parentObject != NULL && !IS_ATTRIBUTE(parentAttributes, TPMA_OBJECT, fixedTPM))
1,850✔
723
    {
724
        if(IS_ATTRIBUTE(attributes, TPMA_OBJECT, encryptedDuplication)
2✔
725
           != IS_ATTRIBUTE(parentAttributes, TPMA_OBJECT, encryptedDuplication))
2✔
726
            return TPM_RCS_ATTRIBUTES;
727
    }
728
    // firmwareLimited/svnLimited can only be set if fixedTPM is also set.
729
    if((IS_ATTRIBUTE(attributes, TPMA_OBJECT, firmwareLimited)
1,850✔
730
        || IS_ATTRIBUTE(attributes, TPMA_OBJECT, svnLimited))
1,850✔
731
       && !IS_ATTRIBUTE(attributes, TPMA_OBJECT, fixedTPM))
×
732
    {
733
        return TPM_RCS_ATTRIBUTES;
734
    }
735

736
    // firmwareLimited/svnLimited also impose requirements on the parent key or
737
    // primary handle.
738
    if(IS_ATTRIBUTE(attributes, TPMA_OBJECT, firmwareLimited))
1,850✔
739
    {
740
#if FW_LIMITED_SUPPORT                        // libtpms added
741
        if(parentObject != NULL)
742
        {
743
            // For an ordinary object, firmwareLimited can only be set if its
744
            // parent is also firmwareLimited.
745
            if(!IS_ATTRIBUTE(parentAttributes, TPMA_OBJECT, firmwareLimited))
746
                return TPM_RCS_ATTRIBUTES;
747
        }
748
        else if(primaryHierarchy != 0)
749
        {
750
            // For a primary object, firmwareLimited can only be set if its
751
            // hierarchy is a firmware-limited hierarchy.
752
            if(!HierarchyIsFirmwareLimited(primaryHierarchy))
753
                return TPM_RCS_ATTRIBUTES;
754
        }
755
        else
756
        {
757
            return TPM_RCS_ATTRIBUTES;
758
        }
759
#else                                // libtpms added begin
760
            (void)primaryHierarchy;
761
        return TPM_RCS_ATTRIBUTES;
762
#endif                                // libtpms added end
763
    }
764
    if(IS_ATTRIBUTE(attributes, TPMA_OBJECT, svnLimited))
1,850✔
765
    {
766
#if SVN_LIMITED_SUPPORT                        // libtpms added
767
        if(parentObject != NULL)
768
        {
769
            // For an ordinary object, svnLimited can only be set if its
770
            // parent is also svnLimited.
771
            if(!IS_ATTRIBUTE(parentAttributes, TPMA_OBJECT, svnLimited))
772
                return TPM_RCS_ATTRIBUTES;
773
        }
774
        else if(primaryHierarchy != 0)
775
        {
776
            // For a primary object, svnLimited can only be set if its
777
            // hierarchy is an svn-limited hierarchy.
778
            if(!HierarchyIsSvnLimited(primaryHierarchy))
779
                return TPM_RCS_ATTRIBUTES;
780
        }
781
        else
782
        {
783
            return TPM_RCS_ATTRIBUTES;
784
        }
785
#else                                // libtpms added begin
786
            (void)primaryHierarchy;
787
        return TPM_RCS_ATTRIBUTES;
788
#endif                                // libtpms added end
789
    }
790

791
    // Special checks for derived objects
792
    if((parentObject != NULL) && (parentObject->attributes.derivation == SET))
1,850✔
793
    {
794
        // A derived object has the same settings for fixedTPM as its parent
795
        if(IS_ATTRIBUTE(attributes, TPMA_OBJECT, fixedTPM)
13✔
796
           != IS_ATTRIBUTE(parentAttributes, TPMA_OBJECT, fixedTPM))
13✔
797
            return TPM_RCS_ATTRIBUTES;
798
        // A derived object is required to be fixedParent
799
        if(!IS_ATTRIBUTE(attributes, TPMA_OBJECT, fixedParent))
13✔
800
            return TPM_RCS_ATTRIBUTES;
801
    }
802
    return SchemeChecks(parentObject, publicArea);
1,850✔
803
}
804

805
//*** FillInCreationData()
806
// Fill in creation data for an object.
807
//  Return Type: void
808
void FillInCreationData(
901✔
809
    TPMI_DH_OBJECT       parentHandle,   // IN: handle of parent
810
    TPMI_ALG_HASH        nameHashAlg,    // IN: name hash algorithm
811
    TPML_PCR_SELECTION*  creationPCR,    // IN: PCR selection
812
    TPM2B_DATA*          outsideData,    // IN: outside data
813
    TPM2B_CREATION_DATA* outCreation,    // OUT: creation data for output
814
    TPM2B_DIGEST*        creationDigest  // OUT: creation digest
815
)
816
{
817
    BYTE       creationBuffer[sizeof(TPMS_CREATION_DATA)];
901✔
818
    BYTE*      buffer;
901✔
819
    HASH_STATE hashState;
901✔
820
    //
821
    // Fill in TPMS_CREATION_DATA in outCreation
822

823
    // Compute PCR digest
824
    PCRComputeCurrentDigest(
901✔
825
        nameHashAlg, creationPCR, &outCreation->creationData.pcrDigest);
826

827
    // Put back PCR selection list
828
    outCreation->creationData.pcrSelect = *creationPCR;
901✔
829

830
    // Get locality
831
    outCreation->creationData.locality = LocalityGetAttributes(_plat__LocalityGet());
901✔
832
    outCreation->creationData.parentNameAlg = TPM_ALG_NULL;
901✔
833

834
    // If the parent is either a primary seed or TPM_ALG_NULL, then  the Name
835
    // and QN of the parent are the parent's handle.
836
    if(HandleGetType(parentHandle) == TPM_HT_PERMANENT)
901✔
837
    {
838
        buffer = &outCreation->creationData.parentName.t.name[0];
623✔
839
        outCreation->creationData.parentName.t.size =
1,246✔
840
            TPM_HANDLE_Marshal(&parentHandle, &buffer, NULL);
623✔
841
        // For a primary or temporary object, the parent name (a handle) and the
842
        // parent's QN are the same
843
        outCreation->creationData.parentQualifiedName =
623✔
844
            outCreation->creationData.parentName;
845
    }
846
    else  // Regular object
847
    {
848
        OBJECT* parentObject = HandleToObject(parentHandle);
278✔
849
        //
850
        // Set name algorithm
851
        outCreation->creationData.parentNameAlg = parentObject->publicArea.nameAlg;
278✔
852

853
        // Copy parent name
854
        outCreation->creationData.parentName = parentObject->name;
278✔
855

856
        // Copy parent qualified name
857
        outCreation->creationData.parentQualifiedName = parentObject->qualifiedName;
278✔
858
    }
859
    // Copy outside information
860
    outCreation->creationData.outsideInfo = *outsideData;
901✔
861

862
    // Marshal creation data to canonical form
863
    buffer = creationBuffer;
901✔
864
    outCreation->size =
1,802✔
865
        TPMS_CREATION_DATA_Marshal(&outCreation->creationData, &buffer, NULL);
901✔
866
    // Compute hash for creation field in public template
867
    creationDigest->t.size = CryptHashStart(&hashState, nameHashAlg);
901✔
868
    CryptDigestUpdate(&hashState, outCreation->size, creationBuffer);
901✔
869
    CryptHashEnd2B(&hashState, &creationDigest->b);
901✔
870

871
    return;
901✔
872
}
873

874
//*** GetSeedForKDF()
875
// Get a seed for KDF.  The KDF for encryption and HMAC key use the same seed.
876
const TPM2B* GetSeedForKDF(OBJECT* protector  // IN: the protector handle
1,563✔
877
)
878
{
879
    // Get seed for encryption key.  Use input seed if provided.
880
    // Otherwise, using protector object's seedValue.  TPM_RH_NULL is the only
881
    // exception that we may not have a loaded object as protector.  In such a
882
    // case, use nullProof as seed.
883
    if(protector == NULL)
1,563✔
884
        return &gr.nullProof.b;
885
    else
886
        return &protector->sensitive.seedValue.b;
1,563✔
887
}
888

889
//*** ProduceOuterWrap()
890
// This function produce outer wrap for a buffer containing the sensitive data.
891
// It requires the sensitive data being marshaled to the outerBuffer, with the
892
// leading bytes reserved for integrity hash.  If iv is used, iv space should
893
// be reserved at the beginning of the buffer.  It assumes the sensitive data
894
// starts at address (outerBuffer + integrity size [+ iv size]).
895
// This function performs:
896
//  1. Add IV before sensitive area if required
897
//  2. encrypt sensitive data, if iv is required, encrypt by iv.  otherwise,
898
//     encrypted by a NULL iv
899
//  3. add HMAC integrity at the beginning of the buffer
900
// It returns the total size of blob with outer wrap
901
UINT16
902
ProduceOuterWrap(OBJECT* protector,   // IN: The handle of the object that provides
411✔
903
                                      //     protection.  For object, it is parent
904
                                      //     handle. For credential, it is the handle
905
                                      //     of encrypt object.
906
                 TPM2B*     name,     // IN: the name of the object
907
                 TPM_ALG_ID hashAlg,  // IN: hash algorithm for outer wrap
908
                 TPM2B*     seed,     // IN: an external seed may be provided for
909
                                      //     duplication blob. For non duplication
910
                                      //     blob, this parameter should be NULL
911
                 BOOL   useIV,        // IN: indicate if an IV is used
912
                 UINT16 dataSize,     // IN: the size of sensitive data, excluding the
913
                                      //     leading integrity buffer size or the
914
                                      //     optional iv size
915
                 BYTE* outerBuffer    // IN/OUT: outer buffer with sensitive data in
916
                                      //     it
917
)
918
{
919
    TPM_ALG_ID    symAlg;
411✔
920
    UINT16        keyBits;
411✔
921
    TPM2B_SYM_KEY symKey;
411✔
922
    TPM2B_IV      ivRNG;  // IV from RNG
411✔
923
    TPM2B_IV*     iv     = NULL;
411✔
924
    UINT16        ivSize = 0;     // size of iv area, including the size field
411✔
925
    BYTE*         sensitiveData;  // pointer to the sensitive data
411✔
926
    TPM2B_DIGEST  integrity;
411✔
927
    UINT16        integritySize;
411✔
928
    BYTE*         buffer;  // Auxiliary buffer pointer
411✔
929
                           //
930
    // Compute the beginning of sensitive data.  The outer integrity should
931
    // always exist if this function is called to make an outer wrap
932
    integritySize = sizeof(UINT16) + CryptHashGetDigestSize(hashAlg);
411✔
933
    sensitiveData = outerBuffer + integritySize;
411✔
934

935
    // If iv is used, adjust the pointer of sensitive data and add iv before it
936
    if(useIV)
411✔
937
    {
938
        ivSize = GetIV2BSize(protector);
376✔
939

940
        // Generate IV from RNG.  The iv data size should be the total IV area
941
        // size minus the size of size field
942
        ivRNG.t.size = ivSize - sizeof(UINT16);
376✔
943
        CryptRandomGenerate(ivRNG.t.size, ivRNG.t.buffer);
376✔
944

945
        // Marshal IV to buffer
946
        buffer = sensitiveData;
376✔
947
        TPM2B_IV_Marshal(&ivRNG, &buffer, NULL);
376✔
948

949
        // adjust sensitive data starting after IV area
950
        sensitiveData += ivSize;
376✔
951

952
        // Use iv for encryption
953
        iv = &ivRNG;
376✔
954
    }
955
    // Compute symmetric key parameters for outer buffer encryption
956
    ComputeProtectionKeyParms(
411✔
957
        protector, hashAlg, name, seed, &symAlg, &keyBits, &symKey);
958
    // Encrypt inner buffer in place
959
    CryptSymmetricEncrypt(sensitiveData,
411✔
960
                          symAlg,
961
                          keyBits,
962
                          symKey.t.buffer,
963
                          iv,
964
                          TPM_ALG_CFB,
965
                          dataSize,
966
                          sensitiveData);
967
    // Compute outer integrity.  Integrity computation includes the optional IV
968
    // area
969
    ComputeOuterIntegrity(name,
411✔
970
                          protector,
971
                          hashAlg,
972
                          seed,
973
                          dataSize + ivSize,
411✔
974
                          outerBuffer + integritySize,
975
                          &integrity);
976
    // Add integrity at the beginning of outer buffer
977
    buffer = outerBuffer;
411✔
978
    TPM2B_DIGEST_Marshal(&integrity, &buffer, NULL);
411✔
979

980
    // return the total size in outer wrap
981
    return dataSize + integritySize + ivSize;
411✔
982
}
983

984
//*** UnwrapOuter()
985
// This function remove the outer wrap of a blob containing sensitive data
986
// This function performs:
987
//  1. check integrity of outer blob
988
//  2. decrypt outer blob
989
//
990
//  Return Type: TPM_RC
991
//      TPM_RCS_INSUFFICIENT     error during sensitive data unmarshaling
992
//      TPM_RCS_INTEGRITY        sensitive data integrity is broken
993
//      TPM_RCS_SIZE             error during sensitive data unmarshaling
994
//      TPM_RCS_VALUE            IV size for CFB does not match the encryption
995
//                               algorithm block size
996
TPM_RC
997
UnwrapOuter(OBJECT* protector,   // IN: The object that provides
442✔
998
                                 //     protection.  For object, it is parent
999
                                 //     handle. For credential, it is the
1000
                                 //     encrypt object.
1001
            TPM2B*     name,     // IN: the name of the object
1002
            TPM_ALG_ID hashAlg,  // IN: hash algorithm for outer wrap
1003
            TPM2B*     seed,     // IN: an external seed may be provided for
1004
                                 //     duplication blob. For non duplication
1005
                                 //     blob, this parameter should be NULL.
1006
            BOOL   useIV,        // IN: indicates if an IV is used
1007
            UINT16 dataSize,     // IN: size of sensitive data in outerBuffer,
1008
                                 //     including the leading integrity buffer
1009
                                 //     size, and an optional iv area
1010
            BYTE* outerBuffer    // IN/OUT: sensitive data
1011
)
1012
{
1013
    TPM_RC        result;
442✔
1014
    TPM_ALG_ID    symAlg = TPM_ALG_NULL;
442✔
1015
    TPM2B_SYM_KEY symKey;
442✔
1016
    UINT16        keyBits = 0;
442✔
1017
    TPM2B_IV      ivIn;  // input IV retrieved from input buffer
442✔
1018
    TPM2B_IV*     iv = NULL;
442✔
1019
    BYTE*         sensitiveData;  // pointer to the sensitive data
442✔
1020
    TPM2B_DIGEST  integrityToCompare;
442✔
1021
    TPM2B_DIGEST  integrity;
442✔
1022
    INT32         size;
442✔
1023
    //
1024
    // Unmarshal integrity
1025
    sensitiveData = outerBuffer;
442✔
1026
    size          = (INT32)dataSize;
442✔
1027
    result        = TPM2B_DIGEST_Unmarshal(&integrity, &sensitiveData, &size);
442✔
1028
    if(result == TPM_RC_SUCCESS)
442✔
1029
    {
1030
        // Compute integrity to compare
1031
        ComputeOuterIntegrity(name,
442✔
1032
                              protector,
1033
                              hashAlg,
1034
                              seed,
1035
                              (UINT16)size,
442✔
1036
                              sensitiveData,
1037
                              &integrityToCompare);
1038
        // Compare outer blob integrity
1039
        if(!MemoryEqual2B(&integrity.b, &integrityToCompare.b))
442✔
1040
            return TPM_RCS_INTEGRITY;
1041
        // Get the symmetric algorithm parameters used for encryption
1042
        ComputeProtectionKeyParms(
439✔
1043
            protector, hashAlg, name, seed, &symAlg, &keyBits, &symKey);
1044
        // Retrieve IV if it is used
1045
        if(useIV)
439✔
1046
        {
1047
            result = TPM2B_IV_Unmarshal(&ivIn, &sensitiveData, &size);
404✔
1048
            if(result == TPM_RC_SUCCESS)
404✔
1049
            {
1050
                // The input iv size for CFB must match the encryption algorithm
1051
                // block size
1052
                if(ivIn.t.size != CryptGetSymmetricBlockSize(symAlg, keyBits))
404✔
1053
                    result = TPM_RC_VALUE;
1054
                else
1055
                    iv = &ivIn;
1056
            }
1057
        }
1058
    }
1059
    // If no errors, decrypt private in place. Since this function uses CFB,
1060
    // CryptSymmetricDecrypt() will not return any errors. It may fail but it will
1061
    // not return an error.
1062
    if(result == TPM_RC_SUCCESS)
439✔
1063
        CryptSymmetricDecrypt(sensitiveData,
439✔
1064
                              symAlg,
1065
                              keyBits,
1066
                              symKey.t.buffer,
1067
                              iv,
1068
                              TPM_ALG_CFB,
1069
                              (UINT16)size,
439✔
1070
                              sensitiveData);
1071
    return result;
1072
}
1073

1074
//*** MarshalSensitive()
1075
// This function is used to marshal a sensitive area. Among other things, it
1076
// adjusts the size of the authValue to be no smaller than the digest of
1077
// 'nameAlg'
1078
// Returns the size of the marshaled area.
1079
static UINT16 MarshalSensitive(
409✔
1080
    OBJECT*         parent LIBTPMS_ATTR_UNUSED,     // IN: the object parent (optional)
1081
    BYTE*           buffer,     // OUT: receiving buffer
1082
    TPMT_SENSITIVE* sensitive,  // IN: the sensitive area to marshal
1083
    TPMI_ALG_HASH   nameAlg     // IN:
1084
)
1085
{
1086
    BYTE* sizeField = buffer;  // saved so that size can be
409✔
1087
                               // marshaled after it is known
1088
    UINT16 retVal;
409✔
1089
    //
1090
    // Pad the authValue if needed
1091
    MemoryPad2B(&sensitive->authValue.b, CryptHashGetDigestSize(nameAlg));
409✔
1092
    buffer += 2;
409✔
1093

1094
    // Marshal the structure
1095
#if 0 /* ALG_RSA */            // libtpms changed: We never set the RSA_prime_flag!
1096
    // If the sensitive size is the special case for a prime in the type
1097
    if((sensitive->sensitive.rsa.t.size & RSA_prime_flag) > 0)
1098
    {
1099
        UINT16 sizeSave = sensitive->sensitive.rsa.t.size;
1100
        //
1101
        // Turn off the flag that indicates that the sensitive->sensitive contains
1102
        // the CRT form of the exponent.
1103
        sensitive->sensitive.rsa.t.size &= ~(RSA_prime_flag);
1104
        // If the parent isn't fixedTPM, then truncate the sensitive data to be
1105
        // the size of the prime. Otherwise, leave it at the current size which
1106
        // is the full CRT size.
1107
        if(parent == NULL
1108
           || !IS_ATTRIBUTE(
1109
               parent->publicArea.objectAttributes, TPMA_OBJECT, fixedTPM))
1110
            sensitive->sensitive.rsa.t.size /= 5;
1111
        retVal = TPMT_SENSITIVE_Marshal(sensitive, &buffer, NULL);
1112
        // Restore the flag and the size.
1113
        sensitive->sensitive.rsa.t.size = sizeSave;
1114
    }
1115
    else
1116
#endif
1117
        retVal = TPMT_SENSITIVE_Marshal(sensitive, &buffer, NULL);
409✔
1118

1119
    // Marshal the size
1120
    retVal = (UINT16)(retVal + UINT16_Marshal(&retVal, &sizeField, NULL));
409✔
1121

1122
    return retVal;
409✔
1123
}
1124

1125
//*** SensitiveToPrivate()
1126
// This function prepare the private blob for off the chip storage
1127
// The operations in this function:
1128
//  1. marshal TPM2B_SENSITIVE structure into the buffer of TPM2B_PRIVATE
1129
//  2. apply encryption to the sensitive area.
1130
//  3. apply outer integrity computation.
1131
void SensitiveToPrivate(
376✔
1132
    TPMT_SENSITIVE* sensitive,  // IN: sensitive structure
1133
    TPM2B_NAME*     name,       // IN: the name of the object
1134
    OBJECT*         parent,     // IN: The parent object
1135
    TPM_ALG_ID      nameAlg,    // IN: hash algorithm in public area.  This
1136
                                //     parameter is used when parentHandle is
1137
                                //     NULL, in which case the object is
1138
                                //     temporary.
1139
    TPM2B_PRIVATE* outPrivate   // OUT: output private structure
1140
)
1141
{
1142
    BYTE*         sensitiveData;  // pointer to the sensitive data
376✔
1143
    UINT16        dataSize;       // data blob size
376✔
1144
    TPMI_ALG_HASH hashAlg;        // hash algorithm for integrity
376✔
1145
    UINT16        integritySize;
376✔
1146
    UINT16        ivSize;
376✔
1147
    //
1148
    pAssert(name != NULL && name->t.size != 0);
376✔
1149

1150
    // Find the hash algorithm for integrity computation
1151
    if(parent == NULL)
376✔
1152
    {
1153
        // For Temporary Object, using self name algorithm
1154
        hashAlg = nameAlg;
1155
    }
1156
    else
1157
    {
1158
        // Otherwise, using parent's name algorithm
1159
        hashAlg = parent->publicArea.nameAlg;
376✔
1160
    }
1161
    // Starting of sensitive data without wrappers
1162
    sensitiveData = outPrivate->t.buffer;
376✔
1163

1164
    // Compute the integrity size
1165
    integritySize = sizeof(UINT16) + CryptHashGetDigestSize(hashAlg);
376✔
1166

1167
    // Reserve space for integrity
1168
    sensitiveData += integritySize;
376✔
1169

1170
    // Get iv size
1171
    ivSize = GetIV2BSize(parent);
376✔
1172

1173
    // Reserve space for iv
1174
    sensitiveData += ivSize;
376✔
1175

1176
    // Marshal the sensitive area including authValue size adjustments.
1177
    dataSize = MarshalSensitive(parent, sensitiveData, sensitive, nameAlg);
376✔
1178

1179
    //Produce outer wrap, including encryption and HMAC
1180
    outPrivate->t.size = ProduceOuterWrap(
376✔
1181
        parent, &name->b, hashAlg, NULL, TRUE, dataSize, outPrivate->t.buffer);
1182
    return;
376✔
1183
}
1184

1185
//*** PrivateToSensitive()
1186
// Unwrap an input private area; check the integrity; decrypt and retrieve data
1187
// to a sensitive structure.
1188
// The operations in this function:
1189
//  1. check the integrity HMAC of the input private area
1190
//  2. decrypt the private buffer
1191
//  3. unmarshal TPMT_SENSITIVE structure into the buffer of TPMT_SENSITIVE
1192
//
1193
//  Return Type: TPM_RC
1194
//      TPM_RCS_INTEGRITY       if the private area integrity is bad
1195
//      TPM_RC_SENSITIVE        unmarshal errors while unmarshaling TPMS_ENCRYPT
1196
//                              from input private
1197
//      TPM_RCS_SIZE            error during sensitive data unmarshaling
1198
//      TPM_RCS_VALUE           outer wrapper does not have an iV of the correct
1199
//                              size
1200
TPM_RC
1201
PrivateToSensitive(TPM2B*     inPrivate,  // IN: input private structure
407✔
1202
                   TPM2B*     name,       // IN: the name of the object
1203
                   OBJECT*    parent,     // IN: parent object
1204
                   TPM_ALG_ID nameAlg,    // IN: hash algorithm in public area.  It is
1205
                   //     passed separately because we only pass
1206
                   //     name, rather than the whole public area
1207
                   //     of the object.  This parameter is used in
1208
                   //     the following two cases: 1. primary
1209
                   //     objects. 2. duplication blob with inner
1210
                   //     wrap.  In other cases, this parameter
1211
                   //     will be ignored
1212
                   TPMT_SENSITIVE* sensitive  // OUT: sensitive structure
1213
)
1214
{
1215
    TPM_RC        result;
407✔
1216
    BYTE*         buffer;
407✔
1217
    INT32         size;
407✔
1218
    BYTE*         sensitiveData;  // pointer to the sensitive data
407✔
1219
    UINT16        dataSize;
407✔
1220
    UINT16        dataSizeInput;
407✔
1221
    TPMI_ALG_HASH hashAlg;  // hash algorithm for integrity
407✔
1222
    UINT16        integritySize;
407✔
1223
    UINT16        ivSize;
407✔
1224
    //
1225
    // Make sure that name is provided
1226
    pAssert(name != NULL && name->size != 0);
407✔
1227

1228
    // Find the hash algorithm for integrity computation
1229
    // For Temporary Object (parent == NULL) use self name algorithm;
1230
    // Otherwise, using parent's name algorithm
1231
    hashAlg = (parent == NULL) ? nameAlg : parent->publicArea.nameAlg;
407✔
1232

1233
    // unwrap outer
1234
    result = UnwrapOuter(
814✔
1235
        parent, name, hashAlg, NULL, TRUE, inPrivate->size, inPrivate->buffer);
407✔
1236
    if(result != TPM_RC_SUCCESS)
407✔
1237
        return result;
1238
    // Compute the inner integrity size.
1239
    integritySize = sizeof(UINT16) + CryptHashGetDigestSize(hashAlg);
404✔
1240

1241
    // Get iv size
1242
    ivSize = GetIV2BSize(parent);
404✔
1243

1244
    // The starting of sensitive data and data size without outer wrapper
1245
    sensitiveData = inPrivate->buffer + integritySize + ivSize;
404✔
1246
    dataSize      = inPrivate->size - integritySize - ivSize;
404✔
1247

1248
    // Unmarshal input data size
1249
    buffer = sensitiveData;
404✔
1250
    size   = (INT32)dataSize;
404✔
1251
    result = UINT16_Unmarshal(&dataSizeInput, &buffer, &size);
404✔
1252
    if(result == TPM_RC_SUCCESS)
404✔
1253
    {
1254
        if((dataSizeInput + sizeof(UINT16)) != dataSize)
404✔
1255
            result = TPM_RC_SENSITIVE;
1256
        else
1257
        {
1258
            // Unmarshal sensitive buffer to sensitive structure
1259
            result = TPMT_SENSITIVE_Unmarshal(sensitive, &buffer, &size);
404✔
1260
            if(result != TPM_RC_SUCCESS || size != 0)
404✔
1261
            {
1262
                result = TPM_RC_SENSITIVE;
×
1263
            }
1264
        }
1265
    }
1266
    return result;
1267
}
1268

1269
//*** SensitiveToDuplicate()
1270
// This function prepare the duplication blob from the sensitive area.
1271
// The operations in this function:
1272
//  1. marshal TPMT_SENSITIVE structure into the buffer of TPM2B_PRIVATE
1273
//  2. apply inner wrap to the sensitive area if required
1274
//  3. apply outer wrap if required
1275
void SensitiveToDuplicate(
33✔
1276
    TPMT_SENSITIVE* sensitive,    // IN: sensitive structure
1277
    TPM2B*          name,         // IN: the name of the object
1278
    OBJECT*         parent,       // IN: The new parent object
1279
    TPM_ALG_ID      nameAlg,      // IN: hash algorithm in public area. It
1280
                                  //     is passed separately because we
1281
                                  //     only pass name, rather than the
1282
                                  //     whole public area of the object.
1283
    TPM2B* seed,                  // IN: the external seed. If external
1284
                                  //     seed is provided with size of 0,
1285
                                  //     no outer wrap should be applied
1286
                                  //     to duplication blob.
1287
    TPMT_SYM_DEF_OBJECT* symDef,  // IN: Symmetric key definition. If the
1288
                                  //     symmetric key algorithm is NULL,
1289
                                  //     no inner wrap should be applied.
1290
    TPM2B_DATA* innerSymKey,      // IN/OUT: a symmetric key may be
1291
                                  //     provided to encrypt the inner
1292
                                  //     wrap of a duplication blob. May
1293
                                  //     be generated here if needed.
1294
    TPM2B_PRIVATE* outPrivate     // OUT: output private structure
1295
)
1296
{
1297
    BYTE*         sensitiveData;             // pointer to the sensitive data
33✔
1298
    TPMI_ALG_HASH outerHash = TPM_ALG_NULL;  // The hash algorithm for outer wrap
33✔
1299
    TPMI_ALG_HASH innerHash = TPM_ALG_NULL;  // The hash algorithm for inner wrap
33✔
1300
    UINT16        dataSize;                  // data blob size
33✔
1301
    BOOL          doInnerWrap = FALSE;
33✔
1302
    BOOL          doOuterWrap = FALSE;
33✔
1303
    //
1304
    // Make sure that name is provided
1305
    pAssert(name != NULL && name->size != 0);
33✔
1306

1307
    // Make sure symDef and innerSymKey are not NULL
1308
    pAssert(symDef != NULL && innerSymKey != NULL);
33✔
1309

1310
    // Starting of sensitive data without wrappers
1311
    sensitiveData = outPrivate->t.buffer;
33✔
1312

1313
    // Find out if inner wrap is required
1314
    if(symDef->algorithm != TPM_ALG_NULL)
33✔
1315
    {
1316
        doInnerWrap = TRUE;
13✔
1317

1318
        // Use self nameAlg as inner hash algorithm
1319
        innerHash = nameAlg;
13✔
1320

1321
        // Adjust sensitive data pointer
1322
        sensitiveData += sizeof(UINT16) + CryptHashGetDigestSize(innerHash);
13✔
1323
    }
1324
    // Find out if outer wrap is required
1325
    if(seed->size != 0)
33✔
1326
    {
1327
        doOuterWrap = TRUE;
33✔
1328

1329
        // Use parent nameAlg as outer hash algorithm
1330
        outerHash = parent->publicArea.nameAlg;
33✔
1331

1332
        // Adjust sensitive data pointer
1333
        sensitiveData += sizeof(UINT16) + CryptHashGetDigestSize(outerHash);
33✔
1334
    }
1335
    // Marshal sensitive area
1336
    dataSize = MarshalSensitive(NULL, sensitiveData, sensitive, nameAlg);
33✔
1337

1338
    // Apply inner wrap for duplication blob.  It includes both integrity and
1339
    // encryption
1340
    if(doInnerWrap)
33✔
1341
    {
1342
        BYTE* innerBuffer = NULL;
13✔
1343
        BOOL  symKeyInput = TRUE;
13✔
1344
        innerBuffer       = outPrivate->t.buffer;
13✔
1345
        // Skip outer integrity space
1346
        if(doOuterWrap)
13✔
1347
            innerBuffer += sizeof(UINT16) + CryptHashGetDigestSize(outerHash);
13✔
1348
        dataSize = ProduceInnerIntegrity(name, innerHash, dataSize, innerBuffer);
13✔
1349
        // Generate inner encryption key if needed
1350
        if(innerSymKey->t.size == 0)
13✔
1351
        {
1352
            innerSymKey->t.size = (symDef->keyBits.sym + 7) / 8;
×
1353
            CryptRandomGenerate(innerSymKey->t.size, innerSymKey->t.buffer);
×
1354

1355
            // TPM generates symmetric encryption.  Set the flag to FALSE
1356
            symKeyInput = FALSE;
×
1357
        }
1358
        else
1359
        {
1360
            // assume the input key size should matches the symmetric definition
1361
            pAssert(innerSymKey->t.size == (symDef->keyBits.sym + 7) / 8);
13✔
1362
        }
1363

1364
        // Encrypt inner buffer in place
1365
        CryptSymmetricEncrypt(innerBuffer,
13✔
1366
                              symDef->algorithm,
13✔
1367
                              symDef->keyBits.sym,
13✔
1368
                              innerSymKey->t.buffer,
13✔
1369
                              NULL,
1370
                              TPM_ALG_CFB,
1371
                              dataSize,
1372
                              innerBuffer);
1373

1374
        // If the symmetric encryption key is imported, clear the buffer for
1375
        // output
1376
        if(symKeyInput)
13✔
1377
            innerSymKey->t.size = 0;
13✔
1378
    }
1379
    // Apply outer wrap for duplication blob.  It includes both integrity and
1380
    // encryption
1381
    if(doOuterWrap)
33✔
1382
    {
1383
        dataSize = ProduceOuterWrap(
33✔
1384
            parent, name, outerHash, seed, FALSE, dataSize, outPrivate->t.buffer);
1385
    }
1386
    // Data size for output
1387
    outPrivate->t.size = dataSize;
33✔
1388

1389
    return;
33✔
1390
}
1391

1392
//*** DuplicateToSensitive()
1393
// Unwrap a duplication blob.  Check the integrity, decrypt and retrieve data
1394
// to a sensitive structure.
1395
// The operations in this function:
1396
//  1. check the integrity HMAC of the input private area
1397
//  2. decrypt the private buffer
1398
//  3. unmarshal TPMT_SENSITIVE structure into the buffer of TPMT_SENSITIVE
1399
//
1400
//  Return Type: TPM_RC
1401
//      TPM_RC_INSUFFICIENT      unmarshaling sensitive data from 'inPrivate' failed
1402
//      TPM_RC_INTEGRITY         'inPrivate' data integrity is broken
1403
//      TPM_RC_SIZE              unmarshaling sensitive data from 'inPrivate' failed
1404
TPM_RC
1405
DuplicateToSensitive(
91✔
1406
    TPM2B*     inPrivate,         // IN: input private structure
1407
    TPM2B*     name,              // IN: the name of the object
1408
    OBJECT*    parent,            // IN: the parent
1409
    TPM_ALG_ID nameAlg,           // IN: hash algorithm in public area.
1410
    TPM2B*     seed,              // IN: an external seed may be provided.
1411
                                  //     If external seed is provided with
1412
                                  //     size of 0, no outer wrap is
1413
                                  //     applied
1414
    TPMT_SYM_DEF_OBJECT* symDef,  // IN: Symmetric key definition. If the
1415
                                  //     symmetric key algorithm is NULL,
1416
                                  //     no inner wrap is applied
1417
    TPM2B* innerSymKey,           // IN: a symmetric key may be provided
1418
                                  //     to decrypt the inner wrap of a
1419
                                  //     duplication blob.
1420
    TPMT_SENSITIVE* sensitive     // OUT: sensitive structure
1421
)
1422
{
1423
    TPM_RC result;
91✔
1424
    BYTE*  buffer;
91✔
1425
    INT32  size;
91✔
1426
    BYTE*  sensitiveData;  // pointer to the sensitive data
91✔
1427
    UINT16 dataSize;
91✔
1428
    UINT16 dataSizeInput;
91✔
1429
    //
1430
    // Make sure that name is provided
1431
    pAssert(name != NULL && name->size != 0);
91✔
1432

1433
    // Make sure symDef and innerSymKey are not NULL
1434
    pAssert(symDef != NULL && innerSymKey != NULL);
91✔
1435

1436
    // Starting of sensitive data
1437
    sensitiveData = inPrivate->buffer;
91✔
1438
    dataSize      = inPrivate->size;
91✔
1439

1440
    // Find out if outer wrap is applied
1441
    if(seed->size != 0)
91✔
1442
    {
1443
        // Use parent nameAlg as outer hash algorithm
1444
        TPMI_ALG_HASH outerHash = parent->publicArea.nameAlg;
33✔
1445

1446
        result                  = UnwrapOuter(
33✔
1447
            parent, name, outerHash, seed, FALSE, dataSize, sensitiveData);
1448
        if(result != TPM_RC_SUCCESS)
33✔
1449
            return result;
1450
        // Adjust sensitive data pointer and size
1451
        sensitiveData += sizeof(UINT16) + CryptHashGetDigestSize(outerHash);
33✔
1452
        dataSize -= sizeof(UINT16) + CryptHashGetDigestSize(outerHash);
33✔
1453
    }
1454
    // Find out if inner wrap is applied
1455
    if(symDef->algorithm != TPM_ALG_NULL)
91✔
1456
    {
1457
        // assume the input key size matches the symmetric definition
1458
        pAssert(innerSymKey->size == (symDef->keyBits.sym + 7) / 8);
13✔
1459

1460
        // Decrypt inner buffer in place
1461
        CryptSymmetricDecrypt(sensitiveData,
13✔
1462
                              symDef->algorithm,
1463
                              symDef->keyBits.sym,
1464
                              innerSymKey->buffer,
13✔
1465
                              NULL,
1466
                              TPM_ALG_CFB,
1467
                              dataSize,
1468
                              sensitiveData);
1469
        // Check inner integrity
1470
        result = CheckInnerIntegrity(name, nameAlg, dataSize, sensitiveData);
13✔
1471
        if(result != TPM_RC_SUCCESS)
13✔
1472
            return result;
1473
        // Adjust sensitive data pointer and size
1474
        sensitiveData += sizeof(UINT16) + CryptHashGetDigestSize(nameAlg);
13✔
1475
        dataSize -= sizeof(UINT16) + CryptHashGetDigestSize(nameAlg);
13✔
1476
    }
1477
    // Unmarshal input data size
1478
    buffer = sensitiveData;
91✔
1479
    size   = (INT32)dataSize;
91✔
1480
    result = UINT16_Unmarshal(&dataSizeInput, &buffer, &size);
91✔
1481
    if(result == TPM_RC_SUCCESS)
91✔
1482
    {
1483
        if((dataSizeInput + sizeof(UINT16)) != dataSize)
91✔
1484
            result = TPM_RC_SIZE;
1485
        else
1486
        {
1487
            // Unmarshal sensitive buffer to sensitive structure
1488
            result = TPMT_SENSITIVE_Unmarshal(sensitive, &buffer, &size);
91✔
1489

1490
            // if the results is OK make sure that all the data was unmarshaled
1491
            if(result == TPM_RC_SUCCESS && size != 0)
91✔
1492
                result = TPM_RC_SIZE;
×
1493
        }
1494
    }
1495
    return result;
1496
}
1497

1498
//*** SecretToCredential()
1499
// This function prepare the credential blob from a secret (a TPM2B_DIGEST)
1500
// The operations in this function:
1501
//  1. marshal TPM2B_DIGEST structure into the buffer of TPM2B_ID_OBJECT
1502
//  2. encrypt the private buffer, excluding the leading integrity HMAC area
1503
//  3. compute integrity HMAC and append to the beginning of the buffer.
1504
//  4. Set the total size of TPM2B_ID_OBJECT buffer
1505
void SecretToCredential(TPM2B_DIGEST*    secret,      // IN: secret information
1✔
1506
                        TPM2B*           name,        // IN: the name of the object
1507
                        TPM2B*           seed,        // IN: an external seed.
1508
                        OBJECT*          protector,   // IN: the protector
1509
                        TPM2B_ID_OBJECT* outIDObject  // OUT: output credential
1510
)
1511
{
1512
    BYTE*         buffer;         // Auxiliary buffer pointer
1✔
1513
    BYTE*         sensitiveData;  // pointer to the sensitive data
1✔
1514
    TPMI_ALG_HASH outerHash;      // The hash algorithm for outer wrap
1✔
1515
    UINT16        dataSize;       // data blob size
1✔
1516
                                  //
1517
    pAssert(secret != NULL && outIDObject != NULL);
1✔
1518

1519
    // use protector's name algorithm as outer hash ????
1520
    outerHash = protector->publicArea.nameAlg;
1✔
1521

1522
    // Marshal secret area to credential buffer, leave space for integrity
1523
    sensitiveData = outIDObject->t.credential + sizeof(UINT16)
2✔
1524
                    + CryptHashGetDigestSize(outerHash);
1✔
1525
    // Marshal secret area
1526
    buffer   = sensitiveData;
1✔
1527
    dataSize = TPM2B_DIGEST_Marshal(secret, &buffer, NULL);
1✔
1528

1529
    // Apply outer wrap
1530
    outIDObject->t.size = ProduceOuterWrap(
1✔
1531
        protector, name, outerHash, seed, FALSE, dataSize, outIDObject->t.credential);
1532
    return;
1✔
1533
}
1534

1535
//*** CredentialToSecret()
1536
// Unwrap a credential.  Check the integrity, decrypt and retrieve data
1537
// to a TPM2B_DIGEST structure.
1538
// The operations in this function:
1539
//  1. check the integrity HMAC of the input credential area
1540
//  2. decrypt the credential buffer
1541
//  3. unmarshal TPM2B_DIGEST structure into the buffer of TPM2B_DIGEST
1542
//
1543
//  Return Type: TPM_RC
1544
//      TPM_RC_INSUFFICIENT      error during credential unmarshaling
1545
//      TPM_RC_INTEGRITY         credential integrity is broken
1546
//      TPM_RC_SIZE              error during credential unmarshaling
1547
//      TPM_RC_VALUE             IV size does not match the encryption algorithm
1548
//                               block size
1549
TPM_RC
1550
CredentialToSecret(TPM2B*        inIDObject,  // IN: input credential blob
1✔
1551
                   TPM2B*        name,        // IN: the name of the object
1552
                   TPM2B*        seed,        // IN: an external seed.
1553
                   OBJECT*       protector,   // IN: the protector
1554
                   TPM2B_DIGEST* secret       // OUT: secret information
1555
)
1556
{
1557
    TPM_RC        result;
1✔
1558
    BYTE*         buffer;
1✔
1559
    INT32         size;
1✔
1560
    TPMI_ALG_HASH outerHash;      // The hash algorithm for outer wrap
1✔
1561
    BYTE*         sensitiveData;  // pointer to the sensitive data
1✔
1562
    UINT16        dataSize;
1✔
1563
    //
1564
    // use protector's name algorithm as outer hash
1565
    outerHash = protector->publicArea.nameAlg;
1✔
1566

1567
    // Unwrap outer, a TPM_RC_INTEGRITY error may be returned at this point
1568
    result = UnwrapOuter(protector,
2✔
1569
                         name,
1570
                         outerHash,
1571
                         seed,
1572
                         FALSE,
1573
                         inIDObject->size,
1✔
1574
                         inIDObject->buffer);
1✔
1575
    if(result == TPM_RC_SUCCESS)
1✔
1576
    {
1577
        // Compute the beginning of sensitive data
1578
        sensitiveData =
2✔
1579
            inIDObject->buffer + sizeof(UINT16) + CryptHashGetDigestSize(outerHash);
1✔
1580
        dataSize =
2✔
1581
            inIDObject->size - (sizeof(UINT16) + CryptHashGetDigestSize(outerHash));
1✔
1582
        // Unmarshal secret buffer to TPM2B_DIGEST structure
1583
        buffer = sensitiveData;
1✔
1584
        size   = (INT32)dataSize;
1✔
1585
        result = TPM2B_DIGEST_Unmarshal(secret, &buffer, &size);
1✔
1586

1587
        // If there were no other unmarshaling errors, make sure that the
1588
        // expected amount of data was recovered
1589
        if(result == TPM_RC_SUCCESS && size != 0)
1✔
1590
            return TPM_RC_SIZE;
×
1591
    }
1592
    return result;
1593
}
1594

1595
//*** MemoryRemoveTrailingZeros()
1596
// This function is used to adjust the length of an authorization value.
1597
// It adjusts the size of the TPM2B so that it does not include octets
1598
// at the end of the buffer that contain zero.
1599
// The function returns the number of non-zero octets in the buffer.
1600
UINT16
1601
MemoryRemoveTrailingZeros(TPM2B_AUTH* auth  // IN/OUT: value to adjust
14,595✔
1602
)
1603
{
1604
    while((auth->t.size > 0) && (auth->t.buffer[auth->t.size - 1] == 0))
90,807✔
1605
        auth->t.size--;
76,212✔
1606
    return auth->t.size;
14,595✔
1607
}
1608

1609
//*** SetLabelAndContext()
1610
// This function sets the label and context for a derived key. It is possible
1611
// that 'label' or 'context' can end up being an Empty Buffer.
1612
TPM_RC
1613
SetLabelAndContext(TPMS_DERIVE* labelContext,       // IN/OUT: the recovered label and
13✔
1614
                                                    //      context
1615
                   TPM2B_SENSITIVE_DATA* sensitive  // IN: the sensitive data
1616
)
1617
{
1618
    TPMS_DERIVE sensitiveValue;
13✔
1619
    TPM_RC      result;
13✔
1620
    INT32       size;
13✔
1621
    BYTE*       buff;
13✔
1622
    //
1623
    // Unmarshal a TPMS_DERIVE from the TPM2B_SENSITIVE_DATA buffer
1624
    // If there is something to unmarshal...
1625
    if(sensitive->t.size != 0)
13✔
1626
    {
1627
        size   = sensitive->t.size;
×
1628
        buff   = sensitive->t.buffer;
×
1629
        result = TPMS_DERIVE_Unmarshal(&sensitiveValue, &buff, &size);
×
1630
        if(result != TPM_RC_SUCCESS)
×
1631
            return result;
1632
        // If there was a label in the public area leave it there, otherwise, copy
1633
        // the new value
1634
        if(labelContext->label.t.size == 0)
×
1635
            MemoryCopy2B(&labelContext->label.b,
×
1636
                         &sensitiveValue.label.b,
1637
                         sizeof(labelContext->label.t.buffer));
1638
        // if there was a context string in publicArea, it overrides
1639
        if(labelContext->context.t.size == 0)
×
1640
            MemoryCopy2B(&labelContext->context.b,
×
1641
                         &sensitiveValue.context.b,
1642
                         sizeof(labelContext->label.t.buffer));
1643
    }
1644
    return TPM_RC_SUCCESS;
1645
}
1646

1647
//*** UnmarshalToPublic()
1648
// Support function to unmarshal the template. This is used because the
1649
// Input may be a TPMT_TEMPLATE and that structure does not have the same
1650
// size as a TPMT_PUBLIC because of the difference between the 'unique' and
1651
// 'seed' fields.
1652
// If 'derive' is not NULL, then the 'seed' field is assumed to contain
1653
// a 'label' and 'context' that are unmarshaled into 'derive'.
1654
TPM_RC
1655
UnmarshalToPublic(TPMT_PUBLIC*    tOut,  // OUT: output
58✔
1656
                  TPM2B_TEMPLATE* tIn,   // IN:
1657
                  BOOL derivation,       // IN: indicates if this is for a derivation
1658
                  TPMS_DERIVE* labelContext  // OUT: label and context if derivation
1659
)
1660
{
1661
    BYTE*  buffer = tIn->t.buffer;
58✔
1662
    INT32  size   = tIn->t.size;
58✔
1663
    TPM_RC result;
58✔
1664
    //
1665
    // make sure that tOut is zeroed so that there are no remnants from previous
1666
    // uses
1667
    MemorySet(tOut, 0, sizeof(TPMT_PUBLIC));
58✔
1668
    // Unmarshal the components of the TPMT_PUBLIC up to the unique field
1669
    result = TPMI_ALG_PUBLIC_Unmarshal(&tOut->type, &buffer, &size);
58✔
1670
    if(result != TPM_RC_SUCCESS)
58✔
1671
        return result;
1672
    result = TPMI_ALG_HASH_Unmarshal(&tOut->nameAlg, &buffer, &size, FALSE);
58✔
1673
    if(result != TPM_RC_SUCCESS)
58✔
1674
        return result;
1675
    result = TPMA_OBJECT_Unmarshal(&tOut->objectAttributes, &buffer, &size);
58✔
1676
    if(result != TPM_RC_SUCCESS)
58✔
1677
        return result;
1678
    result = TPM2B_DIGEST_Unmarshal(&tOut->authPolicy, &buffer, &size);
58✔
1679
    if(result != TPM_RC_SUCCESS)
58✔
1680
        return result;
1681
    result =
58✔
1682
        TPMU_PUBLIC_PARMS_Unmarshal(&tOut->parameters, &buffer, &size, tOut->type);
58✔
1683
    if(result != TPM_RC_SUCCESS)
58✔
1684
        return result;
1685
    // Now unmarshal a TPMS_DERIVE if this is for derivation
1686
    if(derivation)
58✔
1687
        result = TPMS_DERIVE_Unmarshal(labelContext, &buffer, &size);
13✔
1688
    else
1689
        // otherwise, unmarshal a TPMU_PUBLIC_ID
1690
        result = TPMU_PUBLIC_ID_Unmarshal(&tOut->unique, &buffer, &size, tOut->type);
45✔
1691
    // Make sure the template was used up
1692
    if((result == TPM_RC_SUCCESS) && (size != 0))
58✔
1693
        result = TPM_RC_SIZE;
×
1694
    return result;
1695
}
1696

1697
#if 0 /* libtpms added */
1698
//*** ObjectSetExternal()
1699
// Set the external attributes for an object.
1700
void ObjectSetExternal(OBJECT* object)
1701
{
1702
    object->attributes.external = SET;
1703
}
1704
#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