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