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