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     // Check authPolicy digest consistency
537     if(   publicArea->authPolicy.t.size != 0
538        && (    publicArea->authPolicy.t.size
539             != CryptGetHashDigestSize(publicArea->nameAlg)
540           )
541       )
542         return TPM_RC_SIZE;
543     // If the parent is fixedTPM (including a Primary Object) the object must have
544     // the same value for fixedTPM and fixedParent
545     if(     parentObject == NULL
546         || parentObject->publicArea.objectAttributes.fixedTPM == SET)
547     {
548         if(    publicArea->objectAttributes.fixedParent
549             != publicArea->objectAttributes.fixedTPM
550           )
551              return TPM_RC_ATTRIBUTES;
552     }
553     else
554         // The parent is not fixedTPM so the object can't be fixedTPM
555         if(publicArea->objectAttributes.fixedTPM == SET)
556              return TPM_RC_ATTRIBUTES;
557     // A restricted object cannot be both sign and decrypt and it can't be neither
558     // sign nor decrypt
559     if (    publicArea->objectAttributes.restricted == SET
560          && (    publicArea->objectAttributes.decrypt
561               == publicArea->objectAttributes.sign)
562        )
563          return TPM_RC_ATTRIBUTES;
564     // A fixedTPM object can not have encryptedDuplication bit SET
565     if(    publicArea->objectAttributes.fixedTPM == SET
566         && publicArea->objectAttributes.encryptedDuplication == SET)
567         return TPM_RC_ATTRIBUTES;
568     // If a parent object has fixedTPM CLEAR, the child must have the
569     // same encryptedDuplication value as its parent.
570     // Primary objects are considered to have a fixedTPM parent (the seeds).
571    if(       (   parentObject != NULL
572               && parentObject->publicArea.objectAttributes.fixedTPM == CLEAR)
573        // Get here if parent is not fixed TPM
574        && (     publicArea->objectAttributes.encryptedDuplication
575              != parentObject->publicArea.objectAttributes.encryptedDuplication
576            )
577       )
578         return TPM_RC_ATTRIBUTES;
579    return SchemeChecks(load, parentHandle, publicArea);
580 }
581 //
582 //
583 //            FillInCreationData()
584 //
585 //      Fill in creation data for an object.
586 //
587 void
FillInCreationData(TPMI_DH_OBJECT parentHandle,TPMI_ALG_HASH nameHashAlg,TPML_PCR_SELECTION * creationPCR,TPM2B_DATA * outsideData,TPM2B_CREATION_DATA * outCreation,TPM2B_DIGEST * creationDigest)588 FillInCreationData(
589     TPMI_DH_OBJECT                     parentHandle,    //   IN: handle of parent
590     TPMI_ALG_HASH                      nameHashAlg,     //   IN: name hash algorithm
591     TPML_PCR_SELECTION                *creationPCR,     //   IN: PCR selection
592     TPM2B_DATA                        *outsideData,     //   IN: outside data
593     TPM2B_CREATION_DATA               *outCreation,     //   OUT: creation data for output
594     TPM2B_DIGEST                      *creationDigest   //   OUT: creation digest
595 //
596    )
597 {
598    BYTE                     creationBuffer[sizeof(TPMS_CREATION_DATA)];
599    BYTE                    *buffer;
600    INT32                    bufferSize;
601    HASH_STATE               hashState;
602    // Fill in TPMS_CREATION_DATA in outCreation
603    // Compute PCR digest
604    PCRComputeCurrentDigest(nameHashAlg, creationPCR,
605                            &outCreation->t.creationData.pcrDigest);
606    // Put back PCR selection list
607    outCreation->t.creationData.pcrSelect = *creationPCR;
608    // Get locality
609    outCreation->t.creationData.locality
610        = LocalityGetAttributes(_plat__LocalityGet());
611    outCreation->t.creationData.parentNameAlg = TPM_ALG_NULL;
612    // If the parent is is either a primary seed or TPM_ALG_NULL, then the Name
613    // and QN of the parent are the parent's handle.
614    if(HandleGetType(parentHandle) == TPM_HT_PERMANENT)
615    {
616        BYTE         *buffer = &outCreation->t.creationData.parentName.t.name[0];
617        INT32         bufferSize = sizeof(TPM_HANDLE);
618        outCreation->t.creationData.parentName.t.size =
619             TPM_HANDLE_Marshal(&parentHandle, &buffer, &bufferSize);
620          // Parent qualified name of a Temporary Object is the same as parent's
621          // name
622          MemoryCopy2B(&outCreation->t.creationData.parentQualifiedName.b,
623                       &outCreation->t.creationData.parentName.b,
624                      sizeof(outCreation->t.creationData.parentQualifiedName.t.name));
625    }
626    else           // Regular object
627    {
628        OBJECT              *parentObject = ObjectGet(parentHandle);
629          // Set name algorithm
630          outCreation->t.creationData.parentNameAlg =
631              parentObject->publicArea.nameAlg;
632          // Copy parent name
633          outCreation->t.creationData.parentName = parentObject->name;
634          // Copy parent qualified name
635          outCreation->t.creationData.parentQualifiedName =
636              parentObject->qualifiedName;
637    }
638    // Copy outside information
639    outCreation->t.creationData.outsideInfo = *outsideData;
640    // Marshal creation data to canonical form
641    buffer = creationBuffer;
642    bufferSize = sizeof(TPMS_CREATION_DATA);
643    outCreation->t.size = TPMS_CREATION_DATA_Marshal(&outCreation->t.creationData,
644                          &buffer, &bufferSize);
645    // Compute hash for creation field in public template
646    creationDigest->t.size = CryptStartHash(nameHashAlg, &hashState);
647    CryptUpdateDigest(&hashState, outCreation->t.size, creationBuffer);
648    CryptCompleteHash2B(&hashState, &creationDigest->b);
649    return;
650 }
651 //           GetSeedForKDF()
652 //
653 //      Get a seed for KDF. The KDF for encryption and HMAC key use the same seed. It returns a pointer to
654 //      the seed
655 //
656 TPM2B_SEED*
GetSeedForKDF(TPM_HANDLE protectorHandle,TPM2B_SEED * seedIn)657 GetSeedForKDF(
658     TPM_HANDLE           protectorHandle,          // IN: the protector handle
659     TPM2B_SEED          *seedIn                    // IN: the optional input seed
660     )
661 {
662     OBJECT                   *protector = NULL; // Pointer to the protector
663     // Get seed for encryption key. Use input seed if provided.
664     // Otherwise, using protector object's seedValue. TPM_RH_NULL is the only
665     // exception that we may not have a loaded object as protector. In such a
666     // case, use nullProof as seed.
667     if(seedIn != NULL)
668     {
669         return seedIn;
670     }
671     else
672     {
673         if(protectorHandle == TPM_RH_NULL)
674         {
675              return (TPM2B_SEED *) &gr.nullProof;
676         }
677         else
678         {
679              protector = ObjectGet(protectorHandle);
680              return (TPM2B_SEED *) &protector->sensitive.seedValue;
681         }
682     }
683 }
684 //
685 //
686 //           ProduceOuterWrap()
687 //
688 //      This function produce outer wrap for a buffer containing the sensitive data. It requires the sensitive data
689 //      being marshaled to the outerBuffer, with the leading bytes reserved for integrity hash. If iv is used, iv
690 //      space should be reserved at the beginning of the buffer. It assumes the sensitive data starts at address
691 //      (outerBuffer + integrity size {+ iv size}). This function performs:
692 //      a) Add IV before sensitive area if required
693 //      b) encrypt sensitive data, if iv is required, encrypt by iv. otherwise, encrypted by a NULL iv
694 //      c) add HMAC integrity at the beginning of the buffer It returns the total size of blob with outer wrap
695 //
696 UINT16
ProduceOuterWrap(TPM_HANDLE protector,TPM2B_NAME * name,TPM_ALG_ID hashAlg,TPM2B_SEED * seed,BOOL useIV,UINT16 dataSize,BYTE * outerBuffer)697 ProduceOuterWrap(
698     TPM_HANDLE           protector,          //   IN: The handle of the object that provides
699                                              //       protection. For object, it is parent
700                                              //       handle. For credential, it is the handle
701                                              //       of encrypt object.
702     TPM2B_NAME          *name,               //   IN: the name of the object
703     TPM_ALG_ID           hashAlg,            //   IN: hash algorithm for outer wrap
704     TPM2B_SEED          *seed,               //   IN: an external seed may be provided for
705                                              //       duplication blob. For non duplication
706                                              //       blob, this parameter should be NULL
707     BOOL                 useIV,              //   IN: indicate if an IV is used
708     UINT16               dataSize,           //   IN: the size of sensitive data, excluding the
709                                              //       leading integrity buffer size or the
710                                              //       optional iv size
711     BYTE                *outerBuffer         //   IN/OUT: outer buffer with sensitive data in
712                                        //     it
713    )
714 {
715    TPM_ALG_ID         symAlg;
716    UINT16             keyBits;
717    TPM2B_SYM_KEY      symKey;
718    TPM2B_IV           ivRNG;           // IV from RNG
719    TPM2B_IV           *iv = NULL;
720    UINT16             ivSize = 0;      // size of iv area, including the size field
721    BYTE               *sensitiveData; // pointer to the sensitive data
722    TPM2B_DIGEST       integrity;
723    UINT16             integritySize;
724    BYTE               *buffer;         // Auxiliary buffer pointer
725    INT32              bufferSize;
726    // Compute the beginning of sensitive data. The outer integrity should
727    // always exist if this function function is called to make an outer wrap
728    integritySize = sizeof(UINT16) + CryptGetHashDigestSize(hashAlg);
729    sensitiveData = outerBuffer + integritySize;
730    // If iv is used, adjust the pointer of sensitive data and add iv before it
731    if(useIV)
732    {
733        ivSize = GetIV2BSize(protector);
734          // Generate IV from RNG. The iv data size should be the total IV area
735          // size minus the size of size field
736          ivRNG.t.size = ivSize - sizeof(UINT16);
737          CryptGenerateRandom(ivRNG.t.size, ivRNG.t.buffer);
738          // Marshal IV to buffer
739          buffer = sensitiveData;
740          bufferSize = sizeof(TPM2B_IV);
741          TPM2B_IV_Marshal(&ivRNG, &buffer, &bufferSize);
742          // adjust sensitive data starting after IV area
743          sensitiveData += ivSize;
744          // Use iv for encryption
745          iv = &ivRNG;
746    }
747    // Compute symmetric key parameters for outer buffer encryption
748    ComputeProtectionKeyParms(protector, hashAlg, name, seed,
749                              &symAlg, &keyBits, &symKey);
750    // Encrypt inner buffer in place
751    CryptSymmetricEncrypt(sensitiveData, symAlg, keyBits,
752                          TPM_ALG_CFB, symKey.t.buffer, iv, dataSize,
753                          sensitiveData);
754    // Compute outer integrity. Integrity computation includes the optional IV
755    // area
756    ComputeOuterIntegrity(name, protector, hashAlg, seed, dataSize + ivSize,
757                          outerBuffer + integritySize, &integrity);
758    // Add integrity at the beginning of outer buffer
759    buffer = outerBuffer;
760    bufferSize = sizeof(TPM2B_DIGEST);
761    TPM2B_DIGEST_Marshal(&integrity, &buffer, &bufferSize);
762    // return the total size in outer wrap
763    return dataSize + integritySize + ivSize;
764 }
765 //
766 //
767 //
768 //           UnwrapOuter()
769 //
770 //      This function remove the outer wrap of a blob containing sensitive data This function performs:
771 //      a) check integrity of outer blob
772 //      b) decrypt outer blob
773 //
774 //      Error Returns                      Meaning
775 //
776 //      TPM_RC_INSUFFICIENT                error during sensitive data unmarshaling
777 //      TPM_RC_INTEGRITY                   sensitive data integrity is broken
778 //      TPM_RC_SIZE                        error during sensitive data unmarshaling
779 //      TPM_RC_VALUE                       IV size for CFB does not match the encryption algorithm block size
780 //
781 TPM_RC
UnwrapOuter(TPM_HANDLE protector,TPM2B_NAME * name,TPM_ALG_ID hashAlg,TPM2B_SEED * seed,BOOL useIV,UINT16 dataSize,BYTE * outerBuffer)782 UnwrapOuter(
783    TPM_HANDLE           protector,             //   IN: The handle of the object that provides
784                                                //       protection. For object, it is parent
785                                                //       handle. For credential, it is the handle
786                                                //       of encrypt object.
787    TPM2B_NAME          *name,                  //   IN: the name of the object
788    TPM_ALG_ID           hashAlg,               //   IN: hash algorithm for outer wrap
789    TPM2B_SEED          *seed,                  //   IN: an external seed may be provided for
790                                                //       duplication blob. For non duplication
791                                                //       blob, this parameter should be NULL.
792    BOOL                 useIV,                 //   IN: indicates if an IV is used
793    UINT16               dataSize,              //   IN: size of sensitive data in outerBuffer,
794                                                //       including the leading integrity buffer
795                                                //       size, and an optional iv area
796    BYTE                *outerBuffer            //   IN/OUT: sensitive data
797    )
798 {
799    TPM_RC              result;
800    TPM_ALG_ID          symAlg = TPM_ALG_NULL;
801    TPM2B_SYM_KEY       symKey;
802    UINT16              keyBits = 0;
803    TPM2B_IV            ivIn;               // input IV retrieved from input buffer
804    TPM2B_IV            *iv = NULL;
805    BYTE                *sensitiveData;               // pointer to the sensitive data
806    TPM2B_DIGEST        integrityToCompare;
807    TPM2B_DIGEST        integrity;
808    INT32               size;
809    // Unmarshal integrity
810    sensitiveData = outerBuffer;
811    size = (INT32) dataSize;
812    result = TPM2B_DIGEST_Unmarshal(&integrity, &sensitiveData, &size);
813    if(result == TPM_RC_SUCCESS)
814    {
815        // Compute integrity to compare
816        ComputeOuterIntegrity(name, protector, hashAlg, seed,
817                              (UINT16) size, sensitiveData,
818                              &integrityToCompare);
819          // Compare outer blob integrity
820          if(!Memory2BEqual(&integrity.b, &integrityToCompare.b))
821              return TPM_RC_INTEGRITY;
822          // Get the symmetric algorithm parameters used for encryption
823          ComputeProtectionKeyParms(protector, hashAlg, name, seed,
824                                           &symAlg, &keyBits, &symKey);
825          // Retrieve IV if it is used
826          if(useIV)
827          {
828              result = TPM2B_IV_Unmarshal(&ivIn, &sensitiveData, &size);
829              if(result == TPM_RC_SUCCESS)
830              {
831                  // The input iv size for CFB must match the encryption algorithm
832                  // block size
833                  if(ivIn.t.size != CryptGetSymmetricBlockSize(symAlg, keyBits))
834                      result = TPM_RC_VALUE;
835                  else
836                      iv = &ivIn;
837              }
838          }
839     }
840     // If no errors, decrypt private in place
841     if(result == TPM_RC_SUCCESS)
842         CryptSymmetricDecrypt(sensitiveData, symAlg, keyBits,
843                               TPM_ALG_CFB, symKey.t.buffer, iv,
844                               (UINT16) size, sensitiveData);
845     return result;
846 }
847 //
848 //
849 //           SensitiveToPrivate()
850 //
851 //      This function prepare the private blob for off the chip storage The operations in this function:
852 //      a) marshal TPM2B_SENSITIVE structure into the buffer of TPM2B_PRIVATE
853 //      b) apply encryption to the sensitive area.
854 //      c) apply outer integrity computation.
855 //
856 void
SensitiveToPrivate(TPMT_SENSITIVE * sensitive,TPM2B_NAME * name,TPM_HANDLE parentHandle,TPM_ALG_ID nameAlg,TPM2B_PRIVATE * outPrivate)857 SensitiveToPrivate(
858     TPMT_SENSITIVE      *sensitive,         //   IN: sensitive structure
859     TPM2B_NAME          *name,              //   IN: the name of the object
860     TPM_HANDLE           parentHandle,      //   IN: The parent's handle
861     TPM_ALG_ID           nameAlg,           //   IN: hash algorithm in public area. This
862                                             //       parameter is used when parentHandle is
863                                             //       NULL, in which case the object is
864                                             //       temporary.
865     TPM2B_PRIVATE       *outPrivate         //   OUT: output private structure
866     )
867 {
868     BYTE                     *buffer;                  //   Auxiliary buffer pointer
869     INT32                    bufferSize;
870     BYTE                     *sensitiveData;           //   pointer to the sensitive data
871     UINT16                   dataSize;                 //   data blob size
872     TPMI_ALG_HASH            hashAlg;                  //   hash algorithm for integrity
873     UINT16                   integritySize;
874     UINT16                   ivSize;
875     pAssert(name != NULL && name->t.size != 0);
876     // Find the hash algorithm for integrity computation
877     if(parentHandle == TPM_RH_NULL)
878     {
879         // For Temporary Object, using self name algorithm
880         hashAlg = nameAlg;
881     }
882     else
883    {
884          // Otherwise, using parent's name algorithm
885          hashAlg = ObjectGetNameAlg(parentHandle);
886    }
887    // Starting of sensitive data without wrappers
888    sensitiveData = outPrivate->t.buffer;
889    // Compute the integrity size
890    integritySize = sizeof(UINT16) + CryptGetHashDigestSize(hashAlg);
891    // Reserve space for integrity
892    sensitiveData += integritySize;
893    // Get iv size
894    ivSize = GetIV2BSize(parentHandle);
895    // Reserve space for iv
896    sensitiveData += ivSize;
897    // Marshal sensitive area, leaving the leading 2 bytes for size
898    buffer = sensitiveData + sizeof(UINT16);
899    bufferSize = sizeof(TPMT_SENSITIVE);
900    dataSize = TPMT_SENSITIVE_Marshal(sensitive, &buffer, &bufferSize);
901    // Adding size before the data area
902    buffer = sensitiveData;
903    bufferSize = sizeof(UINT16);
904    UINT16_Marshal(&dataSize, &buffer, &bufferSize);
905    // Adjust the dataSize to include the size field
906    dataSize += sizeof(UINT16);
907    // Adjust the pointer to inner buffer including the iv
908    sensitiveData = outPrivate->t.buffer + ivSize;
909    //Produce outer wrap, including encryption and HMAC
910    outPrivate->t.size = ProduceOuterWrap(parentHandle, name, hashAlg, NULL,
911                                          TRUE, dataSize, outPrivate->t.buffer);
912    return;
913 }
914 //
915 //
916 //           PrivateToSensitive()
917 //
918 //      Unwrap a input private area. Check the integrity, decrypt and retrieve data to a sensitive structure. The
919 //      operations in this function:
920 //      a) check the integrity HMAC of the input private area
921 //      b) decrypt the private buffer
922 //      c) unmarshal TPMT_SENSITIVE structure into the buffer of TPMT_SENSITIVE
923 //
924 //      Error Returns                   Meaning
925 //
926 //      TPM_RC_INTEGRITY                if the private area integrity is bad
927 //      TPM_RC_SENSITIVE                unmarshal errors while unmarshaling TPMS_ENCRYPT from input
928 //                                      private
929 //      TPM_RC_VALUE                    outer wrapper does not have an iV of the correct size
930 //
931 TPM_RC
PrivateToSensitive(TPM2B_PRIVATE * inPrivate,TPM2B_NAME * name,TPM_HANDLE parentHandle,TPM_ALG_ID nameAlg,TPMT_SENSITIVE * sensitive)932 PrivateToSensitive(
933    TPM2B_PRIVATE       *inPrivate,          // IN: input private structure
934    TPM2B_NAME          *name,               // IN: the name of the object
935    TPM_HANDLE          parentHandle,    // IN: The parent's handle
936    TPM_ALG_ID          nameAlg,         // IN: hash algorithm in public area. It is
937                                         //     passed separately because we only pass
938                                         //     name, rather than the whole public area
939                                         //     of the object. This parameter is used in
940                                         //     the following two cases: 1. primary
941                                         //     objects. 2. duplication blob with inner
942                                         //     wrap. In other cases, this parameter
943                                         //     will be ignored
944    TPMT_SENSITIVE     *sensitive        // OUT: sensitive structure
945    )
946 {
947    TPM_RC             result;
948    BYTE               *buffer;
949    INT32              size;
950    BYTE               *sensitiveData; // pointer to the sensitive data
951    UINT16             dataSize;
952    UINT16             dataSizeInput;
953    TPMI_ALG_HASH      hashAlg;        // hash algorithm for integrity
954    OBJECT             *parent = NULL;
955    UINT16             integritySize;
956    UINT16             ivSize;
957    // Make sure that name is provided
958    pAssert(name != NULL && name->t.size != 0);
959    // Find the hash algorithm for integrity computation
960    if(parentHandle == TPM_RH_NULL)
961    {
962        // For Temporary Object, using self name algorithm
963        hashAlg = nameAlg;
964    }
965    else
966    {
967        // Otherwise, using parent's name algorithm
968        hashAlg = ObjectGetNameAlg(parentHandle);
969    }
970    // unwrap outer
971    result = UnwrapOuter(parentHandle, name, hashAlg, NULL, TRUE,
972                         inPrivate->t.size, inPrivate->t.buffer);
973    if(result != TPM_RC_SUCCESS)
974        return result;
975    // Compute the inner integrity size.
976    integritySize = sizeof(UINT16) + CryptGetHashDigestSize(hashAlg);
977    // Get iv size
978    ivSize = GetIV2BSize(parentHandle);
979    // The starting of sensitive data and data size without outer wrapper
980    sensitiveData = inPrivate->t.buffer + integritySize + ivSize;
981    dataSize = inPrivate->t.size - integritySize - ivSize;
982    // Unmarshal input data size
983    buffer = sensitiveData;
984    size = (INT32) dataSize;
985    result = UINT16_Unmarshal(&dataSizeInput, &buffer, &size);
986    if(result == TPM_RC_SUCCESS)
987    {
988        if((dataSizeInput + sizeof(UINT16)) != dataSize)
989             result = TPM_RC_SENSITIVE;
990        else
991        {
992               // Unmarshal sensitive buffer to sensitive structure
993               result = TPMT_SENSITIVE_Unmarshal(sensitive, &buffer, &size);
994               if(result != TPM_RC_SUCCESS || size != 0)
995               {
996                   pAssert(    (parent == NULL)
997                            || parent->publicArea.objectAttributes.fixedTPM == CLEAR);
998                   result = TPM_RC_SENSITIVE;
999               }
1000               else
1001               {
1002                   // Always remove trailing zeros at load so that it is not necessary
1003                   // to check
1004                   // each time auth is checked.
1005                   MemoryRemoveTrailingZeros(&(sensitive->authValue));
1006               }
1007         }
1008     }
1009     return result;
1010 }
1011 //
1012 //
1013 //          SensitiveToDuplicate()
1014 //
1015 //      This function prepare the duplication blob from the sensitive area. The operations in this function:
1016 //      a) marshal TPMT_SENSITIVE structure into the buffer of TPM2B_PRIVATE
1017 //      b) apply inner wrap to the sensitive area if required
1018 //      c) apply outer wrap if required
1019 //
1020 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)1021 SensitiveToDuplicate(
1022     TPMT_SENSITIVE                *sensitive,          //   IN: sensitive structure
1023     TPM2B_NAME                    *name,               //   IN: the name of the object
1024     TPM_HANDLE                     parentHandle,       //   IN: The new parent's handle
1025     TPM_ALG_ID                     nameAlg,            //   IN: hash algorithm in public area. It
1026                                                        //       is passed separately because we
1027                                                        //       only pass name, rather than the
1028                                                        //       whole public area of the object.
1029     TPM2B_SEED                    *seed,               //   IN: the external seed. If external
1030                                                        //       seed is provided with size of 0,
1031                                                        //       no outer wrap should be applied
1032                                                        //       to duplication blob.
1033     TPMT_SYM_DEF_OBJECT           *symDef,             //   IN: Symmetric key definition. If the
1034                                                        //       symmetric key algorithm is NULL,
1035                                                        //       no inner wrap should be applied.
1036     TPM2B_DATA                    *innerSymKey,        //   IN/OUT: a symmetric key may be
1037                                                        //       provided to encrypt the inner
1038                                                        //       wrap of a duplication blob. May
1039                                                        //       be generated here if needed.
1040     TPM2B_PRIVATE                 *outPrivate          //   OUT: output private structure
1041     )
1042 {
1043     BYTE                *buffer;        // Auxiliary buffer pointer
1044     INT32               bufferSize;
1045     BYTE                *sensitiveData; // pointer to the sensitive data
1046     TPMI_ALG_HASH       outerHash = TPM_ALG_NULL;// The hash algorithm for outer wrap
1047     TPMI_ALG_HASH       innerHash = TPM_ALG_NULL;// The hash algorithm for inner wrap
1048     UINT16              dataSize;       // data blob size
1049     BOOL                doInnerWrap = FALSE;
1050     BOOL                doOuterWrap = FALSE;
1051     // Make sure that name is provided
1052     pAssert(name != NULL && name->t.size != 0);
1053     // Make sure symDef and innerSymKey are not NULL
1054    pAssert(symDef != NULL && innerSymKey != NULL);
1055    // Starting of sensitive data without wrappers
1056    sensitiveData = outPrivate->t.buffer;
1057    // Find out if inner wrap is required
1058    if(symDef->algorithm != TPM_ALG_NULL)
1059    {
1060        doInnerWrap = TRUE;
1061        // Use self nameAlg as inner hash algorithm
1062        innerHash = nameAlg;
1063        // Adjust sensitive data pointer
1064        sensitiveData += sizeof(UINT16) + CryptGetHashDigestSize(innerHash);
1065    }
1066    // Find out if outer wrap is required
1067    if(seed->t.size != 0)
1068    {
1069        doOuterWrap = TRUE;
1070        // Use parent nameAlg as outer hash algorithm
1071        outerHash = ObjectGetNameAlg(parentHandle);
1072        // Adjust sensitive data pointer
1073        sensitiveData += sizeof(UINT16) + CryptGetHashDigestSize(outerHash);
1074    }
1075    // Marshal sensitive area, leaving the leading 2 bytes for size
1076    buffer = sensitiveData + sizeof(UINT16);
1077    bufferSize = sizeof(TPMT_SENSITIVE);
1078    dataSize = TPMT_SENSITIVE_Marshal(sensitive, &buffer, &bufferSize);
1079    // Adding size before the data area
1080    buffer = sensitiveData;
1081    bufferSize = sizeof(UINT16);
1082    UINT16_Marshal(&dataSize, &buffer, &bufferSize);
1083    // Adjust the dataSize to include the size field
1084    dataSize += sizeof(UINT16);
1085    // Apply inner wrap for duplication blob. It includes both integrity and
1086    // encryption
1087    if(doInnerWrap)
1088    {
1089        BYTE             *innerBuffer = NULL;
1090        BOOL             symKeyInput = TRUE;
1091        innerBuffer = outPrivate->t.buffer;
1092        // Skip outer integrity space
1093        if(doOuterWrap)
1094             innerBuffer += sizeof(UINT16) + CryptGetHashDigestSize(outerHash);
1095        dataSize = ProduceInnerIntegrity(name, innerHash, dataSize,
1096                                          innerBuffer);
1097         // Generate inner encryption key if needed
1098         if(innerSymKey->t.size == 0)
1099         {
1100             innerSymKey->t.size = (symDef->keyBits.sym + 7) / 8;
1101             CryptGenerateRandom(innerSymKey->t.size, innerSymKey->t.buffer);
1102              // TPM generates symmetric encryption.   Set the flag to FALSE
1103              symKeyInput = FALSE;
1104         }
1105         else
1106         {
1107              // assume the input key size should matches the symmetric definition
1108              pAssert(innerSymKey->t.size == (symDef->keyBits.sym + 7) / 8);
1109         }
1110         // Encrypt inner buffer in place
1111           CryptSymmetricEncrypt(innerBuffer, symDef->algorithm,
1112                                 symDef->keyBits.sym, TPM_ALG_CFB,
1113                                 innerSymKey->t.buffer, NULL, dataSize,
1114                                 innerBuffer);
1115           // If the symmetric encryption key is imported, clear the buffer for
1116           // output
1117           if(symKeyInput)
1118               innerSymKey->t.size = 0;
1119    }
1120    // Apply outer wrap for duplication blob. It includes both integrity and
1121    // encryption
1122    if(doOuterWrap)
1123    {
1124        dataSize = ProduceOuterWrap(parentHandle, name, outerHash, seed, FALSE,
1125                                    dataSize, outPrivate->t.buffer);
1126    }
1127    // Data size for output
1128    outPrivate->t.size = dataSize;
1129    return;
1130 }
1131 //
1132 //
1133 //           DuplicateToSensitive()
1134 //
1135 //       Unwrap a duplication blob. Check the integrity, decrypt and retrieve data to a sensitive structure. The
1136 //       operations in this function:
1137 //       a) check the integrity HMAC of the input private area
1138 //       b) decrypt the private buffer
1139 //       c) unmarshal TPMT_SENSITIVE structure into the buffer of TPMT_SENSITIVE
1140 //
1141 //       Error Returns                   Meaning
1142 //
1143 //       TPM_RC_INSUFFICIENT             unmarshaling sensitive data from inPrivate failed
1144 //       TPM_RC_INTEGRITY                inPrivate data integrity is broken
1145 //       TPM_RC_SIZE                     unmarshaling sensitive data from inPrivate failed
1146 //
1147 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)1148 DuplicateToSensitive(
1149    TPM2B_PRIVATE                 *inPrivate,           //   IN: input private structure
1150    TPM2B_NAME                    *name,                //   IN: the name of the object
1151    TPM_HANDLE                     parentHandle,        //   IN: The parent's handle
1152    TPM_ALG_ID                     nameAlg,             //   IN: hash algorithm in public area.
1153    TPM2B_SEED                    *seed,                //   IN: an external seed may be provided.
1154                                                        //       If external seed is provided with
1155                                                        //       size of 0, no outer wrap is
1156                                                        //       applied
1157    TPMT_SYM_DEF_OBJECT           *symDef,              //   IN: Symmetric key definition. If the
1158                                                        //       symmetric key algorithm is NULL,
1159                                                        //       no inner wrap is applied
1160    TPM2B_DATA                    *innerSymKey,         //   IN: a symmetric key may be provided
1161                                                        //       to decrypt the inner wrap of a
1162                                                        //       duplication blob.
1163    TPMT_SENSITIVE                *sensitive            //   OUT: sensitive structure
1164    )
1165 {
1166    TPM_RC              result;
1167    BYTE               *buffer;
1168    INT32              size;
1169    BYTE               *sensitiveData; // pointer to the sensitive data
1170    UINT16             dataSize;
1171    UINT16             dataSizeInput;
1172    // Make sure that name is provided
1173    pAssert(name != NULL && name->t.size != 0);
1174    // Make sure symDef and innerSymKey are not NULL
1175    pAssert(symDef != NULL && innerSymKey != NULL);
1176    // Starting of sensitive data
1177    sensitiveData = inPrivate->t.buffer;
1178    dataSize = inPrivate->t.size;
1179    // Find out if outer wrap is applied
1180    if(seed->t.size != 0)
1181    {
1182        TPMI_ALG_HASH   outerHash = TPM_ALG_NULL;
1183         // Use parent nameAlg as outer hash algorithm
1184         outerHash = ObjectGetNameAlg(parentHandle);
1185         result = UnwrapOuter(parentHandle, name, outerHash, seed, FALSE,
1186                              dataSize, sensitiveData);
1187         if(result != TPM_RC_SUCCESS)
1188             return result;
1189         // Adjust sensitive data pointer and size
1190         sensitiveData += sizeof(UINT16) + CryptGetHashDigestSize(outerHash);
1191         dataSize -= sizeof(UINT16) + CryptGetHashDigestSize(outerHash);
1192    }
1193    // Find out if inner wrap is applied
1194    if(symDef->algorithm != TPM_ALG_NULL)
1195    {
1196        TPMI_ALG_HASH   innerHash = TPM_ALG_NULL;
1197         // assume the input key size should matches the symmetric definition
1198         pAssert(innerSymKey->t.size == (symDef->keyBits.sym + 7) / 8);
1199         // Decrypt inner buffer in place
1200         CryptSymmetricDecrypt(sensitiveData, symDef->algorithm,
1201                               symDef->keyBits.sym, TPM_ALG_CFB,
1202                               innerSymKey->t.buffer, NULL, dataSize,
1203                               sensitiveData);
1204         // Use self nameAlg as inner hash algorithm
1205         innerHash = nameAlg;
1206         // Check inner integrity
1207         result = CheckInnerIntegrity(name, innerHash, dataSize, sensitiveData);
1208         if(result != TPM_RC_SUCCESS)
1209             return result;
1210         // Adjust sensitive data pointer and size
1211         sensitiveData += sizeof(UINT16) + CryptGetHashDigestSize(innerHash);
1212         dataSize -= sizeof(UINT16) + CryptGetHashDigestSize(innerHash);
1213    }
1214    // Unmarshal input data size
1215    buffer = sensitiveData;
1216    size = (INT32) dataSize;
1217    result = UINT16_Unmarshal(&dataSizeInput, &buffer, &size);
1218    if(result == TPM_RC_SUCCESS)
1219    {
1220        if((dataSizeInput + sizeof(UINT16)) != dataSize)
1221               result = TPM_RC_SIZE;
1222           else
1223           {
1224               // Unmarshal sensitive buffer to sensitive structure
1225               result = TPMT_SENSITIVE_Unmarshal(sensitive, &buffer, &size);
1226               // if the results is OK make sure that all the data was unmarshaled
1227               if(result == TPM_RC_SUCCESS && size != 0)
1228                   result = TPM_RC_SIZE;
1229        }
1230    }
1231    // Always remove trailing zeros at load so that it is not necessary to check
1232    // each time auth is checked.
1233    if(result == TPM_RC_SUCCESS)
1234        MemoryRemoveTrailingZeros(&(sensitive->authValue));
1235    return result;
1236 }
1237 //
1238 //
1239 //           SecretToCredential()
1240 //
1241 //       This function prepare the credential blob from a secret (a TPM2B_DIGEST) The operations in this
1242 //       function:
1243 //       a) marshal TPM2B_DIGEST structure into the buffer of TPM2B_ID_OBJECT
1244 //       b) encrypt the private buffer, excluding the leading integrity HMAC area
1245 //       c) compute integrity HMAC and append to the beginning of the buffer.
1246 //       d) Set the total size of TPM2B_ID_OBJECT buffer
1247 //
1248 void
SecretToCredential(TPM2B_DIGEST * secret,TPM2B_NAME * name,TPM2B_SEED * seed,TPM_HANDLE protector,TPM2B_ID_OBJECT * outIDObject)1249 SecretToCredential(
1250    TPM2B_DIGEST              *secret,          //   IN: secret information
1251    TPM2B_NAME                *name,            //   IN: the name of the object
1252    TPM2B_SEED                *seed,            //   IN: an external seed.
1253    TPM_HANDLE                 protector,       //   IN: The protector's handle
1254    TPM2B_ID_OBJECT           *outIDObject      //   OUT: output credential
1255    )
1256 {
1257    BYTE                      *buffer;          //   Auxiliary buffer pointer
1258    INT32                      bufferSize;
1259    BYTE                      *sensitiveData;   //   pointer to the sensitive data
1260    TPMI_ALG_HASH              outerHash;       //   The hash algorithm for outer wrap
1261    UINT16                     dataSize;        //   data blob size
1262    pAssert(secret != NULL && outIDObject != NULL);
1263    // use protector's name algorithm as outer hash
1264    outerHash = ObjectGetNameAlg(protector);
1265    // Marshal secret area to credential buffer, leave space for integrity
1266    sensitiveData = outIDObject->t.credential
1267                    + sizeof(UINT16) + CryptGetHashDigestSize(outerHash);
1268    // Marshal secret area
1269    buffer = sensitiveData;
1270    bufferSize = sizeof(TPM2B_DIGEST);
1271    dataSize = TPM2B_DIGEST_Marshal(secret, &buffer, &bufferSize);
1272    // Apply outer wrap
1273    outIDObject->t.size = ProduceOuterWrap(protector,
1274                                           name,
1275                                           outerHash,
1276                                           seed,
1277                                           FALSE,
1278                                           dataSize,
1279                                           outIDObject->t.credential);
1280    return;
1281 }
1282 //
1283 //
1284 //            CredentialToSecret()
1285 //
1286 //       Unwrap a credential. Check the integrity, decrypt and retrieve data to a TPM2B_DIGEST structure. The
1287 //       operations in this function:
1288 //       a) check the integrity HMAC of the input credential area
1289 //       b) decrypt the credential buffer
1290 //       c) unmarshal TPM2B_DIGEST structure into the buffer of TPM2B_DIGEST
1291 //
1292 //       Error Returns                      Meaning
1293 //
1294 //       TPM_RC_INSUFFICIENT                error during credential unmarshaling
1295 //       TPM_RC_INTEGRITY                   credential integrity is broken
1296 //       TPM_RC_SIZE                        error during credential unmarshaling
1297 //       TPM_RC_VALUE                       IV size does not match the encryption algorithm block size
1298 //
1299 TPM_RC
CredentialToSecret(TPM2B_ID_OBJECT * inIDObject,TPM2B_NAME * name,TPM2B_SEED * seed,TPM_HANDLE protector,TPM2B_DIGEST * secret)1300 CredentialToSecret(
1301    TPM2B_ID_OBJECT          *inIDObject,             //   IN: input credential blob
1302    TPM2B_NAME               *name,                   //   IN: the name of the object
1303    TPM2B_SEED               *seed,                   //   IN: an external seed.
1304    TPM_HANDLE                protector,              //   IN: The protector's handle
1305    TPM2B_DIGEST             *secret                  //   OUT: secret information
1306    )
1307 {
1308    TPM_RC                           result;
1309    BYTE                            *buffer;
1310    INT32                            size;
1311    TPMI_ALG_HASH                    outerHash;     // The hash algorithm for outer wrap
1312    BYTE                            *sensitiveData; // pointer to the sensitive data
1313    UINT16                           dataSize;
1314    // use protector's name algorithm as outer hash
1315    outerHash = ObjectGetNameAlg(protector);
1316    // Unwrap outer, a TPM_RC_INTEGRITY error may be returned at this point
1317    result = UnwrapOuter(protector, name, outerHash, seed, FALSE,
1318                         inIDObject->t.size, inIDObject->t.credential);
1319    if(result == TPM_RC_SUCCESS)
1320    {
1321        // Compute the beginning of sensitive data
1322        sensitiveData = inIDObject->t.credential
1323                        + sizeof(UINT16) + CryptGetHashDigestSize(outerHash);
1324        dataSize = inIDObject->t.size
1325                   - (sizeof(UINT16) + CryptGetHashDigestSize(outerHash));
1326           // Unmarshal secret buffer to TPM2B_DIGEST structure
1327           buffer = sensitiveData;
1328           size = (INT32) dataSize;
1329           result = TPM2B_DIGEST_Unmarshal(secret, &buffer, &size);
1330           // If there were no other unmarshaling errors, make sure that the
1331           // expected amount of data was recovered
1332           if(result == TPM_RC_SUCCESS && size != 0)
1333               return TPM_RC_SIZE;
1334    }
1335    return result;
1336 }
1337