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