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