blob: 4cf13c7cb286881f4030a2e6460801dc9b48608d [file] [log] [blame]
// This file was extracted from the TCG Published
// Trusted Platform Module Library
// Part 4: Supporting Routines
// Family "2.0"
// Level 00 Revision 01.16
// October 30, 2014
#include "InternalRoutines.h"
#include "Object_spt_fp.h"
#include "Platform.h"
//
//
//
// Local Functions
//
// EqualCryptSet()
//
// Check if the crypto sets in two public areas are equal
//
// Error Returns Meaning
//
// TPM_RC_ASYMMETRIC mismatched parameters
// TPM_RC_HASH mismatched name algorithm
// TPM_RC_TYPE mismatched type
//
static TPM_RC
EqualCryptSet(
TPMT_PUBLIC *publicArea1, // IN: public area 1
TPMT_PUBLIC *publicArea2 // IN: public area 2
)
{
UINT16 size1;
UINT16 size2;
BYTE params1[sizeof(TPMU_PUBLIC_PARMS)];
BYTE params2[sizeof(TPMU_PUBLIC_PARMS)];
BYTE *buffer;
INT32 bufferSize;
// Compare name hash
if(publicArea1->nameAlg != publicArea2->nameAlg)
return TPM_RC_HASH;
// Compare algorithm
if(publicArea1->type != publicArea2->type)
return TPM_RC_TYPE;
// TPMU_PUBLIC_PARMS field should be identical
buffer = params1;
bufferSize = sizeof(TPMU_PUBLIC_PARMS);
size1 = TPMU_PUBLIC_PARMS_Marshal(&publicArea1->parameters, &buffer,
&bufferSize, publicArea1->type);
buffer = params2;
bufferSize = sizeof(TPMU_PUBLIC_PARMS);
size2 = TPMU_PUBLIC_PARMS_Marshal(&publicArea2->parameters, &buffer,
&bufferSize, publicArea2->type);
if(size1 != size2 || !MemoryEqual(params1, params2, size1))
return TPM_RC_ASYMMETRIC;
return TPM_RC_SUCCESS;
}
//
//
// GetIV2BSize()
//
// Get the size of TPM2B_IV in canonical form that will be append to the start of the sensitive data. It
// includes both size of size field and size of iv data
//
// Return Value Meaning
//
static UINT16
GetIV2BSize(
TPM_HANDLE protectorHandle // IN: the protector handle
)
{
OBJECT *protector = NULL; // Pointer to the protector object
TPM_ALG_ID symAlg;
//
UINT16 keyBits;
// Determine the symmetric algorithm and size of key
if(protectorHandle == TPM_RH_NULL)
{
// Use the context encryption algorithm and key size
symAlg = CONTEXT_ENCRYPT_ALG;
keyBits = CONTEXT_ENCRYPT_KEY_BITS;
}
else
{
protector = ObjectGet(protectorHandle);
symAlg = protector->publicArea.parameters.asymDetail.symmetric.algorithm;
keyBits= protector->publicArea.parameters.asymDetail.symmetric.keyBits.sym;
}
// The IV size is a UINT16 size field plus the block size of the symmetric
// algorithm
return sizeof(UINT16) + CryptGetSymmetricBlockSize(symAlg, keyBits);
}
//
//
// ComputeProtectionKeyParms()
//
// This function retrieves the symmetric protection key parameters for the sensitive data The parameters
// retrieved from this function include encryption algorithm, key size in bit, and a TPM2B_SYM_KEY
// containing the key material as well as the key size in bytes This function is used for any action that
// requires encrypting or decrypting of the sensitive area of an object or a credential blob
//
static void
ComputeProtectionKeyParms(
TPM_HANDLE protectorHandle, // IN: the protector handle
TPM_ALG_ID hashAlg, // IN: hash algorithm for KDFa
TPM2B_NAME *name, // IN: name of the object
TPM2B_SEED *seedIn, // IN: optional seed for duplication blob.
// For non duplication blob, this
// parameter should be NULL
TPM_ALG_ID *symAlg, // OUT: the symmetric algorithm
UINT16 *keyBits, // OUT: the symmetric key size in bits
TPM2B_SYM_KEY *symKey // OUT: the symmetric key
)
{
TPM2B_SEED *seed = NULL;
OBJECT *protector = NULL; // Pointer to the protector
// Determine the algorithms for the KDF and the encryption/decryption
// For TPM_RH_NULL, using context settings
if(protectorHandle == TPM_RH_NULL)
{
// Use the context encryption algorithm and key size
*symAlg = CONTEXT_ENCRYPT_ALG;
symKey->t.size = CONTEXT_ENCRYPT_KEY_BYTES;
*keyBits = CONTEXT_ENCRYPT_KEY_BITS;
}
else
{
TPMT_SYM_DEF_OBJECT *symDef;
protector = ObjectGet(protectorHandle);
symDef = &protector->publicArea.parameters.asymDetail.symmetric;
*symAlg = symDef->algorithm;
*keyBits= symDef->keyBits.sym;
symKey->t.size = (*keyBits + 7) / 8;
}
// Get seed for KDF
seed = GetSeedForKDF(protectorHandle, seedIn);
// KDFa to generate symmetric key and IV value
KDFa(hashAlg, (TPM2B *)seed, "STORAGE", (TPM2B *)name, NULL,
symKey->t.size * 8, symKey->t.buffer, NULL);
return;
}
//
//
// ComputeOuterIntegrity()
//
// The sensitive area parameter is a buffer that holds a space for the integrity value and the marshaled
// sensitive area. The caller should skip over the area set aside for the integrity value and compute the hash
// of the remainder of the object. The size field of sensitive is in unmarshaled form and the sensitive area
// contents is an array of bytes.
//
static void
ComputeOuterIntegrity(
TPM2B_NAME *name, // IN: the name of the object
TPM_HANDLE protectorHandle, // IN: The handle of the object that
// provides protection. For object, it
// is parent handle. For credential, it
// is the handle of encrypt object. For
// a Temporary Object, it is TPM_RH_NULL
TPMI_ALG_HASH hashAlg, // IN: algorithm to use for integrity
TPM2B_SEED *seedIn, // IN: an external seed may be provided for
// duplication blob. For non duplication
// blob, this parameter should be NULL
UINT32 sensitiveSize, // IN: size of the marshaled sensitive data
BYTE *sensitiveData, // IN: sensitive area
TPM2B_DIGEST *integrity // OUT: integrity
)
{
HMAC_STATE hmacState;
TPM2B_DIGEST hmacKey;
TPM2B_SEED *seed = NULL;
// Get seed for KDF
seed = GetSeedForKDF(protectorHandle, seedIn);
// Determine the HMAC key bits
hmacKey.t.size = CryptGetHashDigestSize(hashAlg);
// KDFa to generate HMAC key
KDFa(hashAlg, (TPM2B *)seed, "INTEGRITY", NULL, NULL,
hmacKey.t.size * 8, hmacKey.t.buffer, NULL);
// Start HMAC and get the size of the digest which will become the integrity
integrity->t.size = CryptStartHMAC2B(hashAlg, &hmacKey.b, &hmacState);
// Adding the marshaled sensitive area to the integrity value
CryptUpdateDigest(&hmacState, sensitiveSize, sensitiveData);
// Adding name
CryptUpdateDigest2B(&hmacState, (TPM2B *)name);
// Compute HMAC
CryptCompleteHMAC2B(&hmacState, &integrity->b);
return;
}
//
//
// ComputeInnerIntegrity()
//
// This function computes the integrity of an inner wrap
//
static void
ComputeInnerIntegrity(
TPM_ALG_ID hashAlg, // IN: hash algorithm for inner wrap
TPM2B_NAME *name, // IN: the name of the object
UINT16 dataSize, // IN: the size of sensitive data
BYTE *sensitiveData, // IN: sensitive data
TPM2B_DIGEST *integrity // OUT: inner integrity
)
{
HASH_STATE hashState;
// Start hash and get the size of the digest which will become the integrity
integrity->t.size = CryptStartHash(hashAlg, &hashState);
// Adding the marshaled sensitive area to the integrity value
CryptUpdateDigest(&hashState, dataSize, sensitiveData);
// Adding name
CryptUpdateDigest2B(&hashState, &name->b);
// Compute hash
CryptCompleteHash2B(&hashState, &integrity->b);
return;
}
//
//
// ProduceInnerIntegrity()
//
// This function produces an inner integrity for regular private, credential or duplication blob It requires the
// sensitive data being marshaled to the innerBuffer, with the leading bytes reserved for integrity hash. It
// assume the sensitive data starts at address (innerBuffer + integrity size). This function integrity at the
// beginning of the inner buffer It returns the total size of buffer with the inner wrap
//
static UINT16
ProduceInnerIntegrity(
TPM2B_NAME *name, // IN: the name of the object
TPM_ALG_ID hashAlg, // IN: hash algorithm for inner wrap
UINT16 dataSize, // IN: the size of sensitive data, excluding the
// leading integrity buffer size
BYTE *innerBuffer // IN/OUT: inner buffer with sensitive data in
// it. At input, the leading bytes of this
// buffer is reserved for integrity
)
{
BYTE *sensitiveData; // pointer to the sensitive data
TPM2B_DIGEST integrity;
UINT16 integritySize;
BYTE *buffer; // Auxiliary buffer pointer
INT32 bufferSize;
// sensitiveData points to the beginning of sensitive data in innerBuffer
integritySize = sizeof(UINT16) + CryptGetHashDigestSize(hashAlg);
sensitiveData = innerBuffer + integritySize;
ComputeInnerIntegrity(hashAlg, name, dataSize, sensitiveData, &integrity);
// Add integrity at the beginning of inner buffer
buffer = innerBuffer;
bufferSize = sizeof(TPM2B_DIGEST);
TPM2B_DIGEST_Marshal(&integrity, &buffer, &bufferSize);
return dataSize + integritySize;
}
//
//
// CheckInnerIntegrity()
//
// This function check integrity of inner blob
//
// Error Returns Meaning
//
// TPM_RC_INTEGRITY if the outer blob integrity is bad
// unmarshal errors unmarshal errors while unmarshaling integrity
//
static TPM_RC
CheckInnerIntegrity(
TPM2B_NAME *name, // IN: the name of the object
TPM_ALG_ID hashAlg, // IN: hash algorithm for inner wrap
UINT16 dataSize, // IN: the size of sensitive data, including the
// leading integrity buffer size
BYTE *innerBuffer // IN/OUT: inner buffer with sensitive data in
// it
)
{
TPM_RC result;
TPM2B_DIGEST integrity;
TPM2B_DIGEST integrityToCompare;
BYTE *buffer; // Auxiliary buffer pointer
INT32 size;
// Unmarshal integrity
buffer = innerBuffer;
size = (INT32) dataSize;
result = TPM2B_DIGEST_Unmarshal(&integrity, &buffer, &size);
if(result == TPM_RC_SUCCESS)
{
// Compute integrity to compare
ComputeInnerIntegrity(hashAlg, name, (UINT16) size, buffer,
&integrityToCompare);
// Compare outer blob integrity
if(!Memory2BEqual(&integrity.b, &integrityToCompare.b))
result = TPM_RC_INTEGRITY;
}
return result;
}
//
//
// Public Functions
//
// AreAttributesForParent()
//
// This function is called by create, load, and import functions.
//
// Return Value Meaning
//
// TRUE properties are those of a parent
// FALSE properties are not those of a parent
//
BOOL
AreAttributesForParent(
OBJECT *parentObject // IN: parent handle
)
{
// This function is only called when a parent is needed. Any
// time a "parent" is used, it must be authorized. When
// the authorization is checked, both the public and sensitive
// areas must be loaded. Just make sure...
pAssert(parentObject->attributes.publicOnly == CLEAR);
if(ObjectDataIsStorage(&parentObject->publicArea))
return TRUE;
else
return FALSE;
}
//
//
// SchemeChecks()
//
// This function validates the schemes in the public area of an object. This function is called by
// TPM2_LoadExternal() and PublicAttributesValidation().
//
// Error Returns Meaning
//
// TPM_RC_ASYMMETRIC non-duplicable storage key and its parent have different public
// parameters
// TPM_RC_ATTRIBUTES attempt to inject sensitive data for an asymmetric key; or attempt to
// create a symmetric cipher key that is not a decryption key
// TPM_RC_HASH non-duplicable storage key and its parent have different name
// algorithm
// TPM_RC_KDF incorrect KDF specified for decrypting keyed hash object
// TPM_RC_KEY invalid key size values in an asymmetric key public area
// TPM_RC_SCHEME inconsistent attributes decrypt, sign, restricted and key's scheme ID;
// or hash algorithm is inconsistent with the scheme ID for keyed hash
// object
// TPM_RC_SYMMETRIC a storage key with no symmetric algorithm specified; or non-storage
// key with symmetric algorithm different from TPM_ALG_NULL
// TPM_RC_TYPE unexpected object type; or non-duplicable storage key and its parent
// have different types
//
TPM_RC
SchemeChecks(
BOOL load, // IN: TRUE if load checks, FALSE if
// TPM2_Create()
TPMI_DH_OBJECT parentHandle, // IN: input parent handle
TPMT_PUBLIC *publicArea // IN: public area of the object
)
{
// Checks for an asymmetric key
if(CryptIsAsymAlgorithm(publicArea->type))
{
TPMT_ASYM_SCHEME *keyScheme;
keyScheme = &publicArea->parameters.asymDetail.scheme;
// An asymmetric key can't be injected
// This is only checked when creating an object
if(!load && (publicArea->objectAttributes.sensitiveDataOrigin == CLEAR))
return TPM_RC_ATTRIBUTES;
if(load && !CryptAreKeySizesConsistent(publicArea))
return TPM_RC_KEY;
// Keys that are both signing and decrypting must have TPM_ALG_NULL
// for scheme
if( publicArea->objectAttributes.sign == SET
&& publicArea->objectAttributes.decrypt == SET
&& keyScheme->scheme != TPM_ALG_NULL)
return TPM_RC_SCHEME;
// A restrict sign key must have a non-NULL scheme
if( publicArea->objectAttributes.restricted == SET
&& publicArea->objectAttributes.sign == SET
&& keyScheme->scheme == TPM_ALG_NULL)
return TPM_RC_SCHEME;
// Keys must have a valid sign or decrypt scheme, or a TPM_ALG_NULL
// scheme
// NOTE: The unmarshaling for a public area will unmarshal based on the
// object type. If the type is an RSA key, then only RSA schemes will be
// allowed because a TPMI_ALG_RSA_SCHEME will be unmarshaled and it
// consists only of those algorithms that are allowed with an RSA key.
// This means that there is no need to again make sure that the algorithm
// is compatible with the object type.
if( keyScheme->scheme != TPM_ALG_NULL
&& ( ( publicArea->objectAttributes.sign == SET
&& !CryptIsSignScheme(keyScheme->scheme)
)
|| ( publicArea->objectAttributes.decrypt == SET
&& !CryptIsDecryptScheme(keyScheme->scheme)
)
)
)
return TPM_RC_SCHEME;
// Special checks for an ECC key
#ifdef TPM_ALG_ECC
if(publicArea->type == TPM_ALG_ECC)
{
TPM_ECC_CURVE curveID = publicArea->parameters.eccDetail.curveID;
const TPMT_ECC_SCHEME *curveScheme = CryptGetCurveSignScheme(curveID);
// The curveId must be valid or the unmarshaling is busted.
pAssert(curveScheme != NULL);
// If the curveID requires a specific scheme, then the key must select
// the same scheme
if(curveScheme->scheme != TPM_ALG_NULL)
{
if(keyScheme->scheme != curveScheme->scheme)
return TPM_RC_SCHEME;
// The scheme can allow any hash, or not...
if( curveScheme->details.anySig.hashAlg != TPM_ALG_NULL
&& ( keyScheme->details.anySig.hashAlg
!= curveScheme->details.anySig.hashAlg
)
)
return TPM_RC_SCHEME;
}
// For now, the KDF must be TPM_ALG_NULL
if(publicArea->parameters.eccDetail.kdf.scheme != TPM_ALG_NULL)
return TPM_RC_KDF;
}
#endif
// Checks for a storage key (restricted + decryption)
if( publicArea->objectAttributes.restricted == SET
&& publicArea->objectAttributes.decrypt == SET)
{
// A storage key must have a valid protection key
if( publicArea->parameters.asymDetail.symmetric.algorithm
== TPM_ALG_NULL)
return TPM_RC_SYMMETRIC;
// A storage key must have a null scheme
if(publicArea->parameters.asymDetail.scheme.scheme != TPM_ALG_NULL)
return TPM_RC_SCHEME;
// A storage key must match its parent algorithms unless
// it is duplicable or a primary (including Temporary Primary Objects)
if( HandleGetType(parentHandle) != TPM_HT_PERMANENT
&& publicArea->objectAttributes.fixedParent == SET
)
{
// If the object to be created is a storage key, and is fixedParent,
// its crypto set has to match its parent's crypto set. TPM_RC_TYPE,
// TPM_RC_HASH or TPM_RC_ASYMMETRIC may be returned at this point
return EqualCryptSet(publicArea,
&(ObjectGet(parentHandle)->publicArea));
}
}
else
{
// Non-storage keys must have TPM_ALG_NULL for the symmetric algorithm
if( publicArea->parameters.asymDetail.symmetric.algorithm
!= TPM_ALG_NULL)
return TPM_RC_SYMMETRIC;
}// End of asymmetric decryption key checks
} // End of asymmetric checks
// Check for bit attributes
else if(publicArea->type == TPM_ALG_KEYEDHASH)
{
TPMT_KEYEDHASH_SCHEME *scheme
= &publicArea->parameters.keyedHashDetail.scheme;
// If both sign and decrypt are set the scheme must be TPM_ALG_NULL
// and the scheme selected when the key is used.
// If neither sign nor decrypt is set, the scheme must be TPM_ALG_NULL
// because this is a data object.
if( publicArea->objectAttributes.sign
== publicArea->objectAttributes.decrypt)
{
if(scheme->scheme != TPM_ALG_NULL)
return TPM_RC_SCHEME;
return TPM_RC_SUCCESS;
}
// If this is a decryption key, make sure that is is XOR and that there
// is a KDF
else if(publicArea->objectAttributes.decrypt)
{
if( scheme->scheme != TPM_ALG_XOR
|| scheme->details.xor_.hashAlg == TPM_ALG_NULL)
return TPM_RC_SCHEME;
if(scheme->details.xor_.kdf == TPM_ALG_NULL)
return TPM_RC_KDF;
return TPM_RC_SUCCESS;
}
// only supported signing scheme for keyedHash object is HMAC
if( scheme->scheme != TPM_ALG_HMAC
|| scheme->details.hmac.hashAlg == TPM_ALG_NULL)
return TPM_RC_SCHEME;
// end of the checks for keyedHash
return TPM_RC_SUCCESS;
}
else if (publicArea->type == TPM_ALG_SYMCIPHER)
{
// Must be a decrypting key and may not be a signing key
if( publicArea->objectAttributes.decrypt == CLEAR
|| publicArea->objectAttributes.sign == SET
)
return TPM_RC_ATTRIBUTES;
}
else
return TPM_RC_TYPE;
return TPM_RC_SUCCESS;
}
//
//
// PublicAttributesValidation()
//
// This function validates the values in the public area of an object. This function is called by
// TPM2_Create(), TPM2_Load(), and TPM2_CreatePrimary()
//
// Error Returns Meaning
//
// TPM_RC_ASYMMETRIC non-duplicable storage key and its parent have different public
// parameters
// TPM_RC_ATTRIBUTES fixedTPM, fixedParent, or encryptedDuplication attributes are
// inconsistent between themselves or with those of the parent object;
// inconsistent restricted, decrypt and sign attributes; attempt to inject
// sensitive data for an asymmetric key; attempt to create a symmetric
// cipher key that is not a decryption key
// TPM_RC_HASH non-duplicable storage key and its parent have different name
// algorithm
// TPM_RC_KDF incorrect KDF specified for decrypting keyed hash object
// TPM_RC_KEY invalid key size values in an asymmetric key public area
// TPM_RC_SCHEME inconsistent attributes decrypt, sign, restricted and key's scheme ID;
// or hash algorithm is inconsistent with the scheme ID for keyed hash
// object
// TPM_RC_SIZE authPolicy size does not match digest size of the name algorithm in
// publicArea
// TPM_RC_SYMMETRIC a storage key with no symmetric algorithm specified; or non-storage
// key with symmetric algorithm different from TPM_ALG_NULL
// TPM_RC_TYPE unexpected object type; or non-duplicable storage key and its parent
// have different types
//
TPM_RC
PublicAttributesValidation(
BOOL load, // IN: TRUE if load checks, FALSE if
// TPM2_Create()
TPMI_DH_OBJECT parentHandle, // IN: input parent handle
TPMT_PUBLIC *publicArea // IN: public area of the object
)
{
OBJECT *parentObject = NULL;
if(HandleGetType(parentHandle) != TPM_HT_PERMANENT)
parentObject = ObjectGet(parentHandle);
if (publicArea->nameAlg == TPM_ALG_NULL)
return TPM_RC_HASH;
// Check authPolicy digest consistency
if( publicArea->authPolicy.t.size != 0
&& ( publicArea->authPolicy.t.size
!= CryptGetHashDigestSize(publicArea->nameAlg)
)
)
return TPM_RC_SIZE;
// If the parent is fixedTPM (including a Primary Object) the object must have
// the same value for fixedTPM and fixedParent
if( parentObject == NULL
|| parentObject->publicArea.objectAttributes.fixedTPM == SET)
{
if( publicArea->objectAttributes.fixedParent
!= publicArea->objectAttributes.fixedTPM
)
return TPM_RC_ATTRIBUTES;
}
else
// The parent is not fixedTPM so the object can't be fixedTPM
if(publicArea->objectAttributes.fixedTPM == SET)
return TPM_RC_ATTRIBUTES;
// A restricted object cannot be both sign and decrypt and it can't be neither
// sign nor decrypt
if ( publicArea->objectAttributes.restricted == SET
&& ( publicArea->objectAttributes.decrypt
== publicArea->objectAttributes.sign)
)
return TPM_RC_ATTRIBUTES;
// A fixedTPM object can not have encryptedDuplication bit SET
if( publicArea->objectAttributes.fixedTPM == SET
&& publicArea->objectAttributes.encryptedDuplication == SET)
return TPM_RC_ATTRIBUTES;
// If a parent object has fixedTPM CLEAR, the child must have the
// same encryptedDuplication value as its parent.
// Primary objects are considered to have a fixedTPM parent (the seeds).
if( ( parentObject != NULL
&& parentObject->publicArea.objectAttributes.fixedTPM == CLEAR)
// Get here if parent is not fixed TPM
&& ( publicArea->objectAttributes.encryptedDuplication
!= parentObject->publicArea.objectAttributes.encryptedDuplication
)
)
return TPM_RC_ATTRIBUTES;
return SchemeChecks(load, parentHandle, publicArea);
}
//
//
// FillInCreationData()
//
// Fill in creation data for an object.
//
void
FillInCreationData(
TPMI_DH_OBJECT parentHandle, // IN: handle of parent
TPMI_ALG_HASH nameHashAlg, // IN: name hash algorithm
TPML_PCR_SELECTION *creationPCR, // IN: PCR selection
TPM2B_DATA *outsideData, // IN: outside data
TPM2B_CREATION_DATA *outCreation, // OUT: creation data for output
TPM2B_DIGEST *creationDigest // OUT: creation digest
//
)
{
BYTE creationBuffer[sizeof(TPMS_CREATION_DATA)];
BYTE *buffer;
INT32 bufferSize;
HASH_STATE hashState;
// Fill in TPMS_CREATION_DATA in outCreation
// Compute PCR digest
PCRComputeCurrentDigest(nameHashAlg, creationPCR,
&outCreation->t.creationData.pcrDigest);
// Put back PCR selection list
outCreation->t.creationData.pcrSelect = *creationPCR;
// Get locality
outCreation->t.creationData.locality
= LocalityGetAttributes(_plat__LocalityGet());
outCreation->t.creationData.parentNameAlg = TPM_ALG_NULL;
// If the parent is is either a primary seed or TPM_ALG_NULL, then the Name
// and QN of the parent are the parent's handle.
if(HandleGetType(parentHandle) == TPM_HT_PERMANENT)
{
BYTE *buffer = &outCreation->t.creationData.parentName.t.name[0];
INT32 bufferSize = sizeof(TPM_HANDLE);
outCreation->t.creationData.parentName.t.size =
TPM_HANDLE_Marshal(&parentHandle, &buffer, &bufferSize);
// Parent qualified name of a Temporary Object is the same as parent's
// name
MemoryCopy2B(&outCreation->t.creationData.parentQualifiedName.b,
&outCreation->t.creationData.parentName.b,
sizeof(outCreation->t.creationData.parentQualifiedName.t.name));
}
else // Regular object
{
OBJECT *parentObject = ObjectGet(parentHandle);
// Set name algorithm
outCreation->t.creationData.parentNameAlg =
parentObject->publicArea.nameAlg;
// Copy parent name
outCreation->t.creationData.parentName = parentObject->name;
// Copy parent qualified name
outCreation->t.creationData.parentQualifiedName =
parentObject->qualifiedName;
}
// Copy outside information
outCreation->t.creationData.outsideInfo = *outsideData;
// Marshal creation data to canonical form
buffer = creationBuffer;
bufferSize = sizeof(TPMS_CREATION_DATA);
outCreation->t.size = TPMS_CREATION_DATA_Marshal(&outCreation->t.creationData,
&buffer, &bufferSize);
// Compute hash for creation field in public template
creationDigest->t.size = CryptStartHash(nameHashAlg, &hashState);
CryptUpdateDigest(&hashState, outCreation->t.size, creationBuffer);
CryptCompleteHash2B(&hashState, &creationDigest->b);
return;
}
// GetSeedForKDF()
//
// Get a seed for KDF. The KDF for encryption and HMAC key use the same seed. It returns a pointer to
// the seed
//
TPM2B_SEED*
GetSeedForKDF(
TPM_HANDLE protectorHandle, // IN: the protector handle
TPM2B_SEED *seedIn // IN: the optional input seed
)
{
OBJECT *protector = NULL; // Pointer to the protector
// Get seed for encryption key. Use input seed if provided.
// Otherwise, using protector object's seedValue. TPM_RH_NULL is the only
// exception that we may not have a loaded object as protector. In such a
// case, use nullProof as seed.
if(seedIn != NULL)
{
return seedIn;
}
else
{
if(protectorHandle == TPM_RH_NULL)
{
return (TPM2B_SEED *) &gr.nullProof;
}
else
{
protector = ObjectGet(protectorHandle);
return (TPM2B_SEED *) &protector->sensitive.seedValue;
}
}
}
//
//
// ProduceOuterWrap()
//
// This function produce outer wrap for a buffer containing the sensitive data. It requires the sensitive data
// being marshaled to the outerBuffer, with the leading bytes reserved for integrity hash. If iv is used, iv
// space should be reserved at the beginning of the buffer. It assumes the sensitive data starts at address
// (outerBuffer + integrity size {+ iv size}). This function performs:
// a) Add IV before sensitive area if required
// b) encrypt sensitive data, if iv is required, encrypt by iv. otherwise, encrypted by a NULL iv
// c) add HMAC integrity at the beginning of the buffer It returns the total size of blob with outer wrap
//
UINT16
ProduceOuterWrap(
TPM_HANDLE protector, // IN: The handle of the object that provides
// protection. For object, it is parent
// handle. For credential, it is the handle
// of encrypt object.
TPM2B_NAME *name, // IN: the name of the object
TPM_ALG_ID hashAlg, // IN: hash algorithm for outer wrap
TPM2B_SEED *seed, // IN: an external seed may be provided for
// duplication blob. For non duplication
// blob, this parameter should be NULL
BOOL useIV, // IN: indicate if an IV is used
UINT16 dataSize, // IN: the size of sensitive data, excluding the
// leading integrity buffer size or the
// optional iv size
BYTE *outerBuffer // IN/OUT: outer buffer with sensitive data in
// it
)
{
TPM_ALG_ID symAlg;
UINT16 keyBits;
TPM2B_SYM_KEY symKey;
TPM2B_IV ivRNG; // IV from RNG
TPM2B_IV *iv = NULL;
UINT16 ivSize = 0; // size of iv area, including the size field
BYTE *sensitiveData; // pointer to the sensitive data
TPM2B_DIGEST integrity;
UINT16 integritySize;
BYTE *buffer; // Auxiliary buffer pointer
INT32 bufferSize;
// Compute the beginning of sensitive data. The outer integrity should
// always exist if this function function is called to make an outer wrap
integritySize = sizeof(UINT16) + CryptGetHashDigestSize(hashAlg);
sensitiveData = outerBuffer + integritySize;
// If iv is used, adjust the pointer of sensitive data and add iv before it
if(useIV)
{
ivSize = GetIV2BSize(protector);
// Generate IV from RNG. The iv data size should be the total IV area
// size minus the size of size field
ivRNG.t.size = ivSize - sizeof(UINT16);
CryptGenerateRandom(ivRNG.t.size, ivRNG.t.buffer);
// Marshal IV to buffer
buffer = sensitiveData;
bufferSize = sizeof(TPM2B_IV);
TPM2B_IV_Marshal(&ivRNG, &buffer, &bufferSize);
// adjust sensitive data starting after IV area
sensitiveData += ivSize;
// Use iv for encryption
iv = &ivRNG;
}
// Compute symmetric key parameters for outer buffer encryption
ComputeProtectionKeyParms(protector, hashAlg, name, seed,
&symAlg, &keyBits, &symKey);
// Encrypt inner buffer in place
CryptSymmetricEncrypt(sensitiveData, symAlg, keyBits,
TPM_ALG_CFB, symKey.t.buffer, iv, dataSize,
sensitiveData);
// Compute outer integrity. Integrity computation includes the optional IV
// area
ComputeOuterIntegrity(name, protector, hashAlg, seed, dataSize + ivSize,
outerBuffer + integritySize, &integrity);
// Add integrity at the beginning of outer buffer
buffer = outerBuffer;
bufferSize = sizeof(TPM2B_DIGEST);
TPM2B_DIGEST_Marshal(&integrity, &buffer, &bufferSize);
// return the total size in outer wrap
return dataSize + integritySize + ivSize;
}
//
//
//
// UnwrapOuter()
//
// This function remove the outer wrap of a blob containing sensitive data This function performs:
// a) check integrity of outer blob
// b) decrypt outer blob
//
// Error Returns Meaning
//
// TPM_RC_INSUFFICIENT error during sensitive data unmarshaling
// TPM_RC_INTEGRITY sensitive data integrity is broken
// TPM_RC_SIZE error during sensitive data unmarshaling
// TPM_RC_VALUE IV size for CFB does not match the encryption algorithm block size
//
TPM_RC
UnwrapOuter(
TPM_HANDLE protector, // IN: The handle of the object that provides
// protection. For object, it is parent
// handle. For credential, it is the handle
// of encrypt object.
TPM2B_NAME *name, // IN: the name of the object
TPM_ALG_ID hashAlg, // IN: hash algorithm for outer wrap
TPM2B_SEED *seed, // IN: an external seed may be provided for
// duplication blob. For non duplication
// blob, this parameter should be NULL.
BOOL useIV, // IN: indicates if an IV is used
UINT16 dataSize, // IN: size of sensitive data in outerBuffer,
// including the leading integrity buffer
// size, and an optional iv area
BYTE *outerBuffer // IN/OUT: sensitive data
)
{
TPM_RC result;
TPM_ALG_ID symAlg = TPM_ALG_NULL;
TPM2B_SYM_KEY symKey;
UINT16 keyBits = 0;
TPM2B_IV ivIn; // input IV retrieved from input buffer
TPM2B_IV *iv = NULL;
BYTE *sensitiveData; // pointer to the sensitive data
TPM2B_DIGEST integrityToCompare;
TPM2B_DIGEST integrity;
INT32 size;
// Unmarshal integrity
sensitiveData = outerBuffer;
size = (INT32) dataSize;
result = TPM2B_DIGEST_Unmarshal(&integrity, &sensitiveData, &size);
if(result == TPM_RC_SUCCESS)
{
// Compute integrity to compare
ComputeOuterIntegrity(name, protector, hashAlg, seed,
(UINT16) size, sensitiveData,
&integrityToCompare);
// Compare outer blob integrity
if(!Memory2BEqual(&integrity.b, &integrityToCompare.b))
return TPM_RC_INTEGRITY;
// Get the symmetric algorithm parameters used for encryption
ComputeProtectionKeyParms(protector, hashAlg, name, seed,
&symAlg, &keyBits, &symKey);
// Retrieve IV if it is used
if(useIV)
{
result = TPM2B_IV_Unmarshal(&ivIn, &sensitiveData, &size);
if(result == TPM_RC_SUCCESS)
{
// The input iv size for CFB must match the encryption algorithm
// block size
if(ivIn.t.size != CryptGetSymmetricBlockSize(symAlg, keyBits))
result = TPM_RC_VALUE;
else
iv = &ivIn;
}
}
}
// If no errors, decrypt private in place
if(result == TPM_RC_SUCCESS)
CryptSymmetricDecrypt(sensitiveData, symAlg, keyBits,
TPM_ALG_CFB, symKey.t.buffer, iv,
(UINT16) size, sensitiveData);
return result;
}
//
//
// SensitiveToPrivate()
//
// This function prepare the private blob for off the chip storage The operations in this function:
// a) marshal TPM2B_SENSITIVE structure into the buffer of TPM2B_PRIVATE
// b) apply encryption to the sensitive area.
// c) apply outer integrity computation.
//
void
SensitiveToPrivate(
TPMT_SENSITIVE *sensitive, // IN: sensitive structure
TPM2B_NAME *name, // IN: the name of the object
TPM_HANDLE parentHandle, // IN: The parent's handle
TPM_ALG_ID nameAlg, // IN: hash algorithm in public area. This
// parameter is used when parentHandle is
// NULL, in which case the object is
// temporary.
TPM2B_PRIVATE *outPrivate // OUT: output private structure
)
{
BYTE *buffer; // Auxiliary buffer pointer
INT32 bufferSize;
BYTE *sensitiveData; // pointer to the sensitive data
UINT16 dataSize; // data blob size
TPMI_ALG_HASH hashAlg; // hash algorithm for integrity
UINT16 integritySize;
UINT16 ivSize;
pAssert(name != NULL && name->t.size != 0);
// Find the hash algorithm for integrity computation
if(parentHandle == TPM_RH_NULL)
{
// For Temporary Object, using self name algorithm
hashAlg = nameAlg;
}
else
{
// Otherwise, using parent's name algorithm
hashAlg = ObjectGetNameAlg(parentHandle);
}
// Starting of sensitive data without wrappers
sensitiveData = outPrivate->t.buffer;
// Compute the integrity size
integritySize = sizeof(UINT16) + CryptGetHashDigestSize(hashAlg);
// Reserve space for integrity
sensitiveData += integritySize;
// Get iv size
ivSize = GetIV2BSize(parentHandle);
// Reserve space for iv
sensitiveData += ivSize;
// Marshal sensitive area, leaving the leading 2 bytes for size
buffer = sensitiveData + sizeof(UINT16);
bufferSize = sizeof(TPMT_SENSITIVE);
dataSize = TPMT_SENSITIVE_Marshal(sensitive, &buffer, &bufferSize);
// Adding size before the data area
buffer = sensitiveData;
bufferSize = sizeof(UINT16);
UINT16_Marshal(&dataSize, &buffer, &bufferSize);
// Adjust the dataSize to include the size field
dataSize += sizeof(UINT16);
// Adjust the pointer to inner buffer including the iv
sensitiveData = outPrivate->t.buffer + ivSize;
//Produce outer wrap, including encryption and HMAC
outPrivate->t.size = ProduceOuterWrap(parentHandle, name, hashAlg, NULL,
TRUE, dataSize, outPrivate->t.buffer);
return;
}
//
//
// PrivateToSensitive()
//
// Unwrap a input private area. Check the integrity, decrypt and retrieve data to a sensitive structure. The
// operations in this function:
// a) check the integrity HMAC of the input private area
// b) decrypt the private buffer
// c) unmarshal TPMT_SENSITIVE structure into the buffer of TPMT_SENSITIVE
//
// Error Returns Meaning
//
// TPM_RC_INTEGRITY if the private area integrity is bad
// TPM_RC_SENSITIVE unmarshal errors while unmarshaling TPMS_ENCRYPT from input
// private
// TPM_RC_VALUE outer wrapper does not have an iV of the correct size
//
TPM_RC
PrivateToSensitive(
TPM2B_PRIVATE *inPrivate, // IN: input private structure
TPM2B_NAME *name, // IN: the name of the object
TPM_HANDLE parentHandle, // IN: The parent's handle
TPM_ALG_ID nameAlg, // IN: hash algorithm in public area. It is
// passed separately because we only pass
// name, rather than the whole public area
// of the object. This parameter is used in
// the following two cases: 1. primary
// objects. 2. duplication blob with inner
// wrap. In other cases, this parameter
// will be ignored
TPMT_SENSITIVE *sensitive // OUT: sensitive structure
)
{
TPM_RC result;
BYTE *buffer;
INT32 size;
BYTE *sensitiveData; // pointer to the sensitive data
UINT16 dataSize;
UINT16 dataSizeInput;
TPMI_ALG_HASH hashAlg; // hash algorithm for integrity
OBJECT *parent = NULL;
UINT16 integritySize;
UINT16 ivSize;
// Make sure that name is provided
pAssert(name != NULL && name->t.size != 0);
// Find the hash algorithm for integrity computation
if(parentHandle == TPM_RH_NULL)
{
// For Temporary Object, using self name algorithm
hashAlg = nameAlg;
}
else
{
// Otherwise, using parent's name algorithm
hashAlg = ObjectGetNameAlg(parentHandle);
}
// unwrap outer
result = UnwrapOuter(parentHandle, name, hashAlg, NULL, TRUE,
inPrivate->t.size, inPrivate->t.buffer);
if(result != TPM_RC_SUCCESS)
return result;
// Compute the inner integrity size.
integritySize = sizeof(UINT16) + CryptGetHashDigestSize(hashAlg);
// Get iv size
ivSize = GetIV2BSize(parentHandle);
// The starting of sensitive data and data size without outer wrapper
sensitiveData = inPrivate->t.buffer + integritySize + ivSize;
dataSize = inPrivate->t.size - integritySize - ivSize;
// Unmarshal input data size
buffer = sensitiveData;
size = (INT32) dataSize;
result = UINT16_Unmarshal(&dataSizeInput, &buffer, &size);
if(result == TPM_RC_SUCCESS)
{
if((dataSizeInput + sizeof(UINT16)) != dataSize)
result = TPM_RC_SENSITIVE;
else
{
// Unmarshal sensitive buffer to sensitive structure
result = TPMT_SENSITIVE_Unmarshal(sensitive, &buffer, &size);
if(result != TPM_RC_SUCCESS || size != 0)
{
pAssert( (parent == NULL)
|| parent->publicArea.objectAttributes.fixedTPM == CLEAR);
result = TPM_RC_SENSITIVE;
}
else
{
// Always remove trailing zeros at load so that it is not necessary
// to check
// each time auth is checked.
MemoryRemoveTrailingZeros(&(sensitive->authValue));
}
}
}
return result;
}
//
//
// SensitiveToDuplicate()
//
// This function prepare the duplication blob from the sensitive area. The operations in this function:
// a) marshal TPMT_SENSITIVE structure into the buffer of TPM2B_PRIVATE
// b) apply inner wrap to the sensitive area if required
// c) apply outer wrap if required
//
void
SensitiveToDuplicate(
TPMT_SENSITIVE *sensitive, // IN: sensitive structure
TPM2B_NAME *name, // IN: the name of the object
TPM_HANDLE parentHandle, // IN: The new parent's handle
TPM_ALG_ID nameAlg, // IN: hash algorithm in public area. It
// is passed separately because we
// only pass name, rather than the
// whole public area of the object.
TPM2B_SEED *seed, // IN: the external seed. If external
// seed is provided with size of 0,
// no outer wrap should be applied
// to duplication blob.
TPMT_SYM_DEF_OBJECT *symDef, // IN: Symmetric key definition. If the
// symmetric key algorithm is NULL,
// no inner wrap should be applied.
TPM2B_DATA *innerSymKey, // IN/OUT: a symmetric key may be
// provided to encrypt the inner
// wrap of a duplication blob. May
// be generated here if needed.
TPM2B_PRIVATE *outPrivate // OUT: output private structure
)
{
BYTE *buffer; // Auxiliary buffer pointer
INT32 bufferSize;
BYTE *sensitiveData; // pointer to the sensitive data
TPMI_ALG_HASH outerHash = TPM_ALG_NULL;// The hash algorithm for outer wrap
TPMI_ALG_HASH innerHash = TPM_ALG_NULL;// The hash algorithm for inner wrap
UINT16 dataSize; // data blob size
BOOL doInnerWrap = FALSE;
BOOL doOuterWrap = FALSE;
// Make sure that name is provided
pAssert(name != NULL && name->t.size != 0);
// Make sure symDef and innerSymKey are not NULL
pAssert(symDef != NULL && innerSymKey != NULL);
// Starting of sensitive data without wrappers
sensitiveData = outPrivate->t.buffer;
// Find out if inner wrap is required
if(symDef->algorithm != TPM_ALG_NULL)
{
doInnerWrap = TRUE;
// Use self nameAlg as inner hash algorithm
innerHash = nameAlg;
// Adjust sensitive data pointer
sensitiveData += sizeof(UINT16) + CryptGetHashDigestSize(innerHash);
}
// Find out if outer wrap is required
if(seed->t.size != 0)
{
doOuterWrap = TRUE;
// Use parent nameAlg as outer hash algorithm
outerHash = ObjectGetNameAlg(parentHandle);
// Adjust sensitive data pointer
sensitiveData += sizeof(UINT16) + CryptGetHashDigestSize(outerHash);
}
// Marshal sensitive area, leaving the leading 2 bytes for size
buffer = sensitiveData + sizeof(UINT16);
bufferSize = sizeof(TPMT_SENSITIVE);
dataSize = TPMT_SENSITIVE_Marshal(sensitive, &buffer, &bufferSize);
// Adding size before the data area
buffer = sensitiveData;
bufferSize = sizeof(UINT16);
UINT16_Marshal(&dataSize, &buffer, &bufferSize);
// Adjust the dataSize to include the size field
dataSize += sizeof(UINT16);
// Apply inner wrap for duplication blob. It includes both integrity and
// encryption
if(doInnerWrap)
{
BYTE *innerBuffer = NULL;
BOOL symKeyInput = TRUE;
innerBuffer = outPrivate->t.buffer;
// Skip outer integrity space
if(doOuterWrap)
innerBuffer += sizeof(UINT16) + CryptGetHashDigestSize(outerHash);
dataSize = ProduceInnerIntegrity(name, innerHash, dataSize,
innerBuffer);
// Generate inner encryption key if needed
if(innerSymKey->t.size == 0)
{
innerSymKey->t.size = (symDef->keyBits.sym + 7) / 8;
CryptGenerateRandom(innerSymKey->t.size, innerSymKey->t.buffer);
// TPM generates symmetric encryption. Set the flag to FALSE
symKeyInput = FALSE;
}
else
{
// assume the input key size should matches the symmetric definition
pAssert(innerSymKey->t.size == (symDef->keyBits.sym + 7) / 8);
}
// Encrypt inner buffer in place
CryptSymmetricEncrypt(innerBuffer, symDef->algorithm,
symDef->keyBits.sym, TPM_ALG_CFB,
innerSymKey->t.buffer, NULL, dataSize,
innerBuffer);
// If the symmetric encryption key is imported, clear the buffer for
// output
if(symKeyInput)
innerSymKey->t.size = 0;
}
// Apply outer wrap for duplication blob. It includes both integrity and
// encryption
if(doOuterWrap)
{
dataSize = ProduceOuterWrap(parentHandle, name, outerHash, seed, FALSE,
dataSize, outPrivate->t.buffer);
}
// Data size for output
outPrivate->t.size = dataSize;
return;
}
//
//
// DuplicateToSensitive()
//
// Unwrap a duplication blob. Check the integrity, decrypt and retrieve data to a sensitive structure. The
// operations in this function:
// a) check the integrity HMAC of the input private area
// b) decrypt the private buffer
// c) unmarshal TPMT_SENSITIVE structure into the buffer of TPMT_SENSITIVE
//
// Error Returns Meaning
//
// TPM_RC_INSUFFICIENT unmarshaling sensitive data from inPrivate failed
// TPM_RC_INTEGRITY inPrivate data integrity is broken
// TPM_RC_SIZE unmarshaling sensitive data from inPrivate failed
//
TPM_RC
DuplicateToSensitive(
TPM2B_PRIVATE *inPrivate, // IN: input private structure
TPM2B_NAME *name, // IN: the name of the object
TPM_HANDLE parentHandle, // IN: The parent's handle
TPM_ALG_ID nameAlg, // IN: hash algorithm in public area.
TPM2B_SEED *seed, // IN: an external seed may be provided.
// If external seed is provided with
// size of 0, no outer wrap is
// applied
TPMT_SYM_DEF_OBJECT *symDef, // IN: Symmetric key definition. If the
// symmetric key algorithm is NULL,
// no inner wrap is applied
TPM2B_DATA *innerSymKey, // IN: a symmetric key may be provided
// to decrypt the inner wrap of a
// duplication blob.
TPMT_SENSITIVE *sensitive // OUT: sensitive structure
)
{
TPM_RC result;
BYTE *buffer;
INT32 size;
BYTE *sensitiveData; // pointer to the sensitive data
UINT16 dataSize;
UINT16 dataSizeInput;
// Make sure that name is provided
pAssert(name != NULL && name->t.size != 0);
// Make sure symDef and innerSymKey are not NULL
pAssert(symDef != NULL && innerSymKey != NULL);
// Starting of sensitive data
sensitiveData = inPrivate->t.buffer;
dataSize = inPrivate->t.size;
// Find out if outer wrap is applied
if(seed->t.size != 0)
{
TPMI_ALG_HASH outerHash = TPM_ALG_NULL;
// Use parent nameAlg as outer hash algorithm
outerHash = ObjectGetNameAlg(parentHandle);
result = UnwrapOuter(parentHandle, name, outerHash, seed, FALSE,
dataSize, sensitiveData);
if(result != TPM_RC_SUCCESS)
return result;
// Adjust sensitive data pointer and size
sensitiveData += sizeof(UINT16) + CryptGetHashDigestSize(outerHash);
dataSize -= sizeof(UINT16) + CryptGetHashDigestSize(outerHash);
}
// Find out if inner wrap is applied
if(symDef->algorithm != TPM_ALG_NULL)
{
TPMI_ALG_HASH innerHash = TPM_ALG_NULL;
// assume the input key size should matches the symmetric definition
pAssert(innerSymKey->t.size == (symDef->keyBits.sym + 7) / 8);
// Decrypt inner buffer in place
CryptSymmetricDecrypt(sensitiveData, symDef->algorithm,
symDef->keyBits.sym, TPM_ALG_CFB,
innerSymKey->t.buffer, NULL, dataSize,
sensitiveData);
// Use self nameAlg as inner hash algorithm
innerHash = nameAlg;
// Check inner integrity
result = CheckInnerIntegrity(name, innerHash, dataSize, sensitiveData);
if(result != TPM_RC_SUCCESS)
return result;
// Adjust sensitive data pointer and size
sensitiveData += sizeof(UINT16) + CryptGetHashDigestSize(innerHash);
dataSize -= sizeof(UINT16) + CryptGetHashDigestSize(innerHash);
}
// Unmarshal input data size
buffer = sensitiveData;
size = (INT32) dataSize;
result = UINT16_Unmarshal(&dataSizeInput, &buffer, &size);
if(result == TPM_RC_SUCCESS)
{
if((dataSizeInput + sizeof(UINT16)) != dataSize)
result = TPM_RC_SIZE;
else
{
// Unmarshal sensitive buffer to sensitive structure
result = TPMT_SENSITIVE_Unmarshal(sensitive, &buffer, &size);
// if the results is OK make sure that all the data was unmarshaled
if(result == TPM_RC_SUCCESS && size != 0)
result = TPM_RC_SIZE;
}
}
// Always remove trailing zeros at load so that it is not necessary to check
// each time auth is checked.
if(result == TPM_RC_SUCCESS)
MemoryRemoveTrailingZeros(&(sensitive->authValue));
return result;
}
//
//
// SecretToCredential()
//
// This function prepare the credential blob from a secret (a TPM2B_DIGEST) The operations in this
// function:
// a) marshal TPM2B_DIGEST structure into the buffer of TPM2B_ID_OBJECT
// b) encrypt the private buffer, excluding the leading integrity HMAC area
// c) compute integrity HMAC and append to the beginning of the buffer.
// d) Set the total size of TPM2B_ID_OBJECT buffer
//
void
SecretToCredential(
TPM2B_DIGEST *secret, // IN: secret information
TPM2B_NAME *name, // IN: the name of the object
TPM2B_SEED *seed, // IN: an external seed.
TPM_HANDLE protector, // IN: The protector's handle
TPM2B_ID_OBJECT *outIDObject // OUT: output credential
)
{
BYTE *buffer; // Auxiliary buffer pointer
INT32 bufferSize;
BYTE *sensitiveData; // pointer to the sensitive data
TPMI_ALG_HASH outerHash; // The hash algorithm for outer wrap
UINT16 dataSize; // data blob size
pAssert(secret != NULL && outIDObject != NULL);
// use protector's name algorithm as outer hash
outerHash = ObjectGetNameAlg(protector);
// Marshal secret area to credential buffer, leave space for integrity
sensitiveData = outIDObject->t.credential
+ sizeof(UINT16) + CryptGetHashDigestSize(outerHash);
// Marshal secret area
buffer = sensitiveData;
bufferSize = sizeof(TPM2B_DIGEST);
dataSize = TPM2B_DIGEST_Marshal(secret, &buffer, &bufferSize);
// Apply outer wrap
outIDObject->t.size = ProduceOuterWrap(protector,
name,
outerHash,
seed,
FALSE,
dataSize,
outIDObject->t.credential);
return;
}
//
//
// CredentialToSecret()
//
// Unwrap a credential. Check the integrity, decrypt and retrieve data to a TPM2B_DIGEST structure. The
// operations in this function:
// a) check the integrity HMAC of the input credential area
// b) decrypt the credential buffer
// c) unmarshal TPM2B_DIGEST structure into the buffer of TPM2B_DIGEST
//
// Error Returns Meaning
//
// TPM_RC_INSUFFICIENT error during credential unmarshaling
// TPM_RC_INTEGRITY credential integrity is broken
// TPM_RC_SIZE error during credential unmarshaling
// TPM_RC_VALUE IV size does not match the encryption algorithm block size
//
TPM_RC
CredentialToSecret(
TPM2B_ID_OBJECT *inIDObject, // IN: input credential blob
TPM2B_NAME *name, // IN: the name of the object
TPM2B_SEED *seed, // IN: an external seed.
TPM_HANDLE protector, // IN: The protector's handle
TPM2B_DIGEST *secret // OUT: secret information
)
{
TPM_RC result;
BYTE *buffer;
INT32 size;
TPMI_ALG_HASH outerHash; // The hash algorithm for outer wrap
BYTE *sensitiveData; // pointer to the sensitive data
UINT16 dataSize;
// use protector's name algorithm as outer hash
outerHash = ObjectGetNameAlg(protector);
// Unwrap outer, a TPM_RC_INTEGRITY error may be returned at this point
result = UnwrapOuter(protector, name, outerHash, seed, FALSE,
inIDObject->t.size, inIDObject->t.credential);
if(result == TPM_RC_SUCCESS)
{
// Compute the beginning of sensitive data
sensitiveData = inIDObject->t.credential
+ sizeof(UINT16) + CryptGetHashDigestSize(outerHash);
dataSize = inIDObject->t.size
- (sizeof(UINT16) + CryptGetHashDigestSize(outerHash));
// Unmarshal secret buffer to TPM2B_DIGEST structure
buffer = sensitiveData;
size = (INT32) dataSize;
result = TPM2B_DIGEST_Unmarshal(secret, &buffer, &size);
// If there were no other unmarshaling errors, make sure that the
// expected amount of data was recovered
if(result == TPM_RC_SUCCESS && size != 0)
return TPM_RC_SIZE;
}
return result;
}