diff options
Diffstat (limited to 'src/tcs/tcs_key.c')
-rw-r--r-- | src/tcs/tcs_key.c | 588 |
1 files changed, 588 insertions, 0 deletions
diff --git a/src/tcs/tcs_key.c b/src/tcs/tcs_key.c new file mode 100644 index 0000000..bb73f57 --- /dev/null +++ b/src/tcs/tcs_key.c @@ -0,0 +1,588 @@ + +/* + * Licensed Materials - Property of IBM + * + * trousers - An open source TCG Software Stack + * + * (C) Copyright International Business Machines Corp. 2004-2006 + * + */ + + +#include <string.h> + +#include "trousers/tss.h" +#include "trousers_types.h" +#include "req_mgr.h" +#include "tcs_tsp.h" +#include "tcslog.h" +#include "tcs_utils.h" +#include "tcs_int_literals.h" + +struct key_mem_cache *key_mem_cache_head = NULL; + +TSS_UUID NULL_UUID = { 0, 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0 } }; + + +TSS_RESULT +add_cache_entry(TCS_CONTEXT_HANDLE hContext, + BYTE* blob, + TCS_KEY_HANDLE hParent, + TPM_KEY_HANDLE hSlot, + TCS_KEY_HANDLE* new) +{ + UINT64 offset; + TSS_RESULT result; + TCS_KEY_HANDLE tcsHandle; + TSS_KEY key, *pKey; + + if (!blob) { + pKey = NULL; + } else { + offset = 0; + if ((result = UnloadBlob_TSS_KEY(&offset, blob, &key))) + return result; + + if ((tcsHandle = mc_get_handle_by_pub(&key.pubKey, hParent)) == NULL_TCS_HANDLE) { + pKey = &key; + } else { + mc_set_slot_by_handle(tcsHandle, hSlot); + *new = tcsHandle; + goto done; + } + } + + LogDebugFn("No existing key handle for this key, creating new one..."); + /* Get a new TCS Key Handle */ + tcsHandle = getNextTcsKeyHandle(); + LogDebugFn("calling mc_add_entry, TCS handle: 0x%x, TPM handle 0x%x", tcsHandle, hSlot); + + if ((result = mc_add_entry(tcsHandle, hSlot, pKey))) + goto done; + + LogDebugFn("ctx_mark_key_loaded"); + if (ctx_mark_key_loaded(hContext, tcsHandle)) { + LogError("Error marking key as loaded"); + result = TCSERR(TSS_E_INTERNAL_ERROR); + goto done; + } + + if ((result = mc_set_parent_by_handle(tcsHandle, hParent))) { + LogError("mc_set_parent_by_handle failed."); + goto done; + } + + *new = tcsHandle; +done: + if (blob) + destroy_key_refs(&key); + return result; +} + +/* Check that the context has this key loaded and return the associated slot. Do not search PS if + * the key is not found */ +TSS_RESULT +get_slot_lite(TCS_CONTEXT_HANDLE hContext, TCS_KEY_HANDLE hKey, TPM_KEY_HANDLE *out) +{ + if (ctx_has_key_loaded(hContext, hKey)) { + if ((*out = mc_get_slot_by_handle(hKey)) == NULL_TPM_HANDLE) + return TCSERR(TCS_E_INVALID_KEY); + + return TSS_SUCCESS; + } + + return TCSERR(TCS_E_INVALID_KEY); +} + +/* XXX Can get_slot be merged with ensureKeyIsLoaded? */ + +/* Given a handle, get_slot searches the mem cache for a mapping to a TPM handle. If there is no + * mapping, it looks up the pub key of the handle and attempts to load it by finding its pub key + * in the persistent store. If that's not found, return error. */ +TSS_RESULT +get_slot(TCS_CONTEXT_HANDLE hContext, TCS_KEY_HANDLE hKey, TPM_KEY_HANDLE *out) +{ + TSS_RESULT result = TSS_SUCCESS; + TPM_STORE_PUBKEY *pub = NULL; + TPM_KEY_HANDLE slot; + + LogDebugFn("calling mc_get_slot_by_handle"); + if ((slot = mc_get_slot_by_handle(hKey)) == NULL_TPM_HANDLE) { + LogDebugFn("calling mc_get_pub_by_slot"); + if ((pub = mc_get_pub_by_slot(hKey)) == NULL) + return TCSERR(TCS_E_KM_LOADFAILED); + + LogDebugFn("calling LoadKeyShim"); + /* Otherwise, try to load it using the shim */ + result = LoadKeyShim(hContext, pub, NULL, &slot); + } + + if (!result) + *out = slot; + + return result; +} + +/* load_key_init is the common entry point for all load key requests to the TCSD. These can come in + * as straight load or load2 requests, or through a transport session. + * + * We'll always attempt to load the key if + * A) It requires auth (load should fail if auth is bad, even when its already been loaded by + * another thread) + * B) Its in a transport session (the key blob is encrypted) + * + * Otherwise if the key is already loaded by another thread and it doesn't require auth, then we + * will just set *load_key to FALSE, telling the caller that there's no need to send anything to + * the TPM. + */ +TSS_RESULT +load_key_init(TPM_COMMAND_CODE ord, + TCS_CONTEXT_HANDLE hContext, + TCS_KEY_HANDLE parent_handle, + UINT32 blob_size, + BYTE* blob, + TSS_BOOL encrypted, + TPM_AUTH* auth, + TSS_BOOL* load_key, + UINT64* out_len, + BYTE* out, + TCS_KEY_HANDLE* handle, + TPM_KEY_HANDLE* slot) +{ + TSS_RESULT result = TSS_SUCCESS; + TSS_KEY key; + UINT64 offset; + TPM_KEY_HANDLE tpm_slot; + TCS_KEY_HANDLE tcs_handle; + TSS_BOOL canLoad; + + + if (!encrypted) { + offset = 0; + memset(&key, 0, sizeof(TSS_KEY)); + if ((result = UnloadBlob_TSS_KEY(&offset, blob, &key))) + return result; + } + + if (!auth && !encrypted) { + LogDebugFn("Checking if LoadKeyByBlob can be avoided by using existing key"); + + if ((tcs_handle = mc_get_handle_by_pub(&key.pubKey, parent_handle))) { + LogDebugFn("tcs key handle exists"); + + tpm_slot = mc_get_slot_by_handle(tcs_handle); + if (tpm_slot && (isKeyLoaded(tpm_slot) == TRUE)) { + LogDebugFn("Don't need to reload this key."); + *handle = tcs_handle; + *slot = tpm_slot; + *load_key = FALSE; + goto done; + } + } + } + *load_key = TRUE; + + LogDebugFn("calling canILoadThisKey"); + if (!encrypted) { + if ((result = canILoadThisKey(&(key.algorithmParms), &canLoad))) + goto error; + + if (canLoad == FALSE) { + LogDebugFn("calling evictFirstKey"); + /* Evict a key that isn't the parent */ + if ((result = evictFirstKey(parent_handle))) + goto error; + } + } + +error: + if (!encrypted) + destroy_key_refs(&key); +done: + return result; +} + +TSS_RESULT +load_key_final(TCS_CONTEXT_HANDLE hContext, + TCS_KEY_HANDLE parent_handle, + TCS_KEY_HANDLE* tcs_handle, + BYTE* blob, + TPM_KEY_HANDLE slot) +{ + if (*tcs_handle == NULL_TCS_HANDLE) + return add_cache_entry(hContext, blob, parent_handle, slot, tcs_handle); + else + return mc_set_slot_by_handle(*tcs_handle, slot); +} + +TSS_RESULT +canILoadThisKey(TCPA_KEY_PARMS *parms, TSS_BOOL *b) +{ + UINT16 subCapLength; + UINT64 offset; + BYTE subCap[100]; + TCPA_RESULT result; + UINT32 respDataLength; + BYTE *respData; + + offset = 0; + LoadBlob_KEY_PARMS(&offset, subCap, parms); + subCapLength = offset; + + if ((result = TCSP_GetCapability_Internal(InternalContext, TCPA_CAP_CHECK_LOADED, + subCapLength, subCap, &respDataLength, + &respData))) { + *b = FALSE; + LogDebugFn("NO"); + return result; + } + + *b = respData[0]; + free(respData); + LogDebugFn("%s", *b ? "YES" : "NO"); + + return TSS_SUCCESS; +} + +TCPA_RESULT +internal_EvictByKeySlot(TCPA_KEY_HANDLE slot) +{ + TCPA_RESULT result; + UINT32 paramSize; + UINT64 offset; + BYTE txBlob[TSS_TPM_TXBLOB_SIZE]; + + LogDebug("Entering Evict Key"); + +#ifdef TSS_BUILD_TSS12 + if (TPM_VERSION_IS(1,2)) { + LogDebugFn("Evicting key using FlushSpecific for TPM 1.2"); + + return TCSP_FlushSpecific_Common(slot, TPM_RT_KEY); + } +#endif + + offset = 10; + LoadBlob_UINT32(&offset, slot, txBlob); + LoadBlob_Header(TPM_TAG_RQU_COMMAND, offset, TPM_ORD_EvictKey, txBlob); + + if ((result = req_mgr_submit_req(txBlob))) + return result; + + result = UnloadBlob_Header(txBlob, ¶mSize); + + LogResult("Evict Key", result); + return result; +} + +TSS_RESULT +clearUnknownKeys(TCS_CONTEXT_HANDLE hContext, UINT32 *cleared) +{ + TSS_RESULT result = TSS_SUCCESS; + TCPA_KEY_HANDLE_LIST keyList = { 0, NULL }; + int i; + BYTE *respData = NULL; + UINT32 respDataSize = 0, count = 0; + TCPA_CAPABILITY_AREA capArea = -1; + UINT64 offset = 0; + TSS_BOOL found = FALSE; + struct key_mem_cache *tmp; + + capArea = TCPA_CAP_KEY_HANDLE; + + if ((result = TCSP_GetCapability_Internal(hContext, capArea, 0, NULL, &respDataSize, + &respData))) + return result; + + if ((result = UnloadBlob_KEY_HANDLE_LIST(&offset, respData, &keyList))) + goto done; + +#ifdef TSS_DEBUG + LogDebug("Loaded TPM key handles:"); + for (i = 0; i < keyList.loaded; i++) { + LogDebugFn("%d: %x", i, keyList.handle[i]); + } + + LogDebug("Loaded TCSD key handles:"); + i=0; + for (tmp = key_mem_cache_head; tmp; tmp = tmp->next) { + LogDebugFn("%d: 0x%x -> 0x%x", i++, tmp->tpm_handle, + tmp->tcs_handle); + } +#endif + + for (i = 0; i < keyList.loaded; i++) { + /* as long as we're only called from evictFirstKey(), we don't + * need to lock here */ + for (tmp = key_mem_cache_head; tmp; tmp = tmp->next) { + if (tmp->tpm_handle == keyList.handle[i]) { + found = TRUE; + break; + } + } + if (found) + found = FALSE; + else { + if ((result = internal_EvictByKeySlot(keyList.handle[i]))) + goto done; + else + count++; + } + } + + *cleared = count; +done: + free(keyList.handle); + free(respData); + + return TSS_SUCCESS; +} + +#if 0 +TCPA_RESULT +clearKeysFromChip(TCS_CONTEXT_HANDLE hContext) +{ + TCPA_RESULT result; + TCPA_KEY_HANDLE_LIST keyList; + UINT32 i; + BYTE *respData = 0; + UINT32 respDataSize = 0; + TCPA_CAPABILITY_AREA capArea = -1; + UINT64 offset = 0; + + capArea = TCPA_CAP_KEY_HANDLE; + + if ((result = TCSP_GetCapability_Internal(hContext, capArea, 0, NULL, + &respDataSize, &respData))) + return result; + + if ((result = UnloadBlob_KEY_HANDLE_LIST(&offset, respData, &keyList))) + return result; + for (i = 0; i < keyList.loaded; i++) { + if (keyList.handle[i] == SRK_TPM_HANDLE || /*can't evict SRK */ + keyList.handle[i] == EK_TPM_HANDLE) /*can't evict EK */ + continue; + if ((result = internal_EvictByKeySlot(keyList.handle[i]))) + return result; + } + return TSS_SUCCESS; +} +#endif + +void +LoadBlob_KEY_PARMS(UINT64 *offset, BYTE *blob, TCPA_KEY_PARMS *keyInfo) +{ + LoadBlob_UINT32(offset, keyInfo->algorithmID, blob); + LoadBlob_UINT16(offset, keyInfo->encScheme, blob); + LoadBlob_UINT16(offset, keyInfo->sigScheme, blob); + LoadBlob_UINT32(offset, keyInfo->parmSize, blob); + LoadBlob(offset, keyInfo->parmSize, blob, keyInfo->parms); +} + +TSS_RESULT +UnloadBlob_STORE_PUBKEY(UINT64 *offset, BYTE *blob, TCPA_STORE_PUBKEY *store) +{ + if (!store) { + UINT32 keyLength; + + UnloadBlob_UINT32(offset, &keyLength, blob); + + if (keyLength > 0) + UnloadBlob(offset, keyLength, blob, NULL); + + return TSS_SUCCESS; + } + + UnloadBlob_UINT32(offset, &store->keyLength, blob); + + if (store->keyLength == 0) { + store->key = NULL; + LogWarn("Unloading a public key of size 0!"); + } else { + store->key = (BYTE *)malloc(store->keyLength); + if (store->key == NULL) { + LogError("malloc of %u bytes failed.", store->keyLength); + store->keyLength = 0; + return TCSERR(TSS_E_OUTOFMEMORY); + } + + UnloadBlob(offset, store->keyLength, blob, store->key); + } + + return TSS_SUCCESS; +} + +void +LoadBlob_STORE_PUBKEY(UINT64 *offset, BYTE * blob, TCPA_STORE_PUBKEY * store) +{ + LoadBlob_UINT32(offset, store->keyLength, blob); + LoadBlob(offset, store->keyLength, blob, store->key); +} + +TSS_RESULT +UnloadBlob_TSS_KEY(UINT64 *offset, BYTE *blob, TSS_KEY *key) +{ + TSS_RESULT rc; + + if (!key) { + UINT32 size; + + /* TPM_KEY's ver and TPM_KEY12's tag/file are + the same size, so... */ + UnloadBlob_VERSION(offset, blob, NULL); + UnloadBlob_UINT16(offset, NULL, blob); + UnloadBlob_KEY_FLAGS(offset, blob, NULL); + UnloadBlob_BOOL(offset, NULL, blob); + if ((rc = UnloadBlob_KEY_PARMS(offset, blob, NULL))) + return rc; + UnloadBlob_UINT32(offset, &size, blob); + + if (size > 0) + UnloadBlob(offset, size, blob, NULL); + + if ((rc = UnloadBlob_STORE_PUBKEY(offset, blob, NULL))) + return rc; + + UnloadBlob_UINT32(offset, &size, blob); + + if (size > 0) + UnloadBlob(offset, size, blob, NULL); + + return TSS_SUCCESS; + } + + if (key->hdr.key12.tag == TPM_TAG_KEY12) { + UnloadBlob_UINT16(offset, &key->hdr.key12.tag, blob); + UnloadBlob_UINT16(offset, &key->hdr.key12.fill, blob); + } else + UnloadBlob_TCPA_VERSION(offset, blob, &key->hdr.key11.ver); + UnloadBlob_UINT16(offset, &key->keyUsage, blob); + UnloadBlob_KEY_FLAGS(offset, blob, &key->keyFlags); + UnloadBlob_BOOL(offset, (TSS_BOOL *)&key->authDataUsage, blob); + if ((rc = UnloadBlob_KEY_PARMS(offset, blob, &key->algorithmParms))) + return rc; + UnloadBlob_UINT32(offset, &key->PCRInfoSize, blob); + + if (key->PCRInfoSize == 0) + key->PCRInfo = NULL; + else { + key->PCRInfo = malloc(key->PCRInfoSize); + if (key->PCRInfo == NULL) { + LogError("malloc of %u bytes failed.", key->PCRInfoSize); + key->PCRInfoSize = 0; + free(key->algorithmParms.parms); + key->algorithmParms.parms = NULL; + key->algorithmParms.parmSize = 0; + return TCSERR(TSS_E_OUTOFMEMORY); + } + UnloadBlob(offset, key->PCRInfoSize, blob, key->PCRInfo); + } + + if ((rc = UnloadBlob_STORE_PUBKEY(offset, blob, &key->pubKey))) { + free(key->PCRInfo); + key->PCRInfo = NULL; + key->PCRInfoSize = 0; + free(key->algorithmParms.parms); + key->algorithmParms.parms = NULL; + key->algorithmParms.parmSize = 0; + return rc; + } + UnloadBlob_UINT32(offset, &key->encSize, blob); + + if (key->encSize == 0) + key->encData = NULL; + else { + key->encData = (BYTE *)malloc(key->encSize); + if (key->encData == NULL) { + LogError("malloc of %d bytes failed.", key->encSize); + key->encSize = 0; + free(key->algorithmParms.parms); + key->algorithmParms.parms = NULL; + key->algorithmParms.parmSize = 0; + free(key->PCRInfo); + key->PCRInfo = NULL; + key->PCRInfoSize = 0; + free(key->pubKey.key); + key->pubKey.key = NULL; + key->pubKey.keyLength = 0; + return TCSERR(TSS_E_OUTOFMEMORY); + } + UnloadBlob(offset, key->encSize, blob, key->encData); + } + + return TSS_SUCCESS; +} + +void +LoadBlob_TSS_KEY(UINT64 *offset, BYTE * blob, TSS_KEY * key) +{ + if (key->hdr.key12.tag == TPM_TAG_KEY12) { + LoadBlob_UINT16(offset, key->hdr.key12.tag, blob); + LoadBlob_UINT16(offset, key->hdr.key12.fill, blob); + } else + LoadBlob_TCPA_VERSION(offset, blob, &key->hdr.key11.ver); + LoadBlob_UINT16(offset, key->keyUsage, blob); + LoadBlob_KEY_FLAGS(offset, blob, &key->keyFlags); + LoadBlob_BOOL(offset, key->authDataUsage, blob); + LoadBlob_KEY_PARMS(offset, blob, &key->algorithmParms); + LoadBlob_UINT32(offset, key->PCRInfoSize, blob); + LoadBlob(offset, key->PCRInfoSize, blob, key->PCRInfo); + LoadBlob_STORE_PUBKEY(offset, blob, &key->pubKey); + LoadBlob_UINT32(offset, key->encSize, blob); + LoadBlob(offset, key->encSize, blob, key->encData); +} + +void +LoadBlob_PUBKEY(UINT64 *offset, BYTE * blob, TCPA_PUBKEY * key) +{ + LoadBlob_KEY_PARMS(offset, blob, &(key->algorithmParms)); + LoadBlob_STORE_PUBKEY(offset, blob, &(key->pubKey)); +} + +TSS_RESULT +UnloadBlob_PUBKEY(UINT64 *offset, BYTE *blob, TCPA_PUBKEY *key) +{ + TSS_RESULT rc; + + if (!key) { + if ((rc = UnloadBlob_KEY_PARMS(offset, blob, NULL))) + return rc; + return UnloadBlob_STORE_PUBKEY(offset, blob, NULL); + } + + if ((rc = UnloadBlob_KEY_PARMS(offset, blob, &key->algorithmParms))) + return rc; + if ((rc = UnloadBlob_STORE_PUBKEY(offset, blob, &key->pubKey))) { + free(key->algorithmParms.parms); + key->algorithmParms.parms = NULL; + key->algorithmParms.parmSize = 0; + } + + return rc; +} + +void +LoadBlob_KEY_FLAGS(UINT64 *offset, BYTE * blob, TCPA_KEY_FLAGS * flags) +{ + LoadBlob_UINT32(offset, *flags, blob); +} + +void +destroy_key_refs(TSS_KEY *key) +{ + free(key->algorithmParms.parms); + key->algorithmParms.parms = NULL; + key->algorithmParms.parmSize = 0; + + free(key->pubKey.key); + key->pubKey.key = NULL; + key->pubKey.keyLength = 0; + + free(key->encData); + key->encData = NULL; + key->encSize = 0; + + free(key->PCRInfo); + key->PCRInfo = NULL; + key->PCRInfoSize = 0; +} |