Home | History | Annotate | Line # | Download | only in tcs
      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. 2004-2006
      8  *
      9  */
     10 
     11 #include <stdio.h>
     12 #include <string.h>
     13 #include <stdlib.h>
     14 #include <limits.h>
     15 
     16 #include "trousers/tss.h"
     17 #include "trousers_types.h"
     18 #include "tcs_tsp.h"
     19 #include "tcs_utils.h"
     20 #include "tcs_int_literals.h"
     21 #include "capabilities.h"
     22 #include "tcslog.h"
     23 #include "tcsd_wrap.h"
     24 #include "tcsd.h"
     25 #include "auth_mgr.h"
     26 #include "req_mgr.h"
     27 
     28 
     29 MUTEX_DECLARE_EXTERN(tcsp_lock);
     30 
     31 /* Note: The after taking the auth_mgr_lock in any of the functions below, the
     32  * mem_cache_lock cannot be taken without risking a deadlock. So, the auth_mgr
     33  * functions must be "self-contained" wrt locking */
     34 
     35 /* no locking done in init since its called by only a single thread */
     36 TSS_RESULT
     37 auth_mgr_init()
     38 {
     39 	memset(&auth_mgr, 0, sizeof(struct _auth_mgr));
     40 
     41 	auth_mgr.max_auth_sessions = tpm_metrics.num_auths;
     42 
     43 	auth_mgr.overflow = calloc(TSS_DEFAULT_OVERFLOW_AUTHS, sizeof(COND_VAR *));
     44 	if (auth_mgr.overflow == NULL) {
     45 		LogError("malloc of %zd bytes failed",
     46 			 (TSS_DEFAULT_OVERFLOW_AUTHS * sizeof(COND_VAR *)));
     47 		return TCSERR(TSS_E_OUTOFMEMORY);
     48 	}
     49 	auth_mgr.overflow_size = TSS_DEFAULT_OVERFLOW_AUTHS;
     50 
     51 	auth_mgr.auth_mapper = calloc(TSS_DEFAULT_AUTH_TABLE_SIZE, sizeof(struct auth_map));
     52 	if (auth_mgr.auth_mapper == NULL) {
     53 		LogError("malloc of %zd bytes failed",
     54 			 (TSS_DEFAULT_AUTH_TABLE_SIZE * sizeof(struct auth_map)));
     55 		return TCSERR(TSS_E_OUTOFMEMORY);
     56 	}
     57 	auth_mgr.auth_mapper_size = TSS_DEFAULT_AUTH_TABLE_SIZE;
     58 
     59 	return TSS_SUCCESS;
     60 }
     61 
     62 TSS_RESULT
     63 auth_mgr_final()
     64 {
     65 	UINT32 i;
     66 
     67 	/* wake up any sleeping threads, so they can be joined */
     68 	for (i = 0; i < auth_mgr.overflow_size; i++) {
     69 		if (auth_mgr.overflow[i] != NULL)
     70 			COND_SIGNAL(auth_mgr.overflow[i]);
     71 	}
     72 
     73 	free(auth_mgr.overflow);
     74 	free(auth_mgr.auth_mapper);
     75 
     76 	return TSS_SUCCESS;
     77 }
     78 
     79 TSS_RESULT
     80 auth_mgr_save_ctx(TCS_CONTEXT_HANDLE hContext)
     81 {
     82        TSS_RESULT result = TSS_SUCCESS;
     83 	UINT32 i;
     84 
     85 	for (i = 0; i < auth_mgr.auth_mapper_size; i++) {
     86 		if (auth_mgr.auth_mapper[i].full == TRUE &&
     87 		    auth_mgr.auth_mapper[i].swap == NULL &&
     88 		    auth_mgr.auth_mapper[i].tcs_ctx != hContext) {
     89 			LogDebug("Calling TPM_SaveAuthContext for TCS CTX %x. Swapping out: TCS %x "
     90 				 "TPM %x", hContext, auth_mgr.auth_mapper[i].tcs_ctx,
     91 				 auth_mgr.auth_mapper[i].tpm_handle);
     92 
     93 			if ((result = TPM_SaveAuthContext(auth_mgr.auth_mapper[i].tpm_handle,
     94 							  &auth_mgr.auth_mapper[i].swap_size,
     95 							  &auth_mgr.auth_mapper[i].swap))) {
     96 				LogDebug("TPM_SaveAuthContext failed: 0x%x", result);
     97 				return result;
     98 			}
     99                        break;
    100 		}
    101 	}
    102 
    103        return result;
    104 }
    105 
    106 /* if there's a TCS context waiting to get auth, wake it up or swap it in */
    107 void
    108 auth_mgr_swap_in()
    109 {
    110 	if (auth_mgr.overflow[auth_mgr.of_tail] != NULL) {
    111 		LogDebug("waking up thread %lddd, auth slot has opened", THREAD_ID);
    112 		/* wake up the next sleeping thread in order and increment tail */
    113 		COND_SIGNAL(auth_mgr.overflow[auth_mgr.of_tail]);
    114 		auth_mgr.overflow[auth_mgr.of_tail] = NULL;
    115 		auth_mgr.of_tail = (auth_mgr.of_tail + 1) % auth_mgr.overflow_size;
    116 	} else {
    117 		/* else nobody needs to be swapped in, so continue */
    118 		LogDebug("no threads need to be signaled.");
    119 	}
    120 }
    121 
    122 /* we need to swap out an auth context or add a waiting context to the overflow queue */
    123 TSS_RESULT
    124 auth_mgr_swap_out(TCS_CONTEXT_HANDLE hContext)
    125 {
    126 	COND_VAR *cond;
    127 
    128 	/* If the TPM can do swapping and it succeeds, return, else cond wait below */
    129 	if (tpm_metrics.authctx_swap && !auth_mgr_save_ctx(hContext))
    130 		return TSS_SUCCESS;
    131 
    132 	if ((cond = ctx_get_cond_var(hContext)) == NULL) {
    133 		LogError("Auth swap variable not found for TCS context 0x%x", hContext);
    134 		return TCSERR(TSS_E_INTERNAL_ERROR);
    135 	}
    136 
    137 	/* Test whether we are the last awake thread.  If we are, we can't go to sleep
    138 	 * since then there'd be no worker thread to wake the others up. This situation
    139 	 * can arise when we're on a busy system who's TPM doesn't support auth ctx
    140 	 * swapping.
    141 	 */
    142 	if (auth_mgr.sleeping_threads == (tcsd_options.num_threads - 1)) {
    143 		LogError("auth mgr failing: too many threads already waiting");
    144 		LogTPMERR(TCPA_E_RESOURCES, __FILE__, __LINE__);
    145 		return TCPA_E_RESOURCES;
    146 	}
    147 
    148 	if (auth_mgr.overflow[auth_mgr.of_head] == NULL) {
    149 		auth_mgr.overflow[auth_mgr.of_head] = cond;
    150 		auth_mgr.of_head = (auth_mgr.of_head + 1) % auth_mgr.overflow_size;
    151 		/* go to sleep */
    152 		LogDebug("thread %lddd going to sleep until auth slot opens", THREAD_ID);
    153 		auth_mgr.sleeping_threads++;
    154 		COND_WAIT(cond, &tcsp_lock);
    155 		auth_mgr.sleeping_threads--;
    156 	} else if (auth_mgr.overflow_size + TSS_DEFAULT_OVERFLOW_AUTHS < UINT_MAX) {
    157 		COND_VAR **tmp = auth_mgr.overflow;
    158 
    159 		LogDebugFn("Table of sleeping threads is full (%hu), growing to %hu entries",
    160 			   auth_mgr.sleeping_threads,
    161 			   auth_mgr.overflow_size + TSS_DEFAULT_OVERFLOW_AUTHS);
    162 
    163 		auth_mgr.overflow = calloc(auth_mgr.overflow_size + TSS_DEFAULT_OVERFLOW_AUTHS,
    164 					   sizeof(COND_VAR *));
    165 		if (auth_mgr.overflow == NULL) {
    166 			LogDebugFn("malloc of %zd bytes failed",
    167 				   (auth_mgr.overflow_size + TSS_DEFAULT_OVERFLOW_AUTHS) *
    168 				   sizeof(COND_VAR *));
    169 			auth_mgr.overflow = tmp;
    170 			return TCSERR(TSS_E_OUTOFMEMORY);
    171 		}
    172 		auth_mgr.overflow_size += TSS_DEFAULT_OVERFLOW_AUTHS;
    173 
    174 		LogDebugFn("Success.");
    175 		memcpy(auth_mgr.overflow, tmp, auth_mgr.sleeping_threads * sizeof(COND_VAR *));
    176 		free(tmp);
    177 
    178 		/* XXX This could temporarily wake threads up out of order */
    179 		auth_mgr.of_head = auth_mgr.sleeping_threads;
    180 		auth_mgr.of_tail = 0;
    181 		auth_mgr.overflow[auth_mgr.of_head] = cond;
    182 		auth_mgr.of_head = (auth_mgr.of_head + 1) % auth_mgr.overflow_size;
    183 		LogDebug("thread %lddd going to sleep until auth slot opens", THREAD_ID);
    184 		auth_mgr.sleeping_threads++;
    185 		COND_WAIT(cond, &tcsp_lock);
    186 		auth_mgr.sleeping_threads--;
    187 	} else {
    188 		LogError("Auth table overflow is full (%u entries), some will fail.",
    189 			 auth_mgr.overflow_size);
    190 		return TCSERR(TSS_E_INTERNAL_ERROR);
    191 	}
    192 
    193 	return TSS_SUCCESS;
    194 }
    195 
    196 /* close all auth contexts associated with this TCS_CONTEXT_HANDLE */
    197 TSS_RESULT
    198 auth_mgr_close_context(TCS_CONTEXT_HANDLE tcs_handle)
    199 {
    200 	UINT32 i;
    201 	TSS_RESULT result;
    202 
    203 	for (i = 0; i < auth_mgr.auth_mapper_size; i++) {
    204 		if (auth_mgr.auth_mapper[i].full == TRUE &&
    205 		    auth_mgr.auth_mapper[i].tcs_ctx == tcs_handle) {
    206 			if (auth_mgr.auth_mapper[i].swap) {
    207 				/* This context is swapped out of the TPM, so we can just free the
    208 				 * blob */
    209 				free(auth_mgr.auth_mapper[i].swap);
    210 				auth_mgr.auth_mapper[i].swap = NULL;
    211 				auth_mgr.auth_mapper[i].swap_size = 0;
    212 			} else {
    213 				result = TCSP_FlushSpecific_Common(auth_mgr.auth_mapper[i].tpm_handle,
    214 								   TPM_RT_AUTH);
    215 
    216 				/* Ok, probably dealing with a 1.1 TPM */
    217 				if (result == TPM_E_BAD_ORDINAL)
    218                                        result = internal_TerminateHandle(
    219                                            auth_mgr.auth_mapper[i].tpm_handle);
    220 
    221 				if (result == TCPA_E_INVALID_AUTHHANDLE) {
    222 					LogDebug("Tried to close an invalid auth handle: %x",
    223 						 auth_mgr.auth_mapper[i].tpm_handle);
    224 				} else if (result != TCPA_SUCCESS) {
    225 					LogDebug("TPM_TerminateHandle returned %d", result);
    226 				}
    227 			}
    228                        /* clear the slot */
    229 			auth_mgr.open_auth_sessions--;
    230 			auth_mgr.auth_mapper[i].full = FALSE;
    231                        auth_mgr.auth_mapper[i].tpm_handle = 0;
    232                        auth_mgr.auth_mapper[i].tcs_ctx = 0;
    233 			LogDebug("released auth for TCS %x TPM %x", tcs_handle,
    234                                auth_mgr.auth_mapper[i].tpm_handle);
    235 
    236 			auth_mgr_swap_in();
    237 		}
    238 	}
    239 
    240 	return TSS_SUCCESS;
    241 }
    242 
    243 void
    244 auth_mgr_release_auth(TPM_AUTH *auth0, TPM_AUTH *auth1, TCS_CONTEXT_HANDLE tcs_handle)
    245 {
    246 	if (auth0)
    247 		auth_mgr_release_auth_handle(auth0->AuthHandle, tcs_handle,
    248 					     auth0->fContinueAuthSession);
    249 
    250 	if (auth1)
    251 		auth_mgr_release_auth_handle(auth1->AuthHandle, tcs_handle,
    252 					     auth1->fContinueAuthSession);
    253 }
    254 
    255 /* unload the auth ctx associated with this auth handle */
    256 TSS_RESULT
    257 auth_mgr_release_auth_handle(TCS_AUTHHANDLE tpm_auth_handle, TCS_CONTEXT_HANDLE tcs_handle,
    258 			     TSS_BOOL cont)
    259 {
    260 	UINT32 i;
    261 	TSS_RESULT result = TSS_SUCCESS;
    262 
    263 	for (i = 0; i < auth_mgr.auth_mapper_size; i++) {
    264 		if (auth_mgr.auth_mapper[i].full == TRUE &&
    265 		    auth_mgr.auth_mapper[i].tpm_handle == tpm_auth_handle &&
    266 		    auth_mgr.auth_mapper[i].tcs_ctx == tcs_handle) {
    267 			if (!cont) {
    268                                /*
    269                                 * This function should not be necessary, but
    270                                 * if the main operation resulted in an error,
    271                                 * the TPM may still hold the auth handle
    272                                 * and it must be freed.  Most of the time
    273                                 * this call will result in TPM_E_INVALID_AUTHHANDLE
    274                                 * error which can be ignored.
    275                                 */
    276                                result = TCSP_FlushSpecific_Common(
    277                                    auth_mgr.auth_mapper[i].tpm_handle,
    278                                    TPM_RT_AUTH);
    279 
    280 				/* Ok, probably dealing with a 1.1 TPM */
    281 				if (result == TPM_E_BAD_ORDINAL)
    282                                        result = internal_TerminateHandle(
    283                                            auth_mgr.auth_mapper[i].tpm_handle);
    284 
    285 				if (result == TCPA_E_INVALID_AUTHHANDLE) {
    286 					LogDebug("Tried to close an invalid auth handle: %x",
    287 						 auth_mgr.auth_mapper[i].tpm_handle);
    288 				} else if (result != TCPA_SUCCESS) {
    289 					LogDebug("TPM_TerminateHandle returned %d", result);
    290 				}
    291 
    292                                if (result == TPM_SUCCESS) {
    293                                        LogDebug("released auth for TCS %x TPM %x",
    294                                                 auth_mgr.auth_mapper[i].tcs_ctx, tpm_auth_handle);
    295                                }
    296                                /*
    297                                 * Mark it as released, the "cont" flag indicates
    298                                 * that it is no longer needed.
    299                                 */
    300                                auth_mgr.open_auth_sessions--;
    301                                auth_mgr.auth_mapper[i].full = FALSE;
    302                                auth_mgr.auth_mapper[i].tpm_handle = 0;
    303                                auth_mgr.auth_mapper[i].tcs_ctx = 0;
    304                                auth_mgr_swap_in();
    305 			}
    306                        /* If the cont flag is TRUE, we have to keep the handle */
    307 		}
    308 	}
    309 
    310 	return result;
    311 }
    312 
    313 TSS_RESULT
    314 auth_mgr_check(TCS_CONTEXT_HANDLE tcsContext, TPM_AUTHHANDLE *tpm_auth_handle)
    315 {
    316 	UINT32 i;
    317 	TSS_RESULT result = TSS_SUCCESS;
    318 
    319 	for (i = 0; i < auth_mgr.auth_mapper_size; i++) {
    320 		if (auth_mgr.auth_mapper[i].full == TRUE &&
    321 		    auth_mgr.auth_mapper[i].tpm_handle == *tpm_auth_handle &&
    322 		    auth_mgr.auth_mapper[i].tcs_ctx == tcsContext) {
    323 			/* We have a record of this session, now swap it into the TPM if need be. */
    324 			if (auth_mgr.auth_mapper[i].swap) {
    325 				LogDebugFn("TPM_LoadAuthContext for TCS %x TPM %x", tcsContext,
    326 					   auth_mgr.auth_mapper[i].tpm_handle);
    327 
    328 				result = TPM_LoadAuthContext(auth_mgr.auth_mapper[i].swap_size,
    329 							     auth_mgr.auth_mapper[i].swap,
    330 							     tpm_auth_handle);
    331 				if (result == TSS_SUCCESS) {
    332 					free(auth_mgr.auth_mapper[i].swap);
    333 					auth_mgr.auth_mapper[i].swap = NULL;
    334 					auth_mgr.auth_mapper[i].swap_size = 0;
    335 
    336 					LogDebugFn("TPM_LoadAuthContext succeeded. Old TPM: %x, New"
    337 						   " TPM: %x", auth_mgr.auth_mapper[i].tpm_handle,
    338 						   *tpm_auth_handle);
    339 
    340 					auth_mgr.auth_mapper[i].tpm_handle = *tpm_auth_handle;
    341 				} else if (result == TPM_E_RESOURCES) {
    342 					if ((result = auth_mgr_swap_out(tcsContext))) {
    343 						LogDebugFn("TPM_LoadAuthContext failed with TPM_E_R"
    344 							   "ESOURCES and swapping out failed, retur"
    345 							   "ning error");
    346 						return result;
    347 					}
    348 
    349 					LogDebugFn("Retrying TPM_LoadAuthContext after swap"
    350 						   " out...");
    351 					result =
    352 					      TPM_LoadAuthContext(auth_mgr.auth_mapper[i].swap_size,
    353 								  auth_mgr.auth_mapper[i].swap,
    354 								  tpm_auth_handle);
    355 					free(auth_mgr.auth_mapper[i].swap);
    356 					auth_mgr.auth_mapper[i].swap = NULL;
    357 					auth_mgr.auth_mapper[i].swap_size = 0;
    358 				} else {
    359 					LogDebug("TPM_LoadAuthContext failed: 0x%x.", result);
    360 				}
    361 			}
    362 
    363 			return result;
    364 		}
    365 	}
    366 
    367 	LogDebugFn("Can't find auth for TCS handle %x, should be %x", tcsContext, *tpm_auth_handle);
    368 	return TCSERR(TSS_E_INTERNAL_ERROR);
    369 }
    370 
    371 TSS_RESULT
    372 auth_mgr_add(TCS_CONTEXT_HANDLE tcsContext, TCS_AUTHHANDLE tpm_auth_handle)
    373 {
    374 	struct auth_map *tmp = auth_mgr.auth_mapper;
    375 	UINT32 i;
    376 
    377 	for (i = 0; i < auth_mgr.auth_mapper_size; i++) {
    378 		if (auth_mgr.auth_mapper[i].full == FALSE) {
    379 			auth_mgr.auth_mapper[i].tpm_handle = tpm_auth_handle;
    380 			auth_mgr.auth_mapper[i].tcs_ctx = tcsContext;
    381 			auth_mgr.auth_mapper[i].full = TRUE;
    382 			auth_mgr.open_auth_sessions++;
    383 			LogDebug("added auth for TCS %x TPM %x", tcsContext, tpm_auth_handle);
    384 
    385 			return TSS_SUCCESS;
    386 		}
    387 	}
    388 
    389 
    390 	LogDebugFn("Thread %ld growing the auth table to %u entries", THREAD_ID,
    391 		   auth_mgr.auth_mapper_size + TSS_DEFAULT_AUTH_TABLE_SIZE);
    392 
    393 	auth_mgr.auth_mapper = calloc(auth_mgr.auth_mapper_size +
    394 				      TSS_DEFAULT_AUTH_TABLE_SIZE, sizeof(struct auth_map));
    395 	if (auth_mgr.auth_mapper == NULL) {
    396 		auth_mgr.auth_mapper = tmp;
    397 		return TCSERR(TSS_E_OUTOFMEMORY);
    398 	} else {
    399 		memcpy(auth_mgr.auth_mapper, tmp,
    400 				auth_mgr.auth_mapper_size * sizeof(struct auth_map));
    401 		auth_mgr.auth_mapper_size += TSS_DEFAULT_AUTH_TABLE_SIZE;
    402 		LogDebugFn("Success.");
    403 		return TSS_SUCCESS;
    404 	}
    405 }
    406 
    407 /* A thread wants a new OIAP or OSAP session with the TPM. Returning TRUE indicates that we should
    408  * allow it to open the session, FALSE to indicate that the request should be queued or have
    409  * another thread's session swapped out to make room for it.
    410  */
    411 TSS_BOOL
    412 auth_mgr_req_new(TCS_CONTEXT_HANDLE hContext)
    413 {
    414 	UINT32 i, opened = 0;
    415 
    416 	for (i = 0; i < auth_mgr.auth_mapper_size; i++) {
    417 		if (auth_mgr.auth_mapper[i].full == TRUE &&
    418 		    auth_mgr.auth_mapper[i].tcs_ctx  == hContext) {
    419 			opened++;
    420 		}
    421 	}
    422 
    423 	/* If this TSP has already opened its max open auth handles, deny another open */
    424 	if (opened >= MAX(2, (UINT32)auth_mgr.max_auth_sessions/2)) {
    425 		LogDebug("Max opened auth handles already opened.");
    426 		return FALSE;
    427 	}
    428 
    429 	/* if we have one opened already and there's a slot available, ok */
    430 	if (opened && ((auth_mgr.max_auth_sessions - auth_mgr.open_auth_sessions) >= 1))
    431 		return TRUE;
    432 
    433 	/* we don't already have one open and there are at least 2 slots left */
    434 	if ((auth_mgr.max_auth_sessions - auth_mgr.open_auth_sessions) >= 2)
    435 		return TRUE;
    436 
    437 	LogDebug("Request for new auth handle denied by TCS. (%d opened sessions)", opened);
    438 
    439 	return FALSE;
    440 }
    441 
    442 TSS_RESULT
    443 auth_mgr_oiap(TCS_CONTEXT_HANDLE hContext,	/* in */
    444 	      TCS_AUTHHANDLE *authHandle,	/* out */
    445 	      TCPA_NONCE *nonce0)		/* out */
    446 {
    447 	TSS_RESULT result;
    448 
    449 	/* are the maximum number of auth sessions open? */
    450 	if (auth_mgr_req_new(hContext) == FALSE) {
    451 		if ((result = auth_mgr_swap_out(hContext)))
    452 			goto done;
    453 	}
    454 
    455 	if ((result = TCSP_OIAP_Internal(hContext, authHandle, nonce0)))
    456 		goto done;
    457 
    458 	/* success, add an entry to the table */
    459 	result = auth_mgr_add(hContext, *authHandle);
    460 done:
    461 	return result;
    462 }
    463 
    464 TSS_RESULT
    465 auth_mgr_osap(TCS_CONTEXT_HANDLE hContext,	/* in */
    466 	      TCPA_ENTITY_TYPE entityType,	/* in */
    467 	      UINT32 entityValue,		/* in */
    468 	      TCPA_NONCE nonceOddOSAP,		/* in */
    469 	      TCS_AUTHHANDLE *authHandle,	/* out */
    470 	      TCPA_NONCE *nonceEven,		/* out */
    471 	      TCPA_NONCE *nonceEvenOSAP)	/* out */
    472 {
    473 	TSS_RESULT result;
    474 	UINT32 newEntValue = 0;
    475 
    476 	/* if ET is not KEYHANDLE or KEY, newEntValue is a don't care */
    477 	if (entityType == TCPA_ET_KEYHANDLE || entityType == TCPA_ET_KEY) {
    478 		if (ensureKeyIsLoaded(hContext, entityValue, &newEntValue))
    479 			return TCSERR(TSS_E_FAIL);
    480 	} else {
    481 		newEntValue = entityValue;
    482 	}
    483 
    484 	/* are the maximum number of auth sessions open? */
    485 	if (auth_mgr_req_new(hContext) == FALSE) {
    486 		if ((result = auth_mgr_swap_out(hContext)))
    487 			goto done;
    488 	}
    489 
    490 	if ((result = TCSP_OSAP_Internal(hContext, entityType, newEntValue, nonceOddOSAP,
    491 					 authHandle, nonceEven, nonceEvenOSAP)))
    492 		goto done;
    493 
    494 	/* success, add an entry to the table */
    495 	result = auth_mgr_add(hContext, *authHandle);
    496 done:
    497 	return result;
    498 }
    499 
    500 /* This function is only called directly from the TSP, we use other internal routines to free
    501  * our handles. */
    502 TSS_RESULT
    503 TCSP_TerminateHandle_Internal(TCS_CONTEXT_HANDLE hContext,	/* in */
    504 			      TCS_AUTHHANDLE handle)	/* in */
    505 {
    506 	TSS_RESULT result;
    507 
    508 	LogDebug("Entering TCSI_TerminateHandle");
    509 	if ((result = ctx_verify_context(hContext)))
    510 		return result;
    511 
    512 	if ((result = auth_mgr_check(hContext, &handle)))
    513 		return result;
    514 
    515 	result = auth_mgr_release_auth_handle(handle, hContext, TRUE);
    516 
    517 	LogResult("Terminate Handle", result);
    518 	return result;
    519 }
    520 
    521 TSS_RESULT
    522 TPM_SaveAuthContext(TPM_AUTHHANDLE handle, UINT32 *size, BYTE **blob)
    523 {
    524 	UINT64 offset;
    525 	UINT32 trash, bsize;
    526 	TSS_RESULT result;
    527 	BYTE txBlob[TSS_TPM_TXBLOB_SIZE];
    528 
    529 	offset = 10;
    530 	LoadBlob_UINT32(&offset, handle, txBlob);
    531 	LoadBlob_Header(TPM_TAG_RQU_COMMAND, offset, TPM_ORD_SaveAuthContext, txBlob);
    532 
    533 	if ((result = req_mgr_submit_req(txBlob)))
    534 		return result;
    535 
    536 	result = UnloadBlob_Header(txBlob, &trash);
    537 
    538 	LogDebug("total packet size received from TPM: %u", trash);
    539 
    540 	if (!result) {
    541 		offset = 10;
    542 		UnloadBlob_UINT32(&offset, &bsize, txBlob);
    543 
    544 		LogDebug("Reported blob size from TPM: %u", bsize);
    545 
    546 		*blob = malloc(bsize);
    547 		if (*blob == NULL) {
    548 			LogError("malloc of %u bytes failed.", bsize);
    549 			return TCSERR(TSS_E_OUTOFMEMORY);
    550 		}
    551 		UnloadBlob(&offset, bsize, txBlob, *blob);
    552 		*size = bsize;
    553 	}
    554 
    555 	return result;
    556 }
    557 
    558 TSS_RESULT
    559 TPM_LoadAuthContext(UINT32 size, BYTE *blob, TPM_AUTHHANDLE *handle)
    560 {
    561 	UINT64 offset;
    562 	UINT32 trash;
    563 	TSS_RESULT result;
    564 	BYTE txBlob[TSS_TPM_TXBLOB_SIZE];
    565 
    566 	LogDebugFn("Loading %u byte auth blob back into TPM", size);
    567 
    568 	offset = 10;
    569 	LoadBlob_UINT32(&offset, size, txBlob);
    570 	LoadBlob(&offset, size, txBlob, blob);
    571 	LoadBlob_Header(TPM_TAG_RQU_COMMAND, offset, TPM_ORD_LoadAuthContext, txBlob);
    572 
    573 	if ((result = req_mgr_submit_req(txBlob)))
    574 		return result;
    575 
    576 	result = UnloadBlob_Header(txBlob, &trash);
    577 
    578 	if (!result) {
    579 		offset = 10;
    580 		UnloadBlob_UINT32(&offset, handle, txBlob);
    581 	}
    582 
    583 	return result;
    584 }
    585