summaryrefslogtreecommitdiff
path: root/src/tspi/tspi_ek.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/tspi/tspi_ek.c')
-rw-r--r--src/tspi/tspi_ek.c438
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
+