Home | History | Annotate | Line # | Download | only in tspi
      1 
      2 /*
      3  * Licensed Materials - Property of IBM
      4  *
      5  * trousers - An open source TCG Software Stack
      6  *
      7  * (C) Copyright International Business Machines Corp. 2005, 2007
      8  *
      9  */
     10 
     11 
     12 #include <stdlib.h>
     13 #include <stdio.h>
     14 #include <errno.h>
     15 #include <string.h>
     16 #include <assert.h>
     17 
     18 #include "trousers/tss.h"
     19 #include "trousers/trousers.h"
     20 #include "tcs_tsp.h"
     21 #include "trousers_types.h"
     22 #include "spi_utils.h"
     23 #include "capabilities.h"
     24 #include "tsplog.h"
     25 #include "obj.h"
     26 #include "tsp_tcsi_param.h"
     27 
     28 TSS_RESULT
     29 obj_context_add(TSS_HOBJECT *phObject)
     30 {
     31 	TSS_RESULT result;
     32 	struct tr_context_obj *context = calloc(1, sizeof(struct tr_context_obj));
     33 
     34 	if (context == NULL) {
     35 		LogError("malloc of %zd bytes failed.", sizeof(struct tr_context_obj));
     36 		return TSPERR(TSS_E_OUTOFMEMORY);
     37 	}
     38 
     39 #ifndef TSS_NO_GUI
     40 	context->silentMode = TSS_TSPATTRIB_CONTEXT_NOT_SILENT;
     41 #else
     42 	context->silentMode = TSS_TSPATTRIB_CONTEXT_SILENT;
     43 #endif
     44 	if ((result = get_tcsd_hostname((char **)&context->machineName,
     45 					&context->machineNameLength)) != TSS_SUCCESS) {
     46 		free(context);
     47 		return result;
     48 	}
     49 
     50 	LogDebug("Hostname to be used by the context is %s.", context->machineName);
     51 
     52 	context->hashMode = TSS_TSPATTRIB_HASH_MODE_NOT_NULL;
     53 	context->connection_policy = TSS_TSPATTRIB_CONTEXT_VERSION_V1_1;
     54 
     55 	if ((result = obj_list_add(&context_list, NULL_HCONTEXT, 0, context, phObject))) {
     56 		free(context->machineName);
     57 		free(context);
     58 		return result;
     59 	}
     60 
     61 	/* Add the default policy */
     62 	if ((result = obj_policy_add(*phObject, TSS_POLICY_USAGE, &context->policy))) {
     63 		obj_list_remove(&context_list, &__tspi_obj_context_free, *phObject, *phObject);
     64 		return result;
     65 	}
     66 
     67 	context->tcs_api = &tcs_normal_api;
     68 
     69 	return TSS_SUCCESS;
     70 }
     71 
     72 struct tcs_api_table *
     73 obj_context_get_tcs_api(TSS_HCONTEXT tspContext)
     74 {
     75 	struct tsp_object *obj;
     76 	struct tr_context_obj *context;
     77 	struct tcs_api_table *t;
     78 
     79 	/* If the object cannot be found with the given handle, return a safe value, the normal TCS
     80 	 * API pointer.  Since the handle is bad, the RPC_ function will barf in looking up the
     81 	 * corresponding TCS context handle and an invalid handle error will be returned. */
     82 	if ((obj = obj_list_get_obj(&context_list, tspContext)) == NULL)
     83 		return &tcs_normal_api;
     84 
     85 	context = (struct tr_context_obj *)obj->data;
     86 
     87 	/* Return the current API set we're using, either the normal API, or the transport encrypted
     88 	 * API.  The context->tcs_api variable is switched back and forth between the two sets by
     89 	 * the obj_context_transport_set_control function through a set attrib. */
     90 	t = context->tcs_api;
     91 
     92 	obj_list_put(&context_list);
     93 
     94 	return t;
     95 }
     96 
     97 void
     98 __tspi_obj_context_free(void *data)
     99 {
    100 	struct tr_context_obj *context = (struct tr_context_obj *)data;
    101 
    102 	free(context->machineName);
    103 	free(context);
    104 }
    105 
    106 TSS_BOOL
    107 obj_is_context(TSS_HOBJECT hObject)
    108 {
    109 	TSS_BOOL answer = FALSE;
    110 
    111 	if ((obj_list_get_obj(&context_list, hObject))) {
    112 		answer = TRUE;
    113 		obj_list_put(&context_list);
    114 	}
    115 
    116 	return answer;
    117 }
    118 
    119 /* Clean up transport session if necessary. */
    120 void
    121 obj_context_close(TSS_HCONTEXT tspContext)
    122 {
    123 	struct tsp_object *obj;
    124 	struct tr_context_obj *context;
    125 
    126 	if ((obj = obj_list_get_obj(&context_list, tspContext)) == NULL)
    127 		return;
    128 
    129 	context = (struct tr_context_obj *)obj->data;
    130 
    131 #ifdef TSS_BUILD_TRANSPORT
    132 	if (context->transAuth.AuthHandle) {
    133 		RPC_FlushSpecific(tspContext, context->transAuth.AuthHandle, TPM_RT_TRANS);
    134 
    135 		__tspi_memset(&context->transPub, 0, sizeof(TPM_TRANSPORT_PUBLIC));
    136 		__tspi_memset(&context->transMod, 0, sizeof(TPM_MODIFIER_INDICATOR));
    137 		__tspi_memset(&context->transSecret, 0, sizeof(TPM_TRANSPORT_AUTH));
    138 		__tspi_memset(&context->transAuth, 0, sizeof(TPM_AUTH));
    139 		__tspi_memset(&context->transLogIn, 0, sizeof(TPM_TRANSPORT_LOG_IN));
    140 		__tspi_memset(&context->transLogOut, 0, sizeof(TPM_TRANSPORT_LOG_OUT));
    141 		__tspi_memset(&context->transLogDigest, 0, sizeof(TPM_DIGEST));
    142 	}
    143 #endif
    144 
    145 	obj_list_put(&context_list);
    146 }
    147 
    148 TSS_RESULT
    149 obj_context_get_policy(TSS_HCONTEXT tspContext, UINT32 policyType, TSS_HPOLICY *phPolicy)
    150 {
    151 	struct tsp_object *obj;
    152 	struct tr_context_obj *context;
    153 	TSS_RESULT result = TSS_SUCCESS;
    154 
    155 	if ((obj = obj_list_get_obj(&context_list, tspContext)) == NULL)
    156 		return TSPERR(TSS_E_INVALID_HANDLE);
    157 
    158 	context = (struct tr_context_obj *)obj->data;
    159 
    160 	switch (policyType) {
    161 		case TSS_POLICY_USAGE:
    162 			*phPolicy = context->policy;
    163 			break;
    164 		default:
    165 			result = TSPERR(TSS_E_BAD_PARAMETER);
    166 	}
    167 
    168 	obj_list_put(&context_list);
    169 
    170 	return result;
    171 }
    172 
    173 TSS_RESULT
    174 obj_context_get_machine_name(TSS_HCONTEXT tspContext, UINT32 *size, BYTE **data)
    175 {
    176 	struct tsp_object *obj;
    177 	struct tr_context_obj *context;
    178 	TSS_RESULT result;
    179 
    180 	if ((obj = obj_list_get_obj(&context_list, tspContext)) == NULL)
    181 		return TSPERR(TSS_E_INVALID_HANDLE);
    182 
    183 	context = (struct tr_context_obj *)obj->data;
    184 
    185 	if (context->machineNameLength == 0) {
    186 		*data = NULL;
    187 		*size = 0;
    188 		LogDebug("context->machineName is NULL.");
    189 	} else {
    190 		/*
    191 		 * Don't use calloc_tspi because this memory is
    192 		 * not freed using "free_tspi"
    193 		 */
    194 		*data = calloc(1, context->machineNameLength);
    195 		if (*data == NULL) {
    196 			LogError("malloc of %u bytes failed.",
    197 					context->machineNameLength);
    198 			result = TSPERR(TSS_E_OUTOFMEMORY);
    199 			goto done;
    200 		}
    201 		*size = context->machineNameLength;
    202 		LogDebug("context->machineName: %s.", context->machineName);
    203 		memcpy(*data, context->machineName, *size);
    204 	}
    205 
    206 	result = TSS_SUCCESS;
    207 
    208 done:
    209 	obj_list_put(&context_list);
    210 
    211 	return result;
    212 }
    213 
    214 /* This function converts the machine name to a TSS_UNICODE string before
    215  * returning it, as Tspi_GetAttribData would like. We could do the conversion
    216  * in Tspi_GetAttribData, but we don't have access to the TSP context there */
    217 TSS_RESULT
    218 obj_context_get_machine_name_attrib(TSS_HCONTEXT tspContext, UINT32 *size, BYTE **data)
    219 {
    220 	struct tsp_object *obj;
    221 	struct tr_context_obj *context;
    222 	BYTE *utf_string;
    223 	UINT32 utf_size;
    224 	TSS_RESULT result;
    225 
    226 	if ((obj = obj_list_get_obj(&context_list, tspContext)) == NULL)
    227 		return TSPERR(TSS_E_INVALID_HANDLE);
    228 
    229 	context = (struct tr_context_obj *)obj->data;
    230 
    231 	if (context->machineNameLength == 0) {
    232 		*data = NULL;
    233 		*size = 0;
    234 	} else {
    235 		utf_size = context->machineNameLength;
    236 		utf_string = Trspi_Native_To_UNICODE(context->machineName,
    237 						     &utf_size);
    238 		if (utf_string == NULL) {
    239 			result = TSPERR(TSS_E_INTERNAL_ERROR);
    240 			goto done;
    241 		}
    242 
    243 		*data = calloc_tspi(obj->tspContext, utf_size);
    244 		if (*data == NULL) {
    245 			free(utf_string);
    246 			LogError("malloc of %u bytes failed.", utf_size);
    247 			result = TSPERR(TSS_E_OUTOFMEMORY);
    248 			goto done;
    249 		}
    250 		*size = utf_size;
    251 		memcpy(*data, utf_string, utf_size);
    252 		free(utf_string);
    253 	}
    254 
    255 	result = TSS_SUCCESS;
    256 
    257 done:
    258 	obj_list_put(&context_list);
    259 
    260 	return result;
    261 }
    262 
    263 TSS_RESULT
    264 obj_context_set_machine_name(TSS_HCONTEXT tspContext, BYTE *name, UINT32 len)
    265 {
    266 	struct tsp_object *obj;
    267 	struct tr_context_obj *context;
    268 
    269 	if ((obj = obj_list_get_obj(&context_list, tspContext)) == NULL)
    270 		return TSPERR(TSS_E_INVALID_HANDLE);
    271 
    272 	context = (struct tr_context_obj *)obj->data;
    273 
    274 	free(context->machineName);
    275 
    276     context->machineName = (BYTE *)calloc(1, len);
    277     if (context->machineName == NULL) {
    278         LogError("malloc of %u bytes failed.", len);
    279         return TSPERR(TSS_E_OUTOFMEMORY);
    280     }
    281     memcpy(context->machineName, name, len);
    282 
    283 	context->machineNameLength = len;
    284 
    285 	obj_list_put(&context_list);
    286 
    287 	return TSS_SUCCESS;
    288 }
    289 
    290 TSS_BOOL
    291 obj_context_is_silent(TSS_HCONTEXT tspContext)
    292 {
    293 	struct tsp_object *obj;
    294 	struct tr_context_obj *context;
    295 	TSS_BOOL silent = FALSE;
    296 
    297 	if ((obj = obj_list_get_obj(&context_list, tspContext)) == NULL)
    298 		return FALSE;
    299 
    300 	context = (struct tr_context_obj *)obj->data;
    301 	if (context->silentMode == TSS_TSPATTRIB_CONTEXT_SILENT)
    302 		silent = TRUE;
    303 
    304 	obj_list_put(&context_list);
    305 
    306 	return silent;
    307 }
    308 
    309 TSS_RESULT
    310 obj_context_get_mode(TSS_HCONTEXT tspContext, UINT32 *mode)
    311 {
    312 	struct tsp_object *obj;
    313 	struct tr_context_obj *context;
    314 
    315 	if ((obj = obj_list_get_obj(&context_list, tspContext)) == NULL)
    316 		return TSPERR(TSS_E_INVALID_HANDLE);
    317 
    318 	context = (struct tr_context_obj *)obj->data;
    319 	*mode = context->silentMode;
    320 
    321 	obj_list_put(&context_list);
    322 
    323 	return TSS_SUCCESS;
    324 }
    325 
    326 TSS_RESULT
    327 obj_context_set_mode(TSS_HCONTEXT tspContext, UINT32 mode)
    328 {
    329 	struct tsp_object *obj;
    330 	struct tr_context_obj *context;
    331 
    332 	if ((obj = obj_list_get_obj(&context_list, tspContext)) == NULL)
    333 		return TSPERR(TSS_E_INVALID_HANDLE);
    334 
    335 	context = (struct tr_context_obj *)obj->data;
    336 	context->silentMode = mode;
    337 
    338 	obj_list_put(&context_list);
    339 
    340 	return TSS_SUCCESS;
    341 }
    342 
    343 /* search the list of all policies bound to context @tspContext. If
    344  * one is found of type popup, return TRUE, else return FALSE. */
    345 TSS_BOOL
    346 obj_context_has_popups(TSS_HCONTEXT tspContext)
    347 {
    348 	struct tsp_object *obj;
    349 	struct tr_policy_obj *policy;
    350 	struct obj_list *list = &policy_list;
    351 	TSS_BOOL ret = FALSE;
    352 
    353 	MUTEX_LOCK(list->lock);
    354 
    355 	for (obj = list->head; obj; obj = obj->next) {
    356 		if (obj->tspContext == tspContext) {
    357 			policy = (struct tr_policy_obj *)obj->data;
    358 			if (policy->SecretMode == TSS_SECRET_MODE_POPUP)
    359 				ret = TRUE;
    360 			break;
    361 		}
    362 	}
    363 
    364 	MUTEX_UNLOCK(list->lock);
    365 
    366 	return ret;
    367 }
    368 
    369 TSS_RESULT
    370 obj_context_get_hash_mode(TSS_HCONTEXT tspContext, UINT32 *mode)
    371 {
    372 	struct tsp_object *obj;
    373 	struct tr_context_obj *context;
    374 
    375 	if ((obj = obj_list_get_obj(&context_list, tspContext)) == NULL)
    376 		return TSPERR(TSS_E_INVALID_HANDLE);
    377 
    378 	context = (struct tr_context_obj *)obj->data;
    379 	*mode = context->hashMode;
    380 
    381 	obj_list_put(&context_list);
    382 
    383 	return TSS_SUCCESS;
    384 }
    385 
    386 TSS_RESULT
    387 obj_context_set_hash_mode(TSS_HCONTEXT tspContext, UINT32 mode)
    388 {
    389 	struct tsp_object *obj;
    390 	struct tr_context_obj *context;
    391 
    392 	switch (mode) {
    393 		case TSS_TSPATTRIB_HASH_MODE_NULL:
    394 		case TSS_TSPATTRIB_HASH_MODE_NOT_NULL:
    395 			break;
    396 		default:
    397 			return TSPERR(TSS_E_INVALID_ATTRIB_DATA);
    398 	}
    399 
    400 	if ((obj = obj_list_get_obj(&context_list, tspContext)) == NULL)
    401 		return TSPERR(TSS_E_INVALID_HANDLE);
    402 
    403 	context = (struct tr_context_obj *)obj->data;
    404 	context->hashMode = mode;
    405 
    406 	obj_list_put(&context_list);
    407 
    408 	return TSS_SUCCESS;
    409 }
    410 
    411 TSS_RESULT
    412 obj_context_get_connection_version(TSS_HCONTEXT tspContext, UINT32 *version)
    413 {
    414 	struct tsp_object *obj;
    415 	struct tr_context_obj *context;
    416 
    417 	if ((obj = obj_list_get_obj(&context_list, tspContext)) == NULL)
    418 		return TSPERR(TSS_E_INVALID_HANDLE);
    419 
    420 	context = (struct tr_context_obj *)obj->data;
    421 
    422 	*version = context->current_connection;
    423 
    424 	obj_list_put(&context_list);
    425 
    426 	return TSS_SUCCESS;
    427 }
    428 
    429 TSS_RESULT
    430 obj_context_set_connection_policy(TSS_HCONTEXT tspContext, UINT32 policy)
    431 {
    432 	struct tsp_object *obj;
    433 	struct tr_context_obj *context;
    434 
    435 	switch (policy) {
    436 		case TSS_TSPATTRIB_CONTEXT_VERSION_V1_1:
    437 		case TSS_TSPATTRIB_CONTEXT_VERSION_V1_2:
    438 		case TSS_TSPATTRIB_CONTEXT_VERSION_AUTO:
    439 			break;
    440 		default:
    441 			return TSPERR(TSS_E_INVALID_ATTRIB_DATA);
    442 	}
    443 
    444 	if ((obj = obj_list_get_obj(&context_list, tspContext)) == NULL)
    445 		return TSPERR(TSS_E_INVALID_HANDLE);
    446 
    447 	context = (struct tr_context_obj *)obj->data;
    448 
    449 	context->connection_policy = policy;
    450 
    451 	obj_list_put(&context_list);
    452 
    453 	return TSS_SUCCESS;
    454 }
    455 
    456 #ifdef TSS_BUILD_TRANSPORT
    457 TSS_RESULT
    458 obj_context_set_transport_key(TSS_HCONTEXT tspContext, TSS_HKEY hKey)
    459 {
    460 	struct tsp_object *obj;
    461 	struct tr_context_obj *context;
    462 
    463 	if ((obj = obj_list_get_obj(&context_list, tspContext)) == NULL)
    464 		return TSPERR(TSS_E_INVALID_HANDLE);
    465 
    466 	context = (struct tr_context_obj *)obj->data;
    467 
    468 	context->transKey = hKey;
    469 
    470 	obj_list_put(&context_list);
    471 
    472 	return TSS_SUCCESS;
    473 }
    474 
    475 TSS_RESULT
    476 obj_context_transport_get_mode(TSS_HCONTEXT tspContext, UINT32 value, UINT32 *out)
    477 {
    478 	TSS_RESULT result = TSS_SUCCESS;
    479 	struct tsp_object *obj;
    480 	struct tr_context_obj *context;
    481 
    482 	if ((obj = obj_list_get_obj(&context_list, tspContext)) == NULL)
    483 		return TSPERR(TSS_E_INVALID_HANDLE);
    484 
    485 	context = (struct tr_context_obj *)obj->data;
    486 
    487 	switch (value) {
    488 		case TSS_TSPATTRIB_TRANSPORT_NO_DEFAULT_ENCRYPTION:
    489 			*out = context->flags & TSS_CONTEXT_FLAGS_TRANSPORT_DEFAULT_ENCRYPT ?
    490 			       FALSE : TRUE;
    491 			break;
    492 		case TSS_TSPATTRIB_TRANSPORT_DEFAULT_ENCRYPTION:
    493 			*out = context->flags & TSS_CONTEXT_FLAGS_TRANSPORT_DEFAULT_ENCRYPT ?
    494 			       TRUE : FALSE;
    495 			break;
    496 		case TSS_TSPATTRIB_TRANSPORT_AUTHENTIC_CHANNEL:
    497 			*out = context->flags & TSS_CONTEXT_FLAGS_TRANSPORT_AUTHENTIC ?
    498 			       TRUE : FALSE;
    499 			break;
    500 		case TSS_TSPATTRIB_TRANSPORT_EXCLUSIVE:
    501 			*out = context->flags & TSS_CONTEXT_FLAGS_TRANSPORT_EXCLUSIVE ?
    502 			       TRUE : FALSE;
    503 			break;
    504 		case TSS_TSPATTRIB_TRANSPORT_STATIC_AUTH:
    505 			*out = context->flags & TSS_CONTEXT_FLAGS_TRANSPORT_STATIC_AUTH ?
    506 			       TRUE : FALSE;
    507 			break;
    508 		default:
    509 			LogError("Invalid attribute subflag: 0x%x", value);
    510 			result = TSPERR(TSS_E_INVALID_ATTRIB_SUBFLAG);
    511 			break;
    512 	}
    513 
    514 	obj_list_put(&context_list);
    515 
    516 	return result;
    517 }
    518 
    519 TSS_RESULT
    520 obj_context_transport_get_control(TSS_HCONTEXT tspContext, UINT32 value, UINT32 *out)
    521 {
    522 	TSS_RESULT result = TSS_SUCCESS;
    523 	struct tsp_object *obj;
    524 	struct tr_context_obj *context;
    525 
    526 	if ((obj = obj_list_get_obj(&context_list, tspContext)) == NULL)
    527 		return TSPERR(TSS_E_INVALID_HANDLE);
    528 
    529 	context = (struct tr_context_obj *)obj->data;
    530 
    531 	switch (value) {
    532 		case TSS_TSPATTRIB_DISABLE_TRANSPORT:
    533 			*out = context->flags & TSS_CONTEXT_FLAGS_TRANSPORT_ENABLED ? FALSE : TRUE;
    534 			break;
    535 		case TSS_TSPATTRIB_ENABLE_TRANSPORT:
    536 			*out = context->flags & TSS_CONTEXT_FLAGS_TRANSPORT_ENABLED ? TRUE : FALSE;
    537 			break;
    538 		default:
    539 			LogError("Invalid attribute subflag: 0x%x", value);
    540 			result = TSPERR(TSS_E_INVALID_ATTRIB_SUBFLAG);
    541 			break;
    542 	}
    543 
    544 	obj_list_put(&context_list);
    545 
    546 	return result;
    547 }
    548 
    549 TSS_RESULT
    550 obj_context_transport_set_control(TSS_HCONTEXT tspContext, UINT32 value)
    551 {
    552 	TSS_RESULT result = TSS_SUCCESS;
    553 	struct tsp_object *obj;
    554 	struct tr_context_obj *context;
    555 
    556 	if ((obj = obj_list_get_obj(&context_list, tspContext)) == NULL)
    557 		return TSPERR(TSS_E_INVALID_HANDLE);
    558 
    559 	context = (struct tr_context_obj *)obj->data;
    560 
    561 	switch (value) {
    562 		case TSS_TSPATTRIB_ENABLE_TRANSPORT:
    563 			context->flags |= TSS_CONTEXT_FLAGS_TRANSPORT_ENABLED;
    564 			context->tcs_api = &tcs_transport_api;
    565 			break;
    566 		case TSS_TSPATTRIB_DISABLE_TRANSPORT:
    567 			context->flags &= ~TSS_CONTEXT_FLAGS_TRANSPORT_ENABLED;
    568 			context->tcs_api = &tcs_normal_api;
    569 			break;
    570 		default:
    571 			LogError("Invalid attribute subflag: 0x%x", value);
    572 			result = TSPERR(TSS_E_INTERNAL_ERROR);
    573 			break;
    574 	}
    575 
    576 	obj_list_put(&context_list);
    577 
    578 	return result;
    579 }
    580 
    581 TSS_RESULT
    582 obj_context_transport_set_mode(TSS_HCONTEXT tspContext, UINT32 value)
    583 {
    584 	TSS_RESULT result = TSS_SUCCESS;
    585 	struct tsp_object *obj;
    586 	struct tr_context_obj *context;
    587 
    588 	if ((obj = obj_list_get_obj(&context_list, tspContext)) == NULL)
    589 		return TSPERR(TSS_E_INVALID_HANDLE);
    590 
    591 	context = (struct tr_context_obj *)obj->data;
    592 
    593 	switch (value) {
    594 		case TSS_TSPATTRIB_TRANSPORT_NO_DEFAULT_ENCRYPTION:
    595 			context->flags &= ~TSS_CONTEXT_FLAGS_TRANSPORT_DEFAULT_ENCRYPT;
    596 			break;
    597 		case TSS_TSPATTRIB_TRANSPORT_DEFAULT_ENCRYPTION:
    598 			context->flags |= TSS_CONTEXT_FLAGS_TRANSPORT_DEFAULT_ENCRYPT;
    599 			break;
    600 		case TSS_TSPATTRIB_TRANSPORT_AUTHENTIC_CHANNEL:
    601 			context->flags |= TSS_CONTEXT_FLAGS_TRANSPORT_AUTHENTIC;
    602 			break;
    603 		case TSS_TSPATTRIB_TRANSPORT_EXCLUSIVE:
    604 			context->flags |= TSS_CONTEXT_FLAGS_TRANSPORT_EXCLUSIVE;
    605 			break;
    606 		case TSS_TSPATTRIB_TRANSPORT_STATIC_AUTH:
    607 			context->flags |= TSS_CONTEXT_FLAGS_TRANSPORT_STATIC_AUTH;
    608 			break;
    609 		default:
    610 			LogError("Invalid attribute subflag: 0x%x", value);
    611 			result = TSPERR(TSS_E_INTERNAL_ERROR);
    612 			break;
    613 	}
    614 
    615 	obj_list_put(&context_list);
    616 
    617 	return result;
    618 }
    619 
    620 #if 0
    621 TSS_RESULT
    622 get_trans_props(TSS_HCONTEXT tspContext, UINT32 *alg, UINT16 *enc)
    623 {
    624 	TSS_RESULT result;
    625 	UINT32 algs[] = { TPM_ALG_MGF1, TPM_ALG_AES128, 0 }, a = 0;
    626 	UINT16 encs[] = { TPM_ES_SYM_OFB, TPM_ES_SYM_CNT, TPM_ES_SYM_CBC_PKCS5PAD, 0 }, e = 0;
    627 	BYTE *respData;
    628 	UINT32 respLen, tcsSubCap32;
    629 	UINT16 tcsSubCap16;
    630 
    631 	if (*alg)
    632 		goto check_es;
    633 
    634 	for (a = 0; algs[a]; a++) {
    635 		tcsSubCap32 = endian32(algs[a]);
    636 
    637 		if ((result = RPC_GetTPMCapability(tspContext, TPM_CAP_TRANS_ALG, sizeof(UINT32),
    638 						   (BYTE *)&tcsSubCap32, &respLen, &respData)))
    639 			return result;
    640 
    641 		if (*(TSS_BOOL *)respData == TRUE) {
    642 			free(respData);
    643 			break;
    644 		}
    645 		free(respData);
    646 	}
    647 
    648 	if (!algs[a]) {
    649 		LogError("TPM reports no usable sym algorithms for transport session");
    650 		return TSPERR(TSS_E_INTERNAL_ERROR);
    651 	}
    652 
    653 check_es:
    654 	if (*enc || algs[a] == TPM_ALG_MGF1)
    655 		goto done;
    656 
    657 	for (e = 0; encs[e]; e++) {
    658 		tcsSubCap16 = endian16(encs[e]);
    659 
    660 		if ((result = RPC_GetTPMCapability(tspContext, TPM_CAP_TRANS_ES, sizeof(UINT16),
    661 						   (BYTE *)&tcsSubCap16, &respLen, &respData)))
    662 			return result;
    663 
    664 		if (*(TSS_BOOL *)respData == TRUE) {
    665 			free(respData);
    666 			break;
    667 		}
    668 		free(respData);
    669 	}
    670 
    671 	if (!encs[e]) {
    672 		LogError("TPM reports no usable sym modes for transport session");
    673 		return TSPERR(TSS_E_INTERNAL_ERROR);
    674 	}
    675 
    676 	*alg = algs[a];
    677 	*enc = encs[e];
    678 done:
    679 	return TSS_SUCCESS;
    680 }
    681 #endif
    682 
    683 /* called before each TCSP_ExecuteTransport call */
    684 TSS_RESULT
    685 obj_context_transport_init(TSS_HCONTEXT tspContext)
    686 {
    687 	TSS_RESULT result = TSS_SUCCESS;
    688 	struct tsp_object *obj;
    689 	struct tr_context_obj *context;
    690 
    691 	if ((obj = obj_list_get_obj(&context_list, tspContext)) == NULL)
    692 		return TSPERR(TSS_E_INVALID_HANDLE);
    693 
    694 	context = (struct tr_context_obj *)obj->data;
    695 
    696 	/* return immediately if we're not in a transport session */
    697 	if (!(context->flags & TSS_CONTEXT_FLAGS_TRANSPORT_ENABLED)) {
    698 		result = TSPERR(TSS_E_INTERNAL_ERROR);
    699 		goto done;
    700 	}
    701 
    702 	/* if the session is not yet established, setup and call EstablishTransport */
    703 	if (!(context->flags & TSS_CONTEXT_FLAGS_TRANSPORT_ESTABLISHED)) {
    704 		if ((result = obj_context_transport_establish(tspContext, context)))
    705 			goto done;
    706 	}
    707 
    708 	context->flags |= TSS_CONTEXT_FLAGS_TRANSPORT_ESTABLISHED;
    709 
    710 	result = TSS_SUCCESS;
    711 done:
    712 	obj_list_put(&context_list);
    713 
    714 	return result;
    715 }
    716 
    717 TSS_RESULT
    718 obj_context_transport_establish(TSS_HCONTEXT tspContext, struct tr_context_obj *context)
    719 {
    720 	TSS_RESULT result;
    721 	UINT32 tickLen, secretLen, transPubLen, exclusive = TSS_TCSATTRIB_TRANSPORT_DEFAULT;
    722 	BYTE *ticks, *secret;
    723 	UINT64 offset;
    724 	Trspi_HashCtx hashCtx;
    725 	TPM_DIGEST digest;
    726 	TSS_HPOLICY hTransKeyPolicy;
    727 	TPM_AUTH auth, *pAuth, *pTransAuth;
    728 	TCS_KEY_HANDLE tcsTransKey;
    729 	TSS_BOOL usesAuth = FALSE;
    730 	UINT32 encKeyLen;
    731 	BYTE encKey[256];
    732 	BYTE transPubBlob[sizeof(TPM_TRANSPORT_PUBLIC)];
    733 	BYTE transAuthBlob[sizeof(TPM_TRANSPORT_AUTH)];
    734 
    735 
    736 	context->transPub.tag = TPM_TAG_TRANSPORT_PUBLIC;
    737 	context->transSecret.tag = TPM_TAG_TRANSPORT_AUTH;
    738 
    739 	if ((result = get_local_random(tspContext, FALSE, TPM_SHA1_160_HASH_LEN,
    740 				       (BYTE **)context->transSecret.authData.authdata)))
    741 		return result;
    742 
    743 	if (context->flags & TSS_CONTEXT_FLAGS_TRANSPORT_STATIC_AUTH)
    744 		context->transKey = TPM_KH_TRANSPORT;
    745 
    746 	if (context->flags & TSS_CONTEXT_FLAGS_TRANSPORT_AUTHENTIC)
    747 		context->transPub.transAttributes |= TPM_TRANSPORT_LOG;
    748 
    749 	if (context->flags & TSS_CONTEXT_FLAGS_TRANSPORT_EXCLUSIVE) {
    750 		context->transPub.transAttributes |= TPM_TRANSPORT_EXCLUSIVE;
    751 		exclusive = TSS_TCSATTRIB_TRANSPORT_EXCLUSIVE;
    752 	}
    753 
    754 	/* XXX implement AES128+CTR (Winbond, Infineon), then AES256+CTR (Atmel) */
    755 	context->transPub.algId = TPM_ALG_MGF1;
    756 	context->transPub.encScheme = TPM_ES_NONE;
    757 
    758 	if (context->flags & TSS_CONTEXT_FLAGS_TRANSPORT_DEFAULT_ENCRYPT) {
    759 		context->transPub.transAttributes |= TPM_TRANSPORT_ENCRYPT;
    760 
    761 		if (context->transKey == TPM_KH_TRANSPORT) {
    762 			LogError("No transport key handle has been set yet. Use "
    763 				 "Tspi_Context_SetTransEncryptionKey to set this handle");
    764 			return TSPERR(TSS_E_INTERNAL_ERROR);
    765 		}
    766 	}
    767 
    768 	if (context->transKey == TPM_KH_TRANSPORT) {
    769 		secret = context->transSecret.authData.authdata;
    770 		secretLen = TPM_SHA1_160_HASH_LEN;
    771 	} else {
    772 		offset = 0;
    773 		Trspi_LoadBlob_TRANSPORT_AUTH(&offset, transAuthBlob, &context->transSecret);
    774 		secretLen = offset;
    775 
    776 		/* encrypt the sym key with the wrapping RSA key */
    777 		encKeyLen = sizeof(encKey);
    778 		if ((result = __tspi_rsa_encrypt(context->transKey, secretLen, transAuthBlob, &encKeyLen,
    779 					  encKey)))
    780 			return result;
    781 
    782 		secret = encKey;
    783 		secretLen = encKeyLen;
    784 	}
    785 
    786 	offset = 0;
    787 	Trspi_LoadBlob_TRANSPORT_PUBLIC(&offset, transPubBlob, &context->transPub);
    788 	transPubLen = offset;
    789 
    790 	if (context->transKey != TPM_KH_TRANSPORT) {
    791 		if ((result = obj_rsakey_get_tcs_handle(context->transKey, &tcsTransKey)))
    792 			return result;
    793 
    794 		if ((result = obj_rsakey_get_policy(context->transKey, TSS_POLICY_USAGE,
    795 						    &hTransKeyPolicy, &usesAuth)))
    796 			return result;
    797 
    798 		if (!usesAuth) {
    799 			LogError("Key used to establish a transport session must use auth");
    800 			return TSPERR(TSS_E_TSP_TRANS_AUTHREQUIRED);
    801 		}
    802 	} else
    803 		tcsTransKey = TPM_KH_TRANSPORT;
    804 
    805 	/* If logging is on, do TPM commands spec rev106 step 8.a */
    806 	__tspi_memset(context->transLogDigest.digest, 0, sizeof(TPM_DIGEST));
    807 	if (context->flags & TSS_CONTEXT_FLAGS_TRANSPORT_AUTHENTIC) {
    808 		context->transLogIn.tag = TPM_TAG_TRANSPORT_LOG_IN;
    809 
    810 		/* step 8.a, i */
    811 		result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1);
    812 		result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_EstablishTransport);
    813 		result |= Trspi_HashUpdate(&hashCtx, transPubLen, transPubBlob);
    814 		result |= Trspi_Hash_UINT32(&hashCtx, secretLen);
    815 		result |= Trspi_HashUpdate(&hashCtx, secretLen, secret);
    816 		if ((result |= Trspi_HashFinal(&hashCtx, context->transLogIn.parameters.digest)))
    817 			return result;
    818 
    819 		/* step 8.a, ii */
    820 		__tspi_memset(context->transLogIn.pubKeyHash.digest, 0, sizeof(TPM_DIGEST));
    821 
    822 		/* step 8.a, iii */
    823 		result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1);
    824 		result |= Trspi_Hash_DIGEST(&hashCtx, context->transLogDigest.digest);
    825 		result |= Trspi_Hash_TRANSPORT_LOG_IN(&hashCtx, &context->transLogIn);
    826 		if ((result |= Trspi_HashFinal(&hashCtx, context->transLogDigest.digest)))
    827 			return result;
    828 	}
    829 
    830 	if (usesAuth) {
    831 		result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1);
    832 		result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_EstablishTransport);
    833 		result |= Trspi_HashUpdate(&hashCtx, (UINT32)offset, (BYTE *)transPubBlob);
    834 		result |= Trspi_Hash_UINT32(&hashCtx, secretLen);
    835 		result |= Trspi_HashUpdate(&hashCtx, secretLen, secret);
    836 		if ((result |= Trspi_HashFinal(&hashCtx, (BYTE *)&digest)))
    837 			return result;
    838 
    839 		/* open OIAP session with continueAuthSession = TRUE */
    840 		if ((result = secret_PerformAuth_OIAP(context->transKey, TPM_ORD_EstablishTransport,
    841 						      hTransKeyPolicy, TRUE, &digest, &auth)))
    842 			return result;
    843 
    844 		pAuth = &auth;
    845 	} else
    846 		pAuth = NULL;
    847 
    848 	result = RPC_EstablishTransport(tspContext, exclusive, tcsTransKey, transPubLen,
    849 					transPubBlob, secretLen, secret, pAuth, &context->transMod,
    850 					&context->transAuth.AuthHandle, &tickLen, &ticks,
    851 					&context->transAuth.NonceEven);
    852 	if (result) {
    853 		LogError("Establish Transport command failed: %s", Trspi_Error_String(result));
    854 		return result;
    855 	}
    856 
    857 	result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1);
    858 	result |= Trspi_Hash_UINT32(&hashCtx, result);
    859 	result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_EstablishTransport);
    860 	result |= Trspi_Hash_UINT32(&hashCtx, context->transMod);
    861 	result |= Trspi_HashUpdate(&hashCtx, tickLen, ticks);
    862 	result |= Trspi_Hash_NONCE(&hashCtx, context->transAuth.NonceEven.nonce);
    863 	if ((result |= Trspi_HashFinal(&hashCtx, digest.digest)))
    864 		return result;
    865 
    866 	if (usesAuth) {
    867 		if ((result = obj_policy_validate_auth_oiap(hTransKeyPolicy, &digest, pAuth)))
    868 			return result;
    869 	}
    870 
    871 	/* step 8.b iii */
    872 	offset = 0;
    873 	Trspi_UnloadBlob_CURRENT_TICKS(&offset, ticks, &context->transLogOut.currentTicks);
    874 	free(ticks);
    875 
    876 	/* If logging is on, do TPM commands spec rev106 step 8.b */
    877 	if (context->flags & TSS_CONTEXT_FLAGS_TRANSPORT_AUTHENTIC) {
    878 		context->transLogOut.tag = TPM_TAG_TRANSPORT_LOG_OUT;
    879 
    880 		/* step 8.b i */
    881 		memcpy(context->transLogOut.parameters.digest, digest.digest, sizeof(TPM_DIGEST));
    882 
    883 		/* step 8.b ii */
    884 		context->transLogOut.locality = context->transMod;
    885 
    886 		/* step 8.b iii was done above */
    887 		/* step 8.b iv */
    888 		result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1);
    889 		result |= Trspi_Hash_DIGEST(&hashCtx, context->transLogDigest.digest);
    890 		result |= Trspi_Hash_TRANSPORT_LOG_OUT(&hashCtx, &context->transLogOut);
    891 		if ((result |= Trspi_HashFinal(&hashCtx, context->transLogDigest.digest)))
    892 			return result;
    893 	}
    894 
    895 	LogDebug("Transport session established successfully");
    896 
    897 	pTransAuth = &context->transAuth;
    898 	pTransAuth->fContinueAuthSession = TRUE;
    899 	if ((result = get_local_random(tspContext, FALSE, sizeof(TPM_NONCE),
    900 				       (BYTE **)pTransAuth->NonceOdd.nonce))) {
    901 		LogError("Failed creating random nonce");
    902 		return TSPERR(TSS_E_INTERNAL_ERROR);
    903 	}
    904 
    905 	return TSS_SUCCESS;
    906 }
    907 
    908 TSS_RESULT
    909 do_transport_decryption(TPM_TRANSPORT_PUBLIC *transPub,
    910 			TPM_AUTH *pTransAuth,
    911 			BYTE *secret,
    912 			UINT32 inLen,
    913 			BYTE *in,
    914 			UINT32 *outLen,
    915 			BYTE **out)
    916 {
    917 	TSS_RESULT result;
    918 	UINT32 i, decLen;
    919 	UINT32 seedLen, ivLen;
    920 	BYTE *dec;
    921 	BYTE seed[(2 * sizeof(TPM_NONCE)) + strlen("out") + TPM_SHA1_160_HASH_LEN];
    922 
    923 	/* allocate the most data anyone below might need */
    924 	decLen = inLen;//((inLen / TSS_MAX_SYM_BLOCK_SIZE) + 1) * TSS_MAX_SYM_BLOCK_SIZE;
    925 	if ((dec = malloc(decLen)) == NULL) {
    926 		LogError("malloc of %u bytes failed", decLen);
    927 		return TSPERR(TSS_E_OUTOFMEMORY);
    928 	}
    929 
    930 	/* set the common 3 initial values of 'seed', which is used to generate either the IV or
    931 	 * mask */
    932 	memcpy(seed, pTransAuth->NonceEven.nonce, sizeof(TPM_NONCE));
    933 	memcpy(&seed[sizeof(TPM_NONCE)], pTransAuth->NonceOdd.nonce, sizeof(TPM_NONCE));
    934 	memcpy(&seed[2 * sizeof(TPM_NONCE)], "out", strlen("out"));
    935 
    936 	switch (transPub->algId) {
    937 	case TPM_ALG_MGF1:
    938 	{
    939 		decLen = inLen;
    940 		seedLen = sizeof(seed);
    941 
    942 		/* add the secret data to the seed for MGF1 */
    943 		memcpy(&seed[2 * sizeof(TPM_NONCE) + strlen("out")], secret, TPM_SHA1_160_HASH_LEN);
    944 
    945 		if ((result = Trspi_MGF1(TSS_HASH_SHA1, seedLen, seed, decLen, dec))) {
    946 			free(dec);
    947 			return result;
    948 		}
    949 
    950 		for (i = 0; i < inLen; i++)
    951 			dec[i] ^= in[i];
    952 		break;
    953 	}
    954 	case TPM_ALG_AES128:
    955 	{
    956 		BYTE iv[TSS_MAX_SYM_BLOCK_SIZE];
    957 
    958 		ivLen = TSS_MAX_SYM_BLOCK_SIZE;
    959 		seedLen = (2 * sizeof(TPM_NONCE)) + strlen("out");
    960 
    961 		if ((result = Trspi_MGF1(TSS_HASH_SHA1, seedLen, seed, ivLen, iv))) {
    962 			free(dec);
    963 			return result;
    964 		}
    965 
    966 		/* use the secret data as the key for AES */
    967 		if ((result = Trspi_SymEncrypt(transPub->algId, transPub->encScheme, secret, iv, in,
    968 					       inLen, dec, &decLen))) {
    969 			free(dec);
    970 			return result;
    971 		}
    972 
    973 		break;
    974 	}
    975 	default:
    976 		LogDebug("Unknown algorithm for encrypted transport session: 0x%x",
    977 			 transPub->algId);
    978 		free(dec);
    979 		return TSPERR(TSS_E_INTERNAL_ERROR);
    980 	}
    981 
    982 	*out = dec;
    983 	*outLen = decLen;
    984 
    985 	return result;
    986 }
    987 
    988 TSS_RESULT
    989 do_transport_encryption(TPM_TRANSPORT_PUBLIC *transPub,
    990 			TPM_AUTH *pTransAuth,
    991 			BYTE *secret,
    992 			UINT32 inLen,
    993 			BYTE *in,
    994 			UINT32 *outLen,
    995 			BYTE **out)
    996 {
    997 	TSS_RESULT result;
    998 	UINT32 i, encLen;
    999 	UINT32 seedLen, ivLen;
   1000 	BYTE *enc;
   1001 	BYTE seed[(2 * sizeof(TPM_NONCE)) + strlen("in") + TPM_SHA1_160_HASH_LEN];
   1002 
   1003 	/* allocate the most data anyone below might need */
   1004 	encLen = ((inLen / TSS_MAX_SYM_BLOCK_SIZE) + 1) * TSS_MAX_SYM_BLOCK_SIZE;
   1005 	if ((enc = malloc(encLen)) == NULL) {
   1006 		LogError("malloc of %u bytes failed", encLen);
   1007 		return TSPERR(TSS_E_OUTOFMEMORY);
   1008 	}
   1009 
   1010 	/* set the common 3 initial values of 'seed', which is used to generate either the IV or
   1011 	 * mask */
   1012 	memcpy(seed, pTransAuth->NonceEven.nonce, sizeof(TPM_NONCE));
   1013 	memcpy(&seed[sizeof(TPM_NONCE)], pTransAuth->NonceOdd.nonce, sizeof(TPM_NONCE));
   1014 	memcpy(&seed[2 * sizeof(TPM_NONCE)], "in", strlen("in"));
   1015 
   1016 	switch (transPub->algId) {
   1017 	case TPM_ALG_MGF1:
   1018 	{
   1019 		encLen = inLen;
   1020 		seedLen = sizeof(seed);
   1021 
   1022 		/* add the secret data to the seed for MGF1 */
   1023 		memcpy(&seed[2 * sizeof(TPM_NONCE) + strlen("in")], secret, TPM_SHA1_160_HASH_LEN);
   1024 
   1025 		if ((result = Trspi_MGF1(TSS_HASH_SHA1, seedLen, seed, encLen, enc))) {
   1026 			free(enc);
   1027 			return result;
   1028 		}
   1029 
   1030 		for (i = 0; i < inLen; i++)
   1031 			enc[i] ^= in[i];
   1032 		break;
   1033 	}
   1034 	case TPM_ALG_AES128:
   1035 	{
   1036 		BYTE iv[TSS_MAX_SYM_BLOCK_SIZE];
   1037 
   1038 		ivLen = TSS_MAX_SYM_BLOCK_SIZE;
   1039 		seedLen = (2 * sizeof(TPM_NONCE)) + strlen("in");
   1040 
   1041 		if ((result = Trspi_MGF1(TSS_HASH_SHA1, seedLen, seed, ivLen, iv))) {
   1042 			free(enc);
   1043 			return result;
   1044 		}
   1045 
   1046 		/* use the secret data as the key for AES */
   1047 		if ((result = Trspi_SymEncrypt(transPub->algId, transPub->encScheme, secret, iv, in,
   1048 					       inLen, enc, &encLen))) {
   1049 			free(enc);
   1050 			return result;
   1051 		}
   1052 
   1053 		break;
   1054 	}
   1055 	default:
   1056 		LogDebug("Unknown algorithm for encrypted transport session: 0x%x",
   1057 			 transPub->algId);
   1058 		free(enc);
   1059 		return TSPERR(TSS_E_INTERNAL_ERROR);
   1060 	}
   1061 
   1062 	*out = enc;
   1063 	*outLen = encLen;
   1064 
   1065 	return result;
   1066 }
   1067 
   1068 TSS_RESULT
   1069 obj_context_transport_execute(TSS_HCONTEXT     tspContext,
   1070 			      TPM_COMMAND_CODE ordinal,
   1071 			      UINT32           ulDataLen,
   1072 			      BYTE*            rgbData,
   1073 			      TPM_DIGEST*      pubKeyHash,
   1074 			      UINT32*          handlesLen,
   1075 			      TCS_HANDLE**     handles,
   1076 			      TPM_AUTH*        pAuth1,
   1077 			      TPM_AUTH*        pAuth2,
   1078 			      UINT32*          outLen,
   1079 			      BYTE**           out)
   1080 {
   1081 	TSS_RESULT result = TSS_SUCCESS;
   1082 	struct tsp_object *obj;
   1083 	struct tr_context_obj *context;
   1084 	UINT32 encLen, ulWrappedDataLen = 0;
   1085 	BYTE *pEnc = NULL, *rgbWrappedData = NULL;
   1086 	TPM_RESULT tpmResult;
   1087 	Trspi_HashCtx hashCtx;
   1088 	TPM_DIGEST etDigest, wDigest;
   1089 	TPM_AUTH *pTransAuth;
   1090 	UINT64 currentTicks;
   1091 	TSS_BOOL free_enc = FALSE;
   1092 
   1093 	if ((obj = obj_list_get_obj(&context_list, tspContext)) == NULL)
   1094 		return TSPERR(TSS_E_INVALID_HANDLE);
   1095 
   1096 	context = (struct tr_context_obj *)obj->data;
   1097 
   1098 	pTransAuth = &context->transAuth;
   1099 
   1100 	/* TPM Commands spec rev106 step 6 */
   1101 	result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1);
   1102 	result |= Trspi_Hash_UINT32(&hashCtx, ordinal);
   1103 
   1104 	switch (ordinal) {
   1105 		case TPM_ORD_OSAP:
   1106 		case TPM_ORD_OIAP:
   1107 			break;
   1108 		default:
   1109 			result |= Trspi_HashUpdate(&hashCtx, ulDataLen, rgbData);
   1110 			break;
   1111 	}
   1112 
   1113 	if ((result |= Trspi_HashFinal(&hashCtx, wDigest.digest)))
   1114 		goto done;
   1115 
   1116 	if (context->flags & TSS_CONTEXT_FLAGS_TRANSPORT_AUTHENTIC) {
   1117 		/* TPM Commands spec rev106 step 10.b */
   1118 		memcpy(context->transLogIn.parameters.digest, wDigest.digest, sizeof(TPM_DIGEST));
   1119 		/* TPM Commands spec rev106 step 10.c, d or e, calculated by the caller */
   1120 		if (pubKeyHash)
   1121 			memcpy(context->transLogIn.pubKeyHash.digest, pubKeyHash->digest,
   1122 			       sizeof(TPM_DIGEST));
   1123 		else
   1124 			__tspi_memset(context->transLogIn.pubKeyHash.digest, 0, sizeof(TPM_DIGEST));
   1125 
   1126 		/* TPM Commands spec rev106 step 10.f */
   1127 		result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1);
   1128 		result |= Trspi_Hash_DIGEST(&hashCtx, context->transLogDigest.digest);
   1129 		result |= Trspi_Hash_TRANSPORT_LOG_IN(&hashCtx, &context->transLogIn);
   1130 		if ((result |= Trspi_HashFinal(&hashCtx, context->transLogDigest.digest)))
   1131 			goto done;
   1132 	}
   1133 
   1134 	/* TPM Commands spec rev106 step 7.a */
   1135 	result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1);
   1136 	result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_ExecuteTransport);
   1137 	result |= Trspi_Hash_UINT32(&hashCtx, ulDataLen + TSS_TPM_TXBLOB_HDR_LEN
   1138 							+ (*handlesLen * sizeof(UINT32))
   1139 							+ (pAuth1 ? TPM_AUTH_RQU_SIZE : 0)
   1140 							+ (pAuth2 ? TPM_AUTH_RQU_SIZE : 0));
   1141 	result |= Trspi_HashUpdate(&hashCtx, TPM_SHA1_160_HASH_LEN, wDigest.digest);
   1142 	if ((result |= Trspi_HashFinal(&hashCtx, etDigest.digest)))
   1143 		goto done;
   1144 
   1145 	/* encrypt the data if necessary */
   1146 	if (ulDataLen && context->flags & TSS_CONTEXT_FLAGS_TRANSPORT_DEFAULT_ENCRYPT) {
   1147 		switch (ordinal) {
   1148 		case TPM_ORD_OSAP:
   1149 		case TPM_ORD_OIAP:
   1150 			encLen = ulDataLen;
   1151 			pEnc = rgbData;
   1152 			break;
   1153 		case TPM_ORD_DSAP:
   1154 		{
   1155 			UINT64 offset;
   1156 			UINT32 tmpLen, entityValueLen;
   1157 			BYTE *tmpEnc, *entityValuePtr;
   1158 
   1159 			/* DSAP is a special case where only entityValue is encrypted. So, we'll
   1160 			 * parse through rgbData until we get to entityValue, encrypt it, alloc
   1161 			 * new space for rgbData (since it could be up to a block length larger
   1162 			 * than it came in) and copy the unencrypted data and the encrypted
   1163 			 * entityValue to the new block, setting pEnc and encLen to new values. */
   1164 
   1165 			offset = (2 * sizeof(UINT32)) + sizeof(TPM_NONCE);
   1166 			Trspi_UnloadBlob_UINT32(&offset, &entityValueLen, rgbData);
   1167 
   1168 			entityValuePtr = &rgbData[offset];
   1169 			if ((result = do_transport_encryption(&context->transPub, pTransAuth,
   1170 							context->transSecret.authData.authdata,
   1171 							entityValueLen, entityValuePtr, &tmpLen,
   1172 							&tmpEnc)))
   1173 				goto done;
   1174 
   1175 			/* offset is the amount of data before the block we encrypted and tmpLen is
   1176 			 * the size of the encrypted data */
   1177 			encLen = offset + tmpLen;
   1178 			if ((pEnc = malloc(encLen)) == NULL) {
   1179 				LogError("malloc of %u bytes failed.", encLen);
   1180 				result = TSPERR(TSS_E_OUTOFMEMORY);
   1181 				goto done;
   1182 			}
   1183 			memcpy(pEnc, rgbData, offset);
   1184 			memcpy(&pEnc[offset], tmpEnc, tmpLen);
   1185 			free(tmpEnc);
   1186 
   1187 			free_enc = TRUE;
   1188 			break;
   1189 		}
   1190 		default:
   1191 			if ((result = do_transport_encryption(&context->transPub, pTransAuth,
   1192 							context->transSecret.authData.authdata,
   1193 							ulDataLen, rgbData, &encLen, &pEnc)))
   1194 				goto done;
   1195 
   1196 			free_enc = TRUE;
   1197 			break;
   1198 		}
   1199 	} else {
   1200 		encLen = ulDataLen;
   1201 		pEnc = rgbData;
   1202 	}
   1203 
   1204 	/* TPM Commands spec rev106 step 7.b */
   1205 	HMAC_Auth(context->transSecret.authData.authdata, etDigest.digest, pTransAuth);
   1206 
   1207 	if ((result = RPC_ExecuteTransport(tspContext, ordinal, encLen, pEnc, handlesLen, handles,
   1208 					   pAuth1, pAuth2, pTransAuth, &currentTicks,
   1209 					   &context->transMod, &tpmResult, &ulWrappedDataLen,
   1210 					   &rgbWrappedData))) {
   1211 		LogDebugFn("Execute Transport failed: %s", Trspi_Error_String(result));
   1212 		goto done;
   1213 	}
   1214 
   1215 	if (tpmResult) {
   1216 		LogDebug("Wrapped command ordinal 0x%x failed with result: 0x%x", ordinal,
   1217 			 tpmResult);
   1218 		result = tpmResult;
   1219 		goto done;
   1220 	}
   1221 
   1222 	/* decrypt the returned wrapped data if necessary */
   1223 	if (ulWrappedDataLen && context->flags & TSS_CONTEXT_FLAGS_TRANSPORT_DEFAULT_ENCRYPT) {
   1224 		switch (ordinal) {
   1225 		case TPM_ORD_OSAP:
   1226 		case TPM_ORD_OIAP:
   1227 		case TPM_ORD_DSAP:
   1228 			*outLen = ulWrappedDataLen;
   1229 			*out = rgbWrappedData;
   1230 			break;
   1231 		default:
   1232 			if ((result = do_transport_decryption(&context->transPub, pTransAuth,
   1233 							context->transSecret.authData.authdata,
   1234 							ulWrappedDataLen, rgbWrappedData, outLen,
   1235 							out)))
   1236 					goto done;
   1237 
   1238 			free(rgbWrappedData);
   1239 		}
   1240 	} else {
   1241 		if (outLen) {
   1242 			*outLen = ulWrappedDataLen;
   1243 			*out = rgbWrappedData;
   1244 		}
   1245 	}
   1246 
   1247 	/* TPM Commands spec rev106 step 14 */
   1248 	result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1);
   1249 	result |= Trspi_Hash_UINT32(&hashCtx, tpmResult);
   1250 	result |= Trspi_Hash_UINT32(&hashCtx, ordinal);
   1251 
   1252 	switch (ordinal) {
   1253 		case TPM_ORD_OSAP:
   1254 		case TPM_ORD_OIAP:
   1255 			break;
   1256 		default:
   1257 			if (outLen)
   1258 				result |= Trspi_HashUpdate(&hashCtx, *outLen, *out);
   1259 			break;
   1260 	}
   1261 
   1262 	if ((result |= Trspi_HashFinal(&hashCtx, wDigest.digest)))
   1263 		goto done;
   1264 
   1265 	/* TPM Commands spec rev106 step 15 */
   1266 	result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1);
   1267 	result |= Trspi_Hash_UINT32(&hashCtx, result);
   1268 	result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_ExecuteTransport);
   1269 	result |= Trspi_Hash_UINT64(&hashCtx, currentTicks);
   1270 	result |= Trspi_Hash_UINT32(&hashCtx, context->transMod);
   1271 	result |= Trspi_Hash_UINT32(&hashCtx, (outLen ? *outLen : 0)
   1272 					      + TSS_TPM_TXBLOB_HDR_LEN
   1273 					      + (*handlesLen * sizeof(UINT32))
   1274 					      + (pAuth1 ? TPM_AUTH_RSP_SIZE : 0)
   1275 					      + (pAuth2 ? TPM_AUTH_RSP_SIZE : 0));
   1276 	result |= Trspi_HashUpdate(&hashCtx, TPM_SHA1_160_HASH_LEN, wDigest.digest);
   1277 	if ((result |= Trspi_HashFinal(&hashCtx, etDigest.digest)))
   1278 		goto done;
   1279 
   1280 	if (validateReturnAuth(context->transSecret.authData.authdata, etDigest.digest,
   1281 			       pTransAuth)) {
   1282 		result = TSPERR(TSS_E_TSP_TRANS_AUTHFAIL);
   1283 		goto done;
   1284 	}
   1285 
   1286 	if (context->flags & TSS_CONTEXT_FLAGS_TRANSPORT_AUTHENTIC) {
   1287 		context->transLogOut.currentTicks.currentTicks = currentTicks;
   1288 
   1289 		/* TPM Commands spec rev106 step 16.b */
   1290 		memcpy(context->transLogOut.parameters.digest, wDigest.digest, sizeof(TPM_DIGEST));
   1291 		/* TPM Commands spec rev106 step 16.c done above */
   1292 		/* TPM Commands spec rev106 step 16.d */
   1293 		context->transLogOut.locality = context->transMod;
   1294 
   1295 		/* TPM Commands spec rev106 step 16.d */
   1296 		result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1);
   1297 		result |= Trspi_Hash_DIGEST(&hashCtx, context->transLogDigest.digest);
   1298 		result |= Trspi_Hash_TRANSPORT_LOG_OUT(&hashCtx, &context->transLogOut);
   1299 		if ((result |= Trspi_HashFinal(&hashCtx, context->transLogDigest.digest)))
   1300 			goto done;
   1301 	}
   1302 
   1303 	/* Refresh nonceOdd for continued transport auth session */
   1304 	if ((result = get_local_random(tspContext, FALSE, sizeof(TPM_NONCE),
   1305 				       (BYTE **)pTransAuth->NonceOdd.nonce))) {
   1306 		LogError("Failed creating random nonce");
   1307 	}
   1308 
   1309 done:
   1310 	if (free_enc)
   1311 		free(pEnc);
   1312 	obj_list_put(&context_list);
   1313 
   1314 	return result;
   1315 }
   1316 
   1317 /* called to close a transport session */
   1318 TSS_RESULT
   1319 obj_context_transport_close(TSS_HCONTEXT   tspContext,
   1320 			    TSS_HKEY       hKey,
   1321 			    TSS_HPOLICY    hPolicy,
   1322 			    TSS_BOOL       usesAuth,
   1323 			    TPM_SIGN_INFO* signInfo,
   1324 			    UINT32*        sigLen,
   1325 			    BYTE**         sig)
   1326 {
   1327 	TSS_RESULT result = TSS_SUCCESS;
   1328 	struct tsp_object *obj;
   1329 	struct tr_context_obj *context;
   1330 	Trspi_HashCtx hashCtx;
   1331 	TPM_DIGEST digest;
   1332 	TPM_AUTH auth, *pAuth;
   1333 	TCS_KEY_HANDLE tcsKey;
   1334 	BYTE *ticks = NULL;
   1335 	UINT32 tickLen;
   1336 
   1337 	if ((obj = obj_list_get_obj(&context_list, tspContext)) == NULL)
   1338 		return TSPERR(TSS_E_INVALID_HANDLE);
   1339 
   1340 	context = (struct tr_context_obj *)obj->data;
   1341 
   1342 	/* return immediately if we're not in a transport session */
   1343 	if (!(context->flags & TSS_CONTEXT_FLAGS_TRANSPORT_ENABLED)) {
   1344 		result = TSPERR(TSS_E_INTERNAL_ERROR);
   1345 		goto done;
   1346 	}
   1347 
   1348 	if ((result = obj_rsakey_get_tcs_handle(hKey, &tcsKey)))
   1349 		goto done;
   1350 
   1351 	result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1);
   1352 	result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_ReleaseTransportSigned);
   1353 	result |= Trspi_Hash_NONCE(&hashCtx, signInfo->replay.nonce);
   1354 	if ((result |= Trspi_HashFinal(&hashCtx, (BYTE *)&digest)))
   1355 		goto done;
   1356 
   1357 	if (usesAuth) {
   1358 		if ((result = secret_PerformAuth_OIAP(hKey, TPM_ORD_ReleaseTransportSigned,
   1359 						      hPolicy, FALSE, &digest, &auth)))
   1360 			goto done;
   1361 
   1362 		pAuth = &auth;
   1363 	} else
   1364 		pAuth = NULL;
   1365 
   1366 	/* continue the auth session established in obj_context_transport_establish */
   1367 	HMAC_Auth(context->transSecret.authData.authdata, digest.digest, &context->transAuth);
   1368 
   1369 	if ((result = RPC_ReleaseTransportSigned(tspContext, tcsKey, &signInfo->replay, pAuth,
   1370 						 &context->transAuth,
   1371 						 &context->transLogOut.locality, &tickLen, &ticks,
   1372 						 sigLen, sig)))
   1373 		goto done;
   1374 
   1375 	result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1);
   1376 	result |= Trspi_Hash_UINT32(&hashCtx, result);
   1377 	result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_ReleaseTransportSigned);
   1378 	result |= Trspi_Hash_UINT32(&hashCtx, context->transLogOut.locality);
   1379 	result |= Trspi_HashUpdate(&hashCtx, tickLen, ticks);
   1380 	result |= Trspi_Hash_UINT32(&hashCtx, *sigLen);
   1381 	result |= Trspi_HashUpdate(&hashCtx, *sigLen, *sig);
   1382 	if ((result |= Trspi_HashFinal(&hashCtx, (BYTE *)&digest)))
   1383 		goto done_disabled;
   1384 
   1385 	/* validate the return data using the key's auth */
   1386 	if (pAuth) {
   1387 		if ((result = obj_policy_validate_auth_oiap(hPolicy, &digest, pAuth)))
   1388 			goto done_disabled;
   1389 	}
   1390 
   1391 	/* validate again using the transport session's auth */
   1392 	if ((result = validateReturnAuth(context->transSecret.authData.authdata, digest.digest,
   1393 					 &context->transAuth))) {
   1394 		result = TSPERR(TSS_E_TSP_TRANS_AUTHFAIL);
   1395 		goto done_disabled;
   1396 	}
   1397 
   1398 	if (context->flags & TSS_CONTEXT_FLAGS_TRANSPORT_AUTHENTIC) {
   1399 		UINT64 offset;
   1400 
   1401 		/* TPM Commands Spec step 6.b */
   1402 		result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1);
   1403 		result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_ReleaseTransportSigned);
   1404 		result |= Trspi_Hash_NONCE(&hashCtx, signInfo->replay.nonce);
   1405 		if ((result |= Trspi_HashFinal(&hashCtx, context->transLogOut.parameters.digest)))
   1406 			goto done_disabled;
   1407 
   1408 		/* TPM Commands Spec step 6.c */
   1409 		offset = 0;
   1410 		Trspi_UnloadBlob_CURRENT_TICKS(&offset, ticks, &context->transLogOut.currentTicks);
   1411 		free(ticks);
   1412 
   1413 		/* TPM Commands Spec step 6.d was set above */
   1414 		/* TPM Commands Spec step 6.e */
   1415 		result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1);
   1416 		result |= Trspi_Hash_DIGEST(&hashCtx, context->transLogDigest.digest);
   1417 		result |= Trspi_Hash_TRANSPORT_LOG_OUT(&hashCtx, &context->transLogOut);
   1418 		if ((result |= Trspi_HashFinal(&hashCtx, context->transLogDigest.digest)))
   1419 			goto done_disabled;
   1420 	}
   1421 
   1422 	if ((signInfo->data = malloc(sizeof(TPM_DIGEST))) == NULL) {
   1423 		LogError("malloc %zd bytes failed.", sizeof(TPM_DIGEST));
   1424 		result = TSPERR(TSS_E_OUTOFMEMORY);
   1425 		goto done_disabled;
   1426 	}
   1427 	memcpy(signInfo->data, context->transLogDigest.digest, sizeof(TPM_DIGEST));
   1428 	signInfo->dataLen = sizeof(TPM_DIGEST);
   1429 
   1430 	/* destroy all transport session info, except the key handle */
   1431 	__tspi_memset(&context->transPub, 0, sizeof(TPM_TRANSPORT_PUBLIC));
   1432 	__tspi_memset(&context->transMod, 0, sizeof(TPM_MODIFIER_INDICATOR));
   1433 	__tspi_memset(&context->transSecret, 0, sizeof(TPM_TRANSPORT_AUTH));
   1434 	__tspi_memset(&context->transAuth, 0, sizeof(TPM_AUTH));
   1435 	__tspi_memset(&context->transLogIn, 0, sizeof(TPM_TRANSPORT_LOG_IN));
   1436 	__tspi_memset(&context->transLogOut, 0, sizeof(TPM_TRANSPORT_LOG_OUT));
   1437 	__tspi_memset(&context->transLogDigest, 0, sizeof(TPM_DIGEST));
   1438 
   1439 done_disabled:
   1440 	context->flags &= ~TSS_CONTEXT_FLAGS_TRANSPORT_ESTABLISHED;
   1441 done:
   1442 	obj_list_put(&context_list);
   1443 
   1444 	return result;
   1445 }
   1446 #endif
   1447 
   1448 /* XXX change 0,1,2 to #defines */
   1449 TSS_RESULT
   1450 obj_context_set_tpm_version(TSS_HCONTEXT tspContext, UINT32 ver)
   1451 {
   1452 	TSS_RESULT result = TSS_SUCCESS;
   1453 	struct tsp_object *obj;
   1454 	struct tr_context_obj *context;
   1455 
   1456 	if ((obj = obj_list_get_obj(&context_list, tspContext)) == NULL)
   1457 		return TSPERR(TSS_E_INVALID_HANDLE);
   1458 
   1459 	context = (struct tr_context_obj *)obj->data;
   1460 
   1461 	switch (ver) {
   1462 		case 1:
   1463 			context->flags &= ~TSS_CONTEXT_FLAGS_TPM_VERSION_MASK;
   1464 			context->flags |= TSS_CONTEXT_FLAGS_TPM_VERSION_1;
   1465 			break;
   1466 		case 2:
   1467 			context->flags &= ~TSS_CONTEXT_FLAGS_TPM_VERSION_MASK;
   1468 			context->flags |= TSS_CONTEXT_FLAGS_TPM_VERSION_2;
   1469 			break;
   1470 		default:
   1471 			LogError("Invalid TPM version set: %u", ver);
   1472 			result = TSPERR(TSS_E_INTERNAL_ERROR);
   1473 			break;
   1474 	}
   1475 
   1476 	obj_list_put(&context_list);
   1477 
   1478 	return result;
   1479 }
   1480 
   1481 /* XXX change 0,1,2 to #defines */
   1482 TSS_RESULT
   1483 obj_context_get_tpm_version(TSS_HCONTEXT tspContext, UINT32 *ver)
   1484 {
   1485 	struct tsp_object *obj;
   1486 	struct tr_context_obj *context;
   1487 
   1488 	if ((obj = obj_list_get_obj(&context_list, tspContext)) == NULL)
   1489 		return TSPERR(TSS_E_INVALID_HANDLE);
   1490 
   1491 	context = (struct tr_context_obj *)obj->data;
   1492 
   1493 	if (context->flags & TSS_CONTEXT_FLAGS_TPM_VERSION_1)
   1494 		*ver = 1;
   1495 	else if (context->flags & TSS_CONTEXT_FLAGS_TPM_VERSION_2)
   1496 		*ver = 2;
   1497 	else
   1498 		*ver = 0;
   1499 
   1500 	obj_list_put(&context_list);
   1501 
   1502 	return TSS_SUCCESS;
   1503 }
   1504 
   1505 TSS_RESULT
   1506 obj_context_get_loadkey_ordinal(TSS_HCONTEXT tspContext, TPM_COMMAND_CODE *ordinal)
   1507 {
   1508 	struct tsp_object *obj;
   1509 	struct tr_context_obj *context;
   1510 
   1511 	if ((obj = obj_list_get_obj(&context_list, tspContext)) == NULL)
   1512 		return TSPERR(TSS_E_INVALID_HANDLE);
   1513 
   1514 	context = (struct tr_context_obj *)obj->data;
   1515 
   1516 	switch (context->flags & TSS_CONTEXT_FLAGS_TPM_VERSION_MASK) {
   1517 		case TSS_CONTEXT_FLAGS_TPM_VERSION_2:
   1518 			*ordinal = TPM_ORD_LoadKey2;
   1519 			break;
   1520 		default:
   1521 			LogDebugFn("No TPM version set!");
   1522 			/* fall through */
   1523 		case TSS_CONTEXT_FLAGS_TPM_VERSION_1:
   1524 			*ordinal = TPM_ORD_LoadKey;
   1525 			break;
   1526 	}
   1527 
   1528 	obj_list_put(&context_list);
   1529 
   1530 	return TSS_SUCCESS;
   1531 }
   1532 
   1533