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