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