diff options
Diffstat (limited to 'src/tspi/obj_context.c')
-rw-r--r-- | src/tspi/obj_context.c | 1524 |
1 files changed, 1524 insertions, 0 deletions
diff --git a/src/tspi/obj_context.c b/src/tspi/obj_context.c new file mode 100644 index 0000000..cb2091e --- /dev/null +++ b/src/tspi/obj_context.c @@ -0,0 +1,1524 @@ + +/* + * Licensed Materials - Property of IBM + * + * trousers - An open source TCG Software Stack + * + * (C) Copyright International Business Machines Corp. 2005, 2007 + * + */ + + +#include <stdlib.h> +#include <stdio.h> +#include <errno.h> +#include <string.h> +#include <assert.h> + +#include "trousers/tss.h" +#include "trousers/trousers.h" +#include "tcs_tsp.h" +#include "trousers_types.h" +#include "spi_utils.h" +#include "capabilities.h" +#include "tsplog.h" +#include "obj.h" + + +TSS_RESULT +obj_context_add(TSS_HOBJECT *phObject) +{ + TSS_RESULT result; + struct tr_context_obj *context = calloc(1, sizeof(struct tr_context_obj)); + unsigned len = strlen(TSS_LOCALHOST_STRING) + 1; + + if (context == NULL) { + LogError("malloc of %zd bytes failed.", sizeof(struct tr_context_obj)); + return TSPERR(TSS_E_OUTOFMEMORY); + } + +#ifndef TSS_NO_GUI + context->silentMode = TSS_TSPATTRIB_CONTEXT_NOT_SILENT; +#else + context->silentMode = TSS_TSPATTRIB_CONTEXT_SILENT; +#endif + if ((context->machineName = calloc(1, len)) == NULL) { + LogError("malloc of %u bytes failed", len); + free(context); + return TSPERR(TSS_E_OUTOFMEMORY); + } + memcpy(context->machineName, TSS_LOCALHOST_STRING, len); + context->machineNameLength = len; + + context->hashMode = TSS_TSPATTRIB_HASH_MODE_NOT_NULL; + context->connection_policy = TSS_TSPATTRIB_CONTEXT_VERSION_V1_1; + + if ((result = obj_list_add(&context_list, NULL_HCONTEXT, 0, context, phObject))) { + free(context->machineName); + free(context); + return result; + } + + /* Add the default policy */ + if ((result = obj_policy_add(*phObject, TSS_POLICY_USAGE, &context->policy))) { + obj_list_remove(&context_list, &__tspi_obj_context_free, *phObject, *phObject); + return result; + } + + context->tcs_api = &tcs_normal_api; + + return TSS_SUCCESS; +} + +struct tcs_api_table * +obj_context_get_tcs_api(TSS_HCONTEXT tspContext) +{ + struct tsp_object *obj; + struct tr_context_obj *context; + struct tcs_api_table *t; + + /* If the object cannot be found with the given handle, return a safe value, the normal TCS + * API pointer. Since the handle is bad, the RPC_ function will barf in looking up the + * corresponding TCS context handle and an invalid handle error will be returned. */ + if ((obj = obj_list_get_obj(&context_list, tspContext)) == NULL) + return &tcs_normal_api; + + context = (struct tr_context_obj *)obj->data; + + /* Return the current API set we're using, either the normal API, or the transport encrypted + * API. The context->tcs_api variable is switched back and forth between the two sets by + * the obj_context_transport_set_control function through a set attrib. */ + t = context->tcs_api; + + obj_list_put(&context_list); + + return t; +} + +void +__tspi_obj_context_free(void *data) +{ + struct tr_context_obj *context = (struct tr_context_obj *)data; + + free(context->machineName); + free(context); +} + +TSS_BOOL +obj_is_context(TSS_HOBJECT hObject) +{ + TSS_BOOL answer = FALSE; + + if ((obj_list_get_obj(&context_list, hObject))) { + answer = TRUE; + obj_list_put(&context_list); + } + + return answer; +} + +/* Clean up transport session if necessary. */ +void +obj_context_close(TSS_HCONTEXT tspContext) +{ + struct tsp_object *obj; + struct tr_context_obj *context; + + if ((obj = obj_list_get_obj(&context_list, tspContext)) == NULL) + return; + + context = (struct tr_context_obj *)obj->data; + +#ifdef TSS_BUILD_TRANSPORT + if (context->transAuth.AuthHandle) { + RPC_FlushSpecific(tspContext, context->transAuth.AuthHandle, TPM_RT_TRANS); + + memset(&context->transPub, 0, sizeof(TPM_TRANSPORT_PUBLIC)); + memset(&context->transMod, 0, sizeof(TPM_MODIFIER_INDICATOR)); + memset(&context->transSecret, 0, sizeof(TPM_TRANSPORT_AUTH)); + memset(&context->transAuth, 0, sizeof(TPM_AUTH)); + memset(&context->transLogIn, 0, sizeof(TPM_TRANSPORT_LOG_IN)); + memset(&context->transLogOut, 0, sizeof(TPM_TRANSPORT_LOG_OUT)); + memset(&context->transLogDigest, 0, sizeof(TPM_DIGEST)); + } +#endif + + obj_list_put(&context_list); +} + +TSS_RESULT +obj_context_get_policy(TSS_HCONTEXT tspContext, UINT32 policyType, TSS_HPOLICY *phPolicy) +{ + struct tsp_object *obj; + struct tr_context_obj *context; + TSS_RESULT result = TSS_SUCCESS; + + if ((obj = obj_list_get_obj(&context_list, tspContext)) == NULL) + return TSPERR(TSS_E_INVALID_HANDLE); + + context = (struct tr_context_obj *)obj->data; + + switch (policyType) { + case TSS_POLICY_USAGE: + *phPolicy = context->policy; + break; + default: + result = TSPERR(TSS_E_BAD_PARAMETER); + } + + obj_list_put(&context_list); + + return result; +} + +TSS_RESULT +obj_context_get_machine_name(TSS_HCONTEXT tspContext, UINT32 *size, BYTE **data) +{ + struct tsp_object *obj; + struct tr_context_obj *context; + TSS_RESULT result; + + if ((obj = obj_list_get_obj(&context_list, tspContext)) == NULL) + return TSPERR(TSS_E_INVALID_HANDLE); + + context = (struct tr_context_obj *)obj->data; + + if (context->machineNameLength == 0) { + *data = NULL; + *size = 0; + } else { + /* + * Don't use calloc_tspi because this memory is + * not freed using "free_tspi" + */ + *data = calloc(1, context->machineNameLength); + if (*data == NULL) { + LogError("malloc of %u bytes failed.", + context->machineNameLength); + result = TSPERR(TSS_E_OUTOFMEMORY); + goto done; + } + *size = context->machineNameLength; + memcpy(*data, context->machineName, *size); + } + + result = TSS_SUCCESS; + +done: + obj_list_put(&context_list); + + return result; +} + +/* This function converts the machine name to a TSS_UNICODE string before + * returning it, as Tspi_GetAttribData would like. We could do the conversion + * in Tspi_GetAttribData, but we don't have access to the TSP context there */ +TSS_RESULT +obj_context_get_machine_name_attrib(TSS_HCONTEXT tspContext, UINT32 *size, BYTE **data) +{ + struct tsp_object *obj; + struct tr_context_obj *context; + BYTE *utf_string; + UINT32 utf_size; + TSS_RESULT result; + + if ((obj = obj_list_get_obj(&context_list, tspContext)) == NULL) + return TSPERR(TSS_E_INVALID_HANDLE); + + context = (struct tr_context_obj *)obj->data; + + if (context->machineNameLength == 0) { + *data = NULL; + *size = 0; + } else { + utf_size = context->machineNameLength; + utf_string = Trspi_Native_To_UNICODE(context->machineName, + &utf_size); + if (utf_string == NULL) { + result = TSPERR(TSS_E_INTERNAL_ERROR); + goto done; + } + + *data = calloc_tspi(obj->tspContext, utf_size); + if (*data == NULL) { + free(utf_string); + LogError("malloc of %u bytes failed.", utf_size); + result = TSPERR(TSS_E_OUTOFMEMORY); + goto done; + } + *size = utf_size; + memcpy(*data, utf_string, utf_size); + free(utf_string); + } + + result = TSS_SUCCESS; + +done: + obj_list_put(&context_list); + + return result; +} + +TSS_RESULT +obj_context_set_machine_name(TSS_HCONTEXT tspContext, BYTE *name, UINT32 len) +{ + struct tsp_object *obj; + struct tr_context_obj *context; + + if ((obj = obj_list_get_obj(&context_list, tspContext)) == NULL) + return TSPERR(TSS_E_INVALID_HANDLE); + + context = (struct tr_context_obj *)obj->data; + + free(context->machineName); + context->machineName = name; + context->machineNameLength = len; + + obj_list_put(&context_list); + + return TSS_SUCCESS; +} + +TSS_BOOL +obj_context_is_silent(TSS_HCONTEXT tspContext) +{ + struct tsp_object *obj; + struct tr_context_obj *context; + TSS_BOOL silent = FALSE; + + if ((obj = obj_list_get_obj(&context_list, tspContext)) == NULL) + return FALSE; + + context = (struct tr_context_obj *)obj->data; + if (context->silentMode == TSS_TSPATTRIB_CONTEXT_SILENT) + silent = TRUE; + + obj_list_put(&context_list); + + return silent; +} + +TSS_RESULT +obj_context_get_mode(TSS_HCONTEXT tspContext, UINT32 *mode) +{ + struct tsp_object *obj; + struct tr_context_obj *context; + + if ((obj = obj_list_get_obj(&context_list, tspContext)) == NULL) + return TSPERR(TSS_E_INVALID_HANDLE); + + context = (struct tr_context_obj *)obj->data; + *mode = context->silentMode; + + obj_list_put(&context_list); + + return TSS_SUCCESS; +} + +TSS_RESULT +obj_context_set_mode(TSS_HCONTEXT tspContext, UINT32 mode) +{ + struct tsp_object *obj; + struct tr_context_obj *context; + + if ((obj = obj_list_get_obj(&context_list, tspContext)) == NULL) + return TSPERR(TSS_E_INVALID_HANDLE); + + context = (struct tr_context_obj *)obj->data; + context->silentMode = mode; + + obj_list_put(&context_list); + + return TSS_SUCCESS; +} + +/* search the list of all policies bound to context @tspContext. If + * one is found of type popup, return TRUE, else return FALSE. */ +TSS_BOOL +obj_context_has_popups(TSS_HCONTEXT tspContext) +{ + struct tsp_object *obj; + struct tr_policy_obj *policy; + struct obj_list *list = &policy_list; + TSS_BOOL ret = FALSE; + + MUTEX_LOCK(list->lock); + + for (obj = list->head; obj; obj = obj->next) { + if (obj->tspContext == tspContext) { + policy = (struct tr_policy_obj *)obj->data; + if (policy->SecretMode == TSS_SECRET_MODE_POPUP) + ret = TRUE; + break; + } + } + + MUTEX_UNLOCK(list->lock); + + return ret; +} + +TSS_RESULT +obj_context_get_hash_mode(TSS_HCONTEXT tspContext, UINT32 *mode) +{ + struct tsp_object *obj; + struct tr_context_obj *context; + + if ((obj = obj_list_get_obj(&context_list, tspContext)) == NULL) + return TSPERR(TSS_E_INVALID_HANDLE); + + context = (struct tr_context_obj *)obj->data; + *mode = context->hashMode; + + obj_list_put(&context_list); + + return TSS_SUCCESS; +} + +TSS_RESULT +obj_context_set_hash_mode(TSS_HCONTEXT tspContext, UINT32 mode) +{ + struct tsp_object *obj; + struct tr_context_obj *context; + + switch (mode) { + case TSS_TSPATTRIB_HASH_MODE_NULL: + case TSS_TSPATTRIB_HASH_MODE_NOT_NULL: + break; + default: + return TSPERR(TSS_E_INVALID_ATTRIB_DATA); + } + + if ((obj = obj_list_get_obj(&context_list, tspContext)) == NULL) + return TSPERR(TSS_E_INVALID_HANDLE); + + context = (struct tr_context_obj *)obj->data; + context->hashMode = mode; + + obj_list_put(&context_list); + + return TSS_SUCCESS; +} + +TSS_RESULT +obj_context_get_connection_version(TSS_HCONTEXT tspContext, UINT32 *version) +{ + struct tsp_object *obj; + struct tr_context_obj *context; + + if ((obj = obj_list_get_obj(&context_list, tspContext)) == NULL) + return TSPERR(TSS_E_INVALID_HANDLE); + + context = (struct tr_context_obj *)obj->data; + + *version = context->current_connection; + + obj_list_put(&context_list); + + return TSS_SUCCESS; +} + +TSS_RESULT +obj_context_set_connection_policy(TSS_HCONTEXT tspContext, UINT32 policy) +{ + struct tsp_object *obj; + struct tr_context_obj *context; + + switch (policy) { + case TSS_TSPATTRIB_CONTEXT_VERSION_V1_1: + case TSS_TSPATTRIB_CONTEXT_VERSION_V1_2: + case TSS_TSPATTRIB_CONTEXT_VERSION_AUTO: + break; + default: + return TSPERR(TSS_E_INVALID_ATTRIB_DATA); + } + + if ((obj = obj_list_get_obj(&context_list, tspContext)) == NULL) + return TSPERR(TSS_E_INVALID_HANDLE); + + context = (struct tr_context_obj *)obj->data; + + context->connection_policy = policy; + + obj_list_put(&context_list); + + return TSS_SUCCESS; +} + +#ifdef TSS_BUILD_TRANSPORT +TSS_RESULT +obj_context_set_transport_key(TSS_HCONTEXT tspContext, TSS_HKEY hKey) +{ + struct tsp_object *obj; + struct tr_context_obj *context; + + if ((obj = obj_list_get_obj(&context_list, tspContext)) == NULL) + return TSPERR(TSS_E_INVALID_HANDLE); + + context = (struct tr_context_obj *)obj->data; + + context->transKey = hKey; + + obj_list_put(&context_list); + + return TSS_SUCCESS; +} + +TSS_RESULT +obj_context_transport_get_mode(TSS_HCONTEXT tspContext, UINT32 value, UINT32 *out) +{ + TSS_RESULT result = TSS_SUCCESS; + struct tsp_object *obj; + struct tr_context_obj *context; + + if ((obj = obj_list_get_obj(&context_list, tspContext)) == NULL) + return TSPERR(TSS_E_INVALID_HANDLE); + + context = (struct tr_context_obj *)obj->data; + + switch (value) { + case TSS_TSPATTRIB_TRANSPORT_NO_DEFAULT_ENCRYPTION: + *out = context->flags & TSS_CONTEXT_FLAGS_TRANSPORT_DEFAULT_ENCRYPT ? + FALSE : TRUE; + break; + case TSS_TSPATTRIB_TRANSPORT_DEFAULT_ENCRYPTION: + *out = context->flags & TSS_CONTEXT_FLAGS_TRANSPORT_DEFAULT_ENCRYPT ? + TRUE : FALSE; + break; + case TSS_TSPATTRIB_TRANSPORT_AUTHENTIC_CHANNEL: + *out = context->flags & TSS_CONTEXT_FLAGS_TRANSPORT_AUTHENTIC ? + TRUE : FALSE; + break; + case TSS_TSPATTRIB_TRANSPORT_EXCLUSIVE: + *out = context->flags & TSS_CONTEXT_FLAGS_TRANSPORT_EXCLUSIVE ? + TRUE : FALSE; + break; + case TSS_TSPATTRIB_TRANSPORT_STATIC_AUTH: + *out = context->flags & TSS_CONTEXT_FLAGS_TRANSPORT_STATIC_AUTH ? + TRUE : FALSE; + break; + default: + LogError("Invalid attribute subflag: 0x%x", value); + result = TSPERR(TSS_E_INVALID_ATTRIB_SUBFLAG); + break; + } + + obj_list_put(&context_list); + + return result; +} + +TSS_RESULT +obj_context_transport_get_control(TSS_HCONTEXT tspContext, UINT32 value, UINT32 *out) +{ + TSS_RESULT result = TSS_SUCCESS; + struct tsp_object *obj; + struct tr_context_obj *context; + + if ((obj = obj_list_get_obj(&context_list, tspContext)) == NULL) + return TSPERR(TSS_E_INVALID_HANDLE); + + context = (struct tr_context_obj *)obj->data; + + switch (value) { + case TSS_TSPATTRIB_DISABLE_TRANSPORT: + *out = context->flags & TSS_CONTEXT_FLAGS_TRANSPORT_ENABLED ? FALSE : TRUE; + break; + case TSS_TSPATTRIB_ENABLE_TRANSPORT: + *out = context->flags & TSS_CONTEXT_FLAGS_TRANSPORT_ENABLED ? TRUE : FALSE; + break; + default: + LogError("Invalid attribute subflag: 0x%x", value); + result = TSPERR(TSS_E_INVALID_ATTRIB_SUBFLAG); + break; + } + + obj_list_put(&context_list); + + return result; +} + +TSS_RESULT +obj_context_transport_set_control(TSS_HCONTEXT tspContext, UINT32 value) +{ + TSS_RESULT result = TSS_SUCCESS; + struct tsp_object *obj; + struct tr_context_obj *context; + + if ((obj = obj_list_get_obj(&context_list, tspContext)) == NULL) + return TSPERR(TSS_E_INVALID_HANDLE); + + context = (struct tr_context_obj *)obj->data; + + switch (value) { + case TSS_TSPATTRIB_ENABLE_TRANSPORT: + context->flags |= TSS_CONTEXT_FLAGS_TRANSPORT_ENABLED; + context->tcs_api = &tcs_transport_api; + break; + case TSS_TSPATTRIB_DISABLE_TRANSPORT: + context->flags &= ~TSS_CONTEXT_FLAGS_TRANSPORT_ENABLED; + context->tcs_api = &tcs_normal_api; + break; + default: + LogError("Invalid attribute subflag: 0x%x", value); + result = TSPERR(TSS_E_INTERNAL_ERROR); + break; + } + + obj_list_put(&context_list); + + return result; +} + +TSS_RESULT +obj_context_transport_set_mode(TSS_HCONTEXT tspContext, UINT32 value) +{ + TSS_RESULT result = TSS_SUCCESS; + struct tsp_object *obj; + struct tr_context_obj *context; + + if ((obj = obj_list_get_obj(&context_list, tspContext)) == NULL) + return TSPERR(TSS_E_INVALID_HANDLE); + + context = (struct tr_context_obj *)obj->data; + + switch (value) { + case TSS_TSPATTRIB_TRANSPORT_NO_DEFAULT_ENCRYPTION: + context->flags &= ~TSS_CONTEXT_FLAGS_TRANSPORT_DEFAULT_ENCRYPT; + break; + case TSS_TSPATTRIB_TRANSPORT_DEFAULT_ENCRYPTION: + context->flags |= TSS_CONTEXT_FLAGS_TRANSPORT_DEFAULT_ENCRYPT; + break; + case TSS_TSPATTRIB_TRANSPORT_AUTHENTIC_CHANNEL: + context->flags |= TSS_CONTEXT_FLAGS_TRANSPORT_AUTHENTIC; + break; + case TSS_TSPATTRIB_TRANSPORT_EXCLUSIVE: + context->flags |= TSS_CONTEXT_FLAGS_TRANSPORT_EXCLUSIVE; + break; + case TSS_TSPATTRIB_TRANSPORT_STATIC_AUTH: + context->flags |= TSS_CONTEXT_FLAGS_TRANSPORT_STATIC_AUTH; + break; + default: + LogError("Invalid attribute subflag: 0x%x", value); + result = TSPERR(TSS_E_INTERNAL_ERROR); + break; + } + + obj_list_put(&context_list); + + return result; +} + +#if 0 +TSS_RESULT +get_trans_props(TSS_HCONTEXT tspContext, UINT32 *alg, UINT16 *enc) +{ + TSS_RESULT result; + UINT32 algs[] = { TPM_ALG_MGF1, TPM_ALG_AES128, 0 }, a = 0; + UINT16 encs[] = { TPM_ES_SYM_OFB, TPM_ES_SYM_CNT, TPM_ES_SYM_CBC_PKCS5PAD, 0 }, e = 0; + BYTE *respData; + UINT32 respLen, tcsSubCap32; + UINT16 tcsSubCap16; + + if (*alg) + goto check_es; + + for (a = 0; algs[a]; a++) { + tcsSubCap32 = endian32(algs[a]); + + if ((result = RPC_GetTPMCapability(tspContext, TPM_CAP_TRANS_ALG, sizeof(UINT32), + (BYTE *)&tcsSubCap32, &respLen, &respData))) + return result; + + if (*(TSS_BOOL *)respData == TRUE) { + free(respData); + break; + } + free(respData); + } + + if (!algs[a]) { + LogError("TPM reports no usable sym algorithms for transport session"); + return TSPERR(TSS_E_INTERNAL_ERROR); + } + +check_es: + if (*enc || algs[a] == TPM_ALG_MGF1) + goto done; + + for (e = 0; encs[e]; e++) { + tcsSubCap16 = endian16(encs[e]); + + if ((result = RPC_GetTPMCapability(tspContext, TPM_CAP_TRANS_ES, sizeof(UINT16), + (BYTE *)&tcsSubCap16, &respLen, &respData))) + return result; + + if (*(TSS_BOOL *)respData == TRUE) { + free(respData); + break; + } + free(respData); + } + + if (!encs[e]) { + LogError("TPM reports no usable sym modes for transport session"); + return TSPERR(TSS_E_INTERNAL_ERROR); + } + + *alg = algs[a]; + *enc = encs[e]; +done: + return TSS_SUCCESS; +} +#endif + +/* called before each TCSP_ExecuteTransport call */ +TSS_RESULT +obj_context_transport_init(TSS_HCONTEXT tspContext) +{ + TSS_RESULT result = TSS_SUCCESS; + struct tsp_object *obj; + struct tr_context_obj *context; + + if ((obj = obj_list_get_obj(&context_list, tspContext)) == NULL) + return TSPERR(TSS_E_INVALID_HANDLE); + + context = (struct tr_context_obj *)obj->data; + + /* return immediately if we're not in a transport session */ + if (!(context->flags & TSS_CONTEXT_FLAGS_TRANSPORT_ENABLED)) { + result = TSPERR(TSS_E_INTERNAL_ERROR); + goto done; + } + + /* if the session is not yet established, setup and call EstablishTransport */ + if (!(context->flags & TSS_CONTEXT_FLAGS_TRANSPORT_ESTABLISHED)) { + if ((result = obj_context_transport_establish(tspContext, context))) + goto done; + } + + context->flags |= TSS_CONTEXT_FLAGS_TRANSPORT_ESTABLISHED; + + result = TSS_SUCCESS; +done: + obj_list_put(&context_list); + + return result; +} + +TSS_RESULT +obj_context_transport_establish(TSS_HCONTEXT tspContext, struct tr_context_obj *context) +{ + TSS_RESULT result; + UINT32 tickLen, secretLen, transPubLen, exclusive = TSS_TCSATTRIB_TRANSPORT_DEFAULT; + BYTE *ticks, *secret; + UINT64 offset; + Trspi_HashCtx hashCtx; + TPM_DIGEST digest; + TSS_HPOLICY hTransKeyPolicy; + TPM_AUTH auth, *pAuth, *pTransAuth; + TCS_KEY_HANDLE tcsTransKey; + TSS_BOOL usesAuth = FALSE; + UINT32 encKeyLen; + BYTE encKey[256]; + BYTE transPubBlob[sizeof(TPM_TRANSPORT_PUBLIC)]; + BYTE transAuthBlob[sizeof(TPM_TRANSPORT_AUTH)]; + + + context->transPub.tag = TPM_TAG_TRANSPORT_PUBLIC; + context->transSecret.tag = TPM_TAG_TRANSPORT_AUTH; + + if ((result = get_local_random(tspContext, FALSE, TPM_SHA1_160_HASH_LEN, + (BYTE **)context->transSecret.authData.authdata))) + return result; + + if (context->flags & TSS_CONTEXT_FLAGS_TRANSPORT_STATIC_AUTH) + context->transKey = TPM_KH_TRANSPORT; + + if (context->flags & TSS_CONTEXT_FLAGS_TRANSPORT_AUTHENTIC) + context->transPub.transAttributes |= TPM_TRANSPORT_LOG; + + if (context->flags & TSS_CONTEXT_FLAGS_TRANSPORT_EXCLUSIVE) { + context->transPub.transAttributes |= TPM_TRANSPORT_EXCLUSIVE; + exclusive = TSS_TCSATTRIB_TRANSPORT_EXCLUSIVE; + } + + /* XXX implement AES128+CTR (Winbond, Infineon), then AES256+CTR (Atmel) */ + context->transPub.algId = TPM_ALG_MGF1; + context->transPub.encScheme = TPM_ES_NONE; + + if (context->flags & TSS_CONTEXT_FLAGS_TRANSPORT_DEFAULT_ENCRYPT) { + context->transPub.transAttributes |= TPM_TRANSPORT_ENCRYPT; + + if (context->transKey == TPM_KH_TRANSPORT) { + LogError("No transport key handle has been set yet. Use " + "Tspi_Context_SetTransEncryptionKey to set this handle"); + return TSPERR(TSS_E_INTERNAL_ERROR); + } + } + + if (context->transKey == TPM_KH_TRANSPORT) { + secret = context->transSecret.authData.authdata; + secretLen = TPM_SHA1_160_HASH_LEN; + } else { + offset = 0; + Trspi_LoadBlob_TRANSPORT_AUTH(&offset, transAuthBlob, &context->transSecret); + secretLen = offset; + + /* encrypt the sym key with the wrapping RSA key */ + encKeyLen = sizeof(encKey); + if ((result = __tspi_rsa_encrypt(context->transKey, secretLen, transAuthBlob, &encKeyLen, + encKey))) + return result; + + secret = encKey; + secretLen = encKeyLen; + } + + offset = 0; + Trspi_LoadBlob_TRANSPORT_PUBLIC(&offset, transPubBlob, &context->transPub); + transPubLen = offset; + + if (context->transKey != TPM_KH_TRANSPORT) { + if ((result = obj_rsakey_get_tcs_handle(context->transKey, &tcsTransKey))) + return result; + + if ((result = obj_rsakey_get_policy(context->transKey, TSS_POLICY_USAGE, + &hTransKeyPolicy, &usesAuth))) + return result; + + if (!usesAuth) { + LogError("Key used to establish a transport session must use auth"); + return TSPERR(TSS_E_TSP_TRANS_AUTHREQUIRED); + } + } else + tcsTransKey = TPM_KH_TRANSPORT; + + /* If logging is on, do TPM commands spec rev106 step 8.a */ + memset(context->transLogDigest.digest, 0, sizeof(TPM_DIGEST)); + if (context->flags & TSS_CONTEXT_FLAGS_TRANSPORT_AUTHENTIC) { + context->transLogIn.tag = TPM_TAG_TRANSPORT_LOG_IN; + + /* step 8.a, i */ + result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); + result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_EstablishTransport); + result |= Trspi_HashUpdate(&hashCtx, transPubLen, transPubBlob); + result |= Trspi_Hash_UINT32(&hashCtx, secretLen); + result |= Trspi_HashUpdate(&hashCtx, secretLen, secret); + if ((result |= Trspi_HashFinal(&hashCtx, context->transLogIn.parameters.digest))) + return result; + + /* step 8.a, ii */ + memset(context->transLogIn.pubKeyHash.digest, 0, sizeof(TPM_DIGEST)); + + /* step 8.a, iii */ + result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); + result |= Trspi_Hash_DIGEST(&hashCtx, context->transLogDigest.digest); + result |= Trspi_Hash_TRANSPORT_LOG_IN(&hashCtx, &context->transLogIn); + if ((result |= Trspi_HashFinal(&hashCtx, context->transLogDigest.digest))) + return result; + } + + if (usesAuth) { + result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); + result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_EstablishTransport); + result |= Trspi_HashUpdate(&hashCtx, (UINT32)offset, (BYTE *)transPubBlob); + result |= Trspi_Hash_UINT32(&hashCtx, secretLen); + result |= Trspi_HashUpdate(&hashCtx, secretLen, secret); + if ((result |= Trspi_HashFinal(&hashCtx, (BYTE *)&digest))) + return result; + + /* open OIAP session with continueAuthSession = TRUE */ + if ((result = secret_PerformAuth_OIAP(context->transKey, TPM_ORD_EstablishTransport, + hTransKeyPolicy, TRUE, &digest, &auth))) + return result; + + pAuth = &auth; + } else + pAuth = NULL; + + result = RPC_EstablishTransport(tspContext, exclusive, tcsTransKey, transPubLen, + transPubBlob, secretLen, secret, pAuth, &context->transMod, + &context->transAuth.AuthHandle, &tickLen, &ticks, + &context->transAuth.NonceEven); + if (result) { + LogError("Establish Transport command failed: %s", Trspi_Error_String(result)); + return result; + } + + result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); + result |= Trspi_Hash_UINT32(&hashCtx, result); + result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_EstablishTransport); + result |= Trspi_Hash_UINT32(&hashCtx, context->transMod); + result |= Trspi_HashUpdate(&hashCtx, tickLen, ticks); + result |= Trspi_Hash_NONCE(&hashCtx, context->transAuth.NonceEven.nonce); + if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) + return result; + + if (usesAuth) { + if ((result = obj_policy_validate_auth_oiap(hTransKeyPolicy, &digest, pAuth))) + return result; + } + + /* step 8.b iii */ + offset = 0; + Trspi_UnloadBlob_CURRENT_TICKS(&offset, ticks, &context->transLogOut.currentTicks); + free(ticks); + + /* If logging is on, do TPM commands spec rev106 step 8.b */ + if (context->flags & TSS_CONTEXT_FLAGS_TRANSPORT_AUTHENTIC) { + context->transLogOut.tag = TPM_TAG_TRANSPORT_LOG_OUT; + + /* step 8.b i */ + memcpy(context->transLogOut.parameters.digest, digest.digest, sizeof(TPM_DIGEST)); + + /* step 8.b ii */ + context->transLogOut.locality = context->transMod; + + /* step 8.b iii was done above */ + /* step 8.b iv */ + result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); + result |= Trspi_Hash_DIGEST(&hashCtx, context->transLogDigest.digest); + result |= Trspi_Hash_TRANSPORT_LOG_OUT(&hashCtx, &context->transLogOut); + if ((result |= Trspi_HashFinal(&hashCtx, context->transLogDigest.digest))) + return result; + } + + LogDebug("Transport session established successfully"); + + pTransAuth = &context->transAuth; + pTransAuth->fContinueAuthSession = TRUE; + if ((result = get_local_random(tspContext, FALSE, sizeof(TPM_NONCE), + (BYTE **)pTransAuth->NonceOdd.nonce))) { + LogError("Failed creating random nonce"); + return TSPERR(TSS_E_INTERNAL_ERROR); + } + + return TSS_SUCCESS; +} + +TSS_RESULT +do_transport_decryption(TPM_TRANSPORT_PUBLIC *transPub, + TPM_AUTH *pTransAuth, + BYTE *secret, + UINT32 inLen, + BYTE *in, + UINT32 *outLen, + BYTE **out) +{ + TSS_RESULT result; + UINT32 i, decLen; + UINT32 seedLen, ivLen; + BYTE *dec; + BYTE seed[(2 * sizeof(TPM_NONCE)) + strlen("out") + TPM_SHA1_160_HASH_LEN]; + + /* allocate the most data anyone below might need */ + decLen = inLen;//((inLen / TSS_MAX_SYM_BLOCK_SIZE) + 1) * TSS_MAX_SYM_BLOCK_SIZE; + if ((dec = malloc(decLen)) == NULL) { + LogError("malloc of %u bytes failed", decLen); + return TSPERR(TSS_E_OUTOFMEMORY); + } + + /* set the common 3 initial values of 'seed', which is used to generate either the IV or + * mask */ + memcpy(seed, pTransAuth->NonceEven.nonce, sizeof(TPM_NONCE)); + memcpy(&seed[sizeof(TPM_NONCE)], pTransAuth->NonceOdd.nonce, sizeof(TPM_NONCE)); + memcpy(&seed[2 * sizeof(TPM_NONCE)], "out", strlen("out")); + + switch (transPub->algId) { + case TPM_ALG_MGF1: + { + decLen = inLen; + seedLen = sizeof(seed); + + /* add the secret data to the seed for MGF1 */ + memcpy(&seed[2 * sizeof(TPM_NONCE) + strlen("out")], secret, TPM_SHA1_160_HASH_LEN); + + if ((result = Trspi_MGF1(TSS_HASH_SHA1, seedLen, seed, decLen, dec))) { + free(dec); + return result; + } + + for (i = 0; i < inLen; i++) + dec[i] ^= in[i]; + break; + } + case TPM_ALG_AES128: + { + BYTE iv[TSS_MAX_SYM_BLOCK_SIZE]; + + ivLen = TSS_MAX_SYM_BLOCK_SIZE; + seedLen = (2 * sizeof(TPM_NONCE)) + strlen("out"); + + if ((result = Trspi_MGF1(TSS_HASH_SHA1, seedLen, seed, ivLen, iv))) { + free(dec); + return result; + } + + /* use the secret data as the key for AES */ + if ((result = Trspi_SymEncrypt(transPub->algId, transPub->encScheme, secret, iv, in, + inLen, dec, &decLen))) { + free(dec); + return result; + } + + break; + } + default: + LogDebug("Unknown algorithm for encrypted transport session: 0x%x", + transPub->algId); + free(dec); + return TSPERR(TSS_E_INTERNAL_ERROR); + } + + *out = dec; + *outLen = decLen; + + return result; +} + +TSS_RESULT +do_transport_encryption(TPM_TRANSPORT_PUBLIC *transPub, + TPM_AUTH *pTransAuth, + BYTE *secret, + UINT32 inLen, + BYTE *in, + UINT32 *outLen, + BYTE **out) +{ + TSS_RESULT result; + UINT32 i, encLen; + UINT32 seedLen, ivLen; + BYTE *enc; + BYTE seed[(2 * sizeof(TPM_NONCE)) + strlen("in") + TPM_SHA1_160_HASH_LEN]; + + /* allocate the most data anyone below might need */ + encLen = ((inLen / TSS_MAX_SYM_BLOCK_SIZE) + 1) * TSS_MAX_SYM_BLOCK_SIZE; + if ((enc = malloc(encLen)) == NULL) { + LogError("malloc of %u bytes failed", encLen); + return TSPERR(TSS_E_OUTOFMEMORY); + } + + /* set the common 3 initial values of 'seed', which is used to generate either the IV or + * mask */ + memcpy(seed, pTransAuth->NonceEven.nonce, sizeof(TPM_NONCE)); + memcpy(&seed[sizeof(TPM_NONCE)], pTransAuth->NonceOdd.nonce, sizeof(TPM_NONCE)); + memcpy(&seed[2 * sizeof(TPM_NONCE)], "in", strlen("in")); + + switch (transPub->algId) { + case TPM_ALG_MGF1: + { + encLen = inLen; + seedLen = sizeof(seed); + + /* add the secret data to the seed for MGF1 */ + memcpy(&seed[2 * sizeof(TPM_NONCE) + strlen("in")], secret, TPM_SHA1_160_HASH_LEN); + + if ((result = Trspi_MGF1(TSS_HASH_SHA1, seedLen, seed, encLen, enc))) { + free(enc); + return result; + } + + for (i = 0; i < inLen; i++) + enc[i] ^= in[i]; + break; + } + case TPM_ALG_AES128: + { + BYTE iv[TSS_MAX_SYM_BLOCK_SIZE]; + + ivLen = TSS_MAX_SYM_BLOCK_SIZE; + seedLen = (2 * sizeof(TPM_NONCE)) + strlen("in"); + + if ((result = Trspi_MGF1(TSS_HASH_SHA1, seedLen, seed, ivLen, iv))) { + free(enc); + return result; + } + + /* use the secret data as the key for AES */ + if ((result = Trspi_SymEncrypt(transPub->algId, transPub->encScheme, secret, iv, in, + inLen, enc, &encLen))) { + free(enc); + return result; + } + + break; + } + default: + LogDebug("Unknown algorithm for encrypted transport session: 0x%x", + transPub->algId); + free(enc); + return TSPERR(TSS_E_INTERNAL_ERROR); + } + + *out = enc; + *outLen = encLen; + + return result; +} + +TSS_RESULT +obj_context_transport_execute(TSS_HCONTEXT tspContext, + TPM_COMMAND_CODE ordinal, + UINT32 ulDataLen, + BYTE* rgbData, + TPM_DIGEST* pubKeyHash, + UINT32* handlesLen, + TCS_HANDLE** handles, + TPM_AUTH* pAuth1, + TPM_AUTH* pAuth2, + UINT32* outLen, + BYTE** out) +{ + TSS_RESULT result = TSS_SUCCESS; + struct tsp_object *obj; + struct tr_context_obj *context; + UINT32 encLen, ulWrappedDataLen = 0; + BYTE *pEnc = NULL, *rgbWrappedData = NULL; + TPM_RESULT tpmResult; + Trspi_HashCtx hashCtx; + TPM_DIGEST etDigest, wDigest; + TPM_AUTH *pTransAuth; + UINT64 currentTicks; + TSS_BOOL free_enc = FALSE; + + if ((obj = obj_list_get_obj(&context_list, tspContext)) == NULL) + return TSPERR(TSS_E_INVALID_HANDLE); + + context = (struct tr_context_obj *)obj->data; + + pTransAuth = &context->transAuth; + + /* TPM Commands spec rev106 step 6 */ + result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); + result |= Trspi_Hash_UINT32(&hashCtx, ordinal); + + switch (ordinal) { + case TPM_ORD_OSAP: + case TPM_ORD_OIAP: + break; + default: + result |= Trspi_HashUpdate(&hashCtx, ulDataLen, rgbData); + break; + } + + if ((result |= Trspi_HashFinal(&hashCtx, wDigest.digest))) + goto done; + + if (context->flags & TSS_CONTEXT_FLAGS_TRANSPORT_AUTHENTIC) { + /* TPM Commands spec rev106 step 10.b */ + memcpy(context->transLogIn.parameters.digest, wDigest.digest, sizeof(TPM_DIGEST)); + /* TPM Commands spec rev106 step 10.c, d or e, calculated by the caller */ + if (pubKeyHash) + memcpy(context->transLogIn.pubKeyHash.digest, pubKeyHash->digest, + sizeof(TPM_DIGEST)); + else + memset(context->transLogIn.pubKeyHash.digest, 0, sizeof(TPM_DIGEST)); + + /* TPM Commands spec rev106 step 10.f */ + result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); + result |= Trspi_Hash_DIGEST(&hashCtx, context->transLogDigest.digest); + result |= Trspi_Hash_TRANSPORT_LOG_IN(&hashCtx, &context->transLogIn); + if ((result |= Trspi_HashFinal(&hashCtx, context->transLogDigest.digest))) + goto done; + } + + /* TPM Commands spec rev106 step 7.a */ + result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); + result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_ExecuteTransport); + result |= Trspi_Hash_UINT32(&hashCtx, ulDataLen + TSS_TPM_TXBLOB_HDR_LEN + + (*handlesLen * sizeof(UINT32)) + + (pAuth1 ? TPM_AUTH_RQU_SIZE : 0) + + (pAuth2 ? TPM_AUTH_RQU_SIZE : 0)); + result |= Trspi_HashUpdate(&hashCtx, TPM_SHA1_160_HASH_LEN, wDigest.digest); + if ((result |= Trspi_HashFinal(&hashCtx, etDigest.digest))) + goto done; + + /* encrypt the data if necessary */ + if (ulDataLen && context->flags & TSS_CONTEXT_FLAGS_TRANSPORT_DEFAULT_ENCRYPT) { + switch (ordinal) { + case TPM_ORD_OSAP: + case TPM_ORD_OIAP: + encLen = ulDataLen; + pEnc = rgbData; + break; + case TPM_ORD_DSAP: + { + UINT64 offset; + UINT32 tmpLen, entityValueLen; + BYTE *tmpEnc, *entityValuePtr; + + /* DSAP is a special case where only entityValue is encrypted. So, we'll + * parse through rgbData until we get to entityValue, encrypt it, alloc + * new space for rgbData (since it could be up to a block length larger + * than it came in) and copy the unencrypted data and the encrypted + * entityValue to the new block, setting pEnc and encLen to new values. */ + + offset = (2 * sizeof(UINT32)) + sizeof(TPM_NONCE); + Trspi_UnloadBlob_UINT32(&offset, &entityValueLen, rgbData); + + entityValuePtr = &rgbData[offset]; + if ((result = do_transport_encryption(&context->transPub, pTransAuth, + context->transSecret.authData.authdata, + entityValueLen, entityValuePtr, &tmpLen, + &tmpEnc))) + goto done; + + /* offset is the amount of data before the block we encrypted and tmpLen is + * the size of the encrypted data */ + encLen = offset + tmpLen; + if ((pEnc = malloc(encLen)) == NULL) { + LogError("malloc of %u bytes failed.", encLen); + result = TSPERR(TSS_E_OUTOFMEMORY); + goto done; + } + memcpy(pEnc, rgbData, offset); + memcpy(&pEnc[offset], tmpEnc, tmpLen); + free(tmpEnc); + + free_enc = TRUE; + break; + } + default: + if ((result = do_transport_encryption(&context->transPub, pTransAuth, + context->transSecret.authData.authdata, + ulDataLen, rgbData, &encLen, &pEnc))) + goto done; + + free_enc = TRUE; + break; + } + } else { + encLen = ulDataLen; + pEnc = rgbData; + } + + /* TPM Commands spec rev106 step 7.b */ + HMAC_Auth(context->transSecret.authData.authdata, etDigest.digest, pTransAuth); + + if ((result = RPC_ExecuteTransport(tspContext, ordinal, encLen, pEnc, handlesLen, handles, + pAuth1, pAuth2, pTransAuth, ¤tTicks, + &context->transMod, &tpmResult, &ulWrappedDataLen, + &rgbWrappedData))) { + LogDebugFn("Execute Transport failed: %s", Trspi_Error_String(result)); + goto done; + } + + if (tpmResult) { + LogDebug("Wrapped command ordinal 0x%x failed with result: 0x%x", ordinal, + tpmResult); + result = tpmResult; + goto done; + } + + /* decrypt the returned wrapped data if necessary */ + if (ulWrappedDataLen && context->flags & TSS_CONTEXT_FLAGS_TRANSPORT_DEFAULT_ENCRYPT) { + switch (ordinal) { + case TPM_ORD_OSAP: + case TPM_ORD_OIAP: + case TPM_ORD_DSAP: + *outLen = ulWrappedDataLen; + *out = rgbWrappedData; + break; + default: + if ((result = do_transport_decryption(&context->transPub, pTransAuth, + context->transSecret.authData.authdata, + ulWrappedDataLen, rgbWrappedData, outLen, + out))) + goto done; + + free(rgbWrappedData); + } + } else { + if (outLen) { + *outLen = ulWrappedDataLen; + *out = rgbWrappedData; + } + } + + /* TPM Commands spec rev106 step 14 */ + result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); + result |= Trspi_Hash_UINT32(&hashCtx, tpmResult); + result |= Trspi_Hash_UINT32(&hashCtx, ordinal); + + switch (ordinal) { + case TPM_ORD_OSAP: + case TPM_ORD_OIAP: + break; + default: + if (outLen) + result |= Trspi_HashUpdate(&hashCtx, *outLen, *out); + break; + } + + if ((result |= Trspi_HashFinal(&hashCtx, wDigest.digest))) + goto done; + + /* TPM Commands spec rev106 step 15 */ + result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); + result |= Trspi_Hash_UINT32(&hashCtx, result); + result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_ExecuteTransport); + result |= Trspi_Hash_UINT64(&hashCtx, currentTicks); + result |= Trspi_Hash_UINT32(&hashCtx, context->transMod); + result |= Trspi_Hash_UINT32(&hashCtx, (outLen ? *outLen : 0) + + TSS_TPM_TXBLOB_HDR_LEN + + (*handlesLen * sizeof(UINT32)) + + (pAuth1 ? TPM_AUTH_RSP_SIZE : 0) + + (pAuth2 ? TPM_AUTH_RSP_SIZE : 0)); + result |= Trspi_HashUpdate(&hashCtx, TPM_SHA1_160_HASH_LEN, wDigest.digest); + if ((result |= Trspi_HashFinal(&hashCtx, etDigest.digest))) + goto done; + + if (validateReturnAuth(context->transSecret.authData.authdata, etDigest.digest, + pTransAuth)) { + result = TSPERR(TSS_E_TSP_TRANS_AUTHFAIL); + goto done; + } + + if (context->flags & TSS_CONTEXT_FLAGS_TRANSPORT_AUTHENTIC) { + context->transLogOut.currentTicks.currentTicks = currentTicks; + + /* TPM Commands spec rev106 step 16.b */ + memcpy(context->transLogOut.parameters.digest, wDigest.digest, sizeof(TPM_DIGEST)); + /* TPM Commands spec rev106 step 16.c done above */ + /* TPM Commands spec rev106 step 16.d */ + context->transLogOut.locality = context->transMod; + + /* TPM Commands spec rev106 step 16.d */ + result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); + result |= Trspi_Hash_DIGEST(&hashCtx, context->transLogDigest.digest); + result |= Trspi_Hash_TRANSPORT_LOG_OUT(&hashCtx, &context->transLogOut); + if ((result |= Trspi_HashFinal(&hashCtx, context->transLogDigest.digest))) + goto done; + } + + /* Refresh nonceOdd for continued transport auth session */ + if ((result = get_local_random(tspContext, FALSE, sizeof(TPM_NONCE), + (BYTE **)pTransAuth->NonceOdd.nonce))) { + LogError("Failed creating random nonce"); + } + +done: + if (free_enc) + free(pEnc); + obj_list_put(&context_list); + + return result; +} + +/* called to close a transport session */ +TSS_RESULT +obj_context_transport_close(TSS_HCONTEXT tspContext, + TSS_HKEY hKey, + TSS_HPOLICY hPolicy, + TSS_BOOL usesAuth, + TPM_SIGN_INFO* signInfo, + UINT32* sigLen, + BYTE** sig) +{ + TSS_RESULT result = TSS_SUCCESS; + struct tsp_object *obj; + struct tr_context_obj *context; + Trspi_HashCtx hashCtx; + TPM_DIGEST digest; + TPM_AUTH auth, *pAuth; + TCS_KEY_HANDLE tcsKey; + BYTE *ticks = NULL; + UINT32 tickLen; + + if ((obj = obj_list_get_obj(&context_list, tspContext)) == NULL) + return TSPERR(TSS_E_INVALID_HANDLE); + + context = (struct tr_context_obj *)obj->data; + + /* return immediately if we're not in a transport session */ + if (!(context->flags & TSS_CONTEXT_FLAGS_TRANSPORT_ENABLED)) { + result = TSPERR(TSS_E_INTERNAL_ERROR); + goto done; + } + + if ((result = obj_rsakey_get_tcs_handle(hKey, &tcsKey))) + goto done; + + result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); + result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_ReleaseTransportSigned); + result |= Trspi_Hash_NONCE(&hashCtx, signInfo->replay.nonce); + if ((result |= Trspi_HashFinal(&hashCtx, (BYTE *)&digest))) + goto done; + + if (usesAuth) { + if ((result = secret_PerformAuth_OIAP(hKey, TPM_ORD_ReleaseTransportSigned, + hPolicy, FALSE, &digest, &auth))) + goto done; + + pAuth = &auth; + } else + pAuth = NULL; + + /* continue the auth session established in obj_context_transport_establish */ + HMAC_Auth(context->transSecret.authData.authdata, digest.digest, &context->transAuth); + + if ((result = RPC_ReleaseTransportSigned(tspContext, tcsKey, &signInfo->replay, pAuth, + &context->transAuth, + &context->transLogOut.locality, &tickLen, &ticks, + sigLen, sig))) + goto done; + + result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); + result |= Trspi_Hash_UINT32(&hashCtx, result); + result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_ReleaseTransportSigned); + result |= Trspi_Hash_UINT32(&hashCtx, context->transLogOut.locality); + result |= Trspi_HashUpdate(&hashCtx, tickLen, ticks); + result |= Trspi_Hash_UINT32(&hashCtx, *sigLen); + result |= Trspi_HashUpdate(&hashCtx, *sigLen, *sig); + if ((result |= Trspi_HashFinal(&hashCtx, (BYTE *)&digest))) + goto done_disabled; + + /* validate the return data using the key's auth */ + if (pAuth) { + if ((result = obj_policy_validate_auth_oiap(hPolicy, &digest, pAuth))) + goto done_disabled; + } + + /* validate again using the transport session's auth */ + if ((result = validateReturnAuth(context->transSecret.authData.authdata, digest.digest, + &context->transAuth))) { + result = TSPERR(TSS_E_TSP_TRANS_AUTHFAIL); + goto done_disabled; + } + + if (context->flags & TSS_CONTEXT_FLAGS_TRANSPORT_AUTHENTIC) { + UINT64 offset; + + /* TPM Commands Spec step 6.b */ + result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); + result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_ReleaseTransportSigned); + result |= Trspi_Hash_NONCE(&hashCtx, signInfo->replay.nonce); + if ((result |= Trspi_HashFinal(&hashCtx, context->transLogOut.parameters.digest))) + goto done_disabled; + + /* TPM Commands Spec step 6.c */ + offset = 0; + Trspi_UnloadBlob_CURRENT_TICKS(&offset, ticks, &context->transLogOut.currentTicks); + free(ticks); + + /* TPM Commands Spec step 6.d was set above */ + /* TPM Commands Spec step 6.e */ + result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); + result |= Trspi_Hash_DIGEST(&hashCtx, context->transLogDigest.digest); + result |= Trspi_Hash_TRANSPORT_LOG_OUT(&hashCtx, &context->transLogOut); + if ((result |= Trspi_HashFinal(&hashCtx, context->transLogDigest.digest))) + goto done_disabled; + } + + if ((signInfo->data = malloc(sizeof(TPM_DIGEST))) == NULL) { + LogError("malloc %zd bytes failed.", sizeof(TPM_DIGEST)); + result = TSPERR(TSS_E_OUTOFMEMORY); + goto done_disabled; + } + memcpy(signInfo->data, context->transLogDigest.digest, sizeof(TPM_DIGEST)); + signInfo->dataLen = sizeof(TPM_DIGEST); + + /* destroy all transport session info, except the key handle */ + memset(&context->transPub, 0, sizeof(TPM_TRANSPORT_PUBLIC)); + memset(&context->transMod, 0, sizeof(TPM_MODIFIER_INDICATOR)); + memset(&context->transSecret, 0, sizeof(TPM_TRANSPORT_AUTH)); + memset(&context->transAuth, 0, sizeof(TPM_AUTH)); + memset(&context->transLogIn, 0, sizeof(TPM_TRANSPORT_LOG_IN)); + memset(&context->transLogOut, 0, sizeof(TPM_TRANSPORT_LOG_OUT)); + memset(&context->transLogDigest, 0, sizeof(TPM_DIGEST)); + +done_disabled: + context->flags &= ~TSS_CONTEXT_FLAGS_TRANSPORT_ESTABLISHED; +done: + obj_list_put(&context_list); + + return result; +} +#endif + +/* XXX change 0,1,2 to #defines */ +TSS_RESULT +obj_context_set_tpm_version(TSS_HCONTEXT tspContext, UINT32 ver) +{ + TSS_RESULT result = TSS_SUCCESS; + struct tsp_object *obj; + struct tr_context_obj *context; + + if ((obj = obj_list_get_obj(&context_list, tspContext)) == NULL) + return TSPERR(TSS_E_INVALID_HANDLE); + + context = (struct tr_context_obj *)obj->data; + + switch (ver) { + case 1: + context->flags &= ~TSS_CONTEXT_FLAGS_TPM_VERSION_MASK; + context->flags |= TSS_CONTEXT_FLAGS_TPM_VERSION_1; + break; + case 2: + context->flags &= ~TSS_CONTEXT_FLAGS_TPM_VERSION_MASK; + context->flags |= TSS_CONTEXT_FLAGS_TPM_VERSION_2; + break; + default: + LogError("Invalid TPM version set: %u", ver); + result = TSPERR(TSS_E_INTERNAL_ERROR); + break; + } + + obj_list_put(&context_list); + + return result; +} + +/* XXX change 0,1,2 to #defines */ +TSS_RESULT +obj_context_get_tpm_version(TSS_HCONTEXT tspContext, UINT32 *ver) +{ + struct tsp_object *obj; + struct tr_context_obj *context; + + if ((obj = obj_list_get_obj(&context_list, tspContext)) == NULL) + return TSPERR(TSS_E_INVALID_HANDLE); + + context = (struct tr_context_obj *)obj->data; + + if (context->flags & TSS_CONTEXT_FLAGS_TPM_VERSION_1) + *ver = 1; + else if (context->flags & TSS_CONTEXT_FLAGS_TPM_VERSION_2) + *ver = 2; + else + *ver = 0; + + obj_list_put(&context_list); + + return TSS_SUCCESS; +} + +TSS_RESULT +obj_context_get_loadkey_ordinal(TSS_HCONTEXT tspContext, TPM_COMMAND_CODE *ordinal) +{ + struct tsp_object *obj; + struct tr_context_obj *context; + + if ((obj = obj_list_get_obj(&context_list, tspContext)) == NULL) + return TSPERR(TSS_E_INVALID_HANDLE); + + context = (struct tr_context_obj *)obj->data; + + switch (context->flags & TSS_CONTEXT_FLAGS_TPM_VERSION_MASK) { + case TSS_CONTEXT_FLAGS_TPM_VERSION_2: + *ordinal = TPM_ORD_LoadKey2; + break; + default: + LogDebugFn("No TPM version set!"); + /* fall through */ + case TSS_CONTEXT_FLAGS_TPM_VERSION_1: + *ordinal = TPM_ORD_LoadKey; + break; + } + + obj_list_put(&context_list); + + return TSS_SUCCESS; +} + |