1 /* Microsoft Reference Implementation for TPM 2.0
2 *
3 * The copyright in this software is being made available under the BSD License,
4 * included below. This software may be subject to other third party and
5 * contributor rights, including patent rights, and no such rights are granted
6 * under this license.
7 *
8 * Copyright (c) Microsoft Corporation
9 *
10 * All rights reserved.
11 *
12 * BSD License
13 *
14 * Redistribution and use in source and binary forms, with or without modification,
15 * are permitted provided that the following conditions are met:
16 *
17 * Redistributions of source code must retain the above copyright notice, this list
18 * of conditions and the following disclaimer.
19 *
20 * Redistributions in binary form must reproduce the above copyright notice, this
21 * list of conditions and the following disclaimer in the documentation and/or
22 * other materials provided with the distribution.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ""AS IS""
25 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
27 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
28 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
31 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 */
35 //** Includes
36 #include "Tpm.h"
37 #include "Object_spt_fp.h"
38
39 //** Local Functions
40
41 //*** GetIV2BSize()
42 // Get the size of TPM2B_IV in canonical form that will be append to the start of
43 // the sensitive data. It includes both size of size field and size of iv data
44 static UINT16
GetIV2BSize(OBJECT * protector)45 GetIV2BSize(
46 OBJECT *protector // IN: the protector handle
47 )
48 {
49 TPM_ALG_ID symAlg;
50 UINT16 keyBits;
51
52 // Determine the symmetric algorithm and size of key
53 if(protector == NULL)
54 {
55 // Use the context encryption algorithm and key size
56 symAlg = CONTEXT_ENCRYPT_ALG;
57 keyBits = CONTEXT_ENCRYPT_KEY_BITS;
58 }
59 else
60 {
61 symAlg = protector->publicArea.parameters.asymDetail.symmetric.algorithm;
62 keyBits = protector->publicArea.parameters.asymDetail.symmetric.keyBits.sym;
63 }
64
65 // The IV size is a UINT16 size field plus the block size of the symmetric
66 // algorithm
67 return sizeof(UINT16) + CryptGetSymmetricBlockSize(symAlg, keyBits);
68 }
69
70 //*** ComputeProtectionKeyParms()
71 // This function retrieves the symmetric protection key parameters for
72 // the sensitive data
73 // The parameters retrieved from this function include encryption algorithm,
74 // key size in bit, and a TPM2B_SYM_KEY containing the key material as well as
75 // the key size in bytes
76 // This function is used for any action that requires encrypting or decrypting of
77 // the sensitive area of an object or a credential blob
78 //
79 /*(See part 1 specification)
80 KDF for generating the protection key material:
81 KDFa(hashAlg, seed, "STORAGE", Name, NULL , bits)
82 where
83 hashAlg for a Primary Object, an algorithm chosen by the TPM vendor
84 for derivations from Primary Seeds. For all other objects,
85 the nameAlg of the object's parent.
86 seed for a Primary Object in the Platform Hierarchy, the PPS.
87 For Primary Objects in either Storage or Endorsement Hierarchy,
88 the SPS. For Temporary Objects, the context encryption seed.
89 For all other objects, the symmetric seed value in the
90 sensitive area of the object's parent.
91 STORAGE label to differentiate use of KDFa() (see 4.7)
92 Name the Name of the object being encrypted
93 bits the number of bits required for a symmetric key and IV
94 */
95 // Return Type: void
96 static void
ComputeProtectionKeyParms(OBJECT * protector,TPM_ALG_ID hashAlg,TPM2B * name,TPM2B * seedIn,TPM_ALG_ID * symAlg,UINT16 * keyBits,TPM2B_SYM_KEY * symKey)97 ComputeProtectionKeyParms(
98 OBJECT *protector, // IN: the protector object
99 TPM_ALG_ID hashAlg, // IN: hash algorithm for KDFa
100 TPM2B *name, // IN: name of the object
101 TPM2B *seedIn, // IN: optional seed for duplication blob.
102 // For non duplication blob, this
103 // parameter should be NULL
104 TPM_ALG_ID *symAlg, // OUT: the symmetric algorithm
105 UINT16 *keyBits, // OUT: the symmetric key size in bits
106 TPM2B_SYM_KEY *symKey // OUT: the symmetric key
107 )
108 {
109 const TPM2B *seed = seedIn;
110
111 // Determine the algorithms for the KDF and the encryption/decryption
112 // For TPM_RH_NULL, using context settings
113 if(protector == NULL)
114 {
115 // Use the context encryption algorithm and key size
116 *symAlg = CONTEXT_ENCRYPT_ALG;
117 symKey->t.size = CONTEXT_ENCRYPT_KEY_BYTES;
118 *keyBits = CONTEXT_ENCRYPT_KEY_BITS;
119 }
120 else
121 {
122 TPMT_SYM_DEF_OBJECT *symDef;
123 symDef = &protector->publicArea.parameters.asymDetail.symmetric;
124 *symAlg = symDef->algorithm;
125 *keyBits = symDef->keyBits.sym;
126 symKey->t.size = (*keyBits + 7) / 8;
127 }
128 // Get seed for KDF
129 if(seed == NULL)
130 seed = GetSeedForKDF(protector);
131 // KDFa to generate symmetric key and IV value
132 CryptKDFa(hashAlg, seed, STORAGE_KEY, name, NULL,
133 symKey->t.size * 8, symKey->t.buffer, NULL, FALSE);
134 return;
135 }
136
137 //*** ComputeOuterIntegrity()
138 // The sensitive area parameter is a buffer that holds a space for
139 // the integrity value and the marshaled sensitive area. The caller should
140 // skip over the area set aside for the integrity value
141 // and compute the hash of the remainder of the object.
142 // The size field of sensitive is in unmarshaled form and the
143 // sensitive area contents is an array of bytes.
144 /*(See part 1 specification)
145 KDFa(hashAlg, seed, "INTEGRITY", NULL, NULL , bits) (38)
146 where
147 hashAlg for a Primary Object, the nameAlg of the object. For all other
148 objects the nameAlg of the object's parent.
149 seed for a Primary Object in the Platform Hierarchy, the PPS. For
150 Primary Objects in either Storage or Endorsement Hierarchy,
151 the SPS. For a Temporary Object, the context encryption key.
152 For all other objects, the symmetric seed value in the sensitive
153 area of the object's parent.
154 "INTEGRITY" a value used to differentiate the uses of the KDF.
155 bits the number of bits in the digest produced by hashAlg.
156 Key is then used in the integrity computation.
157 HMACnameAlg(HMACkey, encSensitive || Name )
158 where
159 HMACnameAlg() the HMAC function using nameAlg of the object's parent
160 HMACkey value derived from the parent symmetric protection value
161 encSensitive symmetrically encrypted sensitive area
162 Name the Name of the object being protected
163 */
164 // Return Type: void
165 static void
ComputeOuterIntegrity(TPM2B * name,OBJECT * protector,TPMI_ALG_HASH hashAlg,TPM2B * seedIn,UINT32 sensitiveSize,BYTE * sensitiveData,TPM2B_DIGEST * integrity)166 ComputeOuterIntegrity(
167 TPM2B *name, // IN: the name of the object
168 OBJECT *protector, // IN: the object that
169 // provides protection. For an object,
170 // it is a parent. For a credential, it
171 // is the encrypt object. For
172 // a Temporary Object, it is NULL
173 TPMI_ALG_HASH hashAlg, // IN: algorithm to use for integrity
174 TPM2B *seedIn, // IN: an external seed may be provided for
175 // duplication blob. For non duplication
176 // blob, this parameter should be NULL
177 UINT32 sensitiveSize, // IN: size of the marshaled sensitive data
178 BYTE *sensitiveData, // IN: sensitive area
179 TPM2B_DIGEST *integrity // OUT: integrity
180 )
181 {
182 HMAC_STATE hmacState;
183 TPM2B_DIGEST hmacKey;
184 const TPM2B *seed = seedIn;
185 //
186 // Get seed for KDF
187 if(seed == NULL)
188 seed = GetSeedForKDF(protector);
189 // Determine the HMAC key bits
190 hmacKey.t.size = CryptHashGetDigestSize(hashAlg);
191
192 // KDFa to generate HMAC key
193 CryptKDFa(hashAlg, seed, INTEGRITY_KEY, NULL, NULL,
194 hmacKey.t.size * 8, hmacKey.t.buffer, NULL, FALSE);
195 // Start HMAC and get the size of the digest which will become the integrity
196 integrity->t.size = CryptHmacStart2B(&hmacState, hashAlg, &hmacKey.b);
197
198 // Adding the marshaled sensitive area to the integrity value
199 CryptDigestUpdate(&hmacState.hashState, sensitiveSize, sensitiveData);
200
201 // Adding name
202 CryptDigestUpdate2B(&hmacState.hashState, name);
203
204 // Compute HMAC
205 CryptHmacEnd2B(&hmacState, &integrity->b);
206
207 return;
208 }
209
210 //*** ComputeInnerIntegrity()
211 // This function computes the integrity of an inner wrap
212 static void
ComputeInnerIntegrity(TPM_ALG_ID hashAlg,TPM2B * name,UINT16 dataSize,BYTE * sensitiveData,TPM2B_DIGEST * integrity)213 ComputeInnerIntegrity(
214 TPM_ALG_ID hashAlg, // IN: hash algorithm for inner wrap
215 TPM2B *name, // IN: the name of the object
216 UINT16 dataSize, // IN: the size of sensitive data
217 BYTE *sensitiveData, // IN: sensitive data
218 TPM2B_DIGEST *integrity // OUT: inner integrity
219 )
220 {
221 HASH_STATE hashState;
222 //
223 // Start hash and get the size of the digest which will become the integrity
224 integrity->t.size = CryptHashStart(&hashState, hashAlg);
225
226 // Adding the marshaled sensitive area to the integrity value
227 CryptDigestUpdate(&hashState, dataSize, sensitiveData);
228
229 // Adding name
230 CryptDigestUpdate2B(&hashState, name);
231
232 // Compute hash
233 CryptHashEnd2B(&hashState, &integrity->b);
234
235 return;
236 }
237
238 //*** ProduceInnerIntegrity()
239 // This function produces an inner integrity for regular private, credential or
240 // duplication blob
241 // It requires the sensitive data being marshaled to the innerBuffer, with the
242 // leading bytes reserved for integrity hash. It assume the sensitive data
243 // starts at address (innerBuffer + integrity size).
244 // This function integrity at the beginning of the inner buffer
245 // It returns the total size of buffer with the inner wrap
246 static UINT16
ProduceInnerIntegrity(TPM2B * name,TPM_ALG_ID hashAlg,UINT16 dataSize,BYTE * innerBuffer)247 ProduceInnerIntegrity(
248 TPM2B *name, // IN: the name of the object
249 TPM_ALG_ID hashAlg, // IN: hash algorithm for inner wrap
250 UINT16 dataSize, // IN: the size of sensitive data, excluding the
251 // leading integrity buffer size
252 BYTE *innerBuffer // IN/OUT: inner buffer with sensitive data in
253 // it. At input, the leading bytes of this
254 // buffer is reserved for integrity
255 )
256 {
257 BYTE *sensitiveData; // pointer to the sensitive data
258 TPM2B_DIGEST integrity;
259 UINT16 integritySize;
260 BYTE *buffer; // Auxiliary buffer pointer
261 //
262 // sensitiveData points to the beginning of sensitive data in innerBuffer
263 integritySize = sizeof(UINT16) + CryptHashGetDigestSize(hashAlg);
264 sensitiveData = innerBuffer + integritySize;
265
266 ComputeInnerIntegrity(hashAlg, name, dataSize, sensitiveData, &integrity);
267
268 // Add integrity at the beginning of inner buffer
269 buffer = innerBuffer;
270 TPM2B_DIGEST_Marshal(&integrity, &buffer, NULL);
271
272 return dataSize + integritySize;
273 }
274
275 //*** CheckInnerIntegrity()
276 // This function check integrity of inner blob
277 // Return Type: TPM_RC
278 // TPM_RC_INTEGRITY if the outer blob integrity is bad
279 // unmarshal errors unmarshal errors while unmarshaling integrity
280 static TPM_RC
CheckInnerIntegrity(TPM2B * name,TPM_ALG_ID hashAlg,UINT16 dataSize,BYTE * innerBuffer)281 CheckInnerIntegrity(
282 TPM2B *name, // IN: the name of the object
283 TPM_ALG_ID hashAlg, // IN: hash algorithm for inner wrap
284 UINT16 dataSize, // IN: the size of sensitive data, including the
285 // leading integrity buffer size
286 BYTE *innerBuffer // IN/OUT: inner buffer with sensitive data in
287 // it
288 )
289 {
290 TPM_RC result;
291 TPM2B_DIGEST integrity;
292 TPM2B_DIGEST integrityToCompare;
293 BYTE *buffer; // Auxiliary buffer pointer
294 INT32 size;
295 //
296 // Unmarshal integrity
297 buffer = innerBuffer;
298 size = (INT32)dataSize;
299 result = TPM2B_DIGEST_Unmarshal(&integrity, &buffer, &size);
300 if(result == TPM_RC_SUCCESS)
301 {
302 // Compute integrity to compare
303 ComputeInnerIntegrity(hashAlg, name, (UINT16)size, buffer,
304 &integrityToCompare);
305 // Compare outer blob integrity
306 if(!MemoryEqual2B(&integrity.b, &integrityToCompare.b))
307 result = TPM_RC_INTEGRITY;
308 }
309 return result;
310 }
311
312 //** Public Functions
313
314 //*** AdjustAuthSize()
315 // This function will validate that the input authValue is no larger than the
316 // digestSize for the nameAlg. It will then pad with zeros to the size of the
317 // digest.
318 BOOL
AdjustAuthSize(TPM2B_AUTH * auth,TPMI_ALG_HASH nameAlg)319 AdjustAuthSize(
320 TPM2B_AUTH *auth, // IN/OUT: value to adjust
321 TPMI_ALG_HASH nameAlg // IN:
322 )
323 {
324 UINT16 digestSize;
325 //
326 // If there is no nameAlg, then this is a LoadExternal and the authVale can
327 // be any size up to the maximum allowed by the implementation
328 digestSize = (nameAlg == TPM_ALG_NULL) ? sizeof(TPMU_HA)
329 : CryptHashGetDigestSize(nameAlg);
330 if(digestSize < MemoryRemoveTrailingZeros(auth))
331 return FALSE;
332 else if(digestSize > auth->t.size)
333 MemoryPad2B(&auth->b, digestSize);
334 auth->t.size = digestSize;
335
336 return TRUE;
337 }
338
339 //*** AreAttributesForParent()
340 // This function is called by create, load, and import functions.
341 //
342 // Note: The 'isParent' attribute is SET when an object is loaded and it has
343 // attributes that are suitable for a parent object.
344 // Return Type: BOOL
345 // TRUE(1) properties are those of a parent
346 // FALSE(0) properties are not those of a parent
347 BOOL
ObjectIsParent(OBJECT * parentObject)348 ObjectIsParent(
349 OBJECT *parentObject // IN: parent handle
350 )
351 {
352 return parentObject->attributes.isParent;
353 }
354
355 //*** CreateChecks()
356 // Attribute checks that are unique to creation.
357 // Return Type: TPM_RC
358 // TPM_RC_ATTRIBUTES sensitiveDataOrigin is not consistent with the
359 // object type
360 // other returns from PublicAttributesValidation()
361 TPM_RC
CreateChecks(OBJECT * parentObject,TPMT_PUBLIC * publicArea,UINT16 sensitiveDataSize)362 CreateChecks(
363 OBJECT *parentObject,
364 TPMT_PUBLIC *publicArea,
365 UINT16 sensitiveDataSize
366 )
367 {
368 TPMA_OBJECT attributes = publicArea->objectAttributes;
369 TPM_RC result = TPM_RC_SUCCESS;
370 //
371 // If the caller indicates that they have provided the data, then make sure that
372 // they have provided some data.
373 if((!IS_ATTRIBUTE(attributes, TPMA_OBJECT, sensitiveDataOrigin))
374 && (sensitiveDataSize == 0))
375 return TPM_RCS_ATTRIBUTES;
376 // For an ordinary object, data can only be provided when sensitiveDataOrigin
377 // is CLEAR
378 if((parentObject != NULL)
379 && (IS_ATTRIBUTE(attributes, TPMA_OBJECT, sensitiveDataOrigin))
380 && (sensitiveDataSize != 0))
381 return TPM_RCS_ATTRIBUTES;
382 switch(publicArea->type)
383 {
384 case TPM_ALG_KEYEDHASH:
385 // if this is a data object (sign == decrypt == CLEAR) then the
386 // TPM cannot be the data source.
387 if(!IS_ATTRIBUTE(attributes, TPMA_OBJECT, sign)
388 && !IS_ATTRIBUTE(attributes, TPMA_OBJECT, decrypt)
389 && IS_ATTRIBUTE(attributes, TPMA_OBJECT, sensitiveDataOrigin))
390 result = TPM_RC_ATTRIBUTES;
391 // comment out the next line in order to prevent a fixedTPM derivation
392 // parent
393 // break;
394 case TPM_ALG_SYMCIPHER:
395 // A restricted key symmetric key (SYMCIPHER and KEYEDHASH)
396 // must have sensitiveDataOrigin SET unless it has fixedParent and
397 // fixedTPM CLEAR.
398 if(IS_ATTRIBUTE(attributes, TPMA_OBJECT, restricted))
399 if(!IS_ATTRIBUTE(attributes, TPMA_OBJECT, sensitiveDataOrigin))
400 if(IS_ATTRIBUTE(attributes, TPMA_OBJECT, fixedParent)
401 || IS_ATTRIBUTE(attributes, TPMA_OBJECT, fixedTPM))
402 result = TPM_RCS_ATTRIBUTES;
403 break;
404 default: // Asymmetric keys cannot have the sensitive portion provided
405 if(!IS_ATTRIBUTE(attributes, TPMA_OBJECT, sensitiveDataOrigin))
406 result = TPM_RCS_ATTRIBUTES;
407 break;
408 }
409 if(TPM_RC_SUCCESS == result)
410 {
411 result = PublicAttributesValidation(parentObject, publicArea);
412 }
413 return result;
414 }
415 //*** SchemeChecks
416 // This function is called by TPM2_LoadExternal() and PublicAttributesValidation().
417 // This function validates the schemes in the public area of an object.
418 // Return Type: TPM_RC
419 // TPM_RC_HASH non-duplicable storage key and its parent have different
420 // name algorithm
421 // TPM_RC_KDF incorrect KDF specified for decrypting keyed hash object
422 // TPM_RC_KEY invalid key size values in an asymmetric key public area
423 // TPM_RCS_SCHEME inconsistent attributes 'decrypt', 'sign', 'restricted'
424 // and key's scheme ID; or hash algorithm is inconsistent
425 // with the scheme ID for keyed hash object
426 // TPM_RC_SYMMETRIC a storage key with no symmetric algorithm specified; or
427 // non-storage key with symmetric algorithm different from
428 // TPM_ALG_NULL
429 TPM_RC
SchemeChecks(OBJECT * parentObject,TPMT_PUBLIC * publicArea)430 SchemeChecks(
431 OBJECT *parentObject, // IN: parent (null if primary seed)
432 TPMT_PUBLIC *publicArea // IN: public area of the object
433 )
434 {
435 TPMT_SYM_DEF_OBJECT *symAlgs = NULL;
436 TPM_ALG_ID scheme = TPM_ALG_NULL;
437 TPMA_OBJECT attributes = publicArea->objectAttributes;
438 TPMU_PUBLIC_PARMS *parms = &publicArea->parameters;
439 //
440 switch(publicArea->type)
441 {
442 case TPM_ALG_SYMCIPHER:
443 symAlgs = &parms->symDetail.sym;
444 // If this is a decrypt key, then only the block cipher modes (not
445 // SMAC) are valid. TPM_ALG_NULL is OK too. If this is a 'sign' key,
446 // then any mode that got through the unmarshaling is OK.
447 if(IS_ATTRIBUTE(attributes, TPMA_OBJECT, decrypt)
448 && !CryptSymModeIsValid(symAlgs->mode.sym, TRUE))
449 return TPM_RCS_SCHEME;
450 break;
451 case TPM_ALG_KEYEDHASH:
452 scheme = parms->keyedHashDetail.scheme.scheme;
453 // if both sign and decrypt
454 if(IS_ATTRIBUTE(attributes, TPMA_OBJECT, sign)
455 == IS_ATTRIBUTE(attributes, TPMA_OBJECT, decrypt))
456 {
457 // if both sign and decrypt are set or clear, then need
458 // TPM_ALG_NULL as scheme
459 if(scheme != TPM_ALG_NULL)
460 return TPM_RCS_SCHEME;
461 }
462 else if(IS_ATTRIBUTE(attributes, TPMA_OBJECT, sign)
463 && scheme != TPM_ALG_HMAC)
464 return TPM_RCS_SCHEME;
465 else if(IS_ATTRIBUTE(attributes, TPMA_OBJECT, decrypt))
466 {
467 if(scheme != TPM_ALG_XOR)
468 return TPM_RCS_SCHEME;
469 // If this is a derivation parent, then the KDF needs to be
470 // SP800-108 for this implementation. This is the only derivation
471 // supported by this implementation. Other implementations could
472 // support additional schemes. There is no default.
473 if(IS_ATTRIBUTE(attributes, TPMA_OBJECT, restricted))
474 {
475 if(parms->keyedHashDetail.scheme.details.xor.kdf
476 != TPM_ALG_KDF1_SP800_108)
477 return TPM_RCS_SCHEME;
478 // Must select a digest.
479 if(CryptHashGetDigestSize(
480 parms->keyedHashDetail.scheme.details.xor.hashAlg) == 0)
481 return TPM_RCS_HASH;
482 }
483 }
484 break;
485 default: // handling for asymmetric
486 scheme = parms->asymDetail.scheme.scheme;
487 symAlgs = &parms->asymDetail.symmetric;
488 // if the key is both sign and decrypt, then the scheme must be
489 // TPM_ALG_NULL because there is no way to specify both a sign and a
490 // decrypt scheme in the key.
491 if(IS_ATTRIBUTE(attributes, TPMA_OBJECT, sign)
492 == IS_ATTRIBUTE(attributes, TPMA_OBJECT, decrypt))
493 {
494 // scheme must be TPM_ALG_NULL
495 if(scheme != TPM_ALG_NULL)
496 return TPM_RCS_SCHEME;
497 }
498 else if(IS_ATTRIBUTE(attributes, TPMA_OBJECT, sign))
499 {
500 // If this is a signing key, see if it has a signing scheme
501 if(CryptIsAsymSignScheme(publicArea->type, scheme))
502 {
503 // if proper signing scheme then it needs a proper hash
504 if(parms->asymDetail.scheme.details.anySig.hashAlg
505 == TPM_ALG_NULL)
506 return TPM_RCS_SCHEME;
507 }
508 else
509 {
510 // signing key that does not have a proper signing scheme.
511 // This is OK if the key is not restricted and its scheme
512 // is TPM_ALG_NULL
513 if(IS_ATTRIBUTE(attributes, TPMA_OBJECT, restricted)
514 || scheme != TPM_ALG_NULL)
515 return TPM_RCS_SCHEME;
516 }
517 }
518 else if(IS_ATTRIBUTE(attributes, TPMA_OBJECT, decrypt))
519 {
520 if(IS_ATTRIBUTE(attributes, TPMA_OBJECT, restricted))
521 {
522 // for a restricted decryption key (a parent), scheme
523 // is required to be TPM_ALG_NULL
524 if(scheme != TPM_ALG_NULL)
525 return TPM_RCS_SCHEME;
526 }
527 else
528 {
529 // For an unrestricted decryption key, the scheme has to
530 // be a valid scheme or TPM_ALG_NULL
531 if(scheme != TPM_ALG_NULL &&
532 !CryptIsAsymDecryptScheme(publicArea->type, scheme))
533 return TPM_RCS_SCHEME;
534 }
535 }
536 if(!IS_ATTRIBUTE(attributes, TPMA_OBJECT, restricted)
537 || !IS_ATTRIBUTE(attributes, TPMA_OBJECT, decrypt))
538 {
539 // For an asymmetric key that is not a parent, the symmetric
540 // algorithms must be TPM_ALG_NULL
541 if(symAlgs->algorithm != TPM_ALG_NULL)
542 return TPM_RCS_SYMMETRIC;
543 }
544 // Special checks for an ECC key
545 #if ALG_ECC
546 if(publicArea->type == TPM_ALG_ECC)
547 {
548 TPM_ECC_CURVE curveID;
549 const TPMT_ECC_SCHEME *curveScheme;
550
551 curveID = publicArea->parameters.eccDetail.curveID;
552 curveScheme = CryptGetCurveSignScheme(curveID);
553 // The curveId must be valid or the unmarshaling is busted.
554 pAssert(curveScheme != NULL);
555
556 // If the curveID requires a specific scheme, then the key must
557 // select the same scheme
558 if(curveScheme->scheme != TPM_ALG_NULL)
559 {
560 TPMS_ECC_PARMS *ecc = &publicArea->parameters.eccDetail;
561 if(scheme != curveScheme->scheme)
562 return TPM_RCS_SCHEME;
563 // The scheme can allow any hash, or not...
564 if(curveScheme->details.anySig.hashAlg != TPM_ALG_NULL
565 && (ecc->scheme.details.anySig.hashAlg
566 != curveScheme->details.anySig.hashAlg))
567 return TPM_RCS_SCHEME;
568 }
569 // For now, the KDF must be TPM_ALG_NULL
570 if(publicArea->parameters.eccDetail.kdf.scheme != TPM_ALG_NULL)
571 return TPM_RCS_KDF;
572 }
573 #endif
574 break;
575 }
576 // If this is a restricted decryption key with symmetric algorithms, then it
577 // is an ordinary parent (not a derivation parent). It needs to specific
578 // symmetric algorithms other than TPM_ALG_NULL
579 if(symAlgs != NULL
580 && IS_ATTRIBUTE(attributes, TPMA_OBJECT, restricted)
581 && IS_ATTRIBUTE(attributes, TPMA_OBJECT, decrypt))
582 {
583 if(symAlgs->algorithm == TPM_ALG_NULL)
584 return TPM_RCS_SYMMETRIC;
585 #if 0 //??
586 // This next check is under investigation. Need to see if it will break Windows
587 // before it is enabled. If it does not, then it should be default because a
588 // the mode used with a parent is always CFB and Part 2 indicates as much.
589 if(symAlgs->mode.sym != TPM_ALG_CFB)
590 return TPM_RCS_MODE;
591 #endif
592 // If this parent is not duplicable, then the symmetric algorithms
593 // (encryption and hash) must match those of its parent
594 if(IS_ATTRIBUTE(attributes, TPMA_OBJECT, fixedParent)
595 && (parentObject != NULL))
596 {
597 if(publicArea->nameAlg != parentObject->publicArea.nameAlg)
598 return TPM_RCS_HASH;
599 if(!MemoryEqual(symAlgs, &parentObject->publicArea.parameters,
600 sizeof(TPMT_SYM_DEF_OBJECT)))
601 return TPM_RCS_SYMMETRIC;
602 }
603 }
604 return TPM_RC_SUCCESS;
605 }
606
607 //*** PublicAttributesValidation()
608 // This function validates the values in the public area of an object.
609 // This function is used in the processing of TPM2_Create, TPM2_CreatePrimary,
610 // TPM2_CreateLoaded(), TPM2_Load(), TPM2_Import(), and TPM2_LoadExternal().
611 // For TPM2_Import() this is only used if the new parent has fixedTPM SET. For
612 // TPM2_LoadExternal(), this is not used for a public-only key
613 // Return Type: TPM_RC
614 // TPM_RC_ATTRIBUTES 'fixedTPM', 'fixedParent', or 'encryptedDuplication'
615 // attributes are inconsistent between themselves or with
616 // those of the parent object;
617 // inconsistent 'restricted', 'decrypt' and 'sign'
618 // attributes;
619 // attempt to inject sensitive data for an asymmetric key;
620 // attempt to create a symmetric cipher key that is not
621 // a decryption key
622 // TPM_RC_HASH nameAlg is TPM_ALG_NULL
623 // TPM_RC_SIZE 'authPolicy' size does not match digest size of the name
624 // algorithm in 'publicArea'
625 // other returns from SchemeChecks()
626 TPM_RC
PublicAttributesValidation(OBJECT * parentObject,TPMT_PUBLIC * publicArea)627 PublicAttributesValidation(
628 OBJECT *parentObject, // IN: input parent object
629 TPMT_PUBLIC *publicArea // IN: public area of the object
630 )
631 {
632 TPMA_OBJECT attributes = publicArea->objectAttributes;
633 TPMA_OBJECT parentAttributes = TPMA_ZERO_INITIALIZER();
634 //
635 if(parentObject != NULL)
636 parentAttributes = parentObject->publicArea.objectAttributes;
637 if(publicArea->nameAlg == TPM_ALG_NULL)
638 return TPM_RCS_HASH;
639 // If there is an authPolicy, it needs to be the size of the digest produced
640 // by the nameAlg of the object
641 if((publicArea->authPolicy.t.size != 0
642 && (publicArea->authPolicy.t.size
643 != CryptHashGetDigestSize(publicArea->nameAlg))))
644 return TPM_RCS_SIZE;
645 // If the parent is fixedTPM (including a Primary Object) the object must have
646 // the same value for fixedTPM and fixedParent
647 if(parentObject == NULL
648 || IS_ATTRIBUTE(parentAttributes, TPMA_OBJECT, fixedTPM))
649 {
650 if(IS_ATTRIBUTE(attributes, TPMA_OBJECT, fixedParent)
651 != IS_ATTRIBUTE(attributes, TPMA_OBJECT, fixedTPM))
652 return TPM_RCS_ATTRIBUTES;
653 }
654 else
655 {
656 // The parent is not fixedTPM so the object can't be fixedTPM
657 if(IS_ATTRIBUTE(attributes, TPMA_OBJECT, fixedTPM))
658 return TPM_RCS_ATTRIBUTES;
659 }
660 // See if sign and decrypt are the same
661 if(IS_ATTRIBUTE(attributes, TPMA_OBJECT, sign)
662 == IS_ATTRIBUTE(attributes, TPMA_OBJECT, decrypt))
663 {
664 // a restricted key cannot have both SET or both CLEAR
665 if(IS_ATTRIBUTE(attributes, TPMA_OBJECT, restricted))
666 return TPM_RC_ATTRIBUTES;
667 // only a data object may have both sign and decrypt CLEAR
668 // BTW, since we know that decrypt==sign, no need to check both
669 if(publicArea->type != TPM_ALG_KEYEDHASH
670 && !IS_ATTRIBUTE(attributes, TPMA_OBJECT, sign))
671 return TPM_RC_ATTRIBUTES;
672 }
673 // If the object can't be duplicated (directly or indirectly) then there
674 // is no justification for having encryptedDuplication SET
675 if(IS_ATTRIBUTE(attributes, TPMA_OBJECT, fixedTPM)
676 && IS_ATTRIBUTE(attributes, TPMA_OBJECT, encryptedDuplication))
677 return TPM_RCS_ATTRIBUTES;
678 // If a parent object has fixedTPM CLEAR, the child must have the
679 // same encryptedDuplication value as its parent.
680 // Primary objects are considered to have a fixedTPM parent (the seeds).
681 if(parentObject != NULL
682 && !IS_ATTRIBUTE(parentAttributes, TPMA_OBJECT, fixedTPM))
683 {
684 if(IS_ATTRIBUTE(attributes, TPMA_OBJECT, encryptedDuplication)
685 != IS_ATTRIBUTE(parentAttributes, TPMA_OBJECT, encryptedDuplication))
686 return TPM_RCS_ATTRIBUTES;
687 }
688 // Special checks for derived objects
689 if((parentObject != NULL) && (parentObject->attributes.derivation == SET))
690 {
691 // A derived object has the same settings for fixedTPM as its parent
692 if(IS_ATTRIBUTE(attributes, TPMA_OBJECT, fixedTPM)
693 != IS_ATTRIBUTE(parentAttributes, TPMA_OBJECT, fixedTPM))
694 return TPM_RCS_ATTRIBUTES;
695 // A derived object is required to be fixedParent
696 if(!IS_ATTRIBUTE(attributes, TPMA_OBJECT, fixedParent))
697 return TPM_RCS_ATTRIBUTES;
698 }
699 return SchemeChecks(parentObject, publicArea);
700 }
701
702 //*** FillInCreationData()
703 // Fill in creation data for an object.
704 // Return Type: void
705 void
FillInCreationData(TPMI_DH_OBJECT parentHandle,TPMI_ALG_HASH nameHashAlg,TPML_PCR_SELECTION * creationPCR,TPM2B_DATA * outsideData,TPM2B_CREATION_DATA * outCreation,TPM2B_DIGEST * creationDigest)706 FillInCreationData(
707 TPMI_DH_OBJECT parentHandle, // IN: handle of parent
708 TPMI_ALG_HASH nameHashAlg, // IN: name hash algorithm
709 TPML_PCR_SELECTION *creationPCR, // IN: PCR selection
710 TPM2B_DATA *outsideData, // IN: outside data
711 TPM2B_CREATION_DATA *outCreation, // OUT: creation data for output
712 TPM2B_DIGEST *creationDigest // OUT: creation digest
713 )
714 {
715 BYTE creationBuffer[sizeof(TPMS_CREATION_DATA)];
716 BYTE *buffer;
717 HASH_STATE hashState;
718 //
719 // Fill in TPMS_CREATION_DATA in outCreation
720
721 // Compute PCR digest
722 PCRComputeCurrentDigest(nameHashAlg, creationPCR,
723 &outCreation->creationData.pcrDigest);
724
725 // Put back PCR selection list
726 outCreation->creationData.pcrSelect = *creationPCR;
727
728 // Get locality
729 outCreation->creationData.locality
730 = LocalityGetAttributes(_plat__LocalityGet());
731 outCreation->creationData.parentNameAlg = TPM_ALG_NULL;
732
733 // If the parent is either a primary seed or TPM_ALG_NULL, then the Name
734 // and QN of the parent are the parent's handle.
735 if(HandleGetType(parentHandle) == TPM_HT_PERMANENT)
736 {
737 buffer = &outCreation->creationData.parentName.t.name[0];
738 outCreation->creationData.parentName.t.size =
739 TPM_HANDLE_Marshal(&parentHandle, &buffer, NULL);
740 // For a primary or temporary object, the parent name (a handle) and the
741 // parent's QN are the same
742 outCreation->creationData.parentQualifiedName
743 = outCreation->creationData.parentName;
744 }
745 else // Regular object
746 {
747 OBJECT *parentObject = HandleToObject(parentHandle);
748 //
749 // Set name algorithm
750 outCreation->creationData.parentNameAlg = parentObject->publicArea.nameAlg;
751
752 // Copy parent name
753 outCreation->creationData.parentName = parentObject->name;
754
755 // Copy parent qualified name
756 outCreation->creationData.parentQualifiedName = parentObject->qualifiedName;
757 }
758 // Copy outside information
759 outCreation->creationData.outsideInfo = *outsideData;
760
761 // Marshal creation data to canonical form
762 buffer = creationBuffer;
763 outCreation->size = TPMS_CREATION_DATA_Marshal(&outCreation->creationData,
764 &buffer, NULL);
765 // Compute hash for creation field in public template
766 creationDigest->t.size = CryptHashStart(&hashState, nameHashAlg);
767 CryptDigestUpdate(&hashState, outCreation->size, creationBuffer);
768 CryptHashEnd2B(&hashState, &creationDigest->b);
769
770 return;
771 }
772
773 //*** GetSeedForKDF()
774 // Get a seed for KDF. The KDF for encryption and HMAC key use the same seed.
775 const TPM2B *
GetSeedForKDF(OBJECT * protector)776 GetSeedForKDF(
777 OBJECT *protector // IN: the protector handle
778 )
779 {
780 // Get seed for encryption key. Use input seed if provided.
781 // Otherwise, using protector object's seedValue. TPM_RH_NULL is the only
782 // exception that we may not have a loaded object as protector. In such a
783 // case, use nullProof as seed.
784 if(protector == NULL)
785 return &gr.nullProof.b;
786 else
787 return &protector->sensitive.seedValue.b;
788 }
789
790 //*** ProduceOuterWrap()
791 // This function produce outer wrap for a buffer containing the sensitive data.
792 // It requires the sensitive data being marshaled to the outerBuffer, with the
793 // leading bytes reserved for integrity hash. If iv is used, iv space should
794 // be reserved at the beginning of the buffer. It assumes the sensitive data
795 // starts at address (outerBuffer + integrity size [+ iv size]).
796 // This function performs:
797 // 1. Add IV before sensitive area if required
798 // 2. encrypt sensitive data, if iv is required, encrypt by iv. otherwise,
799 // encrypted by a NULL iv
800 // 3. add HMAC integrity at the beginning of the buffer
801 // It returns the total size of blob with outer wrap
802 UINT16
ProduceOuterWrap(OBJECT * protector,TPM2B * name,TPM_ALG_ID hashAlg,TPM2B * seed,BOOL useIV,UINT16 dataSize,BYTE * outerBuffer)803 ProduceOuterWrap(
804 OBJECT *protector, // IN: The handle of the object that provides
805 // protection. For object, it is parent
806 // handle. For credential, it is the handle
807 // of encrypt object.
808 TPM2B *name, // IN: the name of the object
809 TPM_ALG_ID hashAlg, // IN: hash algorithm for outer wrap
810 TPM2B *seed, // IN: an external seed may be provided for
811 // duplication blob. For non duplication
812 // blob, this parameter should be NULL
813 BOOL useIV, // IN: indicate if an IV is used
814 UINT16 dataSize, // IN: the size of sensitive data, excluding the
815 // leading integrity buffer size or the
816 // optional iv size
817 BYTE *outerBuffer // IN/OUT: outer buffer with sensitive data in
818 // it
819 )
820 {
821 TPM_ALG_ID symAlg;
822 UINT16 keyBits;
823 TPM2B_SYM_KEY symKey;
824 TPM2B_IV ivRNG; // IV from RNG
825 TPM2B_IV *iv = NULL;
826 UINT16 ivSize = 0; // size of iv area, including the size field
827 BYTE *sensitiveData; // pointer to the sensitive data
828 TPM2B_DIGEST integrity;
829 UINT16 integritySize;
830 BYTE *buffer; // Auxiliary buffer pointer
831 //
832 // Compute the beginning of sensitive data. The outer integrity should
833 // always exist if this function is called to make an outer wrap
834 integritySize = sizeof(UINT16) + CryptHashGetDigestSize(hashAlg);
835 sensitiveData = outerBuffer + integritySize;
836
837 // If iv is used, adjust the pointer of sensitive data and add iv before it
838 if(useIV)
839 {
840 ivSize = GetIV2BSize(protector);
841
842 // Generate IV from RNG. The iv data size should be the total IV area
843 // size minus the size of size field
844 ivRNG.t.size = ivSize - sizeof(UINT16);
845 CryptRandomGenerate(ivRNG.t.size, ivRNG.t.buffer);
846
847 // Marshal IV to buffer
848 buffer = sensitiveData;
849 TPM2B_IV_Marshal(&ivRNG, &buffer, NULL);
850
851 // adjust sensitive data starting after IV area
852 sensitiveData += ivSize;
853
854 // Use iv for encryption
855 iv = &ivRNG;
856 }
857 // Compute symmetric key parameters for outer buffer encryption
858 ComputeProtectionKeyParms(protector, hashAlg, name, seed,
859 &symAlg, &keyBits, &symKey);
860 // Encrypt inner buffer in place
861 CryptSymmetricEncrypt(sensitiveData, symAlg, keyBits,
862 symKey.t.buffer, iv, TPM_ALG_CFB, dataSize,
863 sensitiveData);
864 // Compute outer integrity. Integrity computation includes the optional IV
865 // area
866 ComputeOuterIntegrity(name, protector, hashAlg, seed, dataSize + ivSize,
867 outerBuffer + integritySize, &integrity);
868 // Add integrity at the beginning of outer buffer
869 buffer = outerBuffer;
870 TPM2B_DIGEST_Marshal(&integrity, &buffer, NULL);
871
872 // return the total size in outer wrap
873 return dataSize + integritySize + ivSize;
874 }
875
876 //*** UnwrapOuter()
877 // This function remove the outer wrap of a blob containing sensitive data
878 // This function performs:
879 // 1. check integrity of outer blob
880 // 2. decrypt outer blob
881 //
882 // Return Type: TPM_RC
883 // TPM_RCS_INSUFFICIENT error during sensitive data unmarshaling
884 // TPM_RCS_INTEGRITY sensitive data integrity is broken
885 // TPM_RCS_SIZE error during sensitive data unmarshaling
886 // TPM_RCS_VALUE IV size for CFB does not match the encryption
887 // algorithm block size
888 TPM_RC
UnwrapOuter(OBJECT * protector,TPM2B * name,TPM_ALG_ID hashAlg,TPM2B * seed,BOOL useIV,UINT16 dataSize,BYTE * outerBuffer)889 UnwrapOuter(
890 OBJECT *protector, // IN: The object that provides
891 // protection. For object, it is parent
892 // handle. For credential, it is the
893 // encrypt object.
894 TPM2B *name, // IN: the name of the object
895 TPM_ALG_ID hashAlg, // IN: hash algorithm for outer wrap
896 TPM2B *seed, // IN: an external seed may be provided for
897 // duplication blob. For non duplication
898 // blob, this parameter should be NULL.
899 BOOL useIV, // IN: indicates if an IV is used
900 UINT16 dataSize, // IN: size of sensitive data in outerBuffer,
901 // including the leading integrity buffer
902 // size, and an optional iv area
903 BYTE *outerBuffer // IN/OUT: sensitive data
904 )
905 {
906 TPM_RC result;
907 TPM_ALG_ID symAlg = TPM_ALG_NULL;
908 TPM2B_SYM_KEY symKey;
909 UINT16 keyBits = 0;
910 TPM2B_IV ivIn; // input IV retrieved from input buffer
911 TPM2B_IV *iv = NULL;
912 BYTE *sensitiveData; // pointer to the sensitive data
913 TPM2B_DIGEST integrityToCompare;
914 TPM2B_DIGEST integrity;
915 INT32 size;
916 //
917 // Unmarshal integrity
918 sensitiveData = outerBuffer;
919 size = (INT32)dataSize;
920 result = TPM2B_DIGEST_Unmarshal(&integrity, &sensitiveData, &size);
921 if(result == TPM_RC_SUCCESS)
922 {
923 // Compute integrity to compare
924 ComputeOuterIntegrity(name, protector, hashAlg, seed,
925 (UINT16)size, sensitiveData,
926 &integrityToCompare);
927 // Compare outer blob integrity
928 if(!MemoryEqual2B(&integrity.b, &integrityToCompare.b))
929 return TPM_RCS_INTEGRITY;
930 // Get the symmetric algorithm parameters used for encryption
931 ComputeProtectionKeyParms(protector, hashAlg, name, seed,
932 &symAlg, &keyBits, &symKey);
933 // Retrieve IV if it is used
934 if(useIV)
935 {
936 result = TPM2B_IV_Unmarshal(&ivIn, &sensitiveData, &size);
937 if(result == TPM_RC_SUCCESS)
938 {
939 // The input iv size for CFB must match the encryption algorithm
940 // block size
941 if(ivIn.t.size != CryptGetSymmetricBlockSize(symAlg, keyBits))
942 result = TPM_RC_VALUE;
943 else
944 iv = &ivIn;
945 }
946 }
947 }
948 // If no errors, decrypt private in place. Since this function uses CFB,
949 // CryptSymmetricDecrypt() will not return any errors. It may fail but it will
950 // not return an error.
951 if(result == TPM_RC_SUCCESS)
952 CryptSymmetricDecrypt(sensitiveData, symAlg, keyBits,
953 symKey.t.buffer, iv, TPM_ALG_CFB,
954 (UINT16)size, sensitiveData);
955 return result;
956 }
957
958 //*** MarshalSensitive()
959 // This function is used to marshal a sensitive area. Among other things, it
960 // adjusts the size of the authValue to be no smaller than the digest of
961 // 'nameAlg'
962 // Returns the size of the marshaled area.
963 static UINT16
MarshalSensitive(OBJECT * parent,BYTE * buffer,TPMT_SENSITIVE * sensitive,TPMI_ALG_HASH nameAlg)964 MarshalSensitive(
965 OBJECT *parent, // IN: the object parent (optional)
966 BYTE *buffer, // OUT: receiving buffer
967 TPMT_SENSITIVE *sensitive, // IN: the sensitive area to marshal
968 TPMI_ALG_HASH nameAlg // IN:
969 )
970 {
971 BYTE *sizeField = buffer; // saved so that size can be
972 // marshaled after it is known
973 UINT16 retVal;
974 //
975 // Pad the authValue if needed
976 MemoryPad2B(&sensitive->authValue.b, CryptHashGetDigestSize(nameAlg));
977 buffer += 2;
978
979 // Marshal the structure
980 #if ALG_RSA
981 // If the sensitive size is the special case for a prime in the type
982 if((sensitive->sensitive.rsa.t.size & RSA_prime_flag) > 0)
983 {
984 UINT16 sizeSave = sensitive->sensitive.rsa.t.size;
985 //
986 // Turn off the flag that indicates that the sensitive->sensitive contains
987 // the CRT form of the exponent.
988 sensitive->sensitive.rsa.t.size &= ~(RSA_prime_flag);
989 // If the parent isn't fixedTPM, then truncate the sensitive data to be
990 // the size of the prime. Otherwise, leave it at the current size which
991 // is the full CRT size.
992 if(parent == NULL
993 || !IS_ATTRIBUTE(parent->publicArea.objectAttributes,
994 TPMA_OBJECT, fixedTPM))
995 sensitive->sensitive.rsa.t.size /= 5;
996 retVal = TPMT_SENSITIVE_Marshal(sensitive, &buffer, NULL);
997 // Restore the flag and the size.
998 sensitive->sensitive.rsa.t.size = sizeSave;
999 }
1000 else
1001 #endif
1002 retVal = TPMT_SENSITIVE_Marshal(sensitive, &buffer, NULL);
1003
1004 // Marshal the size
1005 retVal = (UINT16)(retVal + UINT16_Marshal(&retVal, &sizeField, NULL));
1006
1007 return retVal;
1008 }
1009
1010 //*** SensitiveToPrivate()
1011 // This function prepare the private blob for off the chip storage
1012 // The operations in this function:
1013 // 1. marshal TPM2B_SENSITIVE structure into the buffer of TPM2B_PRIVATE
1014 // 2. apply encryption to the sensitive area.
1015 // 3. apply outer integrity computation.
1016 void
SensitiveToPrivate(TPMT_SENSITIVE * sensitive,TPM2B_NAME * name,OBJECT * parent,TPM_ALG_ID nameAlg,TPM2B_PRIVATE * outPrivate)1017 SensitiveToPrivate(
1018 TPMT_SENSITIVE *sensitive, // IN: sensitive structure
1019 TPM2B_NAME *name, // IN: the name of the object
1020 OBJECT *parent, // IN: The parent object
1021 TPM_ALG_ID nameAlg, // IN: hash algorithm in public area. This
1022 // parameter is used when parentHandle is
1023 // NULL, in which case the object is
1024 // temporary.
1025 TPM2B_PRIVATE *outPrivate // OUT: output private structure
1026 )
1027 {
1028 BYTE *sensitiveData; // pointer to the sensitive data
1029 UINT16 dataSize; // data blob size
1030 TPMI_ALG_HASH hashAlg; // hash algorithm for integrity
1031 UINT16 integritySize;
1032 UINT16 ivSize;
1033 //
1034 pAssert(name != NULL && name->t.size != 0);
1035
1036 // Find the hash algorithm for integrity computation
1037 if(parent == NULL)
1038 {
1039 // For Temporary Object, using self name algorithm
1040 hashAlg = nameAlg;
1041 }
1042 else
1043 {
1044 // Otherwise, using parent's name algorithm
1045 hashAlg = parent->publicArea.nameAlg;
1046 }
1047 // Starting of sensitive data without wrappers
1048 sensitiveData = outPrivate->t.buffer;
1049
1050 // Compute the integrity size
1051 integritySize = sizeof(UINT16) + CryptHashGetDigestSize(hashAlg);
1052
1053 // Reserve space for integrity
1054 sensitiveData += integritySize;
1055
1056 // Get iv size
1057 ivSize = GetIV2BSize(parent);
1058
1059 // Reserve space for iv
1060 sensitiveData += ivSize;
1061
1062 // Marshal the sensitive area including authValue size adjustments.
1063 dataSize = MarshalSensitive(parent, sensitiveData, sensitive, nameAlg);
1064
1065 //Produce outer wrap, including encryption and HMAC
1066 outPrivate->t.size = ProduceOuterWrap(parent, &name->b, hashAlg, NULL,
1067 TRUE, dataSize, outPrivate->t.buffer);
1068 return;
1069 }
1070
1071 //*** PrivateToSensitive()
1072 // Unwrap an input private area; check the integrity; decrypt and retrieve data
1073 // to a sensitive structure.
1074 // The operations in this function:
1075 // 1. check the integrity HMAC of the input private area
1076 // 2. decrypt the private buffer
1077 // 3. unmarshal TPMT_SENSITIVE structure into the buffer of TPMT_SENSITIVE
1078 // Return Type: TPM_RC
1079 // TPM_RCS_INTEGRITY if the private area integrity is bad
1080 // TPM_RC_SENSITIVE unmarshal errors while unmarshaling TPMS_ENCRYPT
1081 // from input private
1082 // TPM_RCS_SIZE error during sensitive data unmarshaling
1083 // TPM_RCS_VALUE outer wrapper does not have an iV of the correct
1084 // size
1085 TPM_RC
PrivateToSensitive(TPM2B * inPrivate,TPM2B * name,OBJECT * parent,TPM_ALG_ID nameAlg,TPMT_SENSITIVE * sensitive)1086 PrivateToSensitive(
1087 TPM2B *inPrivate, // IN: input private structure
1088 TPM2B *name, // IN: the name of the object
1089 OBJECT *parent, // IN: parent object
1090 TPM_ALG_ID nameAlg, // IN: hash algorithm in public area. It is
1091 // passed separately because we only pass
1092 // name, rather than the whole public area
1093 // of the object. This parameter is used in
1094 // the following two cases: 1. primary
1095 // objects. 2. duplication blob with inner
1096 // wrap. In other cases, this parameter
1097 // will be ignored
1098 TPMT_SENSITIVE *sensitive // OUT: sensitive structure
1099 )
1100 {
1101 TPM_RC result;
1102 BYTE *buffer;
1103 INT32 size;
1104 BYTE *sensitiveData; // pointer to the sensitive data
1105 UINT16 dataSize;
1106 UINT16 dataSizeInput;
1107 TPMI_ALG_HASH hashAlg; // hash algorithm for integrity
1108 UINT16 integritySize;
1109 UINT16 ivSize;
1110 //
1111 // Make sure that name is provided
1112 pAssert(name != NULL && name->size != 0);
1113
1114 // Find the hash algorithm for integrity computation
1115 // For Temporary Object (parent == NULL) use self name algorithm;
1116 // Otherwise, using parent's name algorithm
1117 hashAlg = (parent == NULL) ? nameAlg : parent->publicArea.nameAlg;
1118
1119 // unwrap outer
1120 result = UnwrapOuter(parent, name, hashAlg, NULL, TRUE,
1121 inPrivate->size, inPrivate->buffer);
1122 if(result != TPM_RC_SUCCESS)
1123 return result;
1124 // Compute the inner integrity size.
1125 integritySize = sizeof(UINT16) + CryptHashGetDigestSize(hashAlg);
1126
1127 // Get iv size
1128 ivSize = GetIV2BSize(parent);
1129
1130 // The starting of sensitive data and data size without outer wrapper
1131 sensitiveData = inPrivate->buffer + integritySize + ivSize;
1132 dataSize = inPrivate->size - integritySize - ivSize;
1133
1134 // Unmarshal input data size
1135 buffer = sensitiveData;
1136 size = (INT32)dataSize;
1137 result = UINT16_Unmarshal(&dataSizeInput, &buffer, &size);
1138 if(result == TPM_RC_SUCCESS)
1139 {
1140 if((dataSizeInput + sizeof(UINT16)) != dataSize)
1141 result = TPM_RC_SENSITIVE;
1142 else
1143 {
1144 // Unmarshal sensitive buffer to sensitive structure
1145 result = TPMT_SENSITIVE_Unmarshal(sensitive, &buffer, &size);
1146 if(result != TPM_RC_SUCCESS || size != 0)
1147 {
1148 result = TPM_RC_SENSITIVE;
1149 }
1150 }
1151 }
1152 return result;
1153 }
1154
1155 //*** SensitiveToDuplicate()
1156 // This function prepare the duplication blob from the sensitive area.
1157 // The operations in this function:
1158 // 1. marshal TPMT_SENSITIVE structure into the buffer of TPM2B_PRIVATE
1159 // 2. apply inner wrap to the sensitive area if required
1160 // 3. apply outer wrap if required
1161 void
SensitiveToDuplicate(TPMT_SENSITIVE * sensitive,TPM2B * name,OBJECT * parent,TPM_ALG_ID nameAlg,TPM2B * seed,TPMT_SYM_DEF_OBJECT * symDef,TPM2B_DATA * innerSymKey,TPM2B_PRIVATE * outPrivate)1162 SensitiveToDuplicate(
1163 TPMT_SENSITIVE *sensitive, // IN: sensitive structure
1164 TPM2B *name, // IN: the name of the object
1165 OBJECT *parent, // IN: The new parent object
1166 TPM_ALG_ID nameAlg, // IN: hash algorithm in public area. It
1167 // is passed separately because we
1168 // only pass name, rather than the
1169 // whole public area of the object.
1170 TPM2B *seed, // IN: the external seed. If external
1171 // seed is provided with size of 0,
1172 // no outer wrap should be applied
1173 // to duplication blob.
1174 TPMT_SYM_DEF_OBJECT *symDef, // IN: Symmetric key definition. If the
1175 // symmetric key algorithm is NULL,
1176 // no inner wrap should be applied.
1177 TPM2B_DATA *innerSymKey, // IN/OUT: a symmetric key may be
1178 // provided to encrypt the inner
1179 // wrap of a duplication blob. May
1180 // be generated here if needed.
1181 TPM2B_PRIVATE *outPrivate // OUT: output private structure
1182 )
1183 {
1184 BYTE *sensitiveData; // pointer to the sensitive data
1185 TPMI_ALG_HASH outerHash = TPM_ALG_NULL;// The hash algorithm for outer wrap
1186 TPMI_ALG_HASH innerHash = TPM_ALG_NULL;// The hash algorithm for inner wrap
1187 UINT16 dataSize; // data blob size
1188 BOOL doInnerWrap = FALSE;
1189 BOOL doOuterWrap = FALSE;
1190 //
1191 // Make sure that name is provided
1192 pAssert(name != NULL && name->size != 0);
1193
1194 // Make sure symDef and innerSymKey are not NULL
1195 pAssert(symDef != NULL && innerSymKey != NULL);
1196
1197 // Starting of sensitive data without wrappers
1198 sensitiveData = outPrivate->t.buffer;
1199
1200 // Find out if inner wrap is required
1201 if(symDef->algorithm != TPM_ALG_NULL)
1202 {
1203 doInnerWrap = TRUE;
1204
1205 // Use self nameAlg as inner hash algorithm
1206 innerHash = nameAlg;
1207
1208 // Adjust sensitive data pointer
1209 sensitiveData += sizeof(UINT16) + CryptHashGetDigestSize(innerHash);
1210 }
1211 // Find out if outer wrap is required
1212 if(seed->size != 0)
1213 {
1214 doOuterWrap = TRUE;
1215
1216 // Use parent nameAlg as outer hash algorithm
1217 outerHash = parent->publicArea.nameAlg;
1218
1219 // Adjust sensitive data pointer
1220 sensitiveData += sizeof(UINT16) + CryptHashGetDigestSize(outerHash);
1221 }
1222 // Marshal sensitive area
1223 dataSize = MarshalSensitive(NULL, sensitiveData, sensitive, nameAlg);
1224
1225 // Apply inner wrap for duplication blob. It includes both integrity and
1226 // encryption
1227 if(doInnerWrap)
1228 {
1229 BYTE *innerBuffer = NULL;
1230 BOOL symKeyInput = TRUE;
1231 innerBuffer = outPrivate->t.buffer;
1232 // Skip outer integrity space
1233 if(doOuterWrap)
1234 innerBuffer += sizeof(UINT16) + CryptHashGetDigestSize(outerHash);
1235 dataSize = ProduceInnerIntegrity(name, innerHash, dataSize,
1236 innerBuffer);
1237 // Generate inner encryption key if needed
1238 if(innerSymKey->t.size == 0)
1239 {
1240 innerSymKey->t.size = (symDef->keyBits.sym + 7) / 8;
1241 CryptRandomGenerate(innerSymKey->t.size, innerSymKey->t.buffer);
1242
1243 // TPM generates symmetric encryption. Set the flag to FALSE
1244 symKeyInput = FALSE;
1245 }
1246 else
1247 {
1248 // assume the input key size should matches the symmetric definition
1249 pAssert(innerSymKey->t.size == (symDef->keyBits.sym + 7) / 8);
1250 }
1251
1252 // Encrypt inner buffer in place
1253 CryptSymmetricEncrypt(innerBuffer, symDef->algorithm,
1254 symDef->keyBits.sym, innerSymKey->t.buffer, NULL,
1255 TPM_ALG_CFB, dataSize, innerBuffer);
1256
1257 // If the symmetric encryption key is imported, clear the buffer for
1258 // output
1259 if(symKeyInput)
1260 innerSymKey->t.size = 0;
1261 }
1262 // Apply outer wrap for duplication blob. It includes both integrity and
1263 // encryption
1264 if(doOuterWrap)
1265 {
1266 dataSize = ProduceOuterWrap(parent, name, outerHash, seed, FALSE,
1267 dataSize, outPrivate->t.buffer);
1268 }
1269 // Data size for output
1270 outPrivate->t.size = dataSize;
1271
1272 return;
1273 }
1274
1275 //*** DuplicateToSensitive()
1276 // Unwrap a duplication blob. Check the integrity, decrypt and retrieve data
1277 // to a sensitive structure.
1278 // The operations in this function:
1279 // 1. check the integrity HMAC of the input private area
1280 // 2. decrypt the private buffer
1281 // 3. unmarshal TPMT_SENSITIVE structure into the buffer of TPMT_SENSITIVE
1282 //
1283 // Return Type: TPM_RC
1284 // TPM_RC_INSUFFICIENT unmarshaling sensitive data from 'inPrivate' failed
1285 // TPM_RC_INTEGRITY 'inPrivate' data integrity is broken
1286 // TPM_RC_SIZE unmarshaling sensitive data from 'inPrivate' failed
1287 TPM_RC
DuplicateToSensitive(TPM2B * inPrivate,TPM2B * name,OBJECT * parent,TPM_ALG_ID nameAlg,TPM2B * seed,TPMT_SYM_DEF_OBJECT * symDef,TPM2B * innerSymKey,TPMT_SENSITIVE * sensitive)1288 DuplicateToSensitive(
1289 TPM2B *inPrivate, // IN: input private structure
1290 TPM2B *name, // IN: the name of the object
1291 OBJECT *parent, // IN: the parent
1292 TPM_ALG_ID nameAlg, // IN: hash algorithm in public area.
1293 TPM2B *seed, // IN: an external seed may be provided.
1294 // If external seed is provided with
1295 // size of 0, no outer wrap is
1296 // applied
1297 TPMT_SYM_DEF_OBJECT *symDef, // IN: Symmetric key definition. If the
1298 // symmetric key algorithm is NULL,
1299 // no inner wrap is applied
1300 TPM2B *innerSymKey, // IN: a symmetric key may be provided
1301 // to decrypt the inner wrap of a
1302 // duplication blob.
1303 TPMT_SENSITIVE *sensitive // OUT: sensitive structure
1304 )
1305 {
1306 TPM_RC result;
1307 BYTE *buffer;
1308 INT32 size;
1309 BYTE *sensitiveData; // pointer to the sensitive data
1310 UINT16 dataSize;
1311 UINT16 dataSizeInput;
1312 //
1313 // Make sure that name is provided
1314 pAssert(name != NULL && name->size != 0);
1315
1316 // Make sure symDef and innerSymKey are not NULL
1317 pAssert(symDef != NULL && innerSymKey != NULL);
1318
1319 // Starting of sensitive data
1320 sensitiveData = inPrivate->buffer;
1321 dataSize = inPrivate->size;
1322
1323 // Find out if outer wrap is applied
1324 if(seed->size != 0)
1325 {
1326 // Use parent nameAlg as outer hash algorithm
1327 TPMI_ALG_HASH outerHash = parent->publicArea.nameAlg;
1328
1329 result = UnwrapOuter(parent, name, outerHash, seed, FALSE,
1330 dataSize, sensitiveData);
1331 if(result != TPM_RC_SUCCESS)
1332 return result;
1333 // Adjust sensitive data pointer and size
1334 sensitiveData += sizeof(UINT16) + CryptHashGetDigestSize(outerHash);
1335 dataSize -= sizeof(UINT16) + CryptHashGetDigestSize(outerHash);
1336 }
1337 // Find out if inner wrap is applied
1338 if(symDef->algorithm != TPM_ALG_NULL)
1339 {
1340 // assume the input key size matches the symmetric definition
1341 pAssert(innerSymKey->size == (symDef->keyBits.sym + 7) / 8);
1342
1343 // Decrypt inner buffer in place
1344 CryptSymmetricDecrypt(sensitiveData, symDef->algorithm,
1345 symDef->keyBits.sym, innerSymKey->buffer, NULL,
1346 TPM_ALG_CFB, dataSize, sensitiveData);
1347 // Check inner integrity
1348 result = CheckInnerIntegrity(name, nameAlg, dataSize, sensitiveData);
1349 if(result != TPM_RC_SUCCESS)
1350 return result;
1351 // Adjust sensitive data pointer and size
1352 sensitiveData += sizeof(UINT16) + CryptHashGetDigestSize(nameAlg);
1353 dataSize -= sizeof(UINT16) + CryptHashGetDigestSize(nameAlg);
1354 }
1355 // Unmarshal input data size
1356 buffer = sensitiveData;
1357 size = (INT32)dataSize;
1358 result = UINT16_Unmarshal(&dataSizeInput, &buffer, &size);
1359 if(result == TPM_RC_SUCCESS)
1360 {
1361 if((dataSizeInput + sizeof(UINT16)) != dataSize)
1362 result = TPM_RC_SIZE;
1363 else
1364 {
1365 // Unmarshal sensitive buffer to sensitive structure
1366 result = TPMT_SENSITIVE_Unmarshal(sensitive, &buffer, &size);
1367
1368 // if the results is OK make sure that all the data was unmarshaled
1369 if(result == TPM_RC_SUCCESS && size != 0)
1370 result = TPM_RC_SIZE;
1371 }
1372 }
1373 return result;
1374 }
1375
1376 //*** SecretToCredential()
1377 // This function prepare the credential blob from a secret (a TPM2B_DIGEST)
1378 // The operations in this function:
1379 // 1. marshal TPM2B_DIGEST structure into the buffer of TPM2B_ID_OBJECT
1380 // 2. encrypt the private buffer, excluding the leading integrity HMAC area
1381 // 3. compute integrity HMAC and append to the beginning of the buffer.
1382 // 4. Set the total size of TPM2B_ID_OBJECT buffer
1383 void
SecretToCredential(TPM2B_DIGEST * secret,TPM2B * name,TPM2B * seed,OBJECT * protector,TPM2B_ID_OBJECT * outIDObject)1384 SecretToCredential(
1385 TPM2B_DIGEST *secret, // IN: secret information
1386 TPM2B *name, // IN: the name of the object
1387 TPM2B *seed, // IN: an external seed.
1388 OBJECT *protector, // IN: the protector
1389 TPM2B_ID_OBJECT *outIDObject // OUT: output credential
1390 )
1391 {
1392 BYTE *buffer; // Auxiliary buffer pointer
1393 BYTE *sensitiveData; // pointer to the sensitive data
1394 TPMI_ALG_HASH outerHash; // The hash algorithm for outer wrap
1395 UINT16 dataSize; // data blob size
1396 //
1397 pAssert(secret != NULL && outIDObject != NULL);
1398
1399 // use protector's name algorithm as outer hash ????
1400 outerHash = protector->publicArea.nameAlg;
1401
1402 // Marshal secret area to credential buffer, leave space for integrity
1403 sensitiveData = outIDObject->t.credential
1404 + sizeof(UINT16) + CryptHashGetDigestSize(outerHash);
1405 // Marshal secret area
1406 buffer = sensitiveData;
1407 dataSize = TPM2B_DIGEST_Marshal(secret, &buffer, NULL);
1408
1409 // Apply outer wrap
1410 outIDObject->t.size = ProduceOuterWrap(protector, name, outerHash, seed, FALSE,
1411 dataSize, outIDObject->t.credential);
1412 return;
1413 }
1414
1415 //*** CredentialToSecret()
1416 // Unwrap a credential. Check the integrity, decrypt and retrieve data
1417 // to a TPM2B_DIGEST structure.
1418 // The operations in this function:
1419 // 1. check the integrity HMAC of the input credential area
1420 // 2. decrypt the credential buffer
1421 // 3. unmarshal TPM2B_DIGEST structure into the buffer of TPM2B_DIGEST
1422 //
1423 // Return Type: TPM_RC
1424 // TPM_RC_INSUFFICIENT error during credential unmarshaling
1425 // TPM_RC_INTEGRITY credential integrity is broken
1426 // TPM_RC_SIZE error during credential unmarshaling
1427 // TPM_RC_VALUE IV size does not match the encryption algorithm
1428 // block size
1429 TPM_RC
CredentialToSecret(TPM2B * inIDObject,TPM2B * name,TPM2B * seed,OBJECT * protector,TPM2B_DIGEST * secret)1430 CredentialToSecret(
1431 TPM2B *inIDObject, // IN: input credential blob
1432 TPM2B *name, // IN: the name of the object
1433 TPM2B *seed, // IN: an external seed.
1434 OBJECT *protector, // IN: the protector
1435 TPM2B_DIGEST *secret // OUT: secret information
1436 )
1437 {
1438 TPM_RC result;
1439 BYTE *buffer;
1440 INT32 size;
1441 TPMI_ALG_HASH outerHash; // The hash algorithm for outer wrap
1442 BYTE *sensitiveData; // pointer to the sensitive data
1443 UINT16 dataSize;
1444 //
1445 // use protector's name algorithm as outer hash
1446 outerHash = protector->publicArea.nameAlg;
1447
1448 // Unwrap outer, a TPM_RC_INTEGRITY error may be returned at this point
1449 result = UnwrapOuter(protector, name, outerHash, seed, FALSE,
1450 inIDObject->size, inIDObject->buffer);
1451 if(result == TPM_RC_SUCCESS)
1452 {
1453 // Compute the beginning of sensitive data
1454 sensitiveData = inIDObject->buffer
1455 + sizeof(UINT16) + CryptHashGetDigestSize(outerHash);
1456 dataSize = inIDObject->size
1457 - (sizeof(UINT16) + CryptHashGetDigestSize(outerHash));
1458 // Unmarshal secret buffer to TPM2B_DIGEST structure
1459 buffer = sensitiveData;
1460 size = (INT32)dataSize;
1461 result = TPM2B_DIGEST_Unmarshal(secret, &buffer, &size);
1462
1463 // If there were no other unmarshaling errors, make sure that the
1464 // expected amount of data was recovered
1465 if(result == TPM_RC_SUCCESS && size != 0)
1466 return TPM_RC_SIZE;
1467 }
1468 return result;
1469 }
1470
1471 //*** MemoryRemoveTrailingZeros()
1472 // This function is used to adjust the length of an authorization value.
1473 // It adjusts the size of the TPM2B so that it does not include octets
1474 // at the end of the buffer that contain zero.
1475 // The function returns the number of non-zero octets in the buffer.
1476 UINT16
MemoryRemoveTrailingZeros(TPM2B_AUTH * auth)1477 MemoryRemoveTrailingZeros(
1478 TPM2B_AUTH *auth // IN/OUT: value to adjust
1479 )
1480 {
1481 while((auth->t.size > 0) && (auth->t.buffer[auth->t.size - 1] == 0))
1482 auth->t.size--;
1483 return auth->t.size;
1484 }
1485
1486 //*** SetLabelAndContext()
1487 // This function sets the label and context for a derived key. It is possible
1488 // that 'label' or 'context' can end up being an Empty Buffer.
1489 TPM_RC
SetLabelAndContext(TPMS_DERIVE * labelContext,TPM2B_SENSITIVE_DATA * sensitive)1490 SetLabelAndContext(
1491 TPMS_DERIVE *labelContext, // IN/OUT: the recovered label and
1492 // context
1493 TPM2B_SENSITIVE_DATA *sensitive // IN: the sensitive data
1494 )
1495 {
1496 TPMS_DERIVE sensitiveValue;
1497 TPM_RC result;
1498 INT32 size;
1499 BYTE *buff;
1500 //
1501 // Unmarshal a TPMS_DERIVE from the TPM2B_SENSITIVE_DATA buffer
1502 // If there is something to unmarshal...
1503 if(sensitive->t.size != 0)
1504 {
1505 size = sensitive->t.size;
1506 buff = sensitive->t.buffer;
1507 result = TPMS_DERIVE_Unmarshal(&sensitiveValue, &buff, &size);
1508 if(result != TPM_RC_SUCCESS)
1509 return result;
1510 // If there was a label in the public area leave it there, otherwise, copy
1511 // the new value
1512 if(labelContext->label.t.size == 0)
1513 MemoryCopy2B(&labelContext->label.b, &sensitiveValue.label.b,
1514 sizeof(labelContext->label.t.buffer));
1515 // if there was a context string in publicArea, it overrides
1516 if(labelContext->context.t.size == 0)
1517 MemoryCopy2B(&labelContext->context.b, &sensitiveValue.context.b,
1518 sizeof(labelContext->label.t.buffer));
1519 }
1520 return TPM_RC_SUCCESS;
1521 }
1522
1523 //*** UnmarshalToPublic()
1524 // Support function to unmarshal the template. This is used because the
1525 // Input may be a TPMT_TEMPLATE and that structure does not have the same
1526 // size as a TPMT_PUBLIC because of the difference between the 'unique' and
1527 // 'seed' fields.
1528 // If 'derive' is not NULL, then the 'seed' field is assumed to contain
1529 // a 'label' and 'context' that are unmarshaled into 'derive'.
1530 TPM_RC
UnmarshalToPublic(TPMT_PUBLIC * tOut,TPM2B_TEMPLATE * tIn,BOOL derivation,TPMS_DERIVE * labelContext)1531 UnmarshalToPublic(
1532 TPMT_PUBLIC *tOut, // OUT: output
1533 TPM2B_TEMPLATE *tIn, // IN:
1534 BOOL derivation, // IN: indicates if this is for a derivation
1535 TPMS_DERIVE *labelContext// OUT: label and context if derivation
1536 )
1537 {
1538 BYTE *buffer = tIn->t.buffer;
1539 INT32 size = tIn->t.size;
1540 TPM_RC result;
1541 //
1542 // make sure that tOut is zeroed so that there are no remnants from previous
1543 // uses
1544 MemorySet(tOut, 0, sizeof(TPMT_PUBLIC));
1545 // Unmarshal the components of the TPMT_PUBLIC up to the unique field
1546 result = TPMI_ALG_PUBLIC_Unmarshal(&tOut->type, &buffer, &size);
1547 if(result != TPM_RC_SUCCESS)
1548 return result;
1549 result = TPMI_ALG_HASH_Unmarshal(&tOut->nameAlg, &buffer, &size, FALSE);
1550 if(result != TPM_RC_SUCCESS)
1551 return result;
1552 result = TPMA_OBJECT_Unmarshal(&tOut->objectAttributes, &buffer, &size);
1553 if(result != TPM_RC_SUCCESS)
1554 return result;
1555 result = TPM2B_DIGEST_Unmarshal(&tOut->authPolicy, &buffer, &size);
1556 if(result != TPM_RC_SUCCESS)
1557 return result;
1558 result = TPMU_PUBLIC_PARMS_Unmarshal(&tOut->parameters, &buffer, &size,
1559 tOut->type);
1560 if(result != TPM_RC_SUCCESS)
1561 return result;
1562 // Now unmarshal a TPMS_DERIVE if this is for derivation
1563 if(derivation)
1564 result = TPMS_DERIVE_Unmarshal(labelContext, &buffer, &size);
1565 else
1566 // otherwise, unmarshal a TPMU_PUBLIC_ID
1567 result = TPMU_PUBLIC_ID_Unmarshal(&tOut->unique, &buffer, &size,
1568 tOut->type);
1569 // Make sure the template was used up
1570 if((result == TPM_RC_SUCCESS) && (size != 0))
1571 result = TPM_RC_SIZE;
1572 return result;
1573 }
1574
1575
1576 //*** ObjectSetExternal()
1577 // Set the external attributes for an object.
1578 void
ObjectSetExternal(OBJECT * object)1579 ObjectSetExternal(
1580 OBJECT *object
1581 )
1582 {
1583 object->attributes.external = SET;
1584 }