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 
     12 #include <string.h>
     13 
     14 #include "trousers/tss.h"
     15 #include "trousers_types.h"
     16 #include "req_mgr.h"
     17 #include "tcs_tsp.h"
     18 #include "tcslog.h"
     19 #include "tcs_utils.h"
     20 #include "tcs_int_literals.h"
     21 
     22 struct key_mem_cache *key_mem_cache_head = NULL;
     23 
     24 TSS_UUID NULL_UUID = { 0, 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0 } };
     25 
     26 
     27 TSS_RESULT
     28 add_cache_entry(TCS_CONTEXT_HANDLE hContext,
     29 		BYTE*              blob,
     30 		TCS_KEY_HANDLE     hParent,
     31 		TPM_KEY_HANDLE     hSlot,
     32 		TCS_KEY_HANDLE*    new)
     33 {
     34 	UINT64 offset;
     35 	TSS_RESULT result;
     36 	TCS_KEY_HANDLE tcsHandle;
     37 	TSS_KEY key, *pKey;
     38 
     39 	if (!blob) {
     40 		pKey = NULL;
     41 	} else {
     42 		offset = 0;
     43 		if ((result = UnloadBlob_TSS_KEY(&offset, blob, &key)))
     44 			return result;
     45 
     46 		if ((tcsHandle = mc_get_handle_by_pub(&key.pubKey, hParent)) == NULL_TCS_HANDLE) {
     47 			pKey = &key;
     48 		} else {
     49 			mc_set_slot_by_handle(tcsHandle, hSlot);
     50 			*new = tcsHandle;
     51 			goto done;
     52 		}
     53 	}
     54 
     55 	LogDebugFn("No existing key handle for this key, creating new one...");
     56 	/* Get a new TCS Key Handle */
     57 	tcsHandle = getNextTcsKeyHandle();
     58 	LogDebugFn("calling mc_add_entry, TCS handle: 0x%x, TPM handle 0x%x", tcsHandle, hSlot);
     59 
     60 	if ((result = mc_add_entry(tcsHandle, hSlot, pKey)))
     61 		goto done;
     62 
     63 	LogDebugFn("ctx_mark_key_loaded");
     64 	if (ctx_mark_key_loaded(hContext, tcsHandle)) {
     65 		LogError("Error marking key as loaded");
     66 		result = TCSERR(TSS_E_INTERNAL_ERROR);
     67 		goto done;
     68 	}
     69 
     70 	if ((result = mc_set_parent_by_handle(tcsHandle, hParent))) {
     71 		LogError("mc_set_parent_by_handle failed.");
     72 		goto done;
     73 	}
     74 
     75 	*new = tcsHandle;
     76 done:
     77 	if (blob)
     78 		destroy_key_refs(&key);
     79 	return result;
     80 }
     81 
     82 /* Check that the context has this key loaded and return the associated slot. Do not search PS if
     83  * the key is not found */
     84 TSS_RESULT
     85 get_slot_lite(TCS_CONTEXT_HANDLE hContext, TCS_KEY_HANDLE hKey, TPM_KEY_HANDLE *out)
     86 {
     87 	if (ctx_has_key_loaded(hContext, hKey)) {
     88 		if ((*out = mc_get_slot_by_handle(hKey)) == NULL_TPM_HANDLE)
     89 			return TCSERR(TCS_E_INVALID_KEY);
     90 
     91 		return TSS_SUCCESS;
     92 	}
     93 
     94 	return TCSERR(TCS_E_INVALID_KEY);
     95 }
     96 
     97 /* XXX Can get_slot be merged with ensureKeyIsLoaded? */
     98 
     99 /* Given a handle, get_slot searches the mem cache for a mapping to a TPM handle. If there is no
    100  * mapping, it looks up the pub key of the handle and attempts to load it by finding its pub key
    101  * in the persistent store. If that's not found, return error. */
    102 TSS_RESULT
    103 get_slot(TCS_CONTEXT_HANDLE hContext, TCS_KEY_HANDLE hKey, TPM_KEY_HANDLE *out)
    104 {
    105 	TSS_RESULT result = TSS_SUCCESS;
    106 	TPM_STORE_PUBKEY *pub = NULL;
    107 	TPM_KEY_HANDLE slot;
    108 
    109         LogDebugFn("calling mc_get_slot_by_handle");
    110         if ((slot = mc_get_slot_by_handle(hKey)) == NULL_TPM_HANDLE) {
    111                 LogDebugFn("calling mc_get_pub_by_slot");
    112                 if ((pub = mc_get_pub_by_slot(hKey)) == NULL)
    113                         return TCSERR(TCS_E_KM_LOADFAILED);
    114 
    115                 LogDebugFn("calling LoadKeyShim");
    116                 /* Otherwise, try to load it using the shim */
    117                 result = LoadKeyShim(hContext, pub, NULL, &slot);
    118         }
    119 
    120 	if (!result)
    121 		*out = slot;
    122 
    123 	return result;
    124 }
    125 
    126 /* load_key_init is the common entry point for all load key requests to the TCSD. These can come in
    127  * as straight load or load2 requests, or through a transport session.
    128  *
    129  * We'll always attempt to load the key if
    130  * A) It requires auth (load should fail if auth is bad, even when its already been loaded by
    131  *    another thread)
    132  * B) Its in a transport session (the key blob is encrypted)
    133  *
    134  * Otherwise if the key is already loaded by another thread and it doesn't require auth, then we
    135  * will just set *load_key to FALSE, telling the caller that there's no need to send anything to
    136  * the TPM.
    137  */
    138 TSS_RESULT
    139 load_key_init(TPM_COMMAND_CODE   ord,
    140 	      TCS_CONTEXT_HANDLE hContext,
    141 	      TCS_KEY_HANDLE     parent_handle,
    142 	      UINT32             blob_size,
    143 	      BYTE*              blob,
    144 	      TSS_BOOL           encrypted,
    145 	      TPM_AUTH*          auth,
    146 	      TSS_BOOL*          load_key,
    147 	      UINT64*            out_len,
    148 	      BYTE*              out,
    149 	      TCS_KEY_HANDLE*    handle,
    150 	      TPM_KEY_HANDLE*    slot)
    151 {
    152 	TSS_RESULT result = TSS_SUCCESS;
    153 	TSS_KEY key;
    154 	UINT64 offset;
    155 	TPM_KEY_HANDLE tpm_slot;
    156 	TCS_KEY_HANDLE tcs_handle;
    157 	TSS_BOOL canLoad;
    158 
    159 
    160 	if (!encrypted) {
    161 		offset = 0;
    162 		memset(&key, 0, sizeof(TSS_KEY));
    163 		if ((result = UnloadBlob_TSS_KEY(&offset, blob, &key)))
    164 			return result;
    165 	}
    166 
    167 	if (!auth && !encrypted) {
    168 		LogDebugFn("Checking if LoadKeyByBlob can be avoided by using existing key");
    169 
    170 		if ((tcs_handle = mc_get_handle_by_pub(&key.pubKey, parent_handle))) {
    171 			LogDebugFn("tcs key handle exists");
    172 
    173 			tpm_slot = mc_get_slot_by_handle(tcs_handle);
    174 			if (tpm_slot && (isKeyLoaded(tpm_slot) == TRUE)) {
    175 				LogDebugFn("Don't need to reload this key.");
    176 				*handle = tcs_handle;
    177 				*slot = tpm_slot;
    178 				*load_key = FALSE;
    179 				goto done;
    180 			}
    181 		}
    182 	}
    183 	*load_key = TRUE;
    184 
    185 	LogDebugFn("calling canILoadThisKey");
    186 	if (!encrypted) {
    187 		if ((result = canILoadThisKey(&(key.algorithmParms), &canLoad)))
    188 			goto error;
    189 
    190 		if (canLoad == FALSE) {
    191 			LogDebugFn("calling evictFirstKey");
    192 			/* Evict a key that isn't the parent */
    193 			if ((result = evictFirstKey(parent_handle)))
    194 				goto error;
    195 		}
    196 	}
    197 
    198 error:
    199 	if (!encrypted)
    200 		destroy_key_refs(&key);
    201 done:
    202 	return result;
    203 }
    204 
    205 TSS_RESULT
    206 load_key_final(TCS_CONTEXT_HANDLE hContext,
    207 	       TCS_KEY_HANDLE     parent_handle,
    208 	       TCS_KEY_HANDLE*    tcs_handle,
    209 	       BYTE*              blob,
    210 	       TPM_KEY_HANDLE     slot)
    211 {
    212 	if (*tcs_handle == NULL_TCS_HANDLE)
    213 		return add_cache_entry(hContext, blob, parent_handle, slot, tcs_handle);
    214 	else
    215 		return mc_set_slot_by_handle(*tcs_handle, slot);
    216 }
    217 
    218 TSS_RESULT
    219 canILoadThisKey(TCPA_KEY_PARMS *parms, TSS_BOOL *b)
    220 {
    221 	UINT16 subCapLength;
    222 	UINT64 offset;
    223 	BYTE subCap[100];
    224 	TCPA_RESULT result;
    225 	UINT32 respDataLength;
    226 	BYTE *respData;
    227 
    228 	offset = 0;
    229 	LoadBlob_KEY_PARMS(&offset, subCap, parms);
    230 	subCapLength = offset;
    231 
    232 	if ((result = TCSP_GetCapability_Internal(InternalContext, TCPA_CAP_CHECK_LOADED,
    233 						  subCapLength, subCap, &respDataLength,
    234 						  &respData))) {
    235 		*b = FALSE;
    236 		LogDebugFn("NO");
    237 		return result;
    238 	}
    239 
    240 	*b = respData[0];
    241 	free(respData);
    242 	LogDebugFn("%s", *b ? "YES" : "NO");
    243 
    244 	return TSS_SUCCESS;
    245 }
    246 
    247 TCPA_RESULT
    248 internal_EvictByKeySlot(TCPA_KEY_HANDLE slot)
    249 {
    250 	TCPA_RESULT result;
    251 	UINT32 paramSize;
    252 	UINT64 offset;
    253 	BYTE txBlob[TSS_TPM_TXBLOB_SIZE];
    254 
    255 	LogDebug("Entering Evict Key");
    256 
    257 #ifdef TSS_BUILD_TSS12
    258 	if (TPM_VERSION_IS(1,2)) {
    259 		LogDebugFn("Evicting key using FlushSpecific for TPM 1.2");
    260 
    261 		return TCSP_FlushSpecific_Common(slot, TPM_RT_KEY);
    262 	}
    263 #endif
    264 
    265 	offset = 10;
    266 	LoadBlob_UINT32(&offset, slot, txBlob);
    267 	LoadBlob_Header(TPM_TAG_RQU_COMMAND, offset, TPM_ORD_EvictKey, txBlob);
    268 
    269 	if ((result = req_mgr_submit_req(txBlob)))
    270 		return result;
    271 
    272 	result = UnloadBlob_Header(txBlob, &paramSize);
    273 
    274 	LogResult("Evict Key", result);
    275 	return result;
    276 }
    277 
    278 TSS_RESULT
    279 clearUnknownKeys(TCS_CONTEXT_HANDLE hContext, UINT32 *cleared)
    280 {
    281 	TSS_RESULT result = TSS_SUCCESS;
    282 	TCPA_KEY_HANDLE_LIST keyList = { 0, NULL };
    283 	int i;
    284 	BYTE *respData = NULL;
    285 	UINT32 respDataSize = 0, count = 0;
    286 	TCPA_CAPABILITY_AREA capArea = -1;
    287 	UINT64 offset = 0;
    288 	TSS_BOOL found = FALSE;
    289 	struct key_mem_cache *tmp;
    290 
    291 	capArea = TCPA_CAP_KEY_HANDLE;
    292 
    293 	if ((result = TCSP_GetCapability_Internal(hContext, capArea, 0, NULL, &respDataSize,
    294 						  &respData)))
    295 		return result;
    296 
    297 	if ((result = UnloadBlob_KEY_HANDLE_LIST(&offset, respData, &keyList)))
    298 		goto done;
    299 
    300 #ifdef TSS_DEBUG
    301 	LogDebug("Loaded TPM key handles:");
    302 	for (i = 0; i < keyList.loaded; i++) {
    303 		LogDebugFn("%d: %x", i, keyList.handle[i]);
    304 	}
    305 
    306 	LogDebug("Loaded TCSD key handles:");
    307 	i=0;
    308 	for (tmp = key_mem_cache_head; tmp; tmp = tmp->next) {
    309 		LogDebugFn("%d: 0x%x -> 0x%x", i++, tmp->tpm_handle,
    310 			    tmp->tcs_handle);
    311 	}
    312 #endif
    313 
    314 	for (i = 0; i < keyList.loaded; i++) {
    315 		/* as long as we're only called from evictFirstKey(), we don't
    316 		 * need to lock here */
    317 		for (tmp = key_mem_cache_head; tmp; tmp = tmp->next) {
    318 			if (tmp->tpm_handle == keyList.handle[i]) {
    319 				found = TRUE;
    320 				break;
    321 			}
    322 		}
    323 		if (found)
    324 			found = FALSE;
    325 		else {
    326 			if ((result = internal_EvictByKeySlot(keyList.handle[i])))
    327 				goto done;
    328 			else
    329 				count++;
    330 		}
    331 	}
    332 
    333 	*cleared = count;
    334 done:
    335 	free(keyList.handle);
    336 	free(respData);
    337 
    338 	return TSS_SUCCESS;
    339 }
    340 
    341 #if 0
    342 TCPA_RESULT
    343 clearKeysFromChip(TCS_CONTEXT_HANDLE hContext)
    344 {
    345 	TCPA_RESULT result;
    346 	TCPA_KEY_HANDLE_LIST keyList;
    347 	UINT32 i;
    348 	BYTE *respData = 0;
    349 	UINT32 respDataSize = 0;
    350 	TCPA_CAPABILITY_AREA capArea = -1;
    351 	UINT64 offset = 0;
    352 
    353 	capArea = TCPA_CAP_KEY_HANDLE;
    354 
    355 	if ((result = TCSP_GetCapability_Internal(hContext, capArea, 0, NULL,
    356 					&respDataSize, &respData)))
    357 		return result;
    358 
    359 	if ((result = UnloadBlob_KEY_HANDLE_LIST(&offset, respData, &keyList)))
    360 		return result;
    361 	for (i = 0; i < keyList.loaded; i++) {
    362 		if (keyList.handle[i] == SRK_TPM_HANDLE ||	/*can't evict SRK */
    363 		    keyList.handle[i] == EK_TPM_HANDLE)	/*can't evict EK */
    364 			continue;
    365 		if ((result = internal_EvictByKeySlot(keyList.handle[i])))
    366 			return result;
    367 	}
    368 	return TSS_SUCCESS;
    369 }
    370 #endif
    371 
    372 void
    373 LoadBlob_KEY_PARMS(UINT64 *offset, BYTE *blob, TCPA_KEY_PARMS *keyInfo)
    374 {
    375 	LoadBlob_UINT32(offset, keyInfo->algorithmID, blob);
    376 	LoadBlob_UINT16(offset, keyInfo->encScheme, blob);
    377 	LoadBlob_UINT16(offset, keyInfo->sigScheme, blob);
    378 	LoadBlob_UINT32(offset, keyInfo->parmSize, blob);
    379 	LoadBlob(offset, keyInfo->parmSize, blob, keyInfo->parms);
    380 }
    381 
    382 TSS_RESULT
    383 UnloadBlob_STORE_PUBKEY(UINT64 *offset, BYTE *blob, TCPA_STORE_PUBKEY *store)
    384 {
    385 	if (!store) {
    386 		UINT32 keyLength;
    387 
    388 		UnloadBlob_UINT32(offset, &keyLength, blob);
    389 
    390 		if (keyLength > 0)
    391 			UnloadBlob(offset, keyLength, blob, NULL);
    392 
    393 		return TSS_SUCCESS;
    394 	}
    395 
    396 	UnloadBlob_UINT32(offset, &store->keyLength, blob);
    397 
    398 	if (store->keyLength == 0) {
    399 		store->key = NULL;
    400 		LogWarn("Unloading a public key of size 0!");
    401 	} else {
    402 		store->key = (BYTE *)malloc(store->keyLength);
    403 		if (store->key == NULL) {
    404 			LogError("malloc of %u bytes failed.", store->keyLength);
    405 			store->keyLength = 0;
    406 			return TCSERR(TSS_E_OUTOFMEMORY);
    407 		}
    408 
    409 		UnloadBlob(offset, store->keyLength, blob, store->key);
    410 	}
    411 
    412 	return TSS_SUCCESS;
    413 }
    414 
    415 void
    416 LoadBlob_STORE_PUBKEY(UINT64 *offset, BYTE * blob, TCPA_STORE_PUBKEY * store)
    417 {
    418 	LoadBlob_UINT32(offset, store->keyLength, blob);
    419 	LoadBlob(offset, store->keyLength, blob, store->key);
    420 }
    421 
    422 TSS_RESULT
    423 UnloadBlob_TSS_KEY(UINT64 *offset, BYTE *blob, TSS_KEY *key)
    424 {
    425 	TSS_RESULT rc;
    426 
    427 	if (!key) {
    428 		UINT32 size;
    429 
    430 		/* TPM_KEY's ver and TPM_KEY12's tag/file are
    431 		   the same size, so... */
    432 		UnloadBlob_VERSION(offset, blob, NULL);
    433 		UnloadBlob_UINT16(offset, NULL, blob);
    434 		UnloadBlob_KEY_FLAGS(offset, blob, NULL);
    435 		UnloadBlob_BOOL(offset, NULL, blob);
    436 		if ((rc = UnloadBlob_KEY_PARMS(offset, blob, NULL)))
    437 			return rc;
    438 		UnloadBlob_UINT32(offset, &size, blob);
    439 
    440 		if (size > 0)
    441 			UnloadBlob(offset, size, blob, NULL);
    442 
    443 		if ((rc = UnloadBlob_STORE_PUBKEY(offset, blob, NULL)))
    444 			return rc;
    445 
    446 		UnloadBlob_UINT32(offset, &size, blob);
    447 
    448 		if (size > 0)
    449 			UnloadBlob(offset, size, blob, NULL);
    450 
    451 		return TSS_SUCCESS;
    452 	}
    453 
    454 	if (key->hdr.key12.tag == TPM_TAG_KEY12) {
    455 		UnloadBlob_UINT16(offset, &key->hdr.key12.tag, blob);
    456 		UnloadBlob_UINT16(offset, &key->hdr.key12.fill, blob);
    457 	} else
    458 		UnloadBlob_TCPA_VERSION(offset, blob, &key->hdr.key11.ver);
    459 	UnloadBlob_UINT16(offset, &key->keyUsage, blob);
    460 	UnloadBlob_KEY_FLAGS(offset, blob, &key->keyFlags);
    461 	UnloadBlob_BOOL(offset, (TSS_BOOL *)&key->authDataUsage, blob);
    462 	if ((rc = UnloadBlob_KEY_PARMS(offset, blob, &key->algorithmParms)))
    463 		return rc;
    464 	UnloadBlob_UINT32(offset, &key->PCRInfoSize, blob);
    465 
    466 	if (key->PCRInfoSize == 0)
    467 		key->PCRInfo = NULL;
    468 	else {
    469 		key->PCRInfo = malloc(key->PCRInfoSize);
    470 		if (key->PCRInfo == NULL) {
    471 			LogError("malloc of %u bytes failed.", key->PCRInfoSize);
    472 			key->PCRInfoSize = 0;
    473 			free(key->algorithmParms.parms);
    474 			key->algorithmParms.parms = NULL;
    475 			key->algorithmParms.parmSize = 0;
    476 			return TCSERR(TSS_E_OUTOFMEMORY);
    477 		}
    478 		UnloadBlob(offset, key->PCRInfoSize, blob, key->PCRInfo);
    479 	}
    480 
    481 	if ((rc = UnloadBlob_STORE_PUBKEY(offset, blob, &key->pubKey))) {
    482 		free(key->PCRInfo);
    483 		key->PCRInfo = NULL;
    484 		key->PCRInfoSize = 0;
    485 		free(key->algorithmParms.parms);
    486 		key->algorithmParms.parms = NULL;
    487 		key->algorithmParms.parmSize = 0;
    488 		return rc;
    489 	}
    490 	UnloadBlob_UINT32(offset, &key->encSize, blob);
    491 
    492 	if (key->encSize == 0)
    493 		key->encData = NULL;
    494 	else {
    495 		key->encData = (BYTE *)malloc(key->encSize);
    496 		if (key->encData == NULL) {
    497 			LogError("malloc of %d bytes failed.", key->encSize);
    498 			key->encSize = 0;
    499 			free(key->algorithmParms.parms);
    500 			key->algorithmParms.parms = NULL;
    501 			key->algorithmParms.parmSize = 0;
    502 			free(key->PCRInfo);
    503 			key->PCRInfo = NULL;
    504 			key->PCRInfoSize = 0;
    505 			free(key->pubKey.key);
    506 			key->pubKey.key = NULL;
    507 			key->pubKey.keyLength = 0;
    508 			return TCSERR(TSS_E_OUTOFMEMORY);
    509 		}
    510 		UnloadBlob(offset, key->encSize, blob, key->encData);
    511 	}
    512 
    513 	return TSS_SUCCESS;
    514 }
    515 
    516 void
    517 LoadBlob_TSS_KEY(UINT64 *offset, BYTE * blob, TSS_KEY * key)
    518 {
    519 	if (key->hdr.key12.tag == TPM_TAG_KEY12) {
    520 		LoadBlob_UINT16(offset, key->hdr.key12.tag, blob);
    521 		LoadBlob_UINT16(offset, key->hdr.key12.fill, blob);
    522 	} else
    523 		LoadBlob_TCPA_VERSION(offset, blob, &key->hdr.key11.ver);
    524 	LoadBlob_UINT16(offset, key->keyUsage, blob);
    525 	LoadBlob_KEY_FLAGS(offset, blob, &key->keyFlags);
    526 	LoadBlob_BOOL(offset, key->authDataUsage, blob);
    527 	LoadBlob_KEY_PARMS(offset, blob, &key->algorithmParms);
    528 	LoadBlob_UINT32(offset, key->PCRInfoSize, blob);
    529 	LoadBlob(offset, key->PCRInfoSize, blob, key->PCRInfo);
    530 	LoadBlob_STORE_PUBKEY(offset, blob, &key->pubKey);
    531 	LoadBlob_UINT32(offset, key->encSize, blob);
    532 	LoadBlob(offset, key->encSize, blob, key->encData);
    533 }
    534 
    535 void
    536 LoadBlob_PUBKEY(UINT64 *offset, BYTE * blob, TCPA_PUBKEY * key)
    537 {
    538 	LoadBlob_KEY_PARMS(offset, blob, &(key->algorithmParms));
    539 	LoadBlob_STORE_PUBKEY(offset, blob, &(key->pubKey));
    540 }
    541 
    542 TSS_RESULT
    543 UnloadBlob_PUBKEY(UINT64 *offset, BYTE *blob, TCPA_PUBKEY *key)
    544 {
    545 	TSS_RESULT rc;
    546 
    547 	if (!key) {
    548 		if ((rc = UnloadBlob_KEY_PARMS(offset, blob, NULL)))
    549 			return rc;
    550 		return UnloadBlob_STORE_PUBKEY(offset, blob, NULL);
    551 	}
    552 
    553 	if ((rc = UnloadBlob_KEY_PARMS(offset, blob, &key->algorithmParms)))
    554 		return rc;
    555 	if ((rc = UnloadBlob_STORE_PUBKEY(offset, blob, &key->pubKey))) {
    556 		free(key->algorithmParms.parms);
    557 		key->algorithmParms.parms = NULL;
    558 		key->algorithmParms.parmSize = 0;
    559 	}
    560 
    561 	return rc;
    562 }
    563 
    564 void
    565 LoadBlob_KEY_FLAGS(UINT64 *offset, BYTE * blob, TCPA_KEY_FLAGS * flags)
    566 {
    567 	LoadBlob_UINT32(offset, *flags, blob);
    568 }
    569 
    570 void
    571 destroy_key_refs(TSS_KEY *key)
    572 {
    573 	free(key->algorithmParms.parms);
    574 	key->algorithmParms.parms = NULL;
    575 	key->algorithmParms.parmSize = 0;
    576 
    577 	free(key->pubKey.key);
    578 	key->pubKey.key = NULL;
    579 	key->pubKey.keyLength = 0;
    580 
    581 	free(key->encData);
    582 	key->encData = NULL;
    583 	key->encSize = 0;
    584 
    585 	free(key->PCRInfo);
    586 	key->PCRInfo = NULL;
    587 	key->PCRInfoSize = 0;
    588 }
    589