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