diff options
Diffstat (limited to 'src/tcs/tcsi_ps.c')
-rw-r--r-- | src/tcs/tcsi_ps.c | 636 |
1 files changed, 636 insertions, 0 deletions
diff --git a/src/tcs/tcsi_ps.c b/src/tcs/tcsi_ps.c new file mode 100644 index 0000000..87db219 --- /dev/null +++ b/src/tcs/tcsi_ps.c @@ -0,0 +1,636 @@ + +/* + * Licensed Materials - Property of IBM + * + * trousers - An open source TCG Software Stack + * + * (C) Copyright International Business Machines Corp. 2004 + * + */ + + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "trousers/tss.h" +#include "trousers_types.h" +#include "tcs_tsp.h" +#include "tcs_utils.h" +#include "tcs_int_literals.h" +#include "capabilities.h" +#include "tcslog.h" +#include "tcsps.h" + +TSS_RESULT +TCS_RegisterKey_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ + TSS_UUID *WrappingKeyUUID, /* in */ + TSS_UUID *KeyUUID, /* in */ + UINT32 cKeySize, /* in */ + BYTE * rgbKey, /* in */ + UINT32 cVendorData, /* in */ + BYTE * gbVendorData) /* in */ +{ + TSS_RESULT result; + TSS_BOOL is_reg; + + if ((result = ctx_verify_context(hContext))) + return result; + + /* Check if key is already regisitered */ + if (isUUIDRegistered(KeyUUID, &is_reg) != TSS_SUCCESS) { + LogError("Failed checking if UUID is registered."); + return TCSERR(TSS_E_INTERNAL_ERROR); + } + + if (is_reg == TRUE || TSS_UUID_IS_OWNEREVICT(KeyUUID)) { + LogDebug("UUID is already registered"); + return TCSERR(TSS_E_KEY_ALREADY_REGISTERED); + } + + LogDebugUnrollKey(rgbKey); + + /* Go ahead and store it in system persistant storage */ + if ((result = ps_write_key(KeyUUID, WrappingKeyUUID, gbVendorData, cVendorData, rgbKey, + cKeySize))) { + LogError("Error writing key to file"); + return result; + } + + return TSS_SUCCESS; +} + +TSS_RESULT +TCS_UnregisterKey_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ + TSS_UUID KeyUUID) /* in */ +{ + TSS_RESULT result; + + if ((result = ctx_verify_context(hContext))) + return result; + + return ps_remove_key(&KeyUUID); +} + +TSS_RESULT +TCS_EnumRegisteredKeys_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ + TSS_UUID * pKeyUUID, /* in */ + UINT32 * pcKeyHierarchySize, /* out */ + TSS_KM_KEYINFO ** ppKeyHierarchy) /* out */ +{ + TSS_RESULT result = TSS_SUCCESS; + UINT32 count = 0, i; + TSS_KM_KEYINFO *ret = NULL; + TSS_UUID tmp_uuid; + struct key_disk_cache *disk_ptr, *tmp_ptrs[MAX_KEY_CHILDREN]; + struct key_mem_cache *mem_ptr; + TSS_BOOL is_reg = FALSE; + + LogDebug("Enum Reg Keys"); + + if (pcKeyHierarchySize == NULL || ppKeyHierarchy == NULL) + return TCSERR(TSS_E_BAD_PARAMETER); + + if ((result = ctx_verify_context(hContext))) + return result; + + if (pKeyUUID != NULL) { + /* First have to verify the key is registered */ + if ((result = isUUIDRegistered(pKeyUUID, &is_reg))) + return result; + + if (is_reg == FALSE) { + /* This return code is not listed as possible in the TSS 1.1 spec, + * but it makes more sense than just TCS_SUCCESS or TSS_E_FAIL */ + return TCSERR(TSS_E_PS_KEY_NOTFOUND); + } + } + + /* this entire operation needs to be atomic wrt registered keys. We must + * lock the mem cache as well to test if a given key is loaded. */ + MUTEX_LOCK(disk_cache_lock); + MUTEX_LOCK(mem_cache_lock); + + /* return an array of all registered keys if pKeyUUID == NULL */ + if (pKeyUUID == NULL) { + /* determine the number of registered keys */ + for (disk_ptr = key_disk_cache_head; disk_ptr; disk_ptr = disk_ptr->next) { + if (disk_ptr->flags & CACHE_FLAG_VALID) + count++; + } + + /* malloc a structure for each of them */ + if (count != 0) { + ret = calloc(count, sizeof(TSS_KM_KEYINFO)); + if (ret == NULL) { + LogError("malloc of %zd bytes failed.", + (count * sizeof(TSS_KM_KEYINFO))); + count = 0; + result = TCSERR(TSS_E_OUTOFMEMORY); + goto done; + } + } else { + goto done; + } + + /* fill out the structure for each key */ + i = 0; + for (disk_ptr = key_disk_cache_head; disk_ptr; disk_ptr = disk_ptr->next) { + if (disk_ptr->flags & CACHE_FLAG_VALID) { + /* look for a mem cache entry to check if its loaded */ + for (mem_ptr = key_mem_cache_head; mem_ptr; mem_ptr = mem_ptr->next) { + if (!memcmp(&mem_ptr->uuid, &disk_ptr->uuid, sizeof(TSS_UUID))) { + if ((result = fill_key_info(disk_ptr, mem_ptr, &ret[i]))) { + free(ret); + ret = NULL; + count = 0; + goto done; + } + break; + } + } + /* if there is no mem cache entry for this key, go ahead and call + * fill_key_info(), it will pull everything from disk */ + if (mem_ptr == NULL) { + if ((result = fill_key_info(disk_ptr, NULL, &ret[i]))) { + free(ret); + ret = NULL; + count = 0; + goto done; + } + } + i++; + } + } + } else { + /* return a chain of a key and its parents up to the SRK */ + /* determine the number of keys in the chain */ + memcpy(&tmp_uuid, pKeyUUID, sizeof(TSS_UUID)); + disk_ptr = key_disk_cache_head; + while (disk_ptr != NULL && count < MAX_KEY_CHILDREN) + { + if (disk_ptr->flags & CACHE_FLAG_VALID && + !memcmp(&disk_ptr->uuid, &tmp_uuid, sizeof(TSS_UUID))) + { + /* increment count, then search for the parent */ + count++; + /* save a pointer to this cache entry */ + tmp_ptrs[count - 1] = disk_ptr; + /* if the parent of this key is NULL, we're at the root of the tree */ + if (!memcmp(&disk_ptr->parent_uuid, &NULL_UUID, sizeof(TSS_UUID))) + break; + /* overwrite tmp_uuid with the parent, which we will now search for */ + memcpy(&tmp_uuid, &disk_ptr->parent_uuid, sizeof(TSS_UUID)); + disk_ptr = key_disk_cache_head; + continue; + } + disk_ptr = disk_ptr->next; + } + /* when we reach this point, we have an array of TSS_UUID's that leads from the + * requested key up to the SRK*/ + + /* malloc a structure for each of them */ + if (count != 0) { + ret = calloc(count, sizeof(TSS_KM_KEYINFO)); + if (ret == NULL) { + LogError("malloc of %zd bytes failed.", + (count * sizeof(TSS_KM_KEYINFO))); + count = 0; + result = TCSERR(TSS_E_OUTOFMEMORY); + goto done; + } + } else { + goto done; + } + + for (i = 0; i < count; i++) { + /* look for a mem cache entry to check if its loaded */ + for (mem_ptr = key_mem_cache_head; mem_ptr; mem_ptr = mem_ptr->next) { + if (!memcmp(&mem_ptr->uuid, &tmp_ptrs[i]->uuid, sizeof(TSS_UUID))) { + if ((result = fill_key_info(tmp_ptrs[i], mem_ptr, &ret[i]))) { + free(ret); + ret = NULL; + count = 0; + goto done; + } + break; + } + } + /* if there is no mem cache entry for this key, go ahead and call + * fill_key_info(), it will pull everything from disk */ + if (mem_ptr == NULL) { + if ((result = fill_key_info(tmp_ptrs[i], NULL, &ret[i]))) { + free(ret); + ret = NULL; + count = 0; + goto done; + } + } + } + } +done: + + MUTEX_UNLOCK(disk_cache_lock); + MUTEX_UNLOCK(mem_cache_lock); + + *ppKeyHierarchy = ret; + *pcKeyHierarchySize = count; + + return result; +} + +TSS_RESULT +TCS_EnumRegisteredKeys_Internal2(TCS_CONTEXT_HANDLE hContext, /* in */ + TSS_UUID * pKeyUUID, /* in */ + UINT32 * pcKeyHierarchySize, /* out */ + TSS_KM_KEYINFO2 ** ppKeyHierarchy) /* out */ +{ + TSS_RESULT result = TSS_SUCCESS; + UINT32 count = 0, i; + TSS_KM_KEYINFO2 *ret = NULL; + TSS_UUID tmp_uuid; + struct key_disk_cache *disk_ptr, *tmp_ptrs[MAX_KEY_CHILDREN]; + struct key_mem_cache *mem_ptr; + TSS_BOOL is_reg = FALSE; + + LogDebug("Enum Reg Keys2"); + + if (pcKeyHierarchySize == NULL || ppKeyHierarchy == NULL) + return TCSERR(TSS_E_BAD_PARAMETER); + + if ((result = ctx_verify_context(hContext))) + return result; + + if (pKeyUUID != NULL) { + /* First have to verify the key is registered */ + if ((result = isUUIDRegistered(pKeyUUID, &is_reg))) + return result; + + if (is_reg == FALSE) { + /* This return code is not listed as possible in the TSS 1.1 spec, + * but it makes more sense than just TCS_SUCCESS or TSS_E_FAIL */ + return TCSERR(TSS_E_PS_KEY_NOTFOUND); + } + } + + /* this entire operation needs to be atomic wrt registered keys. We must + * lock the mem cache as well to test if a given key is loaded. */ + MUTEX_LOCK(disk_cache_lock); + MUTEX_LOCK(mem_cache_lock); + + /* return an array of all registered keys if pKeyUUID == NULL */ + if (pKeyUUID == NULL) { + /* determine the number of registered keys */ + for (disk_ptr = key_disk_cache_head; disk_ptr; disk_ptr = disk_ptr->next) { + if (disk_ptr->flags & CACHE_FLAG_VALID) + count++; + } + + /* malloc a structure for each of them */ + if (count != 0) { + ret = calloc(count, sizeof(TSS_KM_KEYINFO2)); + if (ret == NULL) { + LogError("malloc of %zd bytes failed.", + (count * sizeof(TSS_KM_KEYINFO2))); + count = 0; + result = TCSERR(TSS_E_OUTOFMEMORY); + goto done; + } + } else { + goto done; + } + + /* fill out the structure for each key */ + i = 0; + for (disk_ptr = key_disk_cache_head; disk_ptr; disk_ptr = disk_ptr->next) { + if (disk_ptr->flags & CACHE_FLAG_VALID) { + /* look for a mem cache entry to check if its loaded */ + for (mem_ptr = key_mem_cache_head; mem_ptr; mem_ptr = mem_ptr->next) { + if (!memcmp(&mem_ptr->uuid, &disk_ptr->uuid, sizeof(TSS_UUID))) { + if ((result = fill_key_info2(disk_ptr, mem_ptr, &ret[i]))) { + free(ret); + ret = NULL; + count = 0; + goto done; + } + break; + } + } + /* if there is no mem cache entry for this key, go ahead and call + * fill_key_info2(), it will pull everything from disk */ + if (mem_ptr == NULL) { + if ((result = fill_key_info2(disk_ptr, NULL, &ret[i]))) { + free(ret); + ret = NULL; + count = 0; + goto done; + } + } + i++; + } + } + } else { + /* return a chain of a key and its parents up to the SRK */ + /* determine the number of keys in the chain */ + memcpy(&tmp_uuid, pKeyUUID, sizeof(TSS_UUID)); + disk_ptr = key_disk_cache_head; + while (disk_ptr != NULL && count < MAX_KEY_CHILDREN) + { + if (disk_ptr->flags & CACHE_FLAG_VALID && + !memcmp(&disk_ptr->uuid, &tmp_uuid, sizeof(TSS_UUID))) + { + /* increment count, then search for the parent */ + count++; + /* save a pointer to this cache entry */ + tmp_ptrs[count - 1] = disk_ptr; + /* if the parent of this key is NULL, we're at the root of the tree */ + if (!memcmp(&disk_ptr->parent_uuid, &NULL_UUID, sizeof(TSS_UUID))) + break; + /* overwrite tmp_uuid with the parent, which we will now search for */ + memcpy(&tmp_uuid, &disk_ptr->parent_uuid, sizeof(TSS_UUID)); + disk_ptr = key_disk_cache_head; + continue; + } + disk_ptr = disk_ptr->next; + } + /* when we reach this point, we have an array of TSS_UUID's that leads from the + * requested key up to the SRK*/ + + /* malloc a structure for each of them */ + if (count != 0) { + ret = calloc(count, sizeof(TSS_KM_KEYINFO2)); + if (ret == NULL) { + LogError("malloc of %zd bytes failed.", + (count * sizeof(TSS_KM_KEYINFO2))); + count = 0; + result = TCSERR(TSS_E_OUTOFMEMORY); + goto done; + } + } else { + goto done; + } + + for (i = 0; i < count; i++) { + /* look for a mem cache entry to check if its loaded */ + for (mem_ptr = key_mem_cache_head; mem_ptr; mem_ptr = mem_ptr->next) { + if (!memcmp(&mem_ptr->uuid, &tmp_ptrs[i]->uuid, sizeof(TSS_UUID))) { + if ((result = fill_key_info2(tmp_ptrs[i], mem_ptr, &ret[i]))) { + free(ret); + ret = NULL; + count = 0; + goto done; + } + break; + } + } + /* if there is no mem cache entry for this key, go ahead and call + * fill_key_info(), it will pull everything from disk */ + if (mem_ptr == NULL) { + if ((result = fill_key_info2(tmp_ptrs[i], NULL, &ret[i]))) { + free(ret); + ret = NULL; + count = 0; + goto done; + } + } + } + } +done: + + MUTEX_UNLOCK(disk_cache_lock); + MUTEX_UNLOCK(mem_cache_lock); + + *ppKeyHierarchy = ret; + *pcKeyHierarchySize = count; + + return result; +} + +TSS_RESULT +TCS_GetRegisteredKey_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ + TSS_UUID *KeyUUID, /* in */ + TSS_KM_KEYINFO ** ppKeyInfo) /* out */ +{ + TSS_RESULT result; + UINT64 offset; + BYTE tcpaKeyBlob[1024]; + TSS_KEY tcpaKey; + UINT16 keySize = sizeof (tcpaKeyBlob); + TSS_UUID parentUUID; + + /* This should be set in case we return before the malloc */ + *ppKeyInfo = NULL; + + if ((result = ctx_verify_context(hContext))) + return result; + + if ((result = ps_get_key_by_uuid(KeyUUID, tcpaKeyBlob, &keySize))) { + return TCSERR(TSS_E_PS_KEY_NOTFOUND); + } + + if ((result = getParentUUIDByUUID(KeyUUID, &parentUUID))) + return TCSERR(TSS_E_FAIL); + + *ppKeyInfo = malloc(sizeof(TSS_KM_KEYINFO)); + if (*ppKeyInfo == NULL) { + LogError("malloc of %zd bytes failed.", sizeof(TSS_KM_KEYINFO)); + return TCSERR(TSS_E_OUTOFMEMORY); + } + + offset = 0; + UnloadBlob_TSS_KEY(&offset, tcpaKeyBlob, &tcpaKey); + + (*ppKeyInfo)->bAuthDataUsage = tcpaKey.authDataUsage; + + (*ppKeyInfo)->fIsLoaded = FALSE; + + if (tcpaKey.hdr.key12.tag == TPM_TAG_KEY12) { + (*ppKeyInfo)->versionInfo.bMajor = TSS_SPEC_MAJOR; + (*ppKeyInfo)->versionInfo.bMinor = TSS_SPEC_MINOR; + (*ppKeyInfo)->versionInfo.bRevMajor = 0; + (*ppKeyInfo)->versionInfo.bRevMinor = 0; + } else { + (*ppKeyInfo)->versionInfo.bMajor = tcpaKey.hdr.key11.ver.major; + (*ppKeyInfo)->versionInfo.bMinor = tcpaKey.hdr.key11.ver.minor; + (*ppKeyInfo)->versionInfo.bRevMajor = tcpaKey.hdr.key11.ver.revMajor; + (*ppKeyInfo)->versionInfo.bRevMinor = tcpaKey.hdr.key11.ver.revMinor; + } + + memcpy(&((*ppKeyInfo)->keyUUID), KeyUUID, sizeof(TSS_UUID)); + + (*ppKeyInfo)->ulVendorDataLength = 0; + (*ppKeyInfo)->rgbVendorData = 0; + + memcpy(&((*ppKeyInfo)->parentKeyUUID), &parentUUID, sizeof(TSS_UUID)); + return TSS_SUCCESS; +} + +TSS_RESULT +TCS_GetRegisteredKeyBlob_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ + TSS_UUID *KeyUUID, /* in */ + UINT32 * pcKeySize, /* out */ + BYTE ** prgbKey) /* out */ +{ + UINT16 keySize; + BYTE buffer[4096]; + TSS_RESULT result; + + if ((result = ctx_verify_context(hContext))) + return result; + + keySize = sizeof(buffer); + if ((result = ps_get_key_by_uuid(KeyUUID, buffer, &keySize))) + return TCSERR(TSS_E_PS_KEY_NOTFOUND); + + *prgbKey = calloc(1, keySize); + if (*prgbKey == NULL) { + LogError("malloc of %d bytes failed.", keySize); + return TCSERR(TSS_E_OUTOFMEMORY); + } else { + memcpy(*prgbKey, buffer, keySize); + } + *pcKeySize = keySize; + + return TSS_SUCCESS; +} + +TSS_RESULT +TCSP_LoadKeyByUUID_Internal(TCS_CONTEXT_HANDLE hContext, /* in */ + TSS_UUID *KeyUUID, /* in */ + TCS_LOADKEY_INFO * pLoadKeyInfo, /* in, out */ + TCS_KEY_HANDLE * phKeyTCSI) /* out */ +{ + UINT32 keyslot = 0, keySize; + UINT32 ordinal; + TSS_RESULT result; + TSS_UUID parentUuid; + BYTE keyBlob[0x1000]; + UINT16 blobSize = sizeof(keyBlob); + UINT64 offset; + TCS_KEY_HANDLE parentTCSKeyHandle; + + if (TPM_VERSION_IS(1,2)) + ordinal = TPM_ORD_LoadKey2; + else + ordinal = TPM_ORD_LoadKey; + + LogDebugFn("Enter: uuid: 0x%lx auth? 0x%x ***********", (unsigned long)KeyUUID, + pLoadKeyInfo == NULL ? 0xdeadbeef : pLoadKeyInfo->authData.AuthHandle); + + if ((result = ctx_verify_context(hContext))) + return result; + + memset(&parentUuid, 0, sizeof(TSS_UUID)); + + if (pLoadKeyInfo && + memcmp(&pLoadKeyInfo->parentKeyUUID, &parentUuid, sizeof(TSS_UUID))) { + if (ps_get_key_by_uuid(&pLoadKeyInfo->keyUUID, keyBlob, &blobSize)) + return TCSERR(TSS_E_PS_KEY_NOTFOUND); + + if (mc_get_handles_by_uuid(&pLoadKeyInfo->parentKeyUUID, &parentTCSKeyHandle, + &keyslot)) + return TCSERR(TCS_E_KM_LOADFAILED); + + return LoadKeyByBlob_Internal(ordinal, hContext, parentTCSKeyHandle, + blobSize, keyBlob, + &pLoadKeyInfo->authData, + phKeyTCSI, &keyslot); + } + + /* if KeyUUID is already loaded, increment the ref count and return */ + if (mc_get_handles_by_uuid(KeyUUID, phKeyTCSI, &keyslot) == TSS_SUCCESS) { + if (keyslot) { + if (ctx_mark_key_loaded(hContext, *phKeyTCSI)) { + LogError("Error marking key as loaded"); + return TCSERR(TSS_E_INTERNAL_ERROR); + } + return TSS_SUCCESS; + } + } + /********************************************************************* + * The first thing to do in this func is setup all the info and make sure + * that we get it all from either the keyfile or the keyCache + * also, it's important to return if the key is already loaded + ***********************************************************************/ + LogDebugFn("calling ps_get_key_by_uuid"); + if (ps_get_key_by_uuid(KeyUUID, keyBlob, &blobSize)) + return TCSERR(TSS_E_PS_KEY_NOTFOUND); + /* convert UINT16 to UIN32 */ + keySize = blobSize; + + LogDebugFn("calling getParentUUIDByUUID"); + /*--- Get my parent's UUID. Since My key is registered, my parent should be as well. */ + if ((result = getParentUUIDByUUID(KeyUUID, &parentUuid))) + return TCSERR(TCS_E_KM_LOADFAILED); + + if ((result = TCSP_LoadKeyByUUID_Internal(hContext, &parentUuid, + pLoadKeyInfo, &parentTCSKeyHandle))) + return result; + + LogDebugFn("calling LoadKeyByBlob_Internal"); + /******************************************************* + * If no errors have happend up till now, then the parent is loaded and ready for use. + * The parent's TCS Handle should be in parentTCSKeyHandle. + ******************************************************/ + if ((result = LoadKeyByBlob_Internal(ordinal, hContext, parentTCSKeyHandle, + keySize, keyBlob, + NULL, + phKeyTCSI, &keyslot))) { + LogDebugFn("LoadKeyByBlob_Internal returned 0x%x", result); + if (result == TCPA_E_AUTHFAIL && pLoadKeyInfo) { + BYTE blob[1000]; + + /* set up a load key info struct */ + memcpy(&pLoadKeyInfo->parentKeyUUID, &parentUuid, sizeof(TSS_UUID)); + memcpy(&pLoadKeyInfo->keyUUID, KeyUUID, sizeof(TSS_UUID)); + + /* calculate the paramDigest */ + offset = 0; + LoadBlob_UINT32(&offset, ordinal, blob); + LoadBlob(&offset, keySize, blob, keyBlob); + if (Hash(TSS_HASH_SHA1, offset, blob, + (BYTE *)&pLoadKeyInfo->paramDigest.digest)) + result = TCSERR(TSS_E_INTERNAL_ERROR); + + result = TCSERR(TCS_E_KM_LOADFAILED); + } + } + + return result; +} + +TSS_RESULT +TCSP_GetRegisteredKeyByPublicInfo_Internal(TCS_CONTEXT_HANDLE tcsContext, /* in */ + TCPA_ALGORITHM_ID algID, /* in */ + UINT32 ulPublicInfoLength, /* in */ + BYTE * rgbPublicInfo, /* in */ + UINT32 * keySize, /* out */ + BYTE ** keyBlob) /* out */ +{ + TCPA_STORE_PUBKEY pubKey; + TSS_RESULT result = TCSERR(TSS_E_FAIL); + + if ((result = ctx_verify_context(tcsContext))) + return result; + + if (algID == TCPA_ALG_RSA) { + /*--- Convert Public info to a structure */ + pubKey.keyLength = ulPublicInfoLength; + pubKey.key = malloc(pubKey.keyLength); + if (pubKey.key == NULL) { + LogError("malloc of %d bytes failed.", pubKey.keyLength); + return TCSERR(TSS_E_OUTOFMEMORY); + } + + memcpy(pubKey.key, rgbPublicInfo, pubKey.keyLength); + + if ((result = ps_get_key_by_pub(&pubKey, keySize, keyBlob))) { + LogDebug("Public key data not found in PS"); + free(pubKey.key); + return TCSERR(TSS_E_PS_KEY_NOTFOUND); + } + } + free(pubKey.key); + + return result; +} |