
/*
 * Licensed Materials - Property of IBM
 *
 * trousers - An open source TCG Software Stack
 *
 * (C) Copyright International Business Machines Corp. 2004-2007
 *
 */


#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include "trousers/tss.h"
#include "trousers/trousers.h"
#include "trousers_types.h"
#include "trousers_types.h"
#include "spi_utils.h"
#include "capabilities.h"
#include "tsplog.h"
#include "obj.h"
#include "authsess.h"

#define TPM_STORE_ASYMKEY_LEN 214 /* Entire TPM_STORE_ASYMKEY length */
#define USAGE_MIG_DIGEST_FLD_LEN 20 /* Usage, Migration and Digest lengths for
                                       TPM_STORE_ASYMKEY */
#define TPM_STORE_PRIVKEY_LEN 151 /* Extracted directly from TPM_STORE_ASYMKEY
                                     field */

TSS_RESULT
Tspi_Key_UnloadKey(TSS_HKEY hKey)	/* in */
{
	TSS_HCONTEXT tspContext;
	TCS_KEY_HANDLE hTcsKey;
	TSS_RESULT result;

	if ((result = obj_rsakey_get_tsp_context(hKey, &tspContext)))
		return result;

	if ((result = obj_rsakey_get_tcs_handle(hKey, &hTcsKey)))
		return result;

	return __tspi_free_resource(tspContext, hTcsKey, TPM_RT_KEY);
}

TSS_RESULT
Tspi_Key_LoadKey(TSS_HKEY hKey,			/* in */
		 TSS_HKEY hUnwrappingKey)	/* in */
{
	TPM_AUTH auth;
	TCPA_DIGEST digest;
	TSS_RESULT result;
	UINT32 keyslot;
	TSS_HCONTEXT tspContext;
	TSS_HPOLICY hPolicy;
	UINT32 keySize;
	BYTE *keyBlob;
	TCS_KEY_HANDLE tcsKey, tcsParentHandle;
	TSS_BOOL usesAuth;
	TPM_AUTH *pAuth;
	Trspi_HashCtx hashCtx;
	TPM_COMMAND_CODE ordinal;

	if (!obj_is_rsakey(hUnwrappingKey))
		return TSPERR(TSS_E_INVALID_HANDLE);

	if ((result = obj_rsakey_get_tsp_context(hKey, &tspContext)))
		return result;

	if ((result = obj_context_get_loadkey_ordinal(tspContext, &ordinal)))
		return result;

	if ((result = obj_rsakey_get_blob(hKey, &keySize, &keyBlob)))
		return result;

	if ((result = obj_rsakey_get_tcs_handle(hUnwrappingKey, &tcsParentHandle)))
		return result;

	if ((result = obj_rsakey_get_policy(hUnwrappingKey, TSS_POLICY_USAGE, &hPolicy,
					    &usesAuth))) {
		free_tspi(tspContext, keyBlob);
		return result;
	}

	if (usesAuth) {
		result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1);
		result |= Trspi_Hash_UINT32(&hashCtx, ordinal);
		result |= Trspi_HashUpdate(&hashCtx, keySize, keyBlob);
		if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) {
			free_tspi(tspContext, keyBlob);
			return result;
		}

		if ((result = secret_PerformAuth_OIAP(hUnwrappingKey, ordinal, hPolicy, FALSE,
						      &digest, &auth))) {
			free_tspi(tspContext, keyBlob);
			return result;
		}
		pAuth = &auth;
	} else {
		pAuth = NULL;
	}

	if ((result = TCS_API(tspContext)->LoadKeyByBlob(tspContext, tcsParentHandle, keySize,
							 keyBlob, pAuth, &tcsKey, &keyslot))) {
		free_tspi(tspContext, keyBlob);
		return result;
	}

	free_tspi(tspContext, keyBlob);

	if (usesAuth) {
		result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1);
		result |= Trspi_Hash_UINT32(&hashCtx, result);
		result |= Trspi_Hash_UINT32(&hashCtx, ordinal);
		if (ordinal == TPM_ORD_LoadKey)
			result |= Trspi_Hash_UINT32(&hashCtx, keyslot);
		if ((result |= Trspi_HashFinal(&hashCtx, digest.digest)))
			return result;

		if ((result = obj_policy_validate_auth_oiap(hPolicy, &digest, &auth)))
			return result;
	}

	return obj_rsakey_set_tcs_handle(hKey, tcsKey);
}

TSS_RESULT
Tspi_Key_GetPubKey(TSS_HKEY hKey,		/* in */
		   UINT32 * pulPubKeyLength,	/* out */
		   BYTE ** prgbPubKey)		/* out */
{
	TPM_AUTH auth;
	TPM_AUTH *pAuth;
	TCPA_DIGEST digest;
	TCPA_RESULT result;
	TSS_HCONTEXT tspContext;
	TSS_HPOLICY hPolicy;
	TCS_KEY_HANDLE tcsKeyHandle;
	TSS_BOOL usesAuth;
	Trspi_HashCtx hashCtx;

	if (pulPubKeyLength == NULL || prgbPubKey == NULL)
		return TSPERR(TSS_E_BAD_PARAMETER);

	if ((result = obj_rsakey_get_tsp_context(hKey, &tspContext)))
		return result;

	if ((result = obj_rsakey_get_policy(hKey, TSS_POLICY_USAGE,
					    &hPolicy, &usesAuth)))
		return result;

	if ((result = obj_rsakey_get_tcs_handle(hKey, &tcsKeyHandle)))
		return result;

	if (usesAuth) {
		result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1);
		result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_GetPubKey);
		if ((result |= Trspi_HashFinal(&hashCtx, digest.digest)))
			return result;

		if ((result = secret_PerformAuth_OIAP(hKey, TPM_ORD_GetPubKey, hPolicy, FALSE,
						      &digest, &auth)))
			return result;
		pAuth = &auth;
	} else {
		pAuth = NULL;
	}

	if ((result = TCS_API(tspContext)->GetPubKey(tspContext, tcsKeyHandle, pAuth,
						     pulPubKeyLength, prgbPubKey)))
		return result;

	if (usesAuth) {
		result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1);
		result |= Trspi_Hash_UINT32(&hashCtx, result);
		result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_GetPubKey);
		result |= Trspi_HashUpdate(&hashCtx, *pulPubKeyLength, *prgbPubKey);
		if ((result |= Trspi_HashFinal(&hashCtx, digest.digest)))
			goto error;

		/* goto error here since prgbPubKey has been set */
		if ((result = obj_policy_validate_auth_oiap(hPolicy, &digest, &auth)))
			goto error;
	}

	if ((result = __tspi_add_mem_entry(tspContext, *prgbPubKey)))
		goto error;

	if (tcsKeyHandle == TPM_KEYHND_SRK)
		obj_rsakey_set_pubkey(hKey, TRUE, *prgbPubKey);

	return TSS_SUCCESS;
error:
	free(*prgbPubKey);
	*prgbPubKey = NULL;
	*pulPubKeyLength = 0;
	return result;
}

TSS_RESULT
Tspi_Key_CreateKey(TSS_HKEY hKey,		/* in */
		   TSS_HKEY hWrappingKey,	/* in */
		   TSS_HPCRS hPcrComposite)	/* in, may be NULL */
{
#ifdef TSS_BUILD_CMK
	UINT32 blobSize;
	BYTE *blob;
	TSS_BOOL isCmk = FALSE;
	TPM_HMAC msaApproval;
	TPM_DIGEST msaDigest;
#endif
	TCPA_DIGEST digest;
	TCPA_RESULT result;
	TCS_KEY_HANDLE parentTCSKeyHandle;
	BYTE *keyBlob = NULL;
	UINT32 keySize;
	UINT32 newKeySize;
	BYTE *newKey = NULL;
	UINT32 ordinal = TPM_ORD_CreateWrapKey;
	TSS_HCONTEXT tspContext;
	Trspi_HashCtx hashCtx;
	struct authsess *xsap = NULL;

	if ((result = obj_rsakey_get_tsp_context(hKey, &tspContext)))
		return result;

	if (hPcrComposite) {
		/* its possible that hPcrComposite could be a bad handle here,
		 * or that no indices of it are yet set, which would throw
		 * internal error. Blanket both those codes with bad
		 * parameter to help the user out */
		if ((result = obj_rsakey_set_pcr_data(hKey, hPcrComposite)))
			return TSPERR(TSS_E_BAD_PARAMETER);
	}

	if ((result = obj_rsakey_get_tcs_handle(hWrappingKey, &parentTCSKeyHandle)))
		return result;

	if ((result = obj_rsakey_get_blob(hKey, &keySize, &keyBlob)))
		return result;

#ifdef TSS_BUILD_CMK
	isCmk = obj_rsakey_is_cmk(hKey);
	if (isCmk) {
		if ((result = obj_rsakey_get_msa_approval(hKey, &blobSize, &blob)))
			goto done;
		memcpy(msaApproval.digest, blob, sizeof(msaApproval.digest));
		free_tspi(tspContext, blob);

		if ((result = obj_rsakey_get_msa_digest(hKey, &blobSize, &blob)))
			goto done;
		memcpy(msaDigest.digest, blob, sizeof(msaDigest.digest));
		free_tspi(tspContext, blob);

		ordinal = TPM_ORD_CMK_CreateKey;
	}
#endif

	if ((result = authsess_xsap_init(tspContext, hWrappingKey, hKey, TSS_AUTH_POLICY_REQUIRED,
					 ordinal, TPM_ET_KEYHANDLE, &xsap)))
		return result;

	/* Setup the Hash Data for the HMAC */
	result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1);
	result |= Trspi_Hash_UINT32(&hashCtx, ordinal);
#ifdef TSS_BUILD_CMK
	if (isCmk) {
		result |= Trspi_Hash_ENCAUTH(&hashCtx, xsap->encAuthUse.authdata);
		result |= Trspi_HashUpdate(&hashCtx, keySize, keyBlob);
		result |= Trspi_Hash_HMAC(&hashCtx, msaApproval.digest);
		result |= Trspi_Hash_DIGEST(&hashCtx, msaDigest.digest);
	} else {
#endif
		result |= Trspi_Hash_DIGEST(&hashCtx, xsap->encAuthUse.authdata);
		result |= Trspi_Hash_DIGEST(&hashCtx, xsap->encAuthMig.authdata);
		result |= Trspi_HashUpdate(&hashCtx, keySize, keyBlob);
#ifdef TSS_BUILD_CMK
	}
#endif
	if ((result |= Trspi_HashFinal(&hashCtx, digest.digest)))
		goto done;

	if ((result = authsess_xsap_hmac(xsap, &digest)))
		goto done;

	/* Now call the function */
#ifdef TSS_BUILD_CMK
	if (isCmk) {
		if ((newKey = malloc(keySize)) == NULL) {
			LogError("malloc of %u bytes failed.", keySize);
			result = TSPERR(TSS_E_OUTOFMEMORY);
			goto done;
		}
		memcpy(newKey, keyBlob, keySize);
		newKeySize = keySize;

		if ((result = RPC_CMK_CreateKey(tspContext, parentTCSKeyHandle,
						(TPM_ENCAUTH *)&xsap->encAuthUse,
						&msaApproval, &msaDigest, &newKeySize, &newKey,
						xsap->pAuth)))
			goto done;
	} else {
#endif
		if ((result = TCS_API(tspContext)->CreateWrapKey(tspContext, parentTCSKeyHandle,
								 (TPM_ENCAUTH *)&xsap->encAuthUse,
								 (TPM_ENCAUTH *)&xsap->encAuthMig,
								 keySize, keyBlob, &newKeySize,
								 &newKey, xsap->pAuth)))
			goto done;
#ifdef TSS_BUILD_CMK
	}
#endif

	/* Validate the Authorization before using the new key */
	result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1);
	result |= Trspi_Hash_UINT32(&hashCtx, result);
	result |= Trspi_Hash_UINT32(&hashCtx, ordinal);
	result |= Trspi_HashUpdate(&hashCtx, newKeySize, newKey);
	if ((result |= Trspi_HashFinal(&hashCtx, digest.digest)))
		goto done;

	if (authsess_xsap_verify(xsap, &digest)) {
		result = TSPERR(TSS_E_TSP_AUTHFAIL);
		goto done;
	}

	/* Push the new key into the existing object */
	result = obj_rsakey_set_tcpakey(hKey, newKeySize, newKey);

done:
	authsess_free(xsap);
	free_tspi(tspContext, keyBlob);
	free(newKey);

	return result;
}

TSS_RESULT
Tspi_Key_WrapKey(TSS_HKEY hKey,			/* in */
		 TSS_HKEY hWrappingKey,		/* in */
		 TSS_HPCRS hPcrComposite)	/* in, may be NULL */
{
	TSS_HPOLICY hUsePolicy, hMigPolicy;
	TCPA_SECRET usage, migration;
	TSS_RESULT result;
	BYTE *keyPrivBlob = NULL, *wrappingPubKey = NULL, *keyBlob = NULL;
	UINT32 keyPrivBlobLen, wrappingPubKeyLen, keyBlobLen;
	BYTE newPrivKey[TPM_STORE_ASYMKEY_LEN]; /* This reflects the size of the
                                               TPM_STORE_ASYMKEY structure
                                               in both TPM 1.1b and 1.2 */
	BYTE encPrivKey[256];
	UINT32 newPrivKeyLen = TPM_STORE_ASYMKEY_LEN, encPrivKeyLen = 256;
	UINT64 offset;
	TSS_KEY keyContainer;
	TCPA_DIGEST digest;
	TSS_HCONTEXT tspContext;
	Trspi_HashCtx hashCtx;

	if ((result = obj_rsakey_get_tsp_context(hKey, &tspContext)))
		return result;

	if (hPcrComposite) {
		if ((result = obj_rsakey_set_pcr_data(hKey, hPcrComposite)))
			return result;
	}

	/* get the key to be wrapped's private key */
	if ((result = obj_rsakey_get_priv_blob(hKey, &keyPrivBlobLen, &keyPrivBlob)))
		goto done;
    /* verify if its under the maximum size, according to the
     * TPM_STORE_ASYMKEY specification */
    if (keyPrivBlobLen > TPM_STORE_PRIVKEY_LEN)
        return TSPERR(TSS_E_ENC_INVALID_LENGTH);

	/* get the key to be wrapped's blob */
	if ((result = obj_rsakey_get_blob(hKey, &keyBlobLen, &keyBlob)))
		goto done;

	/* get the wrapping key's public key */
	if ((result = obj_rsakey_get_modulus(hWrappingKey, &wrappingPubKeyLen, &wrappingPubKey)))
		goto done;

	/* get the key to be wrapped's usage policy */
	if ((result = obj_rsakey_get_policy(hKey, TSS_POLICY_USAGE, &hUsePolicy, NULL)))
		goto done;

	if ((result = obj_rsakey_get_policy(hKey, TSS_POLICY_MIGRATION, &hMigPolicy, NULL)))
		goto done;

	if ((result = obj_policy_get_secret(hUsePolicy, TR_SECRET_CTX_NEW, &usage)))
		goto done;

	if ((result = obj_policy_get_secret(hMigPolicy, TR_SECRET_CTX_NEW, &migration)))
		goto done;

	__tspi_memset(&keyContainer, 0, sizeof(TSS_KEY));

	/* unload the key to be wrapped's blob */
	offset = 0;
	if ((result = UnloadBlob_TSS_KEY(&offset, keyBlob, &keyContainer)))
		return result;

	/* load the key's attributes into an object and get its hash value */
	result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1);
	result |= Hash_TSS_PRIVKEY_DIGEST(&hashCtx, &keyContainer);
	if ((result |= Trspi_HashFinal(&hashCtx, digest.digest)))
		return result;

	free_key_refs(&keyContainer);

	/* create the plaintext private key blob. This is the point where the
     * TPM structure TPM_STORE_ASYMKEY is crafted in the buffer */
	offset = 0;
	Trspi_LoadBlob_BYTE(&offset, TCPA_PT_ASYM, newPrivKey);
	Trspi_LoadBlob(&offset, USAGE_MIG_DIGEST_FLD_LEN,
                   newPrivKey, usage.authdata);
	Trspi_LoadBlob(&offset, USAGE_MIG_DIGEST_FLD_LEN,
                   newPrivKey, migration.authdata);
	Trspi_LoadBlob(&offset, USAGE_MIG_DIGEST_FLD_LEN,
                   newPrivKey, digest.digest);
	Trspi_LoadBlob_UINT32(&offset, keyPrivBlobLen, newPrivKey);
	Trspi_LoadBlob(&offset, keyPrivBlobLen, newPrivKey, keyPrivBlob);
	newPrivKeyLen = offset;

	/* encrypt the private key blob */
	if ((result = Trspi_RSA_Encrypt(newPrivKey, newPrivKeyLen, encPrivKey,
					&encPrivKeyLen, wrappingPubKey,
					wrappingPubKeyLen)))
		goto done;

	/* set the new encrypted private key in the wrapped key object */
	if ((result = obj_rsakey_set_privkey(hKey, FALSE, encPrivKeyLen, encPrivKey)))
		goto done;

done:
	free_tspi(tspContext, keyPrivBlob);
	free_tspi(tspContext, keyBlob);
	free_tspi(tspContext, wrappingPubKey);
	return result;
}

TSS_RESULT
Tspi_Context_LoadKeyByBlob(TSS_HCONTEXT tspContext,	/* in */
			   TSS_HKEY hUnwrappingKey,	/* in */
			   UINT32 ulBlobLength,		/* in */
			   BYTE * rgbBlobData,		/* in */
			   TSS_HKEY * phKey)		/* out */
{
	TPM_AUTH auth;
	UINT64 offset;
	TCPA_DIGEST digest;
	TSS_RESULT result;
	UINT32 keyslot;
	TSS_HPOLICY hPolicy;
	TCS_KEY_HANDLE tcsParentHandle, myTCSKeyHandle;
	TSS_KEY keyContainer;
	TSS_BOOL useAuth;
	TPM_AUTH *pAuth;
	TSS_FLAG initFlags;
	UINT16 realKeyBlobSize;
	TCPA_KEY_USAGE keyUsage;
	UINT32 pubLen;
	Trspi_HashCtx hashCtx;
	TPM_COMMAND_CODE ordinal;

	if (phKey == NULL || rgbBlobData == NULL )
		return TSPERR(TSS_E_BAD_PARAMETER);

	if (!obj_is_rsakey(hUnwrappingKey))
		return TSPERR(TSS_E_INVALID_HANDLE);

	if ((result = obj_context_get_loadkey_ordinal(tspContext, &ordinal)))
		return result;

	if ((result = obj_rsakey_get_tcs_handle(hUnwrappingKey, &tcsParentHandle)))
		return result;

	offset = 0;
	if ((result = UnloadBlob_TSS_KEY(&offset, rgbBlobData, &keyContainer)))
		return result;
	realKeyBlobSize = offset;
	pubLen = keyContainer.pubKey.keyLength;
	keyUsage = keyContainer.keyUsage;
	/* free these now, since they're not used below */
	free_key_refs(&keyContainer);

	if ((result = obj_rsakey_get_policy(hUnwrappingKey, TSS_POLICY_USAGE, &hPolicy, &useAuth)))
		return result;

	if (useAuth) {
		/* Create the Authorization */
		result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1);
		result |= Trspi_Hash_UINT32(&hashCtx, ordinal);
		result |= Trspi_HashUpdate(&hashCtx, ulBlobLength, rgbBlobData);
		if ((result |= Trspi_HashFinal(&hashCtx, digest.digest)))
			return result;

		if ((result = secret_PerformAuth_OIAP(hUnwrappingKey, ordinal, hPolicy, FALSE,
						      &digest, &auth)))
			return result;

		pAuth = &auth;
	} else {
		pAuth = NULL;
	}

	if ((result = TCS_API(tspContext)->LoadKeyByBlob(tspContext, tcsParentHandle, ulBlobLength,
							 rgbBlobData, pAuth, &myTCSKeyHandle,
							 &keyslot)))
		return result;

	if (useAuth) {
		/* ---  Validate return auth */
		result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1);
		result |= Trspi_Hash_UINT32(&hashCtx, result);
		result |= Trspi_Hash_UINT32(&hashCtx, ordinal);
		if (ordinal == TPM_ORD_LoadKey)
			result |= Trspi_Hash_UINT32(&hashCtx, keyslot);
		if ((result |= Trspi_HashFinal(&hashCtx, digest.digest)))
			return result;

		if ((result = obj_policy_validate_auth_oiap(hPolicy, &digest, &auth)))
			return result;
	}

	/* ---  Create a new Object */
	initFlags = 0;
	if (pubLen == 0x100)
		initFlags |= TSS_KEY_SIZE_2048;
	else if (pubLen == 0x80)
		initFlags |= TSS_KEY_SIZE_1024;
	else if (pubLen == 0x40)
		initFlags |= TSS_KEY_SIZE_512;

	/* clear the key type field */
	initFlags &= ~TSS_KEY_TYPE_MASK;

	if (keyUsage == TPM_KEY_STORAGE)
		initFlags |= TSS_KEY_TYPE_STORAGE;
	else
		initFlags |= TSS_KEY_TYPE_SIGNING;	/* loading the blob
							   will fix this
							   back to what it
							   should be. */

	if ((result = obj_rsakey_add(tspContext, initFlags, phKey))) {
		LogDebug("Failed create object");
		return TSPERR(TSS_E_INTERNAL_ERROR);
	}

	if ((result = obj_rsakey_set_tcpakey(*phKey,realKeyBlobSize, rgbBlobData))) {
		LogDebug("Key loaded but failed to setup the key object"
			  "correctly");
		return TSPERR(TSS_E_INTERNAL_ERROR);
	}

	return obj_rsakey_set_tcs_handle(*phKey, myTCSKeyHandle);
}

TSS_RESULT
Tspi_TPM_OwnerGetSRKPubKey(TSS_HTPM hTPM,		/* in */
			   UINT32 * pulPuKeyLength,	/* out */
			   BYTE ** prgbPubKey)		/* out */
{
	TSS_RESULT result;
	TSS_HPOLICY hPolicy;
	TSS_HCONTEXT tspContext;
	TCS_KEY_HANDLE hKey;
	TPM_AUTH auth;
	Trspi_HashCtx hashCtx;
	TCPA_DIGEST digest;

	if (pulPuKeyLength == NULL || prgbPubKey == NULL)
		return TSPERR(TSS_E_BAD_PARAMETER);

	if ((result = obj_tpm_get_tsp_context(hTPM, &tspContext)))
		return result;

	hKey = TPM_KEYHND_SRK;

	if ((result = obj_tpm_get_policy(hTPM, TSS_POLICY_USAGE, &hPolicy)))
		return result;

	result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1);
	result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_OwnerReadInternalPub);
	result |= Trspi_Hash_UINT32(&hashCtx, hKey);
	if ((result |= Trspi_HashFinal(&hashCtx, digest.digest)))
		return result;

	if ((result = secret_PerformAuth_OIAP(hTPM, TPM_ORD_OwnerReadInternalPub,
					      hPolicy, FALSE, &digest, &auth)))
		return result;

	if ((result = TCS_API(tspContext)->OwnerReadInternalPub(tspContext, hKey, &auth,
								pulPuKeyLength, prgbPubKey)))
		return result;

	/* Validate return auth */
	result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1);
	result |= Trspi_Hash_UINT32(&hashCtx, TSS_SUCCESS);
	result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_OwnerReadInternalPub);
	result |= Trspi_HashUpdate(&hashCtx, *pulPuKeyLength, *prgbPubKey);
	if ((result |= Trspi_HashFinal(&hashCtx, digest.digest)))
		goto error;

	if ((result = obj_policy_validate_auth_oiap(hPolicy, &digest, &auth)))
		goto error;

	/* Call a special SRK-seeking command to transparently add the public data to the object */
	if ((result = obj_rsakey_set_srk_pubkey(*prgbPubKey))) {
		LogError("Error setting SRK public data, SRK key object may not exist");
	}

	if ((result = __tspi_add_mem_entry(tspContext, *prgbPubKey)))
		goto error;

	return result;

error:
	free(*prgbPubKey);
	pulPuKeyLength = 0;
	return result;
}

/* TSS 1.2-only interfaces */
#ifdef TSS_BUILD_TSS12
TSS_RESULT
Tspi_TPM_KeyControlOwner(TSS_HTPM hTPM,		/* in */
			 TSS_HKEY hTssKey,	/* in */
			 UINT32 attribName,	/* in */
			 TSS_BOOL attribValue,	/* in */
			 TSS_UUID* pUuidData)	/* out */
{
	TSS_RESULT result;
	TSS_HPOLICY hPolicy;
	TSS_HCONTEXT tspContext;
	TCS_KEY_HANDLE hTcsKey;
	BYTE *pubKey = NULL;
	UINT32 pubKeyLen;
	TPM_KEY_CONTROL tpmAttribName;
	Trspi_HashCtx hashCtx;
	TCPA_DIGEST digest;
	TPM_AUTH ownerAuth;

	LogDebugFn("Enter");

	/* Check valid TPM context, get TSP context */
	if ((result = obj_tpm_get_tsp_context(hTPM, &tspContext)))
		return result;

	/* Get Tcs KeyHandle */
	if ((result = obj_rsakey_get_tcs_handle(hTssKey, &hTcsKey)))
		return result;

	/* Validate/convert attribName */
	switch (attribName) {
		case TSS_TSPATTRIB_KEYCONTROL_OWNEREVICT:
			tpmAttribName = TPM_KEY_CONTROL_OWNER_EVICT;
			break;
		default:
			return TSPERR(TSS_E_BAD_PARAMETER);
	}

	/* Begin Auth - get TPM Policy Handler */
	if ((result = obj_tpm_get_policy(hTPM, TSS_POLICY_USAGE, &hPolicy)))
		return result;

	/* Get associated pubKey */
	if ((result = obj_rsakey_get_pub_blob(hTssKey, &pubKeyLen, &pubKey)))
		return result;

	/* Create hash digest */
	result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1);
	result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_KeyControlOwner);
	LogDebugData(pubKeyLen, pubKey);
	result |= Trspi_HashUpdate(&hashCtx, pubKeyLen, pubKey);
	result |= Trspi_Hash_UINT32(&hashCtx, tpmAttribName);
	result |= Trspi_Hash_BOOL(&hashCtx, attribValue);
	if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) {
		free_tspi(tspContext, pubKey);
		return result;
	}

	if ((result = secret_PerformAuth_OIAP(hTPM, TPM_ORD_KeyControlOwner, hPolicy, FALSE,
					      &digest, &ownerAuth))) {
		free_tspi(tspContext, pubKey);
		return result;
	}

	if ((result = RPC_KeyControlOwner(tspContext, hTcsKey, pubKeyLen, pubKey, tpmAttribName,
					  attribValue, &ownerAuth, pUuidData))) {
		free_tspi(tspContext, pubKey);
		return result;
	}

	/* Validate return auth */
	result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1);
	result |= Trspi_Hash_UINT32(&hashCtx, TSS_SUCCESS);
	result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_KeyControlOwner);
	if ((result |= Trspi_HashFinal(&hashCtx, digest.digest)))
		return result;

	if ((result = obj_policy_validate_auth_oiap(hPolicy, &digest, &ownerAuth)))
		return result;

	/* change hKey internal flag, according to attrib[Name|Value] */
	switch (attribName) {
		case TSS_TSPATTRIB_KEYCONTROL_OWNEREVICT:
			result = obj_rsakey_set_ownerevict(hTssKey, attribValue);
			break;
		default:
			/* NOT-REACHED */
			result = TSPERR(TSS_E_BAD_PARAMETER);
	}

	return result;
}
#endif
