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