/* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004-2007 * */ #include #include #include #include #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