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