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