diff options
Diffstat (limited to 'src/tspi/tspi_ek.c')
-rw-r--r-- | src/tspi/tspi_ek.c | 438 |
1 files changed, 438 insertions, 0 deletions
diff --git a/src/tspi/tspi_ek.c b/src/tspi/tspi_ek.c new file mode 100644 index 0000000..d1b2065 --- /dev/null +++ b/src/tspi/tspi_ek.c @@ -0,0 +1,438 @@ + +/* + * Licensed Materials - Property of IBM + * + * trousers - An open source TCG Software Stack + * + * (C) Copyright International Business Machines Corp. 2004-2007 + * + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <inttypes.h> + +#include "trousers/tss.h" +#include "trousers/trousers.h" +#include "trousers_types.h" +#include "spi_utils.h" +#include "capabilities.h" +#include "tsplog.h" +#include "obj.h" + + +TSS_RESULT +Tspi_TPM_CreateEndorsementKey(TSS_HTPM hTPM, /* in */ + TSS_HKEY hKey, /* in */ + TSS_VALIDATION * pValidationData) /* in, out */ +{ + TCPA_NONCE antiReplay; + TCPA_DIGEST digest; + TSS_RESULT result; + UINT32 ekSize; + BYTE *ek; + TSS_KEY dummyKey; + UINT64 offset; + TCPA_DIGEST hash; + UINT32 newEKSize; + BYTE *newEK; + TSS_HCONTEXT tspContext; + TCPA_PUBKEY pubEK; + Trspi_HashCtx hashCtx; + + memset(&pubEK, 0, sizeof(TCPA_PUBKEY)); + memset(&dummyKey, 0, sizeof(TSS_KEY)); + + if ((result = obj_tpm_get_tsp_context(hTPM, &tspContext))) + return result; + + if ((result = obj_rsakey_get_blob(hKey, &ekSize, &ek))) + return result; + + offset = 0; + if ((result = UnloadBlob_TSS_KEY(&offset, ek, &dummyKey))) + return result; + + offset = 0; + Trspi_LoadBlob_KEY_PARMS(&offset, ek, &dummyKey.algorithmParms); + free_key_refs(&dummyKey); + ekSize = offset; + + if (pValidationData == NULL) { + if ((result = get_local_random(tspContext, FALSE, sizeof(TCPA_NONCE), + (BYTE **)antiReplay.nonce))) { + LogError("Failed to create random nonce"); + return TSPERR(TSS_E_INTERNAL_ERROR); + } + } else { + if (pValidationData->ulExternalDataLength < sizeof(antiReplay.nonce)) + return TSPERR(TSS_E_BAD_PARAMETER); + + memcpy(antiReplay.nonce, pValidationData->rgbExternalData, + sizeof(antiReplay.nonce)); + } + + if ((result = TCS_API(tspContext)->CreateEndorsementKeyPair(tspContext, antiReplay, ekSize, + ek, &newEKSize, &newEK, + &digest))) + return result; + + if (pValidationData == NULL) { + result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); + result |= Trspi_HashUpdate(&hashCtx, newEKSize, newEK); + result |= Trspi_HashUpdate(&hashCtx, TCPA_SHA1_160_HASH_LEN, antiReplay.nonce); + if ((result |= Trspi_HashFinal(&hashCtx, hash.digest))) + goto done; + + if (memcmp(hash.digest, digest.digest, TCPA_SHA1_160_HASH_LEN)) { + LogError("Internal verification failed"); + result = TSPERR(TSS_E_EK_CHECKSUM); + goto done; + } + } else { + pValidationData->rgbData = calloc_tspi(tspContext, newEKSize); + if (pValidationData->rgbData == NULL) { + LogError("malloc of %u bytes failed.", newEKSize); + result = TSPERR(TSS_E_OUTOFMEMORY); + goto done; + } + pValidationData->ulDataLength = newEKSize; + memcpy(pValidationData->rgbData, newEK, newEKSize); + memcpy(&pValidationData->rgbData[ekSize], antiReplay.nonce, + sizeof(antiReplay.nonce)); + + pValidationData->rgbValidationData = calloc_tspi(tspContext, + TCPA_SHA1_160_HASH_LEN); + if (pValidationData->rgbValidationData == NULL) { + LogError("malloc of %d bytes failed.", TCPA_SHA1_160_HASH_LEN); + free_tspi(tspContext, pValidationData->rgbData); + pValidationData->rgbData = NULL; + pValidationData->ulDataLength = 0; + result = TSPERR(TSS_E_OUTOFMEMORY); + goto done; + } + pValidationData->ulValidationDataLength = TCPA_SHA1_160_HASH_LEN; + memcpy(pValidationData->rgbValidationData, digest.digest, TCPA_SHA1_160_HASH_LEN); + } + + if ((result = obj_rsakey_set_pubkey(hKey, FALSE, newEK)) && pValidationData) { + free_tspi(tspContext, pValidationData->rgbValidationData); + free_tspi(tspContext, pValidationData->rgbData); + pValidationData->rgbData = NULL; + pValidationData->ulDataLength = 0; + pValidationData->rgbValidationData = NULL; + pValidationData->ulValidationDataLength = 0; + } + +done: + free(newEK); + + return result; +} + +TSS_RESULT +Tspi_TPM_GetPubEndorsementKey(TSS_HTPM hTPM, /* in */ + TSS_BOOL fOwnerAuthorized, /* in */ + TSS_VALIDATION *pValidationData, /* in, out */ + TSS_HKEY *phEndorsementPubKey) /* out */ +{ + TCPA_DIGEST digest; + TSS_RESULT result; + UINT64 offset; + UINT32 pubEKSize; + BYTE *pubEK; + TCPA_NONCE antiReplay; + TCPA_DIGEST checkSum; + TSS_HOBJECT retKey; + TSS_HCONTEXT tspContext; + TCPA_PUBKEY pubKey; + Trspi_HashCtx hashCtx; + + memset(&pubKey, 0, sizeof(TCPA_PUBKEY)); + + if (phEndorsementPubKey == NULL) + return TSPERR(TSS_E_BAD_PARAMETER); + + if ((result = obj_tpm_get_tsp_context(hTPM, &tspContext))) + return result; + + if (fOwnerAuthorized) + return owner_get_pubek(tspContext, hTPM, phEndorsementPubKey); + + if (pValidationData == NULL) { + if ((result = get_local_random(tspContext, FALSE, sizeof(TCPA_NONCE), + (BYTE **)antiReplay.nonce))) { + LogDebug("Failed to generate random nonce"); + return TSPERR(TSS_E_INTERNAL_ERROR); + } + } else { + if (pValidationData->ulExternalDataLength < sizeof(antiReplay.nonce)) + return TSPERR(TSS_E_BAD_PARAMETER); + + memcpy(antiReplay.nonce, pValidationData->rgbExternalData, + sizeof(antiReplay.nonce)); + } + + /* call down to the TPM */ + if ((result = TCS_API(tspContext)->ReadPubek(tspContext, antiReplay, &pubEKSize, &pubEK, + &checkSum))) + return result; + + /* validate the returned hash, or set up the return so that the user can */ + if (pValidationData == NULL) { + result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); + result |= Trspi_HashUpdate(&hashCtx, pubEKSize, pubEK); + result |= Trspi_HashUpdate(&hashCtx, TPM_SHA1_160_HASH_LEN, antiReplay.nonce); + if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) + goto done; + + /* check validation of the entire pubkey structure */ + if (memcmp(digest.digest, checkSum.digest, TPM_SHA1_160_HASH_LEN)) { + /* validation failed, unload the pubEK in order to hash + * just the pubKey portion of the pubEK. This is done on + * Atmel chips specifically. + */ + offset = 0; + memset(&pubKey, 0, sizeof(TCPA_PUBKEY)); + if ((result = Trspi_UnloadBlob_PUBKEY(&offset, pubEK, &pubKey))) + goto done; + + result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); + result |= Trspi_HashUpdate(&hashCtx, pubKey.pubKey.keyLength, + pubKey.pubKey.key); + result |= Trspi_HashUpdate(&hashCtx, TPM_SHA1_160_HASH_LEN, + antiReplay.nonce); + if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) + goto done; + + if (memcmp(digest.digest, checkSum.digest, TCPA_SHA1_160_HASH_LEN)) { + result = TSPERR(TSS_E_EK_CHECKSUM); + goto done; + } + } + } else { + /* validate the entire TCPA_PUBKEY structure */ + pValidationData->ulDataLength = pubEKSize + TCPA_SHA1_160_HASH_LEN; + pValidationData->rgbData = calloc_tspi(tspContext, + pValidationData->ulDataLength); + if (pValidationData->rgbData == NULL) { + LogError("malloc of %u bytes failed.", + pValidationData->ulDataLength); + pValidationData->ulDataLength = 0; + result = TSPERR(TSS_E_OUTOFMEMORY); + goto done; + } + + memcpy(pValidationData->rgbData, pubEK, pubEKSize); + memcpy(&pValidationData->rgbData[pubEKSize], antiReplay.nonce, + TCPA_SHA1_160_HASH_LEN); + + pValidationData->ulValidationDataLength = TCPA_SHA1_160_HASH_LEN; + pValidationData->rgbValidationData = calloc_tspi(tspContext, + TCPA_SHA1_160_HASH_LEN); + if (pValidationData->rgbValidationData == NULL) { + LogError("malloc of %d bytes failed.", TCPA_SHA1_160_HASH_LEN); + pValidationData->ulValidationDataLength = 0; + pValidationData->ulDataLength = 0; + free_tspi(tspContext,pValidationData->rgbData); + result = TSPERR(TSS_E_OUTOFMEMORY); + goto done; + } + + memcpy(pValidationData->rgbValidationData, checkSum.digest, + TPM_SHA1_160_HASH_LEN); + } + + if ((result = obj_rsakey_add(tspContext, TSS_KEY_SIZE_2048|TSS_KEY_TYPE_LEGACY, &retKey))) + goto done; + + if ((result = obj_rsakey_set_pubkey(retKey, TRUE, pubEK))) + goto done; + + *phEndorsementPubKey = retKey; + +done: + free(pubEK); + return result; +} + +#ifdef TSS_BUILD_TSS12 +TSS_RESULT +Tspi_TPM_CreateRevocableEndorsementKey(TSS_HTPM hTPM, /* in */ + TSS_HKEY hKey, /* in */ + TSS_VALIDATION * pValidationData,/* in, out */ + UINT32 * pulEkResetDataLength, /* in, out */ + BYTE ** prgbEkResetData) /* in, out */ +{ + TPM_NONCE antiReplay; + TPM_DIGEST digest; + TSS_RESULT result; + UINT32 ekSize; + BYTE *ek; + TSS_KEY dummyKey; + UINT64 offset; + TSS_BOOL genResetAuth; + TPM_DIGEST eKResetAuth; + TPM_DIGEST hash; + UINT32 newEKSize; + BYTE *newEK; + TSS_HCONTEXT tspContext; + TPM_PUBKEY pubEK; + Trspi_HashCtx hashCtx; + + memset(&pubEK, 0, sizeof(TPM_PUBKEY)); + memset(&dummyKey, 0, sizeof(TSS_KEY)); + memset(&eKResetAuth, 0xff, sizeof(eKResetAuth)); + + if (!pulEkResetDataLength || !prgbEkResetData) + return TSPERR(TSS_E_BAD_PARAMETER); + + if (*pulEkResetDataLength != 0) { + if (*prgbEkResetData == NULL) + return TSPERR(TSS_E_BAD_PARAMETER); + + if (*pulEkResetDataLength < sizeof(eKResetAuth.digest)) + return TSPERR(TSS_E_BAD_PARAMETER); + + memcpy(eKResetAuth.digest, *prgbEkResetData, sizeof(eKResetAuth.digest)); + genResetAuth = FALSE; + } else { + if (*prgbEkResetData != NULL) + return TSPERR(TSS_E_BAD_PARAMETER); + + genResetAuth = TRUE; + } + + if ((result = obj_tpm_get_tsp_context(hTPM, &tspContext))) + return result; + + if ((result = obj_rsakey_get_blob(hKey, &ekSize, &ek))) + return result; + + offset = 0; + if ((result = UnloadBlob_TSS_KEY(&offset, ek, &dummyKey))) + return result; + + offset = 0; + Trspi_LoadBlob_KEY_PARMS(&offset, ek, &dummyKey.algorithmParms); + free_key_refs(&dummyKey); + ekSize = offset; + + if (pValidationData == NULL) { + if ((result = get_local_random(tspContext, FALSE, sizeof(TPM_NONCE), + (BYTE **)antiReplay.nonce))) { + LogError("Failed to create random nonce"); + return TSPERR(TSS_E_INTERNAL_ERROR); + } + } else { + if (pValidationData->ulExternalDataLength < sizeof(antiReplay.nonce)) + return TSPERR(TSS_E_BAD_PARAMETER); + + memcpy(antiReplay.nonce, pValidationData->rgbExternalData, + sizeof(antiReplay.nonce)); + } + + if ((result = RPC_CreateRevocableEndorsementKeyPair(tspContext, antiReplay, ekSize, ek, + genResetAuth, &eKResetAuth, &newEKSize, + &newEK, &digest))) + return result; + + if (pValidationData == NULL) { + result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1); + result |= Trspi_HashUpdate(&hashCtx, newEKSize, newEK); + result |= Trspi_HashUpdate(&hashCtx, TPM_SHA1_160_HASH_LEN, antiReplay.nonce); + if ((result |= Trspi_HashFinal(&hashCtx, hash.digest))) + goto done; + + if (memcmp(hash.digest, digest.digest, TPM_SHA1_160_HASH_LEN)) { + LogError("Internal verification failed"); + result = TSPERR(TSS_E_EK_CHECKSUM); + goto done; + } + } else { + pValidationData->rgbData = calloc_tspi(tspContext, newEKSize); + if (pValidationData->rgbData == NULL) { + LogError("malloc of %u bytes failed.", newEKSize); + result = TSPERR(TSS_E_OUTOFMEMORY); + goto done; + } + pValidationData->ulDataLength = newEKSize; + memcpy(pValidationData->rgbData, newEK, newEKSize); + memcpy(&pValidationData->rgbData[ekSize], antiReplay.nonce, + sizeof(antiReplay.nonce)); + + pValidationData->rgbValidationData = calloc_tspi(tspContext, + TPM_SHA1_160_HASH_LEN); + if (pValidationData->rgbValidationData == NULL) { + LogError("malloc of %d bytes failed.", TPM_SHA1_160_HASH_LEN); + free_tspi(tspContext, pValidationData->rgbData); + pValidationData->rgbData = NULL; + pValidationData->ulDataLength = 0; + result = TSPERR(TSS_E_OUTOFMEMORY); + goto done; + } + pValidationData->ulValidationDataLength = TPM_SHA1_160_HASH_LEN; + memcpy(pValidationData->rgbValidationData, digest.digest, TPM_SHA1_160_HASH_LEN); + } + + if ((result = obj_rsakey_set_pubkey(hKey, FALSE, newEK))) { + if (pValidationData) { + free_tspi(tspContext, pValidationData->rgbValidationData); + free_tspi(tspContext, pValidationData->rgbData); + pValidationData->rgbData = NULL; + pValidationData->ulDataLength = 0; + pValidationData->rgbValidationData = NULL; + pValidationData->ulValidationDataLength = 0; + } + goto done; + } + + if (genResetAuth) { + if ((*prgbEkResetData = calloc_tspi(tspContext, sizeof(eKResetAuth.digest))) == NULL) { + LogError("malloc of %zd bytes failed.", sizeof(eKResetAuth.digest)); + if (pValidationData) { + free_tspi(tspContext, pValidationData->rgbValidationData); + free_tspi(tspContext, pValidationData->rgbData); + pValidationData->rgbData = NULL; + pValidationData->ulDataLength = 0; + pValidationData->rgbValidationData = NULL; + pValidationData->ulValidationDataLength = 0; + } + goto done; + } + + memcpy(*prgbEkResetData, eKResetAuth.digest, sizeof(eKResetAuth.digest)); + *pulEkResetDataLength = sizeof(eKResetAuth.digest); + } + +done: + free(newEK); + + return result; +} + +TSS_RESULT +Tspi_TPM_RevokeEndorsementKey(TSS_HTPM hTPM, /* in */ + UINT32 ulEkResetDataLength, /* in */ + BYTE * rgbEkResetData) /* in */ +{ + TSS_HCONTEXT tspContext; + TPM_DIGEST eKResetAuth; + TSS_RESULT result; + + if ((result = obj_tpm_get_tsp_context(hTPM, &tspContext))) + return result; + + if (ulEkResetDataLength < sizeof(eKResetAuth.digest) || !rgbEkResetData) + return TSPERR(TSS_E_BAD_PARAMETER); + + memcpy(eKResetAuth.digest, rgbEkResetData, sizeof(eKResetAuth.digest)); + + if ((result = RPC_RevokeEndorsementKeyPair(tspContext, &eKResetAuth))) + return result; + + return result; +} +#endif + |