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