diff options
Diffstat (limited to 'src/tspi/tsp_auth.c')
-rwxr-xr-x | src/tspi/tsp_auth.c | 1230 |
1 files changed, 1230 insertions, 0 deletions
diff --git a/src/tspi/tsp_auth.c b/src/tspi/tsp_auth.c new file mode 100755 index 0000000..4a57ae7 --- /dev/null +++ b/src/tspi/tsp_auth.c @@ -0,0 +1,1230 @@ + +/* + * 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 <time.h> +#include <errno.h> +#include <assert.h> + +#include "trousers/tss.h" +#include "trousers/trousers.h" +#include "trousers_types.h" +#include "tcs_tsp.h" +#include "spi_utils.h" +#include "capabilities.h" +#include "tsplog.h" +#include "obj.h" +#include "authsess.h" + + +TSS_RESULT +secret_PerformAuth_OIAP(TSS_HOBJECT hAuthorizedObject, + UINT32 ulPendingFn, + TSS_HPOLICY hPolicy, + TSS_BOOL cas, /* continue auth session */ + TCPA_DIGEST *hashDigest, + TPM_AUTH *auth) +{ + TSS_RESULT result; + TSS_BOOL bExpired; + UINT32 mode; + TCPA_SECRET secret; + TSS_HCONTEXT tspContext; + TSS_RESULT (*OIAP)(TSS_HCONTEXT, TCS_AUTHHANDLE *, TPM_NONCE *); // XXX hack + TSS_RESULT (*TerminateHandle)(TSS_HCONTEXT, TCS_HANDLE); // XXX hack + + /* This validates that the secret can be used */ + if ((result = obj_policy_has_expired(hPolicy, &bExpired))) + return result; + + if (bExpired == TRUE) + return TSPERR(TSS_E_INVALID_OBJ_ACCESS); + + if ((result = obj_policy_get_tsp_context(hPolicy, &tspContext))) + return result; + + if ((result = obj_policy_get_mode(hPolicy, &mode))) + return result; + + if ((result = Init_AuthNonce(tspContext, cas, auth))) + return result; + + /* XXX hack for opening a transport session */ + if (cas) { + OIAP = RPC_OIAP; + TerminateHandle = RPC_TerminateHandle; + } else { + OIAP = TCS_API(tspContext)->OIAP; + TerminateHandle = TCS_API(tspContext)->TerminateHandle; + } + + /* added retry logic */ + if ((result = OIAP(tspContext, &auth->AuthHandle, &auth->NonceEven))) { + if (result == TCPA_E_RESOURCES) { + int retry = 0; + do { + /* POSIX sleep time, { secs, nanosecs } */ + struct timespec t = { 0, AUTH_RETRY_NANOSECS }; + + nanosleep(&t, NULL); + + result = OIAP(tspContext, &auth->AuthHandle, &auth->NonceEven); + } while (result == TCPA_E_RESOURCES && ++retry < AUTH_RETRY_COUNT); + } + + if (result) + return result; + } + + switch (mode) { + case TSS_SECRET_MODE_CALLBACK: + result = obj_policy_do_hmac(hPolicy, hAuthorizedObject, + TRUE, ulPendingFn, + auth->fContinueAuthSession, + 20, + auth->NonceEven.nonce, + auth->NonceOdd.nonce, + NULL, NULL, 20, + hashDigest->digest, + (BYTE *)&auth->HMAC); + break; + case TSS_SECRET_MODE_SHA1: + case TSS_SECRET_MODE_PLAIN: + case TSS_SECRET_MODE_POPUP: + if ((result = obj_policy_get_secret(hPolicy, TR_SECRET_CTX_NOT_NEW, + &secret))) + break; + + HMAC_Auth(secret.authdata, hashDigest->digest, auth); + break; + case TSS_SECRET_MODE_NONE: + /* fall through */ + default: + result = TSPERR(TSS_E_POLICY_NO_SECRET); + break; + } + + if (result) { + TerminateHandle(tspContext, auth->AuthHandle); + return result; + } + + return obj_policy_dec_counter(hPolicy); +} +#if 0 +TSS_RESULT +secret_PerformXOR_OSAP(TSS_HPOLICY hPolicy, TSS_HPOLICY hUsagePolicy, + TSS_HPOLICY hMigrationPolicy, TSS_HOBJECT hOSAPObject, + UINT16 osapType, UINT32 osapData, + TCPA_ENCAUTH * encAuthUsage, TCPA_ENCAUTH * encAuthMig, + BYTE *sharedSecret, TPM_AUTH * auth, TCPA_NONCE * nonceEvenOSAP) +{ + TSS_BOOL bExpired; + TCPA_SECRET keySecret; + TCPA_SECRET usageSecret; + TCPA_SECRET migSecret = { { 0, } }; + UINT32 keyMode, usageMode, migMode = 0; + TSS_RESULT result; + TSS_HCONTEXT tspContext; + + + if ((result = obj_policy_has_expired(hPolicy, &bExpired))) + return result; + + if (bExpired == TRUE) + return TSPERR(TSS_E_INVALID_OBJ_ACCESS); + + if ((result = obj_policy_has_expired(hUsagePolicy, &bExpired))) + return result; + + if (bExpired == TRUE) + return TSPERR(TSS_E_INVALID_OBJ_ACCESS); + + if (hMigrationPolicy) { + if ((result = obj_policy_has_expired(hMigrationPolicy, &bExpired))) + return result; + + if (bExpired == TRUE) + return TSPERR(TSS_E_INVALID_OBJ_ACCESS); + + if ((result = obj_policy_get_mode(hMigrationPolicy, &migMode))) + return result; + } + + if ((result = obj_policy_get_tsp_context(hPolicy, &tspContext))) + return result; + + if ((result = obj_policy_get_mode(hPolicy, &keyMode))) + return result; + + if ((result = obj_policy_get_mode(hUsagePolicy, &usageMode))) + return result; + + if (keyMode == TSS_SECRET_MODE_CALLBACK || + usageMode == TSS_SECRET_MODE_CALLBACK || + (hMigrationPolicy && migMode == TSS_SECRET_MODE_CALLBACK)) { + if (keyMode != TSS_SECRET_MODE_CALLBACK || + usageMode != TSS_SECRET_MODE_CALLBACK || + (hMigrationPolicy && migMode != TSS_SECRET_MODE_CALLBACK)) + return TSPERR(TSS_E_BAD_PARAMETER); + } + + if (keyMode != TSS_SECRET_MODE_CALLBACK) { + if ((result = obj_policy_get_secret(hPolicy, TR_SECRET_CTX_NOT_NEW, &keySecret))) + return result; + + if ((result = obj_policy_get_secret(hUsagePolicy, TR_SECRET_CTX_NEW, &usageSecret))) + return result; + + if (hMigrationPolicy) { + if ((result = obj_policy_get_secret(hMigrationPolicy, TR_SECRET_CTX_NEW, + &migSecret))) + return result; + } + + if ((result = OSAP_Calc(tspContext, osapType, osapData, + keySecret.authdata, usageSecret.authdata, + migSecret.authdata, encAuthUsage, + encAuthMig, sharedSecret, auth))) + return result; + } else { + /* If the secret mode is NONE here, we don't return an error. This is + * because there are commands such as CreateKey, which require an auth + * session even when creating no-auth keys. A secret of all 0's will be + * used in this case. */ + if ((result = TCS_API(tspContext)->OSAP(tspContext, osapType, osapData, + &auth->NonceOdd, &auth->AuthHandle, + &auth->NonceEven, nonceEvenOSAP))) + return result; + + if ((result = obj_policy_do_xor(hPolicy, hOSAPObject, + hPolicy, TRUE, 20, + auth->NonceEven.nonce, NULL, + nonceEvenOSAP->nonce, + auth->NonceOdd.nonce, 20, + encAuthUsage->authdata, + encAuthMig->authdata))) { + TCS_API(tspContext)->TerminateHandle(tspContext, auth->AuthHandle); + return result; + } + } + + return TSS_SUCCESS; +} + +TSS_RESULT +secret_PerformAuth_OSAP(TSS_HOBJECT hAuthorizedObject, UINT32 ulPendingFn, + TSS_HPOLICY hPolicy, TSS_HPOLICY hUsagePolicy, + TSS_HPOLICY hMigPolicy, BYTE sharedSecret[20], + TPM_AUTH *auth, BYTE *hashDigest, + TCPA_NONCE *nonceEvenOSAP) +{ + TSS_RESULT result; + UINT32 keyMode, usageMode, migMode = 0; + + if ((result = obj_policy_get_mode(hPolicy, &keyMode))) + return result; + + if ((result = obj_policy_get_mode(hUsagePolicy, &usageMode))) + return result; + + if (hMigPolicy) { + if ((result = obj_policy_get_mode(hMigPolicy, &migMode))) + return result; + } + + /* --- If any of them is a callback */ + if (keyMode == TSS_SECRET_MODE_CALLBACK || + usageMode == TSS_SECRET_MODE_CALLBACK || + (hMigPolicy && migMode == TSS_SECRET_MODE_CALLBACK)) { + /* --- And they're not all callback */ + if (keyMode != TSS_SECRET_MODE_CALLBACK || + usageMode != TSS_SECRET_MODE_CALLBACK || + (hMigPolicy && migMode != TSS_SECRET_MODE_CALLBACK)) + return TSPERR(TSS_E_BAD_PARAMETER); + } + + if (keyMode == TSS_SECRET_MODE_CALLBACK) { + if ((result = obj_policy_do_hmac(hPolicy, hAuthorizedObject, + TRUE, ulPendingFn, + auth->fContinueAuthSession, + 20, + auth->NonceEven.nonce, + NULL, + nonceEvenOSAP->nonce, + auth->NonceOdd.nonce, 20, + hashDigest, + (BYTE *)&auth->HMAC))) + return result; + } else { + HMAC_Auth(sharedSecret, hashDigest, auth); + } + + if ((result = obj_policy_dec_counter(hPolicy))) + return result; + + if ((result = obj_policy_dec_counter(hUsagePolicy))) + return result; + + if (hMigPolicy) { + if ((result = obj_policy_dec_counter(hMigPolicy))) + return result; + } + + return TSS_SUCCESS; +} + +TSS_RESULT +secret_ValidateAuth_OSAP(TSS_HOBJECT hAuthorizedObject, UINT32 ulPendingFn, + TSS_HPOLICY hPolicy, TSS_HPOLICY hUsagePolicy, + TSS_HPOLICY hMigPolicy, BYTE sharedSecret[20], + TPM_AUTH *auth, BYTE *hashDigest, + TCPA_NONCE *nonceEvenOSAP) +{ + TSS_RESULT result; + UINT32 keyMode, usageMode, migMode = 0; + + if ((result = obj_policy_get_mode(hPolicy, &keyMode))) + return result; + + if ((result = obj_policy_get_mode(hUsagePolicy, &usageMode))) + return result; + + if (hMigPolicy) { + if ((result = obj_policy_get_mode(hMigPolicy, &migMode))) + return result; + } + + /* --- If any of them is a callback */ + if (keyMode == TSS_SECRET_MODE_CALLBACK || + usageMode == TSS_SECRET_MODE_CALLBACK || + (hMigPolicy && migMode == TSS_SECRET_MODE_CALLBACK)) { + /* --- And they're not all callback */ + if (keyMode != TSS_SECRET_MODE_CALLBACK || + usageMode != TSS_SECRET_MODE_CALLBACK || + (hMigPolicy && migMode != TSS_SECRET_MODE_CALLBACK)) + return TSPERR(TSS_E_BAD_PARAMETER); + } + + if (keyMode != TSS_SECRET_MODE_CALLBACK) { + if (validateReturnAuth(sharedSecret, hashDigest, auth)) + return TSPERR(TSS_E_TSP_AUTHFAIL); + } else { + if ((result = obj_policy_do_hmac(hPolicy, hAuthorizedObject, + FALSE, ulPendingFn, + auth->fContinueAuthSession, + 20, + auth->NonceEven.nonce, + NULL, + nonceEvenOSAP->nonce, + auth->NonceOdd.nonce, 20, + hashDigest, + (BYTE *)&auth->HMAC))) + return result; + } + + return TSS_SUCCESS; +} +#endif +TSS_RESULT +Init_AuthNonce(TSS_HCONTEXT tspContext, TSS_BOOL cas, TPM_AUTH * auth) +{ + TSS_RESULT result; + + auth->fContinueAuthSession = cas; + if ((result = get_local_random(tspContext, FALSE, sizeof(TPM_NONCE), + (BYTE **)auth->NonceOdd.nonce))) { + LogError("Failed creating random nonce"); + return TSPERR(TSS_E_INTERNAL_ERROR); + } + + return TSS_SUCCESS; +} + +TSS_BOOL +validateReturnAuth(BYTE *secret, BYTE *hash, TPM_AUTH *auth) +{ + BYTE digest[20]; + /* auth is expected to have both nonces and the digest from the TPM */ + memcpy(digest, &auth->HMAC, 20); + HMAC_Auth(secret, hash, auth); + + return ((TSS_BOOL) memcmp(digest, &auth->HMAC, 20) != 0); +} + +void +HMAC_Auth(BYTE * secret, BYTE * Digest, TPM_AUTH * auth) +{ + UINT64 offset; + BYTE Blob[61]; + + offset = 0; + Trspi_LoadBlob(&offset, 20, Blob, Digest); + Trspi_LoadBlob(&offset, 20, Blob, auth->NonceEven.nonce); + Trspi_LoadBlob(&offset, 20, Blob, auth->NonceOdd.nonce); + Blob[offset++] = auth->fContinueAuthSession; + + Trspi_HMAC(TSS_HASH_SHA1, 20, secret, offset, Blob, (BYTE *)&auth->HMAC); +} + +TSS_RESULT +OSAP_Calc(TSS_HCONTEXT tspContext, UINT16 EntityType, UINT32 EntityValue, + BYTE * authSecret, BYTE * usageSecret, BYTE * migSecret, + TCPA_ENCAUTH * encAuthUsage, TCPA_ENCAUTH * encAuthMig, + BYTE * sharedSecret, TPM_AUTH * auth) +{ + TSS_RESULT rc; + TCPA_NONCE nonceEvenOSAP; + UINT64 offset; + BYTE hmacBlob[0x200]; + BYTE hashBlob[0x200]; + BYTE xorUsageAuth[20]; + BYTE xorMigAuth[20]; + UINT32 i; + + if ((rc = get_local_random(tspContext, FALSE, sizeof(TPM_NONCE), + (BYTE **)auth->NonceOdd.nonce))) { + LogError("Failed creating random nonce"); + return TSPERR(TSS_E_INTERNAL_ERROR); + } + auth->fContinueAuthSession = 0x00; + + if ((rc = TCS_API(tspContext)->OSAP(tspContext, EntityType, EntityValue, &auth->NonceOdd, + &auth->AuthHandle, &auth->NonceEven, &nonceEvenOSAP))) { + if (rc == TCPA_E_RESOURCES) { + int retry = 0; + do { + /* POSIX sleep time, { secs, nanosecs } */ + struct timespec t = { 0, AUTH_RETRY_NANOSECS }; + + nanosleep(&t, NULL); + + rc = TCS_API(tspContext)->OSAP(tspContext, EntityType, EntityValue, + &auth->NonceOdd, &auth->AuthHandle, + &auth->NonceEven, &nonceEvenOSAP); + } while (rc == TCPA_E_RESOURCES && ++retry < AUTH_RETRY_COUNT); + } + + if (rc) + return rc; + } + + offset = 0; + Trspi_LoadBlob(&offset, 20, hmacBlob, nonceEvenOSAP.nonce); + Trspi_LoadBlob(&offset, 20, hmacBlob, auth->NonceOdd.nonce); + + Trspi_HMAC(TSS_HASH_SHA1, 20, authSecret, offset, hmacBlob, sharedSecret); + + offset = 0; + Trspi_LoadBlob(&offset, 20, hashBlob, sharedSecret); + Trspi_LoadBlob(&offset, 20, hashBlob, auth->NonceEven.nonce); + + if ((rc = Trspi_Hash(TSS_HASH_SHA1, offset, hashBlob, xorUsageAuth))) + return rc; + + offset = 0; + Trspi_LoadBlob(&offset, 20, hashBlob, sharedSecret); + Trspi_LoadBlob(&offset, 20, hashBlob, auth->NonceOdd.nonce); + if ((rc = Trspi_Hash(TSS_HASH_SHA1, offset, hashBlob, xorMigAuth))) + return rc; + + for (i = 0; i < sizeof(TCPA_ENCAUTH); i++) + encAuthUsage->authdata[i] = usageSecret[i] ^ xorUsageAuth[i]; + for (i = 0; i < sizeof(TCPA_ENCAUTH); i++) + encAuthMig->authdata[i] = migSecret[i] ^ xorMigAuth[i]; + + return TSS_SUCCESS; +} + +TSS_RESULT +obj_policy_validate_auth_oiap(TSS_HPOLICY hPolicy, TCPA_DIGEST *hashDigest, TPM_AUTH *auth) +{ + TSS_RESULT result = TSS_SUCCESS; + struct tsp_object *obj; + struct tr_policy_obj *policy; + BYTE wellKnown[TCPA_SHA1_160_HASH_LEN] = TSS_WELL_KNOWN_SECRET; + + if ((obj = obj_list_get_obj(&policy_list, hPolicy)) == NULL) + return TSPERR(TSS_E_INVALID_HANDLE); + + policy = (struct tr_policy_obj *)obj->data; + + switch (policy->SecretMode) { + case TSS_SECRET_MODE_CALLBACK: + result = policy->Tspicb_CallbackHMACAuth( + policy->hmacAppData, + hPolicy, + 0, + auth->fContinueAuthSession, + FALSE, + 20, + auth->NonceEven.nonce, + auth->NonceOdd.nonce, + NULL, NULL, 20, + hashDigest->digest, + (BYTE *)&auth->HMAC); + break; + case TSS_SECRET_MODE_SHA1: + case TSS_SECRET_MODE_PLAIN: + case TSS_SECRET_MODE_POPUP: + if (validateReturnAuth(policy->Secret, hashDigest->digest, auth)) + result = TSPERR(TSS_E_TSP_AUTHFAIL); + break; + case TSS_SECRET_MODE_NONE: + if (validateReturnAuth(wellKnown, hashDigest->digest, auth)) + result = TSPERR(TSS_E_TSP_AUTHFAIL); + break; + default: + result = TSPERR(TSS_E_POLICY_NO_SECRET); + break; + } + + obj_list_put(&policy_list); + + return result; +} + +#if 0 +TSS_RESULT +authsess_oiap_get(TSS_HOBJECT obj, TPM_COMMAND_CODE ord, TPM_DIGEST *digest, TPM_AUTH *auth) +{ + TSS_RESULT result = TSS_SUCCESS; + TSS_BOOL bExpired; + UINT32 mode; + TPM_SECRET secret; + TSS_HCONTEXT tspContext; + TSS_RESULT (*OIAP)(TSS_HCONTEXT, TCS_AUTHHANDLE *, TPM_NONCE *); // XXX hack + TSS_RESULT (*TerminateHandle)(TSS_HCONTEXT, TCS_HANDLE); // XXX hack + + + if (obj_is_tpm(obj)) + result = obj_tpm_get_tsp_context(obj, hContext); + else if (obj_is_rsakey(obj)) + result = obj_rsakey_get_tsp_context(obj, hContext); + else if (obj_is_encdata(obj)) + result = obj_encdata_get_tsp_context(obj, hContext); + else if (obj_is_nvstore(obj)) + result = obj_nvstore_get_tsp_context(obj, hContext); + else + result = TSPERR(TSS_E_INVALID_HANDLE); + +#if 0 + /* This validates that the secret can be used */ + if ((result = obj_policy_has_expired(hPolicy, &bExpired))) + return result; + + if (bExpired == TRUE) + return TSPERR(TSS_E_INVALID_OBJ_ACCESS); + + if ((result = obj_policy_get_tsp_context(hPolicy, &tspContext))) + return result; + + if ((result = obj_policy_get_mode(hPolicy, &mode))) + return result; +#else + if ((result = obj_policy_get_authsess_params())) + return result; +#endif + if ((result = Init_AuthNonce(tspContext, cas, auth))) + return result; + + /* XXX hack for opening a transport session */ + if (cas) { + OIAP = RPC_OIAP; + TerminateHandle = RPC_TerminateHandle; + } else { + OIAP = TCS_API(tspContext)->OIAP; + TerminateHandle = TCS_API(tspContext)->TerminateHandle; + } + + /* added retry logic */ + if ((result = OIAP(tspContext, &auth->AuthHandle, &auth->NonceEven))) { + if (result == TCPA_E_RESOURCES) { + int retry = 0; + do { + /* POSIX sleep time, { secs, nanosecs } */ + struct timespec t = { 0, AUTH_RETRY_NANOSECS }; + + nanosleep(&t, NULL); + + result = OIAP(tspContext, &auth->AuthHandle, &auth->NonceEven); + } while (result == TCPA_E_RESOURCES && ++retry < AUTH_RETRY_COUNT); + } + + if (result) + return result; + } + + switch (mode) { + case TSS_SECRET_MODE_CALLBACK: + result = obj_policy_do_hmac(hPolicy, hAuthorizedObject, + TRUE, ulPendingFn, + auth->fContinueAuthSession, + 20, + auth->NonceEven.nonce, + auth->NonceOdd.nonce, + NULL, NULL, 20, + hashDigest->digest, + (BYTE *)&auth->HMAC); + break; + case TSS_SECRET_MODE_SHA1: + case TSS_SECRET_MODE_PLAIN: + case TSS_SECRET_MODE_POPUP: + if ((result = obj_policy_get_secret(hPolicy, TR_SECRET_CTX_NOT_NEW, + &secret))) + break; + + HMAC_Auth(secret.authdata, hashDigest->digest, auth); + break; + case TSS_SECRET_MODE_NONE: + /* fall through */ + default: + result = TSPERR(TSS_E_POLICY_NO_SECRET); + break; + } + + if (result) { + TerminateHandle(tspContext, auth->AuthHandle); + return result; + } + + return obj_policy_dec_counter(hPolicy); +} + +TSS_RESULT +authsess_oiap_put(TPM_AUTH *auth) +{ +} +#endif + +#ifdef TSS_BUILD_DELEGATION +TSS_RESULT +authsess_do_dsap(struct authsess *sess) +{ + TSS_RESULT result; + + if ((result = TCS_API(sess->tspContext)->DSAP(sess->tspContext, sess->entity_type, + sess->obj_parent, &sess->nonceOddxSAP, + sess->entityValueSize, sess->entityValue, + &sess->pAuth->AuthHandle, + &sess->pAuth->NonceEven, + &sess->nonceEvenxSAP))) { + if (result == TCPA_E_RESOURCES) { + int retry = 0; + do { + /* POSIX sleep time, { secs, nanosecs } */ + struct timespec t = { 0, AUTH_RETRY_NANOSECS }; + + nanosleep(&t, NULL); + + result = TCS_API(sess->tspContext)->DSAP(sess->tspContext, + sess->entity_type, + sess->obj_parent, + &sess->nonceOddxSAP, + sess->entityValueSize, + sess->entityValue, + &sess->pAuth->AuthHandle, + &sess->pAuth->NonceEven, + &sess->nonceEvenxSAP); + } while (result == TCPA_E_RESOURCES && ++retry < AUTH_RETRY_COUNT); + } + } + + return result; +} +#endif + +TSS_RESULT +authsess_do_osap(struct authsess *sess) +{ + TSS_RESULT result; + + if ((result = TCS_API(sess->tspContext)->OSAP(sess->tspContext, sess->entity_type, + sess->obj_parent, &sess->nonceOddxSAP, + &sess->pAuth->AuthHandle, + &sess->pAuth->NonceEven, + &sess->nonceEvenxSAP))) { + if (result == TCPA_E_RESOURCES) { + int retry = 0; + do { + /* POSIX sleep time, { secs, nanosecs } */ + struct timespec t = { 0, AUTH_RETRY_NANOSECS }; + + nanosleep(&t, NULL); + + result = TCS_API(sess->tspContext)->OSAP(sess->tspContext, + sess->entity_type, + sess->obj_parent, + &sess->nonceOddxSAP, + &sess->pAuth->AuthHandle, + &sess->pAuth->NonceEven, + &sess->nonceEvenxSAP); + } while (result == TCPA_E_RESOURCES && ++retry < AUTH_RETRY_COUNT); + } + } + + return result; +} + +TSS_RESULT +authsess_callback_xor(PVOID lpAppData, + TSS_HOBJECT hOSAPObject, + TSS_HOBJECT hObject, + TSS_FLAG PurposeSecret, + UINT32 ulSizeNonces, + BYTE *rgbNonceEven, + BYTE *rgbNonceOdd, + BYTE *rgbNonceEvenOSAP, + BYTE *rgbNonceOddOSAP, + UINT32 ulSizeEncAuth, + BYTE *rgbEncAuthUsage, + BYTE *rgbEncAuthMigration) +{ + TSS_RESULT result; + BYTE xorUseAuth[sizeof(TPM_DIGEST)]; + BYTE xorMigAuth[sizeof(TPM_DIGEST)]; + Trspi_HashCtx hashCtx; + UINT32 i; + struct authsess *sess = (struct authsess *)lpAppData; + + /* sess->sharedSecret was calculated in authsess_xsap_init */ + + result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); + result |= Trspi_Hash_SECRET(&hashCtx, sess->sharedSecret.digest); + result |= Trspi_Hash_NONCE(&hashCtx, rgbNonceEven); + if ((result |= Trspi_HashFinal(&hashCtx, xorUseAuth))) + return result; + + for (i = 0; i < ulSizeEncAuth; i++) + rgbEncAuthUsage[i] ^= xorUseAuth[i]; + + result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); + result |= Trspi_Hash_SECRET(&hashCtx, sess->sharedSecret.digest); + result |= Trspi_Hash_NONCE(&hashCtx, rgbNonceOdd); + if ((result |= Trspi_HashFinal(&hashCtx, xorMigAuth))) + return result; + + for (i = 0; i < ulSizeEncAuth; i++) + rgbEncAuthMigration[i] ^= xorMigAuth[i]; + + return TSS_SUCCESS; +} + +TSS_RESULT +authsess_callback_hmac(PVOID lpAppData, + TSS_HOBJECT hAuthorizedObject, + TSS_BOOL ReturnOrVerify, + UINT32 ulPendingFunction, + TSS_BOOL ContinueUse, + UINT32 ulSizeNonces, + BYTE *rgbNonceEven, + BYTE *rgbNonceOdd, + BYTE *rgbNonceEvenOSAP, + BYTE *rgbNonceOddOSAP, + UINT32 ulSizeDigestHmac, + BYTE *rgbParamDigest, + BYTE *rgbHmacData) +{ + struct authsess *sess = (struct authsess *)lpAppData; + TSS_RESULT result = TSS_SUCCESS; + UINT64 offset; + BYTE Blob[61]; + + offset = 0; + Trspi_LoadBlob(&offset, ulSizeDigestHmac, Blob, rgbParamDigest); + Trspi_LoadBlob(&offset, ulSizeNonces, Blob, rgbNonceEven); + Trspi_LoadBlob(&offset, ulSizeNonces, Blob, rgbNonceOdd); + Blob[offset++] = ContinueUse; + + if (ReturnOrVerify) { + Trspi_HMAC(TSS_HASH_SHA1, ulSizeDigestHmac, sess->sharedSecret.digest, offset, Blob, + rgbHmacData); + } else { + TPM_HMAC hmacVerify; + + Trspi_HMAC(TSS_HASH_SHA1, ulSizeDigestHmac, sess->sharedSecret.digest, offset, Blob, + hmacVerify.digest); + result = memcmp(rgbHmacData, hmacVerify.digest, ulSizeDigestHmac); + if (result) + result = TPM_E_AUTHFAIL; + } + + return result; +} + +/* Create an OSAP session. @requirements is used in different ways depending on the command to + * indicate whether we should require a policy or auth value */ +TSS_RESULT +authsess_xsap_init(TSS_HCONTEXT tspContext, + TSS_HOBJECT obj_parent, + TSS_HOBJECT obj_child, + TSS_BOOL requirements, + TPM_COMMAND_CODE command, + TPM_ENTITY_TYPE entity_type, + struct authsess **xsess) +{ + TSS_RESULT result; + TSS_BOOL authdatausage = FALSE, req_auth = TRUE, get_child_auth = TRUE, secret_set = FALSE; + BYTE hmacBlob[2 * sizeof(TPM_DIGEST)]; + UINT64 offset; + TSS_BOOL new_secret = TR_SECRET_CTX_NOT_NEW; + struct authsess *sess; + + if ((sess = calloc(1, sizeof(struct authsess))) == NULL) { + LogError("malloc of %zd bytes failed", sizeof(struct authsess)); + return TSPERR(TSS_E_OUTOFMEMORY); + } + + switch (command) { + /* Parent is Key for the cases below */ + case TPM_ORD_Delegate_CreateKeyDelegation: + case TPM_ORD_CreateWrapKey: + case TPM_ORD_CMK_CreateKey: + case TPM_ORD_Seal: + case TPM_ORD_Sealx: + case TPM_ORD_Unseal: + case TPM_ORD_ChangeAuth: + if ((result = obj_rsakey_get_policy(obj_parent, TSS_POLICY_USAGE, + &sess->hUsageParent, NULL))) + goto error; + break; + /* Parent is TPM for the cases below */ + case TPM_ORD_Delegate_CreateOwnerDelegation: + req_auth = FALSE; + /* fall through */ + case TPM_ORD_MakeIdentity: + case TPM_ORD_NV_DefineSpace: + if ((result = obj_tpm_get_policy(obj_parent, TSS_POLICY_USAGE, + &sess->hUsageParent))) + goto error; + break; + case TPM_ORD_ChangeAuthOwner: + /* Special case, ChangeAuthOwner is used to change Owner and SRK auth */ + if (obj_is_rsakey(obj_parent)) { + if ((result = obj_rsakey_get_policy(obj_parent, TSS_POLICY_USAGE, + &sess->hUsageParent, NULL))) + goto error; + } else { + if ((result = obj_tpm_get_policy(obj_parent, TSS_POLICY_USAGE, + &sess->hUsageParent))) + goto error; + } + break; + default: + result = TSPERR(TSS_E_INTERNAL_ERROR); + goto error; + } + + if (requirements && !sess->hUsageParent) { + result = TSPERR(TSS_E_TSP_AUTHREQUIRED); + goto error; + } + + if (sess->hUsageParent) { + /* These are trousers callback functions which will be used to process the auth + * session. If the policy type is callback for hUsageParent, they will be + * overwritten by the application defined callback functions in the policy */ + sess->cb_xor.callback = authsess_callback_xor; + sess->cb_xor.appData = (PVOID)sess; + sess->cb_hmac.callback = authsess_callback_hmac; + sess->cb_hmac.appData = (PVOID)sess; + + /* XXX the parent object doesn't always hold the callbacks */ + if ((result = obj_policy_get_xsap_params(sess->hUsageParent, command, + &sess->entity_type, &sess->entityValueSize, + &sess->entityValue, + sess->parentSecret.authdata, &sess->cb_xor, + &sess->cb_hmac, NULL, &sess->parentMode, + new_secret))) + goto error; + } else + sess->parentMode = TSS_SECRET_MODE_NONE; + + switch (command) { + /* Child is a Key object */ + case TPM_ORD_CreateWrapKey: + case TPM_ORD_CMK_CreateKey: + if ((result = obj_rsakey_get_policies(obj_child, &sess->hUsageChild, + &sess->hMigChild, &authdatausage))) + goto error; + + if (authdatausage && !sess->hUsageChild) { + result = TSPERR(TSS_E_TSP_AUTHREQUIRED); + goto error; + } + + if (obj_rsakey_is_migratable(obj_child)) { + if (!sess->hMigChild) { + result = TSPERR(TSS_E_KEY_NO_MIGRATION_POLICY); + goto error; + } + + if ((result = obj_policy_get_xsap_params(sess->hMigChild, 0, NULL, NULL, + NULL, sess->encAuthMig.authdata, + NULL, NULL, NULL, &sess->mMode, + new_secret))) + goto error; + } + + if ((result = obj_rsakey_get_tcs_handle(obj_parent, &sess->obj_parent))) + goto error; + break; + /* Child is an Encdata object */ + case TPM_ORD_Unseal: +#ifdef TSS_BUILD_SEALX + case TPM_ORD_Sealx: + /* These may be overwritten down below, when obj_policy_get_xsap_params is called + * on the child usage policy */ + sess->cb_sealx.callback = sealx_mask_cb; + sess->cb_sealx.appData = (PVOID)sess; + /* fall through */ +#endif + case TPM_ORD_Seal: + if ((result = obj_encdata_get_policy(obj_child, TSS_POLICY_USAGE, + &sess->hUsageChild))) + goto error; + + if ((result = obj_rsakey_get_tcs_handle(obj_parent, &sess->obj_parent))) + goto error; + break; +#ifdef TSS_BUILD_NV + /* Child is an NV object */ + case TPM_ORD_NV_DefineSpace: + /* The requirements variable tells us whether nv object auth is required */ + req_auth = requirements; + + if (req_auth) { + if (sess->parentMode == TSS_SECRET_MODE_NONE) { + result = TSPERR(TSS_E_TSP_AUTHREQUIRED); + goto error; + } + + if ((result = obj_nvstore_get_policy(obj_child, TSS_POLICY_USAGE, + &sess->hUsageChild))) + goto error; + + /* According to the spec, we must fall back on the TSP context's policy for + * auth if none is set in the NV object */ + if (!sess->hUsageChild) { + if ((result = obj_context_get_policy(tspContext, TSS_POLICY_USAGE, + &sess->hUsageChild))) + goto error; + } + + if ((result = obj_policy_is_secret_set(sess->hUsageChild, &secret_set))) + goto error; + + if (!secret_set) { + result = TSPERR(TSS_E_TSP_AUTHREQUIRED); + goto error; + } + } else { + /* In this case, the TPM is owned, but we're creating a no-auth NV area */ + get_child_auth = FALSE; + } + + break; +#endif + /* Child is a Key object */ + case TPM_ORD_MakeIdentity: + if ((result = obj_rsakey_get_policy(obj_child, TSS_POLICY_USAGE, + &sess->hUsageChild, NULL))) + goto error; + break; + /* Child is a Policy object */ + case TPM_ORD_Delegate_CreateKeyDelegation: + case TPM_ORD_ChangeAuth: + if ((result = obj_rsakey_get_tcs_handle(obj_parent, &sess->obj_parent))) + goto error; + /* fall through */ + case TPM_ORD_Delegate_CreateOwnerDelegation: + case TPM_ORD_ChangeAuthOwner: + sess->hUsageChild = obj_child; + new_secret = TR_SECRET_CTX_NEW; + break; + default: + result = TSPERR(TSS_E_INTERNAL_ERROR); + goto error; + } + + /* If req_auth is FALSE here, we don't actually need to set up an auth session, so returning + * is OK. At this point, authsess->pAuth is NULL, so the TCS API will not get any + * authdata. */ + if (req_auth == FALSE && sess->parentMode == TSS_SECRET_MODE_NONE) + goto done; + + if (get_child_auth) { + if ((result = obj_policy_get_xsap_params(sess->hUsageChild, 0, 0, NULL, NULL, + sess->encAuthUse.authdata, NULL, NULL, + &sess->cb_sealx, &sess->uMode, + new_secret))) + goto error; + } + + if ((result = get_local_random(tspContext, FALSE, sizeof(TPM_NONCE), + (BYTE **)sess->nonceOddxSAP.nonce))) + goto error; + + sess->obj_child = obj_child; + sess->tspContext = tspContext; + sess->pAuth = &sess->auth; + sess->command = command; + +#ifdef TSS_BUILD_DELEGATION + /* if entityValue is set, we have a custom entity, i.e. delegation blob or row */ + if (sess->entityValue) { + /* DSAP's entity type was pulled from the policy in the authsess_xsap_init call + * above */ + if ((result = authsess_do_dsap(sess))) + goto error; + } +#endif + if (!sess->entityValue) { + sess->entity_type = entity_type; + if ((result = authsess_do_osap(sess))) + goto error; + } + + if ((result = get_local_random(tspContext, FALSE, sizeof(TPM_NONCE), + (BYTE **)sess->auth.NonceOdd.nonce))) + goto error; + + /* We have both OSAP nonces, so calculate the shared secret if we're responsible for it */ + if (sess->parentMode != TSS_SECRET_MODE_CALLBACK) { + offset = 0; + Trspi_LoadBlob(&offset, sizeof(TPM_NONCE), hmacBlob, sess->nonceEvenxSAP.nonce); + Trspi_LoadBlob(&offset, sizeof(TPM_NONCE), hmacBlob, sess->nonceOddxSAP.nonce); + + if ((result = Trspi_HMAC(TSS_HASH_SHA1, sizeof(TPM_ENCAUTH), + sess->parentSecret.authdata, offset, hmacBlob, + sess->sharedSecret.digest))) + goto error; + } + + /* XXX What does a PurposeSecret of TRUE mean here? */ + if ((result = + ((TSS_RESULT (*)(PVOID, TSS_HOBJECT, TSS_HOBJECT, TSS_FLAG, + UINT32, BYTE *, BYTE *, BYTE *, BYTE *, UINT32, BYTE *, + BYTE *))sess->cb_xor.callback)(sess->cb_xor.appData, sess->hUsageParent, + sess->hUsageChild, TRUE, sizeof(TPM_DIGEST), + sess->auth.NonceEven.nonce, sess->auth.NonceOdd.nonce, + sess->nonceEvenxSAP.nonce, sess->nonceOddxSAP.nonce, + sizeof(TPM_ENCAUTH), sess->encAuthUse.authdata, + sess->encAuthMig.authdata))) + return result; + +done: + *xsess = sess; + + return TSS_SUCCESS; +error: + free(sess); + return result; +} + +TSS_RESULT +authsess_xsap_hmac(struct authsess *sess, TPM_DIGEST *digest) +{ + TSS_RESULT result; + + /* If no auth session was established using this authsess object, return success */ + if (!sess->pAuth) + return TSS_SUCCESS; + + /* XXX Placeholder for future continueAuthSession support: + * conditionally bump NonceOdd if continueAuthSession == TRUE here + */ + + if ((result = + ((TSS_RESULT (*)(PVOID, TSS_HOBJECT, TSS_BOOL, + UINT32, TSS_BOOL, UINT32, BYTE *, BYTE *, + BYTE *, BYTE *, UINT32, BYTE *, + BYTE *))sess->cb_hmac.callback)(sess->cb_hmac.appData, + sess->hUsageParent, TRUE, sess->command, + sess->auth.fContinueAuthSession, sizeof(TPM_NONCE), + sess->auth.NonceEven.nonce, + sess->auth.NonceOdd.nonce, + sess->nonceEvenxSAP.nonce, + sess->nonceOddxSAP.nonce, sizeof(TPM_DIGEST), + digest->digest, sess->auth.HMAC.authdata))) + return result; + + if (sess->hUsageParent) + obj_policy_dec_counter(sess->hUsageParent); + + if (sess->hUsageChild) + obj_policy_dec_counter(sess->hUsageChild); + + if (sess->hMigChild) + obj_policy_dec_counter(sess->hMigChild); + + return TSS_SUCCESS; +} + +TSS_RESULT +authsess_xsap_verify(struct authsess *sess, TPM_DIGEST *digest) +{ + /* If no auth session was established using this authsess object, return success */ + if (!sess->pAuth) + return TSS_SUCCESS; + + return ((TSS_RESULT (*)(PVOID, TSS_HOBJECT, TSS_BOOL, + UINT32, TSS_BOOL, UINT32, BYTE *, BYTE *, + BYTE *, BYTE *, UINT32, BYTE *, + BYTE *))sess->cb_hmac.callback)(sess->cb_hmac.appData, + sess->hUsageParent, FALSE, sess->command, + sess->auth.fContinueAuthSession, sizeof(TPM_NONCE), + sess->auth.NonceEven.nonce, + sess->auth.NonceOdd.nonce, + sess->nonceEvenxSAP.nonce, + sess->nonceOddxSAP.nonce, sizeof(TPM_DIGEST), + digest->digest, sess->auth.HMAC.authdata); +} + +TSS_RESULT +__tspi_free_resource(TSS_HCONTEXT tspContext, UINT32 handle, UINT32 resourceType) +{ + TSS_RESULT result = TSS_SUCCESS; +#ifdef TSS_BUILD_TSS12 + UINT32 version = 0; + + if ((result = obj_context_get_tpm_version(tspContext, &version))) + return result; + + if (version == 2) { + return TCS_API(tspContext)->FlushSpecific(tspContext, handle, resourceType); + } +#endif + + switch (resourceType) { + case TPM_RT_KEY: + result = TCS_API(tspContext)->EvictKey(tspContext, handle); + break; + case TPM_RT_AUTH: + result = TCS_API(tspContext)->TerminateHandle(tspContext, handle); + break; + default: + LogDebugFn("Trying to free TPM 1.2 resource type 0x%x on 1.1 TPM!", + resourceType); + result = TSPERR(TSS_E_INTERNAL_ERROR); + break; + } + + return result; +} + +void +authsess_free(struct authsess *xsap) +{ + if (xsap) { + if (xsap->auth.AuthHandle && xsap->auth.fContinueAuthSession) + (void)__tspi_free_resource(xsap->tspContext, xsap->auth.AuthHandle, TPM_RT_AUTH); + + free(xsap->entityValue); + free(xsap); + xsap = NULL; + } +} + +#ifdef TSS_BUILD_TRANSPORT +TSS_RESULT +Transport_OIAP(TSS_HCONTEXT tspContext, /* in */ + TCS_AUTHHANDLE* authHandle, /* out */ + TPM_NONCE* nonce0) /* out */ +{ + TSS_RESULT result; + UINT32 decLen = 0; + BYTE *dec = NULL; + UINT64 offset; + TCS_HANDLE handlesLen = 0; + + if ((result = obj_context_transport_init(tspContext))) + return result; + + LogDebugFn("Executing in a transport session"); + + if ((result = obj_context_transport_execute(tspContext, TPM_ORD_OIAP, 0, NULL, NULL, + &handlesLen, NULL, NULL, NULL, &decLen, &dec))) + return result; + + if (decLen != sizeof(TCS_AUTHHANDLE) + sizeof(TPM_NONCE)) + return TSPERR(TSS_E_INTERNAL_ERROR); + + offset = 0; + Trspi_UnloadBlob_UINT32(&offset, authHandle, dec); + Trspi_UnloadBlob_NONCE(&offset, dec, nonce0); + + return result; +} + +TSS_RESULT +Transport_OSAP(TSS_HCONTEXT tspContext, /* in */ + TPM_ENTITY_TYPE entityType, /* in */ + UINT32 entityValue, /* in */ + TPM_NONCE* nonceOddOSAP, /* in */ + TCS_AUTHHANDLE* authHandle, /* out */ + TPM_NONCE* nonceEven, /* out */ + TPM_NONCE* nonceEvenOSAP) /* out */ +{ + TSS_RESULT result; + UINT32 decLen = 0; + BYTE *dec = NULL; + UINT64 offset; + TCS_HANDLE handlesLen = 0; + BYTE data[sizeof(UINT16) + sizeof(UINT32) + sizeof(TPM_NONCE)]; + + if ((result = obj_context_transport_init(tspContext))) + return result; + + LogDebugFn("Executing in a transport session"); + + offset = 0; + Trspi_LoadBlob_UINT16(&offset, entityType, data); + Trspi_LoadBlob_UINT32(&offset, entityValue, data); + Trspi_LoadBlob_NONCE(&offset, data, nonceOddOSAP); + + if ((result = obj_context_transport_execute(tspContext, TPM_ORD_OSAP, sizeof(data), data, + NULL, &handlesLen, NULL, NULL, NULL, &decLen, + &dec))) + return result; + + offset = 0; + Trspi_UnloadBlob_UINT32(&offset, authHandle, dec); + Trspi_UnloadBlob_NONCE(&offset, dec, nonceEven); + Trspi_UnloadBlob_NONCE(&offset, dec, nonceEvenOSAP); + + return TSS_SUCCESS; +} + +TSS_RESULT +Transport_TerminateHandle(TSS_HCONTEXT tspContext, /* in */ + TCS_AUTHHANDLE handle) /* in */ +{ + TSS_RESULT result; + TCS_HANDLE handlesLen = 0, *handles; + + /* Call ExecuteTransport */ + handlesLen = 1; + if ((handles = malloc(sizeof(TCS_HANDLE))) == NULL) { + LogError("malloc of %zd bytes failed", sizeof(TCS_HANDLE)); + return TSPERR(TSS_E_OUTOFMEMORY); + } + + *handles = handle; + + result = obj_context_transport_execute(tspContext, TPM_ORD_Terminate_Handle, 0, NULL, + NULL, &handlesLen, &handles, NULL, NULL, NULL, NULL); + + return result; +} +#endif |